Skip to content

Commit d52f520

Browse files
author
Benjamin Tissoires
committed
selftests/hid: tablets: move the transitions to PenState
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 <peter.hutterer@who-t.net> Acked-by: Jiri Kosina <jkosina@suse.com> Link: https://lore.kernel.org/r/20231206-wip-selftests-v2-5-c0350c2f5986@kernel.org Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
1 parent b5edacf commit d52f520

1 file changed

Lines changed: 109 additions & 106 deletions

File tree

tools/testing/selftests/hid/tests/test_tablet.py

Lines changed: 109 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -132,104 +132,8 @@ def valid_transitions(self) -> Tuple["PenState", ...]:
132132

133133
return tuple()
134134

135-
136-
class Pen(object):
137-
def __init__(self, x, y):
138-
self.x = x
139-
self.y = y
140-
self.tipswitch = False
141-
self.tippressure = 15
142-
self.azimuth = 0
143-
self.inrange = False
144-
self.width = 10
145-
self.height = 10
146-
self.barrelswitch = False
147-
self.invert = False
148-
self.eraser = False
149-
self.x_tilt = 0
150-
self.y_tilt = 0
151-
self.twist = 0
152-
self._old_values = None
153-
self.current_state = None
154-
155-
def _restore(self):
156-
if self._old_values is not None:
157-
for i in [
158-
"x",
159-
"y",
160-
"tippressure",
161-
"azimuth",
162-
"width",
163-
"height",
164-
"twist",
165-
"x_tilt",
166-
"y_tilt",
167-
]:
168-
setattr(self, i, getattr(self._old_values, i))
169-
170-
def move_to(self, state):
171-
# fill in the previous values
172-
if self.current_state == PenState.PEN_IS_OUT_OF_RANGE:
173-
self._restore()
174-
175-
print(f"\n *** pen is moving to {state} ***")
176-
177-
if state == PenState.PEN_IS_OUT_OF_RANGE:
178-
self._old_values = copy.copy(self)
179-
self.x = 0
180-
self.y = 0
181-
self.tipswitch = False
182-
self.tippressure = 0
183-
self.azimuth = 0
184-
self.inrange = False
185-
self.width = 0
186-
self.height = 0
187-
self.invert = False
188-
self.eraser = False
189-
self.x_tilt = 0
190-
self.y_tilt = 0
191-
self.twist = 0
192-
elif state == PenState.PEN_IS_IN_RANGE:
193-
self.tipswitch = False
194-
self.inrange = True
195-
self.invert = False
196-
self.eraser = False
197-
elif state == PenState.PEN_IS_IN_CONTACT:
198-
self.tipswitch = True
199-
self.inrange = True
200-
self.invert = False
201-
self.eraser = False
202-
elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
203-
self.tipswitch = False
204-
self.inrange = True
205-
self.invert = True
206-
self.eraser = False
207-
elif state == PenState.PEN_IS_ERASING:
208-
self.tipswitch = False
209-
self.inrange = True
210-
self.invert = True
211-
self.eraser = True
212-
213-
self.current_state = state
214-
215-
def __assert_axis(self, evdev, axis, value):
216-
if (
217-
axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
218-
and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
219-
):
220-
return
221-
222-
assert (
223-
evdev.value[axis] == value
224-
), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
225-
226-
def assert_expected_input_events(self, evdev):
227-
assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
228-
assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
229-
assert self.current_state == PenState.from_evdev(evdev)
230-
231135
@staticmethod
232-
def legal_transitions() -> Dict[str, Tuple[PenState, ...]]:
136+
def legal_transitions() -> Dict[str, Tuple["PenState", ...]]:
233137
"""This is the first half of the Windows Pen Implementation state machine:
234138
we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
235139
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
@@ -255,7 +159,7 @@ def legal_transitions() -> Dict[str, Tuple[PenState, ...]]:
255159
}
256160

257161
@staticmethod
258-
def legal_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
162+
def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
259163
"""This is the second half of the Windows Pen Implementation state machine:
260164
we now have Invert and Erase bits, so move in/out or proximity with the intend
261165
to erase.
@@ -293,7 +197,7 @@ def legal_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
293197
}
294198

295199
@staticmethod
296-
def tolerated_transitions() -> Dict[str, Tuple[PenState, ...]]:
200+
def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:
297201
"""This is not adhering to the Windows Pen Implementation state machine
298202
but we should expect the kernel to behave properly, mostly for historical
299203
reasons."""
@@ -306,7 +210,7 @@ def tolerated_transitions() -> Dict[str, Tuple[PenState, ...]]:
306210
}
307211

308212
@staticmethod
309-
def tolerated_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
213+
def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
310214
"""This is the second half of the Windows Pen Implementation state machine:
311215
we now have Invert and Erase bits, so move in/out or proximity with the intend
312216
to erase.
@@ -321,7 +225,7 @@ def tolerated_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
321225
}
322226

323227
@staticmethod
324-
def broken_transitions() -> Dict[str, Tuple[PenState, ...]]:
228+
def broken_transitions() -> Dict[str, Tuple["PenState", ...]]:
325229
"""Those tests are definitely not part of the Windows specification.
326230
However, a half broken device might export those transitions.
327231
For example, a pen that has the eraser button might wobble between
@@ -359,6 +263,102 @@ def broken_transitions() -> Dict[str, Tuple[PenState, ...]]:
359263
}
360264

361265

266+
class Pen(object):
267+
def __init__(self, x, y):
268+
self.x = x
269+
self.y = y
270+
self.tipswitch = False
271+
self.tippressure = 15
272+
self.azimuth = 0
273+
self.inrange = False
274+
self.width = 10
275+
self.height = 10
276+
self.barrelswitch = False
277+
self.invert = False
278+
self.eraser = False
279+
self.x_tilt = 0
280+
self.y_tilt = 0
281+
self.twist = 0
282+
self._old_values = None
283+
self.current_state = None
284+
285+
def _restore(self):
286+
if self._old_values is not None:
287+
for i in [
288+
"x",
289+
"y",
290+
"tippressure",
291+
"azimuth",
292+
"width",
293+
"height",
294+
"twist",
295+
"x_tilt",
296+
"y_tilt",
297+
]:
298+
setattr(self, i, getattr(self._old_values, i))
299+
300+
def move_to(self, state):
301+
# fill in the previous values
302+
if self.current_state == PenState.PEN_IS_OUT_OF_RANGE:
303+
self._restore()
304+
305+
print(f"\n *** pen is moving to {state} ***")
306+
307+
if state == PenState.PEN_IS_OUT_OF_RANGE:
308+
self._old_values = copy.copy(self)
309+
self.x = 0
310+
self.y = 0
311+
self.tipswitch = False
312+
self.tippressure = 0
313+
self.azimuth = 0
314+
self.inrange = False
315+
self.width = 0
316+
self.height = 0
317+
self.invert = False
318+
self.eraser = False
319+
self.x_tilt = 0
320+
self.y_tilt = 0
321+
self.twist = 0
322+
elif state == PenState.PEN_IS_IN_RANGE:
323+
self.tipswitch = False
324+
self.inrange = True
325+
self.invert = False
326+
self.eraser = False
327+
elif state == PenState.PEN_IS_IN_CONTACT:
328+
self.tipswitch = True
329+
self.inrange = True
330+
self.invert = False
331+
self.eraser = False
332+
elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
333+
self.tipswitch = False
334+
self.inrange = True
335+
self.invert = True
336+
self.eraser = False
337+
elif state == PenState.PEN_IS_ERASING:
338+
self.tipswitch = False
339+
self.inrange = True
340+
self.invert = True
341+
self.eraser = True
342+
343+
self.current_state = state
344+
345+
def __assert_axis(self, evdev, axis, value):
346+
if (
347+
axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
348+
and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
349+
):
350+
return
351+
352+
assert (
353+
evdev.value[axis] == value
354+
), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
355+
356+
def assert_expected_input_events(self, evdev):
357+
assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
358+
assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
359+
assert self.current_state == PenState.from_evdev(evdev)
360+
361+
362362
class PenDigitizer(base.UHIDTestDevice):
363363
def __init__(
364364
self,
@@ -486,7 +486,7 @@ def _test_states(self, state_list, scribble):
486486
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
487487
@pytest.mark.parametrize(
488488
"state_list",
489-
[pytest.param(v, id=k) for k, v in Pen.legal_transitions().items()],
489+
[pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],
490490
)
491491
def test_valid_pen_states(self, state_list, scribble):
492492
"""This is the first half of the Windows Pen Implementation state machine:
@@ -498,7 +498,10 @@ def test_valid_pen_states(self, state_list, scribble):
498498
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
499499
@pytest.mark.parametrize(
500500
"state_list",
501-
[pytest.param(v, id=k) for k, v in Pen.tolerated_transitions().items()],
501+
[
502+
pytest.param(v, id=k)
503+
for k, v in PenState.tolerated_transitions().items()
504+
],
502505
)
503506
def test_tolerated_pen_states(self, state_list, scribble):
504507
"""This is not adhering to the Windows Pen Implementation state machine
@@ -515,7 +518,7 @@ def test_tolerated_pen_states(self, state_list, scribble):
515518
"state_list",
516519
[
517520
pytest.param(v, id=k)
518-
for k, v in Pen.legal_transitions_with_invert().items()
521+
for k, v in PenState.legal_transitions_with_invert().items()
519522
],
520523
)
521524
def test_valid_invert_pen_states(self, state_list, scribble):
@@ -535,7 +538,7 @@ def test_valid_invert_pen_states(self, state_list, scribble):
535538
"state_list",
536539
[
537540
pytest.param(v, id=k)
538-
for k, v in Pen.tolerated_transitions_with_invert().items()
541+
for k, v in PenState.tolerated_transitions_with_invert().items()
539542
],
540543
)
541544
def test_tolerated_invert_pen_states(self, state_list, scribble):
@@ -553,7 +556,7 @@ def test_tolerated_invert_pen_states(self, state_list, scribble):
553556
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
554557
@pytest.mark.parametrize(
555558
"state_list",
556-
[pytest.param(v, id=k) for k, v in Pen.broken_transitions().items()],
559+
[pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],
557560
)
558561
def test_tolerated_broken_pen_states(self, state_list, scribble):
559562
"""Those tests are definitely not part of the Windows specification.

0 commit comments

Comments
 (0)