Received: by 2002:a05:7412:b10a:b0:f3:1519:9f41 with SMTP id az10csp813490rdb; Thu, 30 Nov 2023 21:41:54 -0800 (PST) X-Google-Smtp-Source: AGHT+IGTZ2RiWUiiJn7vRbqnRbKNb6sBnWRjGMKznp5HV4sRV/ONmrD7SjerORGzScC8V/cstOTx X-Received: by 2002:a05:6808:130a:b0:3ae:16b6:6338 with SMTP id y10-20020a056808130a00b003ae16b66338mr2311977oiv.3.1701409313915; Thu, 30 Nov 2023 21:41:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1701409313; cv=none; d=google.com; s=arc-20160816; b=ZgzZ5Q3Vj1hTxkiAVyV5jtSGpBSpMA9bV9pKrLM0T32q7Xip882XLuDSk3jDldhLQ7 EN7nodxhFO4bExCLO4vbblByQUXFjhdJsex0mStBsBxn4obDSNtewq/igx4/1Ql0dpgn EfuskwgZd8bdZziQhy+/YdsX77yObBjw6BYkYNiXxLw0JNevVE7Nc+7KS/wCx9OvucgK 2ftwOBefHy2jvD9Qa24Qv2LxRq5RqKF7uDnO3zGzM++OTUfP2kXp+xOqTnPOsBvEES/+ 84sBNUqgRhUTb0KpG3h9jKqAjMDbBNzKUL1+L8p1D0Vbg3quMjq5OSDDfinmTPSTpq6h rBKA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:message-id:subject:cc:to:from:date:feedback-id :dkim-signature:dkim-signature; bh=VIVAGb1X16We2oTan/QFiX0huQNGmn/H7YzOv7YDoas=; fh=gchVU1I5vGzalazuyM1sniQLk+Ai7DLVKJKZL80F+yk=; b=jeDfi3QZMqZ6K5SN9jUeS/IjD+wnemOTxH9aozkybscdZauawHlks7iUTuWO1j3cQv vYxbuZlgMRULKHW5XD5ALQmX6UfFJiyI+je7NNAZToaGkm3LJVHuFxiOSJavDUkEXqR2 hOp6H1haZPE3cKBqLw7o6W2j5EjDdjrPvyVcpXF8unHIARL7hKg8yLsoD/v7E6jDgLF4 JiJ4CQ62q70tK0sIrgKgKvmnVCkb6ef8bwZFpD9g8HgE9lBDiPvtOlM85tUDIUWS846C G1pxLjUo4oOtfsvn7YAyHQCIKvPFvD7rUrSRG60GUoemu42ez45obMzksf4PVmWba6Rs 3PXA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@who-t.net header.s=fm3 header.b=S18Ijh+U; dkim=pass header.i=@messagingengine.com header.s=fm1 header.b=q3QBGAOR; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from agentk.vger.email (agentk.vger.email. [23.128.96.32]) by mx.google.com with ESMTPS id b7-20020a655cc7000000b005b958401e4fsi2809516pgt.418.2023.11.30.21.41.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Nov 2023 21:41:53 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) client-ip=23.128.96.32; Authentication-Results: mx.google.com; dkim=pass header.i=@who-t.net header.s=fm3 header.b=S18Ijh+U; dkim=pass header.i=@messagingengine.com header.s=fm1 header.b=q3QBGAOR; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by agentk.vger.email (Postfix) with ESMTP id 4E535801CE9B; Thu, 30 Nov 2023 21:41:49 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at agentk.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377402AbjLAFlb (ORCPT + 99 others); Fri, 1 Dec 2023 00:41:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53182 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229505AbjLAFl3 (ORCPT ); Fri, 1 Dec 2023 00:41:29 -0500 Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C1A011737; Thu, 30 Nov 2023 21:41:34 -0800 (PST) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 314F45C00B3; Fri, 1 Dec 2023 00:41:34 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Fri, 01 Dec 2023 00:41:34 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h=cc :cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to; s=fm3; t=1701409294; x=1701495694; bh=VI VAGb1X16We2oTan/QFiX0huQNGmn/H7YzOv7YDoas=; b=S18Ijh+UMM6gDVZfuT W86hcOHUunu0QwO2bG4eU7TBOpqVN1tkwOqlcyyCphluWNDVSzwB6f3UCD+Pm8Ig /pE1wYvbbi0ayN5JP6zV/BECvXzuZguYykYuFNxQYFygpSsSdZ/eWUy9U07jUBfZ HbSNYgp1YQWHT0z80dcyPR2+z1uciMdqvvGjaXsc5YA7k83XK3+NRnd8gqXEM0M2 iXVqIfcwwk/M1/Kdlhe8dpCQu3s4WQgoxYG7UpRAUHUtqziphng7JW/oIvGIsX0d zll1RQJVVlooSH9t0yytRPmgRmi4KFUT2hNepYNKRTrDhUK7xsxDfFrDKkpcVhaF z8iQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm1; t=1701409294; x=1701495694; bh=VIVAGb1X16We2 oTan/QFiX0huQNGmn/H7YzOv7YDoas=; b=q3QBGAORBI5++33HEkgkcTR2OaZl9 dWDf8pIsr5yV8pM+0uL5rzx7rtv1V0N+p/LmZ5keFpl/crM4JWP3CtrBnKr4fp3y xjEKTKCVXtvcq3zgVPz2darAskEJJvSjfZnmbWhzsBHgYEskbaXHg5IPTfGSwSvO +ykQObSnLizU4oZAt1J43q2nCaV6z/nw5Wy2mhMURMKJfGh1BAMTZ7BtNvQNhiEp vp92frOSSm/KhpsaM1mua1mxZ3JIq55iMZcBJnnKKMvCnDZcJPZDWQE6l2ilaLEe l4dTheglicggL/lDBpFcCJg4ob9499bB8nD8fwsjTUkO7tAxXRqlpCi0g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvkedrudeikedgkeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepfffhvfevuffkfhggtggujgesthdtredttddtvdenucfhrhhomheprfgvthgv rhcujfhuthhtvghrvghruceophgvthgvrhdrhhhuthhtvghrvghrseifhhhoqdhtrdhnvg htqeenucggtffrrghtthgvrhhnpeffgefgtdegueetffdtkeefveeflefhudeifedvgffh geeiheethfeggfekleelfeenucffohhmrghinhepmhhitghrohhsohhfthdrtghomhenuc evlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehpvghtvghr rdhhuhhtthgvrhgvrhesfihhohdqthdrnhgvth X-ME-Proxy: Feedback-ID: i7ce144cd:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 1 Dec 2023 00:41:30 -0500 (EST) Date: Fri, 1 Dec 2023 15:41:27 +1000 From: Peter Hutterer To: Benjamin Tissoires Cc: Jiri Kosina , Benjamin Tissoires , Shuah Khan , linux-input@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH 09/12] selftests/hid: tablets: add variants of states with buttons Message-ID: <20231201054127.GA626305@quokka> References: <20231129-wip-selftests-v1-0-ba15a1fe1b0d@kernel.org> <20231129-wip-selftests-v1-9-ba15a1fe1b0d@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20231129-wip-selftests-v1-9-ba15a1fe1b0d@kernel.org> X-Spam-Status: No, score=-0.9 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on agentk.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (agentk.vger.email [0.0.0.0]); Thu, 30 Nov 2023 21:41:49 -0800 (PST) On Wed, Nov 29, 2023 at 04:24:34PM +0100, Benjamin Tissoires wrote: > Turns out that there are transitions that are unlikely to happen: > for example, having both the tip switch and a button being changed > at the same time (in the same report) would require either a very talented > and precise user or a very bad hardware with a very low sampling rate. > > So instead of manually building the button test by hand and forgetting > about some cases, let's reuse the state machine and transitions we have. > > This patch only adds the states and the valid transitions. The actual > tests will be replaced later. > > Signed-off-by: Benjamin Tissoires > --- > tools/testing/selftests/hid/tests/test_tablet.py | 170 +++++++++++++++++++++-- > 1 file changed, 157 insertions(+), 13 deletions(-) > > diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py > index 83f6501fe984..80269d1a0f0a 100644 > --- a/tools/testing/selftests/hid/tests/test_tablet.py > +++ b/tools/testing/selftests/hid/tests/test_tablet.py > @@ -21,22 +21,66 @@ logger = logging.getLogger("hidtools.test.tablet") > class PenState(Enum): > """Pen states according to Microsoft reference: > https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states > - """ > > - PEN_IS_OUT_OF_RANGE = (False, None) > - PEN_IS_IN_RANGE = (False, libevdev.EV_KEY.BTN_TOOL_PEN) > - PEN_IS_IN_CONTACT = (True, libevdev.EV_KEY.BTN_TOOL_PEN) > - PEN_IS_IN_RANGE_WITH_ERASING_INTENT = (False, libevdev.EV_KEY.BTN_TOOL_RUBBER) > - PEN_IS_ERASING = (True, libevdev.EV_KEY.BTN_TOOL_RUBBER) > + We extend it with the various buttons when we need to check them. > + """ > > - def __init__(self, touch, tool): It'd be nice to have a comment here what the False refers to. Even nicer would be an enum class BtnTouch.DOWN so the code is instantly readable :) Cheers, Peter > + PEN_IS_OUT_OF_RANGE = (False, None, None) > + PEN_IS_IN_RANGE = (False, libevdev.EV_KEY.BTN_TOOL_PEN, None) > + PEN_IS_IN_RANGE_WITH_BUTTON = ( > + False, > + libevdev.EV_KEY.BTN_TOOL_PEN, > + libevdev.EV_KEY.BTN_STYLUS, > + ) > + PEN_IS_IN_RANGE_WITH_SECOND_BUTTON = ( > + False, > + libevdev.EV_KEY.BTN_TOOL_PEN, > + libevdev.EV_KEY.BTN_STYLUS2, > + ) > + PEN_IS_IN_CONTACT = (True, libevdev.EV_KEY.BTN_TOOL_PEN, None) > + PEN_IS_IN_CONTACT_WITH_BUTTON = ( > + True, > + libevdev.EV_KEY.BTN_TOOL_PEN, > + libevdev.EV_KEY.BTN_STYLUS, > + ) > + PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON = ( > + True, > + libevdev.EV_KEY.BTN_TOOL_PEN, > + libevdev.EV_KEY.BTN_STYLUS2, > + ) > + PEN_IS_IN_RANGE_WITH_ERASING_INTENT = (False, libevdev.EV_KEY.BTN_TOOL_RUBBER, None) > + PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = ( > + False, > + libevdev.EV_KEY.BTN_TOOL_RUBBER, > + libevdev.EV_KEY.BTN_STYLUS, > + ) > + PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_SECOND_BUTTON = ( > + False, > + libevdev.EV_KEY.BTN_TOOL_RUBBER, > + libevdev.EV_KEY.BTN_STYLUS2, > + ) > + PEN_IS_ERASING = (True, libevdev.EV_KEY.BTN_TOOL_RUBBER, None) > + PEN_IS_ERASING_WITH_BUTTON = ( > + True, > + libevdev.EV_KEY.BTN_TOOL_RUBBER, > + libevdev.EV_KEY.BTN_STYLUS, > + ) > + PEN_IS_ERASING_WITH_SECOND_BUTTON = ( > + True, > + libevdev.EV_KEY.BTN_TOOL_RUBBER, > + libevdev.EV_KEY.BTN_STYLUS2, > + ) > + > + def __init__(self, touch, tool, button): > self.touch = touch > self.tool = tool > + self.button = button > > @classmethod > def from_evdev(cls, evdev) -> "PenState": > touch = bool(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) > tool = None > + button = None > if ( > evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] > and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] > @@ -53,7 +97,17 @@ class PenState(Enum): > ): > raise ValueError("2 tools are not allowed") > > - return cls((touch, tool)) > + # we take only the highest button in account > + for b in [libevdev.EV_KEY.BTN_STYLUS, libevdev.EV_KEY.BTN_STYLUS2]: > + if bool(evdev.value[b]): > + button = b > + > + # the kernel tends to insert an EV_SYN once removing the tool, so > + # the button will be released after > + if tool is None: > + button = None > + > + return cls((touch, tool, button)) > > def apply(self, events) -> "PenState": > if libevdev.EV_SYN.SYN_REPORT in events: > @@ -62,6 +116,8 @@ class PenState(Enum): > touch_found = False > tool = self.tool > tool_found = False > + button = self.button > + button_found = False > > for ev in events: > if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH): > @@ -76,12 +132,22 @@ class PenState(Enum): > if tool_found: > raise ValueError(f"duplicated BTN_TOOL_* in {events}") > tool_found = True > - if ev.value: > - tool = ev.code > - else: > - tool = None > + tool = ev.code if ev.value else None > + elif ev in ( > + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS), > + libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2), > + ): > + if button_found: > + raise ValueError(f"duplicated BTN_STYLUS* in {events}") > + button_found = True > + button = ev.code if ev.value else None > > - new_state = PenState((touch, tool)) > + # the kernel tends to insert an EV_SYN once removing the tool, so > + # the button will be released after > + if tool is None: > + button = None > + > + new_state = PenState((touch, tool, button)) > assert ( > new_state in self.valid_transitions() > ), f"moving from {self} to {new_state} is forbidden" > @@ -97,14 +163,20 @@ class PenState(Enum): > return ( > PenState.PEN_IS_OUT_OF_RANGE, > PenState.PEN_IS_IN_RANGE, > + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, > + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, > PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT, > PenState.PEN_IS_IN_CONTACT, > + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, > + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, > PenState.PEN_IS_ERASING, > ) > > if self == PenState.PEN_IS_IN_RANGE: > return ( > PenState.PEN_IS_IN_RANGE, > + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, > + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, > PenState.PEN_IS_OUT_OF_RANGE, > PenState.PEN_IS_IN_CONTACT, > ) > @@ -112,6 +184,8 @@ class PenState(Enum): > if self == PenState.PEN_IS_IN_CONTACT: > return ( > PenState.PEN_IS_IN_CONTACT, > + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, > + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, > PenState.PEN_IS_IN_RANGE, > PenState.PEN_IS_OUT_OF_RANGE, > ) > @@ -130,6 +204,38 @@ class PenState(Enum): > PenState.PEN_IS_OUT_OF_RANGE, > ) > > + if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: > + return ( > + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, > + PenState.PEN_IS_IN_RANGE, > + PenState.PEN_IS_OUT_OF_RANGE, > + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, > + ) > + > + if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: > + return ( > + PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, > + PenState.PEN_IS_IN_CONTACT, > + PenState.PEN_IS_IN_RANGE_WITH_BUTTON, > + PenState.PEN_IS_OUT_OF_RANGE, > + ) > + > + if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: > + return ( > + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, > + PenState.PEN_IS_IN_RANGE, > + PenState.PEN_IS_OUT_OF_RANGE, > + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, > + ) > + > + if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: > + return ( > + PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON, > + PenState.PEN_IS_IN_CONTACT, > + PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON, > + PenState.PEN_IS_OUT_OF_RANGE, > + ) > + > return tuple() > > @staticmethod > @@ -364,26 +470,64 @@ class PenDigitizer(base.UHIDTestDevice): > pen.xtilt = 0 > pen.ytilt = 0 > pen.twist = 0 > + pen.barrelswitch = False > + pen.secondarybarrelswitch = False > elif state == PenState.PEN_IS_IN_RANGE: > pen.tipswitch = False > pen.inrange = True > pen.invert = False > pen.eraser = False > + pen.barrelswitch = False > + pen.secondarybarrelswitch = False > elif state == PenState.PEN_IS_IN_CONTACT: > pen.tipswitch = True > pen.inrange = True > pen.invert = False > pen.eraser = False > + pen.barrelswitch = False > + pen.secondarybarrelswitch = False > + elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON: > + pen.tipswitch = False > + pen.inrange = True > + pen.invert = False > + pen.eraser = False > + pen.barrelswitch = True > + pen.secondarybarrelswitch = False > + elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: > + pen.tipswitch = True > + pen.inrange = True > + pen.invert = False > + pen.eraser = False > + pen.barrelswitch = True > + pen.secondarybarrelswitch = False > + elif state == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: > + pen.tipswitch = False > + pen.inrange = True > + pen.invert = False > + pen.eraser = False > + pen.barrelswitch = False > + pen.secondarybarrelswitch = True > + elif state == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON: > + pen.tipswitch = True > + pen.inrange = True > + pen.invert = False > + pen.eraser = False > + pen.barrelswitch = False > + pen.secondarybarrelswitch = True > elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: > pen.tipswitch = False > pen.inrange = True > pen.invert = True > pen.eraser = False > + pen.barrelswitch = False > + pen.secondarybarrelswitch = False > elif state == PenState.PEN_IS_ERASING: > pen.tipswitch = False > pen.inrange = True > pen.invert = False > pen.eraser = True > + pen.barrelswitch = False > + pen.secondarybarrelswitch = False > > pen.current_state = state > > > -- > 2.41.0 >