@@ -317,6 +317,55 @@ def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
317317 ),
318318 }
319319
320+ @staticmethod
321+ def legal_transitions_with_primary_button () -> Dict [str , Tuple ["PenState" , ...]]:
322+ """We revisit the Windows Pen Implementation state machine:
323+ we now have a primary button.
324+ """
325+ return {
326+ "hover-button" : (PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,),
327+ "hover-button -> out-of-range" : (
328+ PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,
329+ PenState .PEN_IS_OUT_OF_RANGE ,
330+ ),
331+ "in-range -> button-press" : (
332+ PenState .PEN_IS_IN_RANGE ,
333+ PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,
334+ ),
335+ "in-range -> button-press -> button-release" : (
336+ PenState .PEN_IS_IN_RANGE ,
337+ PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,
338+ PenState .PEN_IS_IN_RANGE ,
339+ ),
340+ "in-range -> touch -> button-press -> button-release" : (
341+ PenState .PEN_IS_IN_RANGE ,
342+ PenState .PEN_IS_IN_CONTACT ,
343+ PenState .PEN_IS_IN_CONTACT_WITH_BUTTON ,
344+ PenState .PEN_IS_IN_CONTACT ,
345+ ),
346+ "in-range -> touch -> button-press -> release -> button-release" : (
347+ PenState .PEN_IS_IN_RANGE ,
348+ PenState .PEN_IS_IN_CONTACT ,
349+ PenState .PEN_IS_IN_CONTACT_WITH_BUTTON ,
350+ PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,
351+ PenState .PEN_IS_IN_RANGE ,
352+ ),
353+ "in-range -> button-press -> touch -> release -> button-release" : (
354+ PenState .PEN_IS_IN_RANGE ,
355+ PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,
356+ PenState .PEN_IS_IN_CONTACT_WITH_BUTTON ,
357+ PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,
358+ PenState .PEN_IS_IN_RANGE ,
359+ ),
360+ "in-range -> button-press -> touch -> button-release -> release" : (
361+ PenState .PEN_IS_IN_RANGE ,
362+ PenState .PEN_IS_IN_RANGE_WITH_BUTTON ,
363+ PenState .PEN_IS_IN_CONTACT_WITH_BUTTON ,
364+ PenState .PEN_IS_IN_CONTACT ,
365+ PenState .PEN_IS_IN_RANGE ,
366+ ),
367+ }
368+
320369 @staticmethod
321370 def tolerated_transitions () -> Dict [str , Tuple ["PenState" , ...]]:
322371 """This is not adhering to the Windows Pen Implementation state machine
@@ -671,6 +720,22 @@ def test_tolerated_pen_states(self, state_list, scribble):
671720 reasons."""
672721 self ._test_states (state_list , scribble )
673722
723+ @pytest .mark .skip_if_uhdev (
724+ lambda uhdev : "Barrel Switch" not in uhdev .fields ,
725+ "Device not compatible, missing Barrel Switch usage" ,
726+ )
727+ @pytest .mark .parametrize ("scribble" , [True , False ], ids = ["scribble" , "static" ])
728+ @pytest .mark .parametrize (
729+ "state_list" ,
730+ [
731+ pytest .param (v , id = k )
732+ for k , v in PenState .legal_transitions_with_primary_button ().items ()
733+ ],
734+ )
735+ def test_valid_primary_button_pen_states (self , state_list , scribble ):
736+ """Rework the transition state machine by adding the primary button."""
737+ self ._test_states (state_list , scribble )
738+
674739 @pytest .mark .skip_if_uhdev (
675740 lambda uhdev : "Invert" not in uhdev .fields ,
676741 "Device not compatible, missing Invert usage" ,
@@ -728,101 +793,6 @@ def test_tolerated_broken_pen_states(self, state_list, scribble):
728793 state machine."""
729794 self ._test_states (state_list , scribble )
730795
731- @pytest .mark .skip_if_uhdev (
732- lambda uhdev : "Barrel Switch" not in uhdev .fields ,
733- "Device not compatible, missing Barrel Switch usage" ,
734- )
735- def test_primary_button (self ):
736- """Primary button (stylus) pressed, reports as pressed even while hovering.
737- Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN):
738- { 0, 0, 1 } <- hover
739- { 0, 1, 1 } <- primary button pressed
740- { 0, 1, 1 } <- liftoff
741- { 0, 0, 0 } <- leaves
742- """
743-
744- uhdev = self .uhdev
745- evdev = uhdev .get_evdev ()
746-
747- p = Pen (50 , 60 )
748- p .inrange = True
749- events = self .post (uhdev , p )
750- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_TOOL_PEN , 1 ) in events
751- assert evdev .value [libevdev .EV_ABS .ABS_X ] == 50
752- assert evdev .value [libevdev .EV_ABS .ABS_Y ] == 60
753- assert not evdev .value [libevdev .EV_KEY .BTN_STYLUS ]
754-
755- p .barrelswitch = True
756- events = self .post (uhdev , p )
757- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_STYLUS , 1 ) in events
758-
759- p .x += 1
760- p .y -= 1
761- events = self .post (uhdev , p )
762- assert len (events ) == 3 # X, Y, SYN
763- assert libevdev .InputEvent (libevdev .EV_ABS .ABS_X , 51 ) in events
764- assert libevdev .InputEvent (libevdev .EV_ABS .ABS_Y , 59 ) in events
765-
766- p .barrelswitch = False
767- events = self .post (uhdev , p )
768- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_STYLUS , 0 ) in events
769-
770- p .inrange = False
771- events = self .post (uhdev , p )
772- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_TOOL_PEN , 0 ) in events
773-
774- @pytest .mark .skip_if_uhdev (
775- lambda uhdev : "Barrel Switch" not in uhdev .fields ,
776- "Device not compatible, missing Barrel Switch usage" ,
777- )
778- def test_contact_primary_button (self ):
779- """Primary button (stylus) pressed, reports as pressed even while hovering.
780- Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN):
781- { 0, 0, 1 } <- hover
782- { 0, 1, 1 } <- primary button pressed
783- { 1, 1, 1 } <- touch-down
784- { 1, 1, 1 } <- still touch, scribble on the screen
785- { 0, 1, 1 } <- liftoff
786- { 0, 0, 0 } <- leaves
787- """
788-
789- uhdev = self .uhdev
790- evdev = uhdev .get_evdev ()
791-
792- p = Pen (50 , 60 )
793- p .inrange = True
794- events = self .post (uhdev , p )
795- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_TOOL_PEN , 1 ) in events
796- assert evdev .value [libevdev .EV_ABS .ABS_X ] == 50
797- assert evdev .value [libevdev .EV_ABS .ABS_Y ] == 60
798- assert not evdev .value [libevdev .EV_KEY .BTN_STYLUS ]
799-
800- p .barrelswitch = True
801- events = self .post (uhdev , p )
802- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_STYLUS , 1 ) in events
803-
804- p .tipswitch = True
805- events = self .post (uhdev , p )
806- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_TOUCH , 1 ) in events
807- assert evdev .value [libevdev .EV_KEY .BTN_STYLUS ]
808-
809- p .x += 1
810- p .y -= 1
811- events = self .post (uhdev , p )
812- assert len (events ) == 3 # X, Y, SYN
813- assert libevdev .InputEvent (libevdev .EV_ABS .ABS_X , 51 ) in events
814- assert libevdev .InputEvent (libevdev .EV_ABS .ABS_Y , 59 ) in events
815-
816- p .tipswitch = False
817- events = self .post (uhdev , p )
818- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_TOUCH , 0 ) in events
819-
820- p .barrelswitch = False
821- p .inrange = False
822- events = self .post (uhdev , p )
823- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_TOOL_PEN , 0 ) in events
824- assert libevdev .InputEvent (libevdev .EV_KEY .BTN_STYLUS , 0 ) in events
825-
826796
827797class GXTP_pen (PenDigitizer ):
828798 def event (self , pen ):
0 commit comments