From nobody Thu Dec 18 05:08:30 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DBC4EC4167B for ; Wed, 6 Dec 2023 10:46:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377738AbjLFKqp (ORCPT ); Wed, 6 Dec 2023 05:46:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377735AbjLFKqb (ORCPT ); Wed, 6 Dec 2023 05:46:31 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6AED81710 for ; Wed, 6 Dec 2023 02:46:17 -0800 (PST) Received: by smtp.kernel.org (Postfix) with ESMTPSA id E6464C433D9; Wed, 6 Dec 2023 10:46:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1701859577; bh=G76isOTHhVXpWD11gFuYYieLqy+Qq1w644GLBDYxL0E=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Z4nPFDnNWYMrIsi4btVQ5tiwX1Oh9Rrol3runID6mfWpoNLyeJd6Ct9R2E4mJ7tYB dSOcVPNfz45m19lwjXQV/V4rlMFOgxu6J4SJSRe1ztOXziB7PtpnXAv31AjV0rDYaf +mGtYtaP4q4InMbDnDwbmF5PX2jb8jmQNEDQ61neOXn2IZntnG0DZbOml1KnmY7nZG jSf9dv/K3cqZ5oLFCetDk15VvgAdtiL5YnNurs+x22UebGUfzBN7xs2JCs5y4NlGMa rW2d17tE6KFWKtrOfjMom3aIw/lrJY/hC09yUtvEc+rnNqrcNXyOt80Gq/7Q8BLxM1 FE7DjEh3H1k2A== From: Benjamin Tissoires Date: Wed, 06 Dec 2023 11:45:56 +0100 Subject: [PATCH v2 05/15] selftests/hid: tablets: move the transitions to PenState MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20231206-wip-selftests-v2-5-c0350c2f5986@kernel.org> References: <20231206-wip-selftests-v2-0-c0350c2f5986@kernel.org> In-Reply-To: <20231206-wip-selftests-v2-0-c0350c2f5986@kernel.org> To: Jiri Kosina , Benjamin Tissoires , Shuah Khan , Peter Hutterer Cc: linux-input@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Benjamin Tissoires X-Mailer: b4 0.12.4 X-Developer-Signature: v=1; a=ed25519-sha256; t=1701859565; l=11789; i=bentiss@kernel.org; s=20230215; h=from:subject:message-id; bh=G76isOTHhVXpWD11gFuYYieLqy+Qq1w644GLBDYxL0E=; b=aiQ16EfLF7GZKGT93LsDlJ4o49rt0tpbJeeFCXC0cl+eHUA5sjFblKjGMoiKFS9RqXRPKJDlo vmPHsp2dicpDEgepVVv5v8vSScy77DcCB9JVHQKEOzmNGPP/e6r+3X+ X-Developer-Key: i=bentiss@kernel.org; a=ed25519; pk=7D1DyAVh6ajCkuUTudt/chMuXWIJHlv2qCsRkIizvFw= Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Those transitions have nothing to do with `Pen`, so migrate them to `PenState`. The hidden agenda is to remove `Pen` and integrate it into `PenDigitizer` so that we can tweak the events in each state to emulate firmware bugs. Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- no changes in v2 --- tools/testing/selftests/hid/tests/test_tablet.py | 215 ++++++++++++-------= ---- 1 file changed, 109 insertions(+), 106 deletions(-) diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testi= ng/selftests/hid/tests/test_tablet.py index cd9c1269afa6..ddf28c245046 100644 --- a/tools/testing/selftests/hid/tests/test_tablet.py +++ b/tools/testing/selftests/hid/tests/test_tablet.py @@ -132,104 +132,8 @@ class PenState(Enum): =20 return tuple() =20 - -class Pen(object): - def __init__(self, x, y): - self.x =3D x - self.y =3D y - self.tipswitch =3D False - self.tippressure =3D 15 - self.azimuth =3D 0 - self.inrange =3D False - self.width =3D 10 - self.height =3D 10 - self.barrelswitch =3D False - self.invert =3D False - self.eraser =3D False - self.x_tilt =3D 0 - self.y_tilt =3D 0 - self.twist =3D 0 - self._old_values =3D None - self.current_state =3D None - - def _restore(self): - if self._old_values is not None: - for i in [ - "x", - "y", - "tippressure", - "azimuth", - "width", - "height", - "twist", - "x_tilt", - "y_tilt", - ]: - setattr(self, i, getattr(self._old_values, i)) - - def move_to(self, state): - # fill in the previous values - if self.current_state =3D=3D PenState.PEN_IS_OUT_OF_RANGE: - self._restore() - - print(f"\n *** pen is moving to {state} ***") - - if state =3D=3D PenState.PEN_IS_OUT_OF_RANGE: - self._old_values =3D copy.copy(self) - self.x =3D 0 - self.y =3D 0 - self.tipswitch =3D False - self.tippressure =3D 0 - self.azimuth =3D 0 - self.inrange =3D False - self.width =3D 0 - self.height =3D 0 - self.invert =3D False - self.eraser =3D False - self.x_tilt =3D 0 - self.y_tilt =3D 0 - self.twist =3D 0 - elif state =3D=3D PenState.PEN_IS_IN_RANGE: - self.tipswitch =3D False - self.inrange =3D True - self.invert =3D False - self.eraser =3D False - elif state =3D=3D PenState.PEN_IS_IN_CONTACT: - self.tipswitch =3D True - self.inrange =3D True - self.invert =3D False - self.eraser =3D False - elif state =3D=3D PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: - self.tipswitch =3D False - self.inrange =3D True - self.invert =3D True - self.eraser =3D False - elif state =3D=3D PenState.PEN_IS_ERASING: - self.tipswitch =3D False - self.inrange =3D True - self.invert =3D True - self.eraser =3D True - - self.current_state =3D state - - def __assert_axis(self, evdev, axis, value): - if ( - axis =3D=3D libevdev.EV_KEY.BTN_TOOL_RUBBER - and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None - ): - return - - assert ( - evdev.value[axis] =3D=3D value - ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) !=3D {value}" - - def assert_expected_input_events(self, evdev): - assert evdev.value[libevdev.EV_ABS.ABS_X] =3D=3D self.x - assert evdev.value[libevdev.EV_ABS.ABS_Y] =3D=3D self.y - assert self.current_state =3D=3D PenState.from_evdev(evdev) - @staticmethod - def legal_transitions() -> Dict[str, Tuple[PenState, ...]]: + def legal_transitions() -> Dict[str, Tuple["PenState", ...]]: """This is the first half of the Windows Pen Implementation state = machine: we don't have Invert nor Erase bits, so just move in/out-of-range = or proximity. https://docs.microsoft.com/en-us/windows-hardware/design/component= -guidelines/windows-pen-states @@ -255,7 +159,7 @@ class Pen(object): } =20 @staticmethod - def legal_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]: + def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...= ]]: """This is the second half of the Windows Pen Implementation state= machine: we now have Invert and Erase bits, so move in/out or proximity wit= h the intend to erase. @@ -293,7 +197,7 @@ class Pen(object): } =20 @staticmethod - def tolerated_transitions() -> Dict[str, Tuple[PenState, ...]]: + def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]: """This is not adhering to the Windows Pen Implementation state ma= chine but we should expect the kernel to behave properly, mostly for his= torical reasons.""" @@ -306,7 +210,7 @@ class Pen(object): } =20 @staticmethod - def tolerated_transitions_with_invert() -> Dict[str, Tuple[PenState, .= ..]]: + def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState",= ...]]: """This is the second half of the Windows Pen Implementation state= machine: we now have Invert and Erase bits, so move in/out or proximity wit= h the intend to erase. @@ -321,7 +225,7 @@ class Pen(object): } =20 @staticmethod - def broken_transitions() -> Dict[str, Tuple[PenState, ...]]: + def broken_transitions() -> Dict[str, Tuple["PenState", ...]]: """Those tests are definitely not part of the Windows specificatio= n. However, a half broken device might export those transitions. For example, a pen that has the eraser button might wobble between @@ -359,6 +263,102 @@ class Pen(object): } =20 =20 +class Pen(object): + def __init__(self, x, y): + self.x =3D x + self.y =3D y + self.tipswitch =3D False + self.tippressure =3D 15 + self.azimuth =3D 0 + self.inrange =3D False + self.width =3D 10 + self.height =3D 10 + self.barrelswitch =3D False + self.invert =3D False + self.eraser =3D False + self.x_tilt =3D 0 + self.y_tilt =3D 0 + self.twist =3D 0 + self._old_values =3D None + self.current_state =3D None + + def _restore(self): + if self._old_values is not None: + for i in [ + "x", + "y", + "tippressure", + "azimuth", + "width", + "height", + "twist", + "x_tilt", + "y_tilt", + ]: + setattr(self, i, getattr(self._old_values, i)) + + def move_to(self, state): + # fill in the previous values + if self.current_state =3D=3D PenState.PEN_IS_OUT_OF_RANGE: + self._restore() + + print(f"\n *** pen is moving to {state} ***") + + if state =3D=3D PenState.PEN_IS_OUT_OF_RANGE: + self._old_values =3D copy.copy(self) + self.x =3D 0 + self.y =3D 0 + self.tipswitch =3D False + self.tippressure =3D 0 + self.azimuth =3D 0 + self.inrange =3D False + self.width =3D 0 + self.height =3D 0 + self.invert =3D False + self.eraser =3D False + self.x_tilt =3D 0 + self.y_tilt =3D 0 + self.twist =3D 0 + elif state =3D=3D PenState.PEN_IS_IN_RANGE: + self.tipswitch =3D False + self.inrange =3D True + self.invert =3D False + self.eraser =3D False + elif state =3D=3D PenState.PEN_IS_IN_CONTACT: + self.tipswitch =3D True + self.inrange =3D True + self.invert =3D False + self.eraser =3D False + elif state =3D=3D PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT: + self.tipswitch =3D False + self.inrange =3D True + self.invert =3D True + self.eraser =3D False + elif state =3D=3D PenState.PEN_IS_ERASING: + self.tipswitch =3D False + self.inrange =3D True + self.invert =3D True + self.eraser =3D True + + self.current_state =3D state + + def __assert_axis(self, evdev, axis, value): + if ( + axis =3D=3D libevdev.EV_KEY.BTN_TOOL_RUBBER + and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None + ): + return + + assert ( + evdev.value[axis] =3D=3D value + ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) !=3D {value}" + + def assert_expected_input_events(self, evdev): + assert evdev.value[libevdev.EV_ABS.ABS_X] =3D=3D self.x + assert evdev.value[libevdev.EV_ABS.ABS_Y] =3D=3D self.y + assert self.current_state =3D=3D PenState.from_evdev(evdev) + + class PenDigitizer(base.UHIDTestDevice): def __init__( self, @@ -486,7 +486,7 @@ class BaseTest: @pytest.mark.parametrize("scribble", [True, False], ids=3D["scribb= le", "static"]) @pytest.mark.parametrize( "state_list", - [pytest.param(v, id=3Dk) for k, v in Pen.legal_transitions().i= tems()], + [pytest.param(v, id=3Dk) for k, v in PenState.legal_transition= s().items()], ) def test_valid_pen_states(self, state_list, scribble): """This is the first half of the Windows Pen Implementation st= ate machine: @@ -498,7 +498,10 @@ class BaseTest: @pytest.mark.parametrize("scribble", [True, False], ids=3D["scribb= le", "static"]) @pytest.mark.parametrize( "state_list", - [pytest.param(v, id=3Dk) for k, v in Pen.tolerated_transitions= ().items()], + [ + pytest.param(v, id=3Dk) + for k, v in PenState.tolerated_transitions().items() + ], ) def test_tolerated_pen_states(self, state_list, scribble): """This is not adhering to the Windows Pen Implementation stat= e machine @@ -515,7 +518,7 @@ class BaseTest: "state_list", [ pytest.param(v, id=3Dk) - for k, v in Pen.legal_transitions_with_invert().items() + for k, v in PenState.legal_transitions_with_invert().items= () ], ) def test_valid_invert_pen_states(self, state_list, scribble): @@ -535,7 +538,7 @@ class BaseTest: "state_list", [ pytest.param(v, id=3Dk) - for k, v in Pen.tolerated_transitions_with_invert().items() + for k, v in PenState.tolerated_transitions_with_invert().i= tems() ], ) def test_tolerated_invert_pen_states(self, state_list, scribble): @@ -553,7 +556,7 @@ class BaseTest: @pytest.mark.parametrize("scribble", [True, False], ids=3D["scribb= le", "static"]) @pytest.mark.parametrize( "state_list", - [pytest.param(v, id=3Dk) for k, v in Pen.broken_transitions().= items()], + [pytest.param(v, id=3Dk) for k, v in PenState.broken_transitio= ns().items()], ) def test_tolerated_broken_pen_states(self, state_list, scribble): """Those tests are definitely not part of the Windows specific= ation. --=20 2.41.0