@@ -874,6 +874,229 @@ class USIPen(PenDigitizer):
874
874
pass
875
875
876
876
877
+ class XPPen_ArtistPro16Gen2_28bd_095b (PenDigitizer ):
878
+ """
879
+ Pen with two buttons and a rubber end, but which reports
880
+ the second button as an eraser
881
+ """
882
+
883
+ def __init__ (
884
+ self ,
885
+ name ,
886
+ rdesc_str = None ,
887
+ rdesc = None ,
888
+ application = "Pen" ,
889
+ physical = "Stylus" ,
890
+ input_info = (BusType .USB , 0x28BD , 0x095B ),
891
+ evdev_name_suffix = None ,
892
+ ):
893
+ super ().__init__ (
894
+ name , rdesc_str , rdesc , application , physical , input_info , evdev_name_suffix
895
+ )
896
+ self .fields .append ("Secondary Barrel Switch" )
897
+
898
+ def move_to (self , pen , state , button ):
899
+ # fill in the previous values
900
+ if pen .current_state == PenState .PEN_IS_OUT_OF_RANGE :
901
+ pen .restore ()
902
+
903
+ print (f"\n *** pen is moving to { state } ***" )
904
+
905
+ if state == PenState .PEN_IS_OUT_OF_RANGE :
906
+ pen .backup ()
907
+ pen .x = 0
908
+ pen .y = 0
909
+ pen .tipswitch = False
910
+ pen .tippressure = 0
911
+ pen .azimuth = 0
912
+ pen .inrange = False
913
+ pen .width = 0
914
+ pen .height = 0
915
+ pen .invert = False
916
+ pen .eraser = False
917
+ pen .xtilt = 0
918
+ pen .ytilt = 0
919
+ pen .twist = 0
920
+ pen .barrelswitch = False
921
+ elif state == PenState .PEN_IS_IN_RANGE :
922
+ pen .tipswitch = False
923
+ pen .inrange = True
924
+ pen .invert = False
925
+ pen .eraser = False
926
+ pen .barrelswitch = False
927
+ elif state == PenState .PEN_IS_IN_CONTACT :
928
+ pen .tipswitch = True
929
+ pen .inrange = True
930
+ pen .invert = False
931
+ pen .eraser = False
932
+ pen .barrelswitch = False
933
+ elif state == PenState .PEN_IS_IN_RANGE_WITH_BUTTON :
934
+ pen .tipswitch = False
935
+ pen .inrange = True
936
+ pen .invert = False
937
+ assert button is not None
938
+ pen .barrelswitch = button == BtnPressed .PRIMARY_PRESSED
939
+ pen .eraser = button == BtnPressed .SECONDARY_PRESSED
940
+ elif state == PenState .PEN_IS_IN_CONTACT_WITH_BUTTON :
941
+ pen .tipswitch = True
942
+ pen .inrange = True
943
+ pen .invert = False
944
+ assert button is not None
945
+ pen .barrelswitch = button == BtnPressed .PRIMARY_PRESSED
946
+ pen .eraser = button == BtnPressed .SECONDARY_PRESSED
947
+ elif state == PenState .PEN_IS_IN_RANGE_WITH_ERASING_INTENT :
948
+ pen .tipswitch = False
949
+ pen .inrange = True
950
+ pen .invert = True
951
+ pen .eraser = False
952
+ pen .barrelswitch = False
953
+ elif state == PenState .PEN_IS_ERASING :
954
+ pen .tipswitch = True
955
+ pen .inrange = True
956
+ pen .invert = True
957
+ pen .eraser = False
958
+ pen .barrelswitch = False
959
+
960
+ pen .xtilt = 0
961
+ pen .ytilt = 0
962
+ pen .current_state = state
963
+
964
+
965
+ class XPPen_Artist24_28bd_093a (PenDigitizer ):
966
+ """
967
+ Pen that reports secondary barrel switch through eraser
968
+ """
969
+
970
+ def __init__ (
971
+ self ,
972
+ name ,
973
+ rdesc_str = None ,
974
+ rdesc = None ,
975
+ application = "Pen" ,
976
+ physical = "Stylus" ,
977
+ input_info = (BusType .USB , 0x28BD , 0x093A ),
978
+ evdev_name_suffix = None ,
979
+ ):
980
+ super ().__init__ (
981
+ name , rdesc_str , rdesc , application , physical , input_info , evdev_name_suffix
982
+ )
983
+ self .fields .append ("Secondary Barrel Switch" )
984
+ self .previous_state = PenState .PEN_IS_OUT_OF_RANGE
985
+
986
+ def move_to (self , pen , state , button , debug = True ):
987
+ # fill in the previous values
988
+ if pen .current_state == PenState .PEN_IS_OUT_OF_RANGE :
989
+ pen .restore ()
990
+
991
+ if debug :
992
+ print (f"\n *** pen is moving to { state } ***" )
993
+
994
+ if state == PenState .PEN_IS_OUT_OF_RANGE :
995
+ pen .backup ()
996
+ pen .tipswitch = False
997
+ pen .tippressure = 0
998
+ pen .azimuth = 0
999
+ pen .inrange = False
1000
+ pen .width = 0
1001
+ pen .height = 0
1002
+ pen .invert = False
1003
+ pen .eraser = False
1004
+ pen .xtilt = 0
1005
+ pen .ytilt = 0
1006
+ pen .twist = 0
1007
+ pen .barrelswitch = False
1008
+ elif state == PenState .PEN_IS_IN_RANGE :
1009
+ pen .tipswitch = False
1010
+ pen .inrange = True
1011
+ pen .invert = False
1012
+ pen .eraser = False
1013
+ pen .barrelswitch = False
1014
+ elif state == PenState .PEN_IS_IN_CONTACT :
1015
+ pen .tipswitch = True
1016
+ pen .inrange = True
1017
+ pen .invert = False
1018
+ pen .eraser = False
1019
+ pen .barrelswitch = False
1020
+ elif state == PenState .PEN_IS_IN_RANGE_WITH_BUTTON :
1021
+ pen .tipswitch = False
1022
+ pen .inrange = True
1023
+ pen .invert = False
1024
+ assert button is not None
1025
+ pen .barrelswitch = button == BtnPressed .PRIMARY_PRESSED
1026
+ pen .eraser = button == BtnPressed .SECONDARY_PRESSED
1027
+ elif state == PenState .PEN_IS_IN_CONTACT_WITH_BUTTON :
1028
+ pen .tipswitch = True
1029
+ pen .inrange = True
1030
+ pen .invert = False
1031
+ assert button is not None
1032
+ pen .barrelswitch = button == BtnPressed .PRIMARY_PRESSED
1033
+ pen .eraser = button == BtnPressed .SECONDARY_PRESSED
1034
+
1035
+ pen .current_state = state
1036
+
1037
+ def send_intermediate_state (self , pen , state , button ):
1038
+ intermediate_pen = copy .copy (pen )
1039
+ self .move_to (intermediate_pen , state , button , debug = False )
1040
+ return super ().event (intermediate_pen , button )
1041
+
1042
+ def event (self , pen , button ):
1043
+ rs = []
1044
+
1045
+ # the pen reliably sends in-range events in a normal case (non emulation of eraser mode)
1046
+ if self .previous_state == PenState .PEN_IS_IN_CONTACT :
1047
+ if pen .current_state == PenState .PEN_IS_OUT_OF_RANGE :
1048
+ rs .extend (
1049
+ self .send_intermediate_state (pen , PenState .PEN_IS_IN_RANGE , button )
1050
+ )
1051
+
1052
+ if button == BtnPressed .SECONDARY_PRESSED :
1053
+ if self .previous_state == PenState .PEN_IS_IN_RANGE :
1054
+ if pen .current_state == PenState .PEN_IS_IN_RANGE_WITH_BUTTON :
1055
+ rs .extend (
1056
+ self .send_intermediate_state (
1057
+ pen , PenState .PEN_IS_OUT_OF_RANGE , button
1058
+ )
1059
+ )
1060
+
1061
+ if self .previous_state == PenState .PEN_IS_IN_RANGE_WITH_BUTTON :
1062
+ if pen .current_state == PenState .PEN_IS_IN_RANGE :
1063
+ rs .extend (
1064
+ self .send_intermediate_state (
1065
+ pen , PenState .PEN_IS_OUT_OF_RANGE , button
1066
+ )
1067
+ )
1068
+
1069
+ if self .previous_state == PenState .PEN_IS_IN_CONTACT :
1070
+ if pen .current_state == PenState .PEN_IS_IN_CONTACT_WITH_BUTTON :
1071
+ rs .extend (
1072
+ self .send_intermediate_state (
1073
+ pen , PenState .PEN_IS_OUT_OF_RANGE , button
1074
+ )
1075
+ )
1076
+ rs .extend (
1077
+ self .send_intermediate_state (
1078
+ pen , PenState .PEN_IS_IN_RANGE_WITH_BUTTON , button
1079
+ )
1080
+ )
1081
+
1082
+ if self .previous_state == PenState .PEN_IS_IN_CONTACT_WITH_BUTTON :
1083
+ if pen .current_state == PenState .PEN_IS_IN_CONTACT :
1084
+ rs .extend (
1085
+ self .send_intermediate_state (
1086
+ pen , PenState .PEN_IS_OUT_OF_RANGE , button
1087
+ )
1088
+ )
1089
+ rs .extend (
1090
+ self .send_intermediate_state (
1091
+ pen , PenState .PEN_IS_IN_RANGE , button
1092
+ )
1093
+ )
1094
+
1095
+ rs .extend (super ().event (pen , button ))
1096
+ self .previous_state = pen .current_state
1097
+ return rs
1098
+
1099
+
877
1100
################################################################################
878
1101
#
879
1102
# Windows 7 compatible devices
@@ -1052,3 +1275,26 @@ def create_device(self):
1052
1275
rdesc = "05 0d 09 04 a1 01 85 01 09 22 a1 02 55 0e 65 11 35 00 15 00 09 42 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 95 01 75 08 09 51 81 02 75 10 05 01 26 04 20 46 e6 09 09 30 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 95 01 75 08 09 51 81 02 75 10 05 01 26 04 20 46 e6 09 09 30 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 95 01 75 08 09 51 81 02 75 10 05 01 26 04 20 46 e6 09 09 30 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 75 08 09 51 95 01 81 02 05 01 26 04 20 75 10 55 0e 65 11 09 30 35 00 46 e6 09 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 22 a1 02 09 42 15 00 25 01 75 01 95 01 81 02 25 7f 09 30 75 07 81 42 75 08 09 51 95 01 81 02 05 01 26 04 20 75 10 55 0e 65 11 09 30 35 00 46 e6 09 81 02 26 60 15 46 9a 06 09 31 81 02 05 0d 55 0f 75 08 25 ff 45 ff 09 48 81 42 09 49 81 42 55 0e c0 09 54 15 00 25 7f 75 08 95 01 81 02 85 02 09 55 95 01 25 0a b1 02 85 03 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 02 a1 01 09 20 a1 00 85 08 05 01 a4 09 30 35 00 46 e6 09 15 00 26 04 20 55 0d 65 13 75 10 95 01 81 02 09 31 46 9a 06 26 60 15 81 02 b4 05 0d 09 38 95 01 75 08 15 00 25 01 81 02 09 30 75 10 26 ff 0f 81 02 09 31 81 02 09 42 09 44 09 5a 09 3c 09 45 09 32 75 01 95 06 25 01 81 02 95 02 81 03 09 3d 55 0e 65 14 36 d8 dc 46 28 23 16 d8 dc 26 28 23 95 01 75 10 81 02 09 3e 81 02 09 41 15 00 27 a0 8c 00 00 35 00 47 a0 8c 00 00 81 02 05 20 0a 53 04 65 00 16 01 f8 26 ff 07 75 10 95 01 81 02 0a 54 04 81 02 0a 55 04 81 02 0a 57 04 81 02 0a 58 04 81 02 0a 59 04 81 02 0a 72 04 81 02 0a 73 04 81 02 0a 74 04 81 02 05 0d 09 3b 15 00 25 64 75 08 81 02 09 5b 25 ff 75 40 81 02 06 00 ff 09 5b 75 20 81 02 05 0d 09 5c 26 ff 00 75 08 81 02 09 5e 81 02 09 70 a1 02 15 01 25 06 09 72 09 73 09 74 09 75 09 76 09 77 81 20 c0 06 00 ff 09 01 15 00 27 ff ff 00 00 75 10 95 01 81 02 85 09 09 81 a1 02 09 81 15 01 25 04 09 82 09 83 09 84 09 85 81 20 c0 85 10 09 5c a1 02 15 00 25 01 75 08 95 01 09 38 b1 02 09 5c 26 ff 00 b1 02 09 5d 75 01 95 01 25 01 b1 02 95 07 b1 03 c0 85 11 09 5e a1 02 09 38 15 00 25 01 75 08 95 01 b1 02 09 5e 26 ff 00 b1 02 09 5f 75 01 25 01 b1 02 75 07 b1 03 c0 85 12 09 70 a1 02 75 08 95 01 15 00 25 01 09 38 b1 02 09 70 a1 02 25 06 09 72 09 73 09 74 09 75 09 76 09 77 b1 20 c0 09 71 75 01 25 01 b1 02 75 07 b1 03 c0 85 13 09 80 15 00 25 ff 75 40 95 01 b1 02 85 14 09 44 a1 02 09 38 75 08 95 01 25 01 b1 02 15 01 25 03 09 44 a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 09 5a a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 09 45 a1 02 09 a4 09 44 09 5a 09 45 09 a3 b1 20 c0 c0 85 15 75 08 95 01 05 0d 09 90 a1 02 09 38 25 01 b1 02 09 91 75 10 26 ff 0f b1 02 09 92 75 40 25 ff b1 02 05 06 09 2a 75 08 26 ff 00 a1 02 09 2d b1 02 09 2e b1 02 c0 c0 85 16 05 06 09 2b a1 02 05 0d 25 01 09 38 b1 02 05 06 09 2b a1 02 09 2d 26 ff 00 b1 02 09 2e b1 02 c0 c0 85 17 06 00 ff 09 01 a1 02 05 0d 09 38 75 08 95 01 25 01 b1 02 06 00 ff 09 01 75 10 27 ff ff 00 00 b1 02 c0 85 18 05 0d 09 38 75 08 95 01 15 00 25 01 b1 02 c0 c0 06 f0 ff 09 01 a1 01 85 0e 09 01 15 00 25 ff 75 08 95 40 91 02 09 01 15 00 25 ff 75 08 95 40 81 02 c0" ,
1053
1276
input_info = (BusType .I2C , 0x27C6 , 0x0E00 ),
1054
1277
)
1278
+
1279
+
1280
+ class TestXPPen_ArtistPro16Gen2_28bd_095b (BaseTest .TestTablet ):
1281
+ hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o" , True )]
1282
+
1283
+ def create_device (self ):
1284
+ dev = XPPen_ArtistPro16Gen2_28bd_095b (
1285
+ "uhid test XPPen Artist Pro 16 Gen2 28bd 095b" ,
1286
+ rdesc = "05 0d 09 02 a1 01 85 07 09 20 a1 00 09 42 09 44 09 45 09 3c 15 00 25 01 75 01 95 04 81 02 95 01 81 03 09 32 15 00 25 01 95 01 81 02 95 02 81 03 75 10 95 01 35 00 a4 05 01 09 30 65 13 55 0d 46 ff 34 26 ff 7f 81 02 09 31 46 20 21 26 ff 7f 81 02 b4 09 30 45 00 26 ff 3f 81 42 09 3d 15 81 25 7f 75 08 95 01 81 02 09 3e 15 81 25 7f 81 02 c0 c0" ,
1287
+ input_info = (BusType .USB , 0x28BD , 0x095B ),
1288
+ )
1289
+ return dev
1290
+
1291
+
1292
+ class TestXPPen_Artist24_28bd_093a (BaseTest .TestTablet ):
1293
+ hid_bpfs = [("XPPen__Artist24.bpf.o" , True )]
1294
+
1295
+ def create_device (self ):
1296
+ return XPPen_Artist24_28bd_093a (
1297
+ "uhid test XPPen Artist 24 28bd 093a" ,
1298
+ rdesc = "05 0d 09 02 a1 01 85 07 09 20 a1 00 09 42 09 44 09 45 15 00 25 01 75 01 95 03 81 02 95 02 81 03 09 32 95 01 81 02 95 02 81 03 75 10 95 01 35 00 a4 05 01 09 30 65 13 55 0d 46 f0 50 26 ff 7f 81 02 09 31 46 91 2d 26 ff 7f 81 02 b4 09 30 45 00 26 ff 1f 81 42 09 3d 15 81 25 7f 75 08 95 01 81 02 09 3e 15 81 25 7f 81 02 c0 c0" ,
1299
+ input_info = (BusType .USB , 0x28BD , 0x093A ),
1300
+ )
0 commit comments