Commit e14d88d9 authored by Benjamin Tissoires's avatar Benjamin Tissoires

selftests/hid: tablets: reduce the number of pen state

All the *_WITH*BUTTON states were almost identical except for the
button itself.

I need to add a new device with a third button, and adding a bunch of
states is going to be quite cumbersome.

So convert the `button` parameter of PenState as a boolean, and store
which button is the target as an argument to all functions that need it.

Link: https://lore.kernel.org/r/20240410-bpf_sources-v1-12-a8bf16033ef8@kernel.orgReviewed-by: default avatarPeter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
parent e9064630
...@@ -44,58 +44,28 @@ class PenState(Enum): ...@@ -44,58 +44,28 @@ class PenState(Enum):
We extend it with the various buttons when we need to check them. We extend it with the various buttons when we need to check them.
""" """
PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, None PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, False
PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, None PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, False
PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, BtnPressed.PRIMARY_PRESSED PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, True
PEN_IS_IN_RANGE_WITH_SECOND_BUTTON = ( PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, False
BtnTouch.UP, PEN_IS_IN_CONTACT_WITH_BUTTON = BtnTouch.DOWN, ToolType.PEN, True
ToolType.PEN, PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, False
BtnPressed.SECONDARY_PRESSED, PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = BtnTouch.UP, ToolType.RUBBER, True
) PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, False
PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, None PEN_IS_ERASING_WITH_BUTTON = BtnTouch.DOWN, ToolType.RUBBER, True
PEN_IS_IN_CONTACT_WITH_BUTTON = (
BtnTouch.DOWN, def __init__(
ToolType.PEN, self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[bool]
BtnPressed.PRIMARY_PRESSED, ):
)
PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON = (
BtnTouch.DOWN,
ToolType.PEN,
BtnPressed.SECONDARY_PRESSED,
)
PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, None
PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = (
BtnTouch.UP,
ToolType.RUBBER,
BtnPressed.PRIMARY_PRESSED,
)
PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_SECOND_BUTTON = (
BtnTouch.UP,
ToolType.RUBBER,
BtnPressed.SECONDARY_PRESSED,
)
PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, None
PEN_IS_ERASING_WITH_BUTTON = (
BtnTouch.DOWN,
ToolType.RUBBER,
BtnPressed.PRIMARY_PRESSED,
)
PEN_IS_ERASING_WITH_SECOND_BUTTON = (
BtnTouch.DOWN,
ToolType.RUBBER,
BtnPressed.SECONDARY_PRESSED,
)
def __init__(self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[BtnPressed]):
self.touch = touch # type: ignore self.touch = touch # type: ignore
self.tool = tool # type: ignore self.tool = tool # type: ignore
self.button = button # type: ignore self.button = button # type: ignore
@classmethod @classmethod
def from_evdev(cls, evdev) -> "PenState": def from_evdev(cls, evdev, test_button) -> "PenState":
touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH]) touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])
tool = None tool = None
button = None button = False
if ( if (
evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN] and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
...@@ -112,19 +82,20 @@ class PenState(Enum): ...@@ -112,19 +82,20 @@ class PenState(Enum):
): ):
raise ValueError("2 tools are not allowed") raise ValueError("2 tools are not allowed")
# we take only the highest button in account # we take only the provided button into account
for b in [libevdev.EV_KEY.BTN_STYLUS, libevdev.EV_KEY.BTN_STYLUS2]: if test_button is not None:
if bool(evdev.value[b]): button = bool(evdev.value[test_button.value])
button = BtnPressed(b)
# the kernel tends to insert an EV_SYN once removing the tool, so # the kernel tends to insert an EV_SYN once removing the tool, so
# the button will be released after # the button will be released after
if tool is None: if tool is None:
button = None button = False
return cls((touch, tool, button)) # type: ignore return cls((touch, tool, button)) # type: ignore
def apply(self, events: List[libevdev.InputEvent], strict: bool) -> "PenState": def apply(
self, events: List[libevdev.InputEvent], strict: bool, test_button: BtnPressed
) -> "PenState":
if libevdev.EV_SYN.SYN_REPORT in events: if libevdev.EV_SYN.SYN_REPORT in events:
raise ValueError("EV_SYN is in the event sequence") raise ValueError("EV_SYN is in the event sequence")
touch = self.touch touch = self.touch
...@@ -148,19 +119,16 @@ class PenState(Enum): ...@@ -148,19 +119,16 @@ class PenState(Enum):
raise ValueError(f"duplicated BTN_TOOL_* in {events}") raise ValueError(f"duplicated BTN_TOOL_* in {events}")
tool_found = True tool_found = True
tool = ToolType(ev.code) if ev.value else None tool = ToolType(ev.code) if ev.value else None
elif ev in ( elif test_button is not None and ev in (test_button.value,):
libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS),
libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2),
):
if button_found: if button_found:
raise ValueError(f"duplicated BTN_STYLUS* in {events}") raise ValueError(f"duplicated BTN_STYLUS* in {events}")
button_found = True button_found = True
button = BtnPressed(ev.code) if ev.value else None button = bool(ev.value)
# the kernel tends to insert an EV_SYN once removing the tool, so # the kernel tends to insert an EV_SYN once removing the tool, so
# the button will be released after # the button will be released after
if tool is None: if tool is None:
button = None button = False
new_state = PenState((touch, tool, button)) # type: ignore new_state = PenState((touch, tool, button)) # type: ignore
if strict: if strict:
...@@ -183,11 +151,9 @@ class PenState(Enum): ...@@ -183,11 +151,9 @@ class PenState(Enum):
PenState.PEN_IS_OUT_OF_RANGE, PenState.PEN_IS_OUT_OF_RANGE,
PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 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_RANGE_WITH_ERASING_INTENT,
PenState.PEN_IS_IN_CONTACT, PenState.PEN_IS_IN_CONTACT,
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_ERASING, PenState.PEN_IS_ERASING,
) )
...@@ -195,7 +161,6 @@ class PenState(Enum): ...@@ -195,7 +161,6 @@ class PenState(Enum):
return ( return (
PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_BUTTON, PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_OUT_OF_RANGE, PenState.PEN_IS_OUT_OF_RANGE,
PenState.PEN_IS_IN_CONTACT, PenState.PEN_IS_IN_CONTACT,
) )
...@@ -204,7 +169,6 @@ class PenState(Enum): ...@@ -204,7 +169,6 @@ class PenState(Enum):
return ( return (
PenState.PEN_IS_IN_CONTACT, PenState.PEN_IS_IN_CONTACT,
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_RANGE,
) )
...@@ -236,21 +200,6 @@ class PenState(Enum): ...@@ -236,21 +200,6 @@ class PenState(Enum):
PenState.PEN_IS_IN_RANGE_WITH_BUTTON, PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
) )
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,
)
return tuple() return tuple()
def historically_tolerated_transitions(self) -> Tuple["PenState", ...]: def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:
...@@ -263,11 +212,9 @@ class PenState(Enum): ...@@ -263,11 +212,9 @@ class PenState(Enum):
PenState.PEN_IS_OUT_OF_RANGE, PenState.PEN_IS_OUT_OF_RANGE,
PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_BUTTON, 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_RANGE_WITH_ERASING_INTENT,
PenState.PEN_IS_IN_CONTACT, PenState.PEN_IS_IN_CONTACT,
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_ERASING, PenState.PEN_IS_ERASING,
) )
...@@ -275,7 +222,6 @@ class PenState(Enum): ...@@ -275,7 +222,6 @@ class PenState(Enum):
return ( return (
PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_BUTTON, PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_OUT_OF_RANGE, PenState.PEN_IS_OUT_OF_RANGE,
PenState.PEN_IS_IN_CONTACT, PenState.PEN_IS_IN_CONTACT,
) )
...@@ -284,7 +230,6 @@ class PenState(Enum): ...@@ -284,7 +230,6 @@ class PenState(Enum):
return ( return (
PenState.PEN_IS_IN_CONTACT, PenState.PEN_IS_IN_CONTACT,
PenState.PEN_IS_IN_CONTACT_WITH_BUTTON, PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE, PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_OUT_OF_RANGE, PenState.PEN_IS_OUT_OF_RANGE,
) )
...@@ -319,22 +264,6 @@ class PenState(Enum): ...@@ -319,22 +264,6 @@ class PenState(Enum):
PenState.PEN_IS_OUT_OF_RANGE, 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() return tuple()
@staticmethod @staticmethod
...@@ -402,9 +331,9 @@ class PenState(Enum): ...@@ -402,9 +331,9 @@ class PenState(Enum):
} }
@staticmethod @staticmethod
def legal_transitions_with_primary_button() -> Dict[str, Tuple["PenState", ...]]: def legal_transitions_with_button() -> Dict[str, Tuple["PenState", ...]]:
"""We revisit the Windows Pen Implementation state machine: """We revisit the Windows Pen Implementation state machine:
we now have a primary button. we now have a button.
""" """
return { return {
"hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,), "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,),
...@@ -450,56 +379,6 @@ class PenState(Enum): ...@@ -450,56 +379,6 @@ class PenState(Enum):
), ),
} }
@staticmethod
def legal_transitions_with_secondary_button() -> Dict[str, Tuple["PenState", ...]]:
"""We revisit the Windows Pen Implementation state machine:
we now have a secondary button.
Note: we don't looks for 2 buttons interactions.
"""
return {
"hover-button": (PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,),
"hover-button -> out-of-range": (
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_OUT_OF_RANGE,
),
"in-range -> button-press": (
PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
),
"in-range -> button-press -> button-release": (
PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE,
),
"in-range -> touch -> button-press -> button-release": (
PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_CONTACT,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_CONTACT,
),
"in-range -> touch -> button-press -> release -> button-release": (
PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_CONTACT,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE,
),
"in-range -> button-press -> touch -> release -> button-release": (
PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE,
),
"in-range -> button-press -> touch -> button-release -> release": (
PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_CONTACT,
PenState.PEN_IS_IN_RANGE,
),
}
@staticmethod @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 machine """This is not adhering to the Windows Pen Implementation state machine
...@@ -616,10 +495,21 @@ class Pen(object): ...@@ -616,10 +495,21 @@ class Pen(object):
evdev.value[axis] == value evdev.value[axis] == value
), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}" ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
def assert_expected_input_events(self, evdev): def assert_expected_input_events(self, evdev, button):
assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
assert self.current_state == PenState.from_evdev(evdev)
# assert no other buttons than the tested ones are set
buttons = [
BtnPressed.PRIMARY_PRESSED,
BtnPressed.SECONDARY_PRESSED,
]
if button is not None:
buttons.remove(button)
for b in buttons:
assert evdev.value[b.value] is None or evdev.value[b.value] == False
assert self.current_state == PenState.from_evdev(evdev, button)
class PenDigitizer(base.UHIDTestDevice): class PenDigitizer(base.UHIDTestDevice):
...@@ -647,7 +537,7 @@ class PenDigitizer(base.UHIDTestDevice): ...@@ -647,7 +537,7 @@ class PenDigitizer(base.UHIDTestDevice):
continue continue
self.fields = [f.usage_name for f in r] self.fields = [f.usage_name for f in r]
def move_to(self, pen, state): def move_to(self, pen, state, button):
# fill in the previous values # fill in the previous values
if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE: if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
pen.restore() pen.restore()
...@@ -690,29 +580,17 @@ class PenDigitizer(base.UHIDTestDevice): ...@@ -690,29 +580,17 @@ class PenDigitizer(base.UHIDTestDevice):
pen.inrange = True pen.inrange = True
pen.invert = False pen.invert = False
pen.eraser = False pen.eraser = False
pen.barrelswitch = True assert button is not None
pen.secondarybarrelswitch = False pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON: elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
pen.tipswitch = True pen.tipswitch = True
pen.inrange = True pen.inrange = True
pen.invert = False pen.invert = False
pen.eraser = False pen.eraser = False
pen.barrelswitch = True assert button is not None
pen.secondarybarrelswitch = False pen.barrelswitch = button == BtnPressed.PRIMARY_PRESSED
elif state == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON: pen.secondarybarrelswitch = button == BtnPressed.SECONDARY_PRESSED
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: elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
pen.tipswitch = False pen.tipswitch = False
pen.inrange = True pen.inrange = True
...@@ -730,7 +608,7 @@ class PenDigitizer(base.UHIDTestDevice): ...@@ -730,7 +608,7 @@ class PenDigitizer(base.UHIDTestDevice):
pen.current_state = state pen.current_state = state
def event(self, pen): def event(self, pen, button):
rs = [] rs = []
r = self.create_report(application=self.cur_application, data=pen) r = self.create_report(application=self.cur_application, data=pen)
self.call_input_event(r) self.call_input_event(r)
...@@ -771,17 +649,17 @@ class BaseTest: ...@@ -771,17 +649,17 @@ class BaseTest:
def create_device(self): def create_device(self):
raise Exception("please reimplement me in subclasses") raise Exception("please reimplement me in subclasses")
def post(self, uhdev, pen): def post(self, uhdev, pen, test_button):
r = uhdev.event(pen) r = uhdev.event(pen, test_button)
events = uhdev.next_sync_events() events = uhdev.next_sync_events()
self.debug_reports(r, uhdev, events) self.debug_reports(r, uhdev, events)
return events return events
def validate_transitions( def validate_transitions(
self, from_state, pen, evdev, events, allow_intermediate_states self, from_state, pen, evdev, events, allow_intermediate_states, button
): ):
# check that the final state is correct # check that the final state is correct
pen.assert_expected_input_events(evdev) pen.assert_expected_input_events(evdev, button)
state = from_state state = from_state
...@@ -794,12 +672,14 @@ class BaseTest: ...@@ -794,12 +672,14 @@ class BaseTest:
events = events[idx + 1 :] events = events[idx + 1 :]
# now check for a valid transition # now check for a valid transition
state = state.apply(sync_events, not allow_intermediate_states) state = state.apply(sync_events, not allow_intermediate_states, button)
if events: if events:
state = state.apply(sync_events, not allow_intermediate_states) state = state.apply(sync_events, not allow_intermediate_states, button)
def _test_states(self, state_list, scribble, allow_intermediate_states): def _test_states(
self, state_list, scribble, allow_intermediate_states, button=None
):
"""Internal method to test against a list of """Internal method to test against a list of
transition between states. transition between states.
state_list is a list of PenState objects state_list is a list of PenState objects
...@@ -812,10 +692,10 @@ class BaseTest: ...@@ -812,10 +692,10 @@ class BaseTest:
cur_state = PenState.PEN_IS_OUT_OF_RANGE cur_state = PenState.PEN_IS_OUT_OF_RANGE
p = Pen(50, 60) p = Pen(50, 60)
uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE) uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE, button)
events = self.post(uhdev, p) events = self.post(uhdev, p, button)
self.validate_transitions( self.validate_transitions(
cur_state, p, evdev, events, allow_intermediate_states cur_state, p, evdev, events, allow_intermediate_states, button
) )
cur_state = p.current_state cur_state = p.current_state
...@@ -824,18 +704,18 @@ class BaseTest: ...@@ -824,18 +704,18 @@ class BaseTest:
if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE: if scribble and cur_state != PenState.PEN_IS_OUT_OF_RANGE:
p.x += 1 p.x += 1
p.y -= 1 p.y -= 1
events = self.post(uhdev, p) events = self.post(uhdev, p, button)
self.validate_transitions( self.validate_transitions(
cur_state, p, evdev, events, allow_intermediate_states cur_state, p, evdev, events, allow_intermediate_states, button
) )
assert len(events) >= 3 # X, Y, SYN assert len(events) >= 3 # X, Y, SYN
uhdev.move_to(p, state) uhdev.move_to(p, state, button)
if scribble and state != PenState.PEN_IS_OUT_OF_RANGE: if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:
p.x += 1 p.x += 1
p.y -= 1 p.y -= 1
events = self.post(uhdev, p) events = self.post(uhdev, p, button)
self.validate_transitions( self.validate_transitions(
cur_state, p, evdev, events, allow_intermediate_states cur_state, p, evdev, events, allow_intermediate_states, button
) )
cur_state = p.current_state cur_state = p.current_state
...@@ -874,12 +754,17 @@ class BaseTest: ...@@ -874,12 +754,17 @@ class BaseTest:
"state_list", "state_list",
[ [
pytest.param(v, id=k) pytest.param(v, id=k)
for k, v in PenState.legal_transitions_with_primary_button().items() for k, v in PenState.legal_transitions_with_button().items()
], ],
) )
def test_valid_primary_button_pen_states(self, state_list, scribble): def test_valid_primary_button_pen_states(self, state_list, scribble):
"""Rework the transition state machine by adding the primary button.""" """Rework the transition state machine by adding the primary button."""
self._test_states(state_list, scribble, allow_intermediate_states=False) self._test_states(
state_list,
scribble,
allow_intermediate_states=False,
button=BtnPressed.PRIMARY_PRESSED,
)
@pytest.mark.skip_if_uhdev( @pytest.mark.skip_if_uhdev(
lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields, lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,
...@@ -890,12 +775,17 @@ class BaseTest: ...@@ -890,12 +775,17 @@ class BaseTest:
"state_list", "state_list",
[ [
pytest.param(v, id=k) pytest.param(v, id=k)
for k, v in PenState.legal_transitions_with_secondary_button().items() for k, v in PenState.legal_transitions_with_button().items()
], ],
) )
def test_valid_secondary_button_pen_states(self, state_list, scribble): def test_valid_secondary_button_pen_states(self, state_list, scribble):
"""Rework the transition state machine by adding the secondary button.""" """Rework the transition state machine by adding the secondary button."""
self._test_states(state_list, scribble, allow_intermediate_states=False) self._test_states(
state_list,
scribble,
allow_intermediate_states=False,
button=BtnPressed.SECONDARY_PRESSED,
)
@pytest.mark.skip_if_uhdev( @pytest.mark.skip_if_uhdev(
lambda uhdev: "Invert" not in uhdev.fields, lambda uhdev: "Invert" not in uhdev.fields,
...@@ -956,7 +846,7 @@ class BaseTest: ...@@ -956,7 +846,7 @@ class BaseTest:
class GXTP_pen(PenDigitizer): class GXTP_pen(PenDigitizer):
def event(self, pen): def event(self, pen, test_button):
if not hasattr(self, "prev_tip_state"): if not hasattr(self, "prev_tip_state"):
self.prev_tip_state = False self.prev_tip_state = False
...@@ -977,7 +867,7 @@ class GXTP_pen(PenDigitizer): ...@@ -977,7 +867,7 @@ class GXTP_pen(PenDigitizer):
if pen.eraser: if pen.eraser:
internal_pen.invert = False internal_pen.invert = False
return super().event(internal_pen) return super().event(internal_pen, test_button)
class USIPen(PenDigitizer): class USIPen(PenDigitizer):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment