Skip to content

Commit 0389901

Browse files
author
Benjamin Tissoires
committed
selftests/hid: tablets: add a couple of XP-PEN tablets
Those tablets don't need special initialization, but are reporting the events with the wrong usages: - tip switch is used when the eraser should be used - eraser is used instead of the secondary barrel switch Add tests for those so we don't regress in the future. Currently we set x/y tilt to 0 to not trigger the bpf program compensate_coordinates_by_tilt() Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Peter Hutterer <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent e14d88d commit 0389901

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

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

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,229 @@ class USIPen(PenDigitizer):
874874
pass
875875

876876

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+
8771100
################################################################################
8781101
#
8791102
# Windows 7 compatible devices
@@ -1052,3 +1275,26 @@ def create_device(self):
10521275
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",
10531276
input_info=(BusType.I2C, 0x27C6, 0x0E00),
10541277
)
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

Comments
 (0)