test_mouse.py 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. #!/bin/env python3
  2. # SPDX-License-Identifier: GPL-2.0
  3. # -*- coding: utf-8 -*-
  4. #
  5. # Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com>
  6. # Copyright (c) 2017 Red Hat, Inc.
  7. #
  8. from . import base
  9. import hidtools.hid
  10. from hidtools.util import BusType
  11. import libevdev
  12. import logging
  13. import pytest
  14. logger = logging.getLogger("hidtools.test.mouse")
  15. # workaround https://gitlab.freedesktop.org/libevdev/python-libevdev/issues/6
  16. try:
  17. libevdev.EV_REL.REL_WHEEL_HI_RES
  18. except AttributeError:
  19. libevdev.EV_REL.REL_WHEEL_HI_RES = libevdev.EV_REL.REL_0B
  20. libevdev.EV_REL.REL_HWHEEL_HI_RES = libevdev.EV_REL.REL_0C
  21. class InvalidHIDCommunication(Exception):
  22. pass
  23. class MouseData(object):
  24. pass
  25. class BaseMouse(base.UHIDTestDevice):
  26. def __init__(self, rdesc, name=None, input_info=None):
  27. assert rdesc is not None
  28. super().__init__(name, "Mouse", input_info=input_info, rdesc=rdesc)
  29. self.left = False
  30. self.right = False
  31. self.middle = False
  32. def create_report(self, x, y, buttons=None, wheels=None, reportID=None):
  33. """
  34. Return an input report for this device.
  35. :param x: relative x
  36. :param y: relative y
  37. :param buttons: a (l, r, m) tuple of bools for the button states,
  38. where ``None`` is "leave unchanged"
  39. :param wheels: a single value for the vertical wheel or a (vertical, horizontal) tuple for
  40. the two wheels
  41. :param reportID: the numeric report ID for this report, if needed
  42. """
  43. if buttons is not None:
  44. left, right, middle = buttons
  45. if left is not None:
  46. self.left = left
  47. if right is not None:
  48. self.right = right
  49. if middle is not None:
  50. self.middle = middle
  51. left = self.left
  52. right = self.right
  53. middle = self.middle
  54. # Note: the BaseMouse doesn't actually have a wheel but the
  55. # create_report magic only fills in those fields exist, so let's
  56. # make this generic here.
  57. wheel, acpan = 0, 0
  58. if wheels is not None:
  59. if isinstance(wheels, tuple):
  60. wheel = wheels[0]
  61. acpan = wheels[1]
  62. else:
  63. wheel = wheels
  64. reportID = reportID or self.default_reportID
  65. mouse = MouseData()
  66. mouse.b1 = int(left)
  67. mouse.b2 = int(right)
  68. mouse.b3 = int(middle)
  69. mouse.x = x
  70. mouse.y = y
  71. mouse.wheel = wheel
  72. mouse.acpan = acpan
  73. return super().create_report(mouse, reportID=reportID)
  74. def event(self, x, y, buttons=None, wheels=None):
  75. """
  76. Send an input event on the default report ID.
  77. :param x: relative x
  78. :param y: relative y
  79. :param buttons: a (l, r, m) tuple of bools for the button states,
  80. where ``None`` is "leave unchanged"
  81. :param wheels: a single value for the vertical wheel or a (vertical, horizontal) tuple for
  82. the two wheels
  83. """
  84. r = self.create_report(x, y, buttons, wheels)
  85. self.call_input_event(r)
  86. return [r]
  87. class ButtonMouse(BaseMouse):
  88. # fmt: off
  89. report_descriptor = [
  90. 0x05, 0x01, # .Usage Page (Generic Desktop) 0
  91. 0x09, 0x02, # .Usage (Mouse) 2
  92. 0xa1, 0x01, # .Collection (Application) 4
  93. 0x09, 0x02, # ..Usage (Mouse) 6
  94. 0xa1, 0x02, # ..Collection (Logical) 8
  95. 0x09, 0x01, # ...Usage (Pointer) 10
  96. 0xa1, 0x00, # ...Collection (Physical) 12
  97. 0x05, 0x09, # ....Usage Page (Button) 14
  98. 0x19, 0x01, # ....Usage Minimum (1) 16
  99. 0x29, 0x03, # ....Usage Maximum (3) 18
  100. 0x15, 0x00, # ....Logical Minimum (0) 20
  101. 0x25, 0x01, # ....Logical Maximum (1) 22
  102. 0x75, 0x01, # ....Report Size (1) 24
  103. 0x95, 0x03, # ....Report Count (3) 26
  104. 0x81, 0x02, # ....Input (Data,Var,Abs) 28
  105. 0x75, 0x05, # ....Report Size (5) 30
  106. 0x95, 0x01, # ....Report Count (1) 32
  107. 0x81, 0x03, # ....Input (Cnst,Var,Abs) 34
  108. 0x05, 0x01, # ....Usage Page (Generic Desktop) 36
  109. 0x09, 0x30, # ....Usage (X) 38
  110. 0x09, 0x31, # ....Usage (Y) 40
  111. 0x15, 0x81, # ....Logical Minimum (-127) 42
  112. 0x25, 0x7f, # ....Logical Maximum (127) 44
  113. 0x75, 0x08, # ....Report Size (8) 46
  114. 0x95, 0x02, # ....Report Count (2) 48
  115. 0x81, 0x06, # ....Input (Data,Var,Rel) 50
  116. 0xc0, # ...End Collection 52
  117. 0xc0, # ..End Collection 53
  118. 0xc0, # .End Collection 54
  119. ]
  120. # fmt: on
  121. def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
  122. super().__init__(rdesc, name, input_info)
  123. def fake_report(self, x, y, buttons):
  124. if buttons is not None:
  125. left, right, middle = buttons
  126. if left is None:
  127. left = self.left
  128. if right is None:
  129. right = self.right
  130. if middle is None:
  131. middle = self.middle
  132. else:
  133. left = self.left
  134. right = self.right
  135. middle = self.middle
  136. button_mask = sum(1 << i for i, b in enumerate([left, right, middle]) if b)
  137. x = max(-127, min(127, x))
  138. y = max(-127, min(127, y))
  139. x = hidtools.util.to_twos_comp(x, 8)
  140. y = hidtools.util.to_twos_comp(y, 8)
  141. return [button_mask, x, y]
  142. class WheelMouse(ButtonMouse):
  143. # fmt: off
  144. report_descriptor = [
  145. 0x05, 0x01, # Usage Page (Generic Desktop) 0
  146. 0x09, 0x02, # Usage (Mouse) 2
  147. 0xa1, 0x01, # Collection (Application) 4
  148. 0x05, 0x09, # .Usage Page (Button) 6
  149. 0x19, 0x01, # .Usage Minimum (1) 8
  150. 0x29, 0x03, # .Usage Maximum (3) 10
  151. 0x15, 0x00, # .Logical Minimum (0) 12
  152. 0x25, 0x01, # .Logical Maximum (1) 14
  153. 0x95, 0x03, # .Report Count (3) 16
  154. 0x75, 0x01, # .Report Size (1) 18
  155. 0x81, 0x02, # .Input (Data,Var,Abs) 20
  156. 0x95, 0x01, # .Report Count (1) 22
  157. 0x75, 0x05, # .Report Size (5) 24
  158. 0x81, 0x03, # .Input (Cnst,Var,Abs) 26
  159. 0x05, 0x01, # .Usage Page (Generic Desktop) 28
  160. 0x09, 0x01, # .Usage (Pointer) 30
  161. 0xa1, 0x00, # .Collection (Physical) 32
  162. 0x09, 0x30, # ..Usage (X) 34
  163. 0x09, 0x31, # ..Usage (Y) 36
  164. 0x15, 0x81, # ..Logical Minimum (-127) 38
  165. 0x25, 0x7f, # ..Logical Maximum (127) 40
  166. 0x75, 0x08, # ..Report Size (8) 42
  167. 0x95, 0x02, # ..Report Count (2) 44
  168. 0x81, 0x06, # ..Input (Data,Var,Rel) 46
  169. 0xc0, # .End Collection 48
  170. 0x09, 0x38, # .Usage (Wheel) 49
  171. 0x15, 0x81, # .Logical Minimum (-127) 51
  172. 0x25, 0x7f, # .Logical Maximum (127) 53
  173. 0x75, 0x08, # .Report Size (8) 55
  174. 0x95, 0x01, # .Report Count (1) 57
  175. 0x81, 0x06, # .Input (Data,Var,Rel) 59
  176. 0xc0, # End Collection 61
  177. ]
  178. # fmt: on
  179. def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
  180. super().__init__(rdesc, name, input_info)
  181. self.wheel_multiplier = 1
  182. class TwoWheelMouse(WheelMouse):
  183. # fmt: off
  184. report_descriptor = [
  185. 0x05, 0x01, # Usage Page (Generic Desktop) 0
  186. 0x09, 0x02, # Usage (Mouse) 2
  187. 0xa1, 0x01, # Collection (Application) 4
  188. 0x09, 0x01, # .Usage (Pointer) 6
  189. 0xa1, 0x00, # .Collection (Physical) 8
  190. 0x05, 0x09, # ..Usage Page (Button) 10
  191. 0x19, 0x01, # ..Usage Minimum (1) 12
  192. 0x29, 0x10, # ..Usage Maximum (16) 14
  193. 0x15, 0x00, # ..Logical Minimum (0) 16
  194. 0x25, 0x01, # ..Logical Maximum (1) 18
  195. 0x95, 0x10, # ..Report Count (16) 20
  196. 0x75, 0x01, # ..Report Size (1) 22
  197. 0x81, 0x02, # ..Input (Data,Var,Abs) 24
  198. 0x05, 0x01, # ..Usage Page (Generic Desktop) 26
  199. 0x16, 0x01, 0x80, # ..Logical Minimum (-32767) 28
  200. 0x26, 0xff, 0x7f, # ..Logical Maximum (32767) 31
  201. 0x75, 0x10, # ..Report Size (16) 34
  202. 0x95, 0x02, # ..Report Count (2) 36
  203. 0x09, 0x30, # ..Usage (X) 38
  204. 0x09, 0x31, # ..Usage (Y) 40
  205. 0x81, 0x06, # ..Input (Data,Var,Rel) 42
  206. 0x15, 0x81, # ..Logical Minimum (-127) 44
  207. 0x25, 0x7f, # ..Logical Maximum (127) 46
  208. 0x75, 0x08, # ..Report Size (8) 48
  209. 0x95, 0x01, # ..Report Count (1) 50
  210. 0x09, 0x38, # ..Usage (Wheel) 52
  211. 0x81, 0x06, # ..Input (Data,Var,Rel) 54
  212. 0x05, 0x0c, # ..Usage Page (Consumer Devices) 56
  213. 0x0a, 0x38, 0x02, # ..Usage (AC Pan) 58
  214. 0x95, 0x01, # ..Report Count (1) 61
  215. 0x81, 0x06, # ..Input (Data,Var,Rel) 63
  216. 0xc0, # .End Collection 65
  217. 0xc0, # End Collection 66
  218. ]
  219. # fmt: on
  220. def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
  221. super().__init__(rdesc, name, input_info)
  222. self.hwheel_multiplier = 1
  223. class MIDongleMIWirelessMouse(TwoWheelMouse):
  224. # fmt: off
  225. report_descriptor = [
  226. 0x05, 0x01, # Usage Page (Generic Desktop)
  227. 0x09, 0x02, # Usage (Mouse)
  228. 0xa1, 0x01, # Collection (Application)
  229. 0x85, 0x01, # .Report ID (1)
  230. 0x09, 0x01, # .Usage (Pointer)
  231. 0xa1, 0x00, # .Collection (Physical)
  232. 0x95, 0x05, # ..Report Count (5)
  233. 0x75, 0x01, # ..Report Size (1)
  234. 0x05, 0x09, # ..Usage Page (Button)
  235. 0x19, 0x01, # ..Usage Minimum (1)
  236. 0x29, 0x05, # ..Usage Maximum (5)
  237. 0x15, 0x00, # ..Logical Minimum (0)
  238. 0x25, 0x01, # ..Logical Maximum (1)
  239. 0x81, 0x02, # ..Input (Data,Var,Abs)
  240. 0x95, 0x01, # ..Report Count (1)
  241. 0x75, 0x03, # ..Report Size (3)
  242. 0x81, 0x01, # ..Input (Cnst,Arr,Abs)
  243. 0x75, 0x08, # ..Report Size (8)
  244. 0x95, 0x01, # ..Report Count (1)
  245. 0x05, 0x01, # ..Usage Page (Generic Desktop)
  246. 0x09, 0x38, # ..Usage (Wheel)
  247. 0x15, 0x81, # ..Logical Minimum (-127)
  248. 0x25, 0x7f, # ..Logical Maximum (127)
  249. 0x81, 0x06, # ..Input (Data,Var,Rel)
  250. 0x05, 0x0c, # ..Usage Page (Consumer Devices)
  251. 0x0a, 0x38, 0x02, # ..Usage (AC Pan)
  252. 0x95, 0x01, # ..Report Count (1)
  253. 0x81, 0x06, # ..Input (Data,Var,Rel)
  254. 0xc0, # .End Collection
  255. 0x85, 0x02, # .Report ID (2)
  256. 0x09, 0x01, # .Usage (Consumer Control)
  257. 0xa1, 0x00, # .Collection (Physical)
  258. 0x75, 0x0c, # ..Report Size (12)
  259. 0x95, 0x02, # ..Report Count (2)
  260. 0x05, 0x01, # ..Usage Page (Generic Desktop)
  261. 0x09, 0x30, # ..Usage (X)
  262. 0x09, 0x31, # ..Usage (Y)
  263. 0x16, 0x01, 0xf8, # ..Logical Minimum (-2047)
  264. 0x26, 0xff, 0x07, # ..Logical Maximum (2047)
  265. 0x81, 0x06, # ..Input (Data,Var,Rel)
  266. 0xc0, # .End Collection
  267. 0xc0, # End Collection
  268. 0x05, 0x0c, # Usage Page (Consumer Devices)
  269. 0x09, 0x01, # Usage (Consumer Control)
  270. 0xa1, 0x01, # Collection (Application)
  271. 0x85, 0x03, # .Report ID (3)
  272. 0x15, 0x00, # .Logical Minimum (0)
  273. 0x25, 0x01, # .Logical Maximum (1)
  274. 0x75, 0x01, # .Report Size (1)
  275. 0x95, 0x01, # .Report Count (1)
  276. 0x09, 0xcd, # .Usage (Play/Pause)
  277. 0x81, 0x06, # .Input (Data,Var,Rel)
  278. 0x0a, 0x83, 0x01, # .Usage (AL Consumer Control Config)
  279. 0x81, 0x06, # .Input (Data,Var,Rel)
  280. 0x09, 0xb5, # .Usage (Scan Next Track)
  281. 0x81, 0x06, # .Input (Data,Var,Rel)
  282. 0x09, 0xb6, # .Usage (Scan Previous Track)
  283. 0x81, 0x06, # .Input (Data,Var,Rel)
  284. 0x09, 0xea, # .Usage (Volume Down)
  285. 0x81, 0x06, # .Input (Data,Var,Rel)
  286. 0x09, 0xe9, # .Usage (Volume Up)
  287. 0x81, 0x06, # .Input (Data,Var,Rel)
  288. 0x0a, 0x25, 0x02, # .Usage (AC Forward)
  289. 0x81, 0x06, # .Input (Data,Var,Rel)
  290. 0x0a, 0x24, 0x02, # .Usage (AC Back)
  291. 0x81, 0x06, # .Input (Data,Var,Rel)
  292. 0xc0, # End Collection
  293. ]
  294. # fmt: on
  295. device_input_info = (BusType.USB, 0x2717, 0x003B)
  296. device_name = "uhid test MI Dongle MI Wireless Mouse"
  297. def __init__(
  298. self, rdesc=report_descriptor, name=device_name, input_info=device_input_info
  299. ):
  300. super().__init__(rdesc, name, input_info)
  301. def event(self, x, y, buttons=None, wheels=None):
  302. # this mouse spreads the relative pointer and the mouse buttons
  303. # onto 2 distinct reports
  304. rs = []
  305. r = self.create_report(x, y, buttons, wheels, reportID=1)
  306. self.call_input_event(r)
  307. rs.append(r)
  308. r = self.create_report(x, y, buttons, reportID=2)
  309. self.call_input_event(r)
  310. rs.append(r)
  311. return rs
  312. class ResolutionMultiplierMouse(TwoWheelMouse):
  313. # fmt: off
  314. report_descriptor = [
  315. 0x05, 0x01, # Usage Page (Generic Desktop) 83
  316. 0x09, 0x02, # Usage (Mouse) 85
  317. 0xa1, 0x01, # Collection (Application) 87
  318. 0x05, 0x01, # .Usage Page (Generic Desktop) 89
  319. 0x09, 0x02, # .Usage (Mouse) 91
  320. 0xa1, 0x02, # .Collection (Logical) 93
  321. 0x85, 0x11, # ..Report ID (17) 95
  322. 0x09, 0x01, # ..Usage (Pointer) 97
  323. 0xa1, 0x00, # ..Collection (Physical) 99
  324. 0x05, 0x09, # ...Usage Page (Button) 101
  325. 0x19, 0x01, # ...Usage Minimum (1) 103
  326. 0x29, 0x03, # ...Usage Maximum (3) 105
  327. 0x95, 0x03, # ...Report Count (3) 107
  328. 0x75, 0x01, # ...Report Size (1) 109
  329. 0x25, 0x01, # ...Logical Maximum (1) 111
  330. 0x81, 0x02, # ...Input (Data,Var,Abs) 113
  331. 0x95, 0x01, # ...Report Count (1) 115
  332. 0x81, 0x01, # ...Input (Cnst,Arr,Abs) 117
  333. 0x09, 0x05, # ...Usage (Vendor Usage 0x05) 119
  334. 0x81, 0x02, # ...Input (Data,Var,Abs) 121
  335. 0x95, 0x03, # ...Report Count (3) 123
  336. 0x81, 0x01, # ...Input (Cnst,Arr,Abs) 125
  337. 0x05, 0x01, # ...Usage Page (Generic Desktop) 127
  338. 0x09, 0x30, # ...Usage (X) 129
  339. 0x09, 0x31, # ...Usage (Y) 131
  340. 0x95, 0x02, # ...Report Count (2) 133
  341. 0x75, 0x08, # ...Report Size (8) 135
  342. 0x15, 0x81, # ...Logical Minimum (-127) 137
  343. 0x25, 0x7f, # ...Logical Maximum (127) 139
  344. 0x81, 0x06, # ...Input (Data,Var,Rel) 141
  345. 0xa1, 0x02, # ...Collection (Logical) 143
  346. 0x85, 0x12, # ....Report ID (18) 145
  347. 0x09, 0x48, # ....Usage (Resolution Multiplier) 147
  348. 0x95, 0x01, # ....Report Count (1) 149
  349. 0x75, 0x02, # ....Report Size (2) 151
  350. 0x15, 0x00, # ....Logical Minimum (0) 153
  351. 0x25, 0x01, # ....Logical Maximum (1) 155
  352. 0x35, 0x01, # ....Physical Minimum (1) 157
  353. 0x45, 0x04, # ....Physical Maximum (4) 159
  354. 0xb1, 0x02, # ....Feature (Data,Var,Abs) 161
  355. 0x35, 0x00, # ....Physical Minimum (0) 163
  356. 0x45, 0x00, # ....Physical Maximum (0) 165
  357. 0x75, 0x06, # ....Report Size (6) 167
  358. 0xb1, 0x01, # ....Feature (Cnst,Arr,Abs) 169
  359. 0x85, 0x11, # ....Report ID (17) 171
  360. 0x09, 0x38, # ....Usage (Wheel) 173
  361. 0x15, 0x81, # ....Logical Minimum (-127) 175
  362. 0x25, 0x7f, # ....Logical Maximum (127) 177
  363. 0x75, 0x08, # ....Report Size (8) 179
  364. 0x81, 0x06, # ....Input (Data,Var,Rel) 181
  365. 0xc0, # ...End Collection 183
  366. 0x05, 0x0c, # ...Usage Page (Consumer Devices) 184
  367. 0x75, 0x08, # ...Report Size (8) 186
  368. 0x0a, 0x38, 0x02, # ...Usage (AC Pan) 188
  369. 0x81, 0x06, # ...Input (Data,Var,Rel) 191
  370. 0xc0, # ..End Collection 193
  371. 0xc0, # .End Collection 194
  372. 0xc0, # End Collection 195
  373. ]
  374. # fmt: on
  375. def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
  376. super().__init__(rdesc, name, input_info)
  377. self.default_reportID = 0x11
  378. # Feature Report 12, multiplier Feature value must be set to 0b01,
  379. # i.e. 1. We should extract that from the descriptor instead
  380. # of hardcoding it here, but meanwhile this will do.
  381. self.set_feature_report = [0x12, 0x1]
  382. def set_report(self, req, rnum, rtype, data):
  383. if rtype != self.UHID_FEATURE_REPORT:
  384. raise InvalidHIDCommunication(f"Unexpected report type: {rtype}")
  385. if rnum != 0x12:
  386. raise InvalidHIDCommunication(f"Unexpected report number: {rnum}")
  387. if data != self.set_feature_report:
  388. raise InvalidHIDCommunication(
  389. f"Unexpected data: {data}, expected {self.set_feature_report}"
  390. )
  391. self.wheel_multiplier = 4
  392. return 0
  393. class BadResolutionMultiplierMouse(ResolutionMultiplierMouse):
  394. def set_report(self, req, rnum, rtype, data):
  395. super().set_report(req, rnum, rtype, data)
  396. self.wheel_multiplier = 1
  397. self.hwheel_multiplier = 1
  398. return 32 # EPIPE
  399. class BadReportDescriptorMouse(BaseMouse):
  400. """
  401. This "device" was one autogenerated by syzbot. There are a lot of issues in
  402. it, and the most problematic is that it declares features that have no
  403. size.
  404. This leads to report->size being set to 0 and can mess up with usbhid
  405. internals. Fortunately, uhid merely passes the incoming buffer, without
  406. touching it so a buffer of size 0 will be translated to [] without
  407. triggering a kernel oops.
  408. Because the report descriptor is wrong, no input are created, and we need
  409. to tweak a little bit the parameters to make it look correct.
  410. """
  411. # fmt: off
  412. report_descriptor = [
  413. 0x96, 0x01, 0x00, # Report Count (1) 0
  414. 0x06, 0x01, 0x00, # Usage Page (Generic Desktop) 3
  415. # 0x03, 0x00, 0x00, 0x00, 0x00, # Ignored by the kernel somehow
  416. 0x2a, 0x90, 0xa0, # Usage Maximum (41104) 6
  417. 0x27, 0x00, 0x00, 0x00, 0x00, # Logical Maximum (0) 9
  418. 0xb3, 0x81, 0x3e, 0x25, 0x03, # Feature (Cnst,Arr,Abs,Vol) 14
  419. 0x1b, 0xdd, 0xe8, 0x40, 0x50, # Usage Minimum (1346431197) 19
  420. 0x3b, 0x5d, 0x8c, 0x3d, 0xda, # Designator Index 24
  421. ]
  422. # fmt: on
  423. def __init__(
  424. self, rdesc=report_descriptor, name=None, input_info=(3, 0x045E, 0x07DA)
  425. ):
  426. super().__init__(rdesc, name, input_info)
  427. self.high_resolution_report_called = False
  428. def get_evdev(self, application=None):
  429. assert self._input_nodes is None
  430. return (
  431. "Ok" # should be a list or None, but both would fail, so abusing the system
  432. )
  433. def next_sync_events(self, application=None):
  434. # there are no evdev nodes, so no events
  435. return []
  436. def is_ready(self):
  437. # we wait for the SET_REPORT command to come
  438. return self.high_resolution_report_called
  439. def set_report(self, req, rnum, rtype, data):
  440. if rtype != self.UHID_FEATURE_REPORT:
  441. raise InvalidHIDCommunication(f"Unexpected report type: {rtype}")
  442. if rnum != 0x0:
  443. raise InvalidHIDCommunication(f"Unexpected report number: {rnum}")
  444. if len(data) != 1:
  445. raise InvalidHIDCommunication(f"Unexpected data: {data}, expected '[0]'")
  446. self.high_resolution_report_called = True
  447. return 0
  448. class ResolutionMultiplierHWheelMouse(TwoWheelMouse):
  449. # fmt: off
  450. report_descriptor = [
  451. 0x05, 0x01, # Usage Page (Generic Desktop) 0
  452. 0x09, 0x02, # Usage (Mouse) 2
  453. 0xa1, 0x01, # Collection (Application) 4
  454. 0x05, 0x01, # .Usage Page (Generic Desktop) 6
  455. 0x09, 0x02, # .Usage (Mouse) 8
  456. 0xa1, 0x02, # .Collection (Logical) 10
  457. 0x85, 0x1a, # ..Report ID (26) 12
  458. 0x09, 0x01, # ..Usage (Pointer) 14
  459. 0xa1, 0x00, # ..Collection (Physical) 16
  460. 0x05, 0x09, # ...Usage Page (Button) 18
  461. 0x19, 0x01, # ...Usage Minimum (1) 20
  462. 0x29, 0x05, # ...Usage Maximum (5) 22
  463. 0x95, 0x05, # ...Report Count (5) 24
  464. 0x75, 0x01, # ...Report Size (1) 26
  465. 0x15, 0x00, # ...Logical Minimum (0) 28
  466. 0x25, 0x01, # ...Logical Maximum (1) 30
  467. 0x81, 0x02, # ...Input (Data,Var,Abs) 32
  468. 0x75, 0x03, # ...Report Size (3) 34
  469. 0x95, 0x01, # ...Report Count (1) 36
  470. 0x81, 0x01, # ...Input (Cnst,Arr,Abs) 38
  471. 0x05, 0x01, # ...Usage Page (Generic Desktop) 40
  472. 0x09, 0x30, # ...Usage (X) 42
  473. 0x09, 0x31, # ...Usage (Y) 44
  474. 0x95, 0x02, # ...Report Count (2) 46
  475. 0x75, 0x10, # ...Report Size (16) 48
  476. 0x16, 0x01, 0x80, # ...Logical Minimum (-32767) 50
  477. 0x26, 0xff, 0x7f, # ...Logical Maximum (32767) 53
  478. 0x81, 0x06, # ...Input (Data,Var,Rel) 56
  479. 0xa1, 0x02, # ...Collection (Logical) 58
  480. 0x85, 0x12, # ....Report ID (18) 60
  481. 0x09, 0x48, # ....Usage (Resolution Multiplier) 62
  482. 0x95, 0x01, # ....Report Count (1) 64
  483. 0x75, 0x02, # ....Report Size (2) 66
  484. 0x15, 0x00, # ....Logical Minimum (0) 68
  485. 0x25, 0x01, # ....Logical Maximum (1) 70
  486. 0x35, 0x01, # ....Physical Minimum (1) 72
  487. 0x45, 0x0c, # ....Physical Maximum (12) 74
  488. 0xb1, 0x02, # ....Feature (Data,Var,Abs) 76
  489. 0x85, 0x1a, # ....Report ID (26) 78
  490. 0x09, 0x38, # ....Usage (Wheel) 80
  491. 0x35, 0x00, # ....Physical Minimum (0) 82
  492. 0x45, 0x00, # ....Physical Maximum (0) 84
  493. 0x95, 0x01, # ....Report Count (1) 86
  494. 0x75, 0x10, # ....Report Size (16) 88
  495. 0x16, 0x01, 0x80, # ....Logical Minimum (-32767) 90
  496. 0x26, 0xff, 0x7f, # ....Logical Maximum (32767) 93
  497. 0x81, 0x06, # ....Input (Data,Var,Rel) 96
  498. 0xc0, # ...End Collection 98
  499. 0xa1, 0x02, # ...Collection (Logical) 99
  500. 0x85, 0x12, # ....Report ID (18) 101
  501. 0x09, 0x48, # ....Usage (Resolution Multiplier) 103
  502. 0x75, 0x02, # ....Report Size (2) 105
  503. 0x15, 0x00, # ....Logical Minimum (0) 107
  504. 0x25, 0x01, # ....Logical Maximum (1) 109
  505. 0x35, 0x01, # ....Physical Minimum (1) 111
  506. 0x45, 0x0c, # ....Physical Maximum (12) 113
  507. 0xb1, 0x02, # ....Feature (Data,Var,Abs) 115
  508. 0x35, 0x00, # ....Physical Minimum (0) 117
  509. 0x45, 0x00, # ....Physical Maximum (0) 119
  510. 0x75, 0x04, # ....Report Size (4) 121
  511. 0xb1, 0x01, # ....Feature (Cnst,Arr,Abs) 123
  512. 0x85, 0x1a, # ....Report ID (26) 125
  513. 0x05, 0x0c, # ....Usage Page (Consumer Devices) 127
  514. 0x95, 0x01, # ....Report Count (1) 129
  515. 0x75, 0x10, # ....Report Size (16) 131
  516. 0x16, 0x01, 0x80, # ....Logical Minimum (-32767) 133
  517. 0x26, 0xff, 0x7f, # ....Logical Maximum (32767) 136
  518. 0x0a, 0x38, 0x02, # ....Usage (AC Pan) 139
  519. 0x81, 0x06, # ....Input (Data,Var,Rel) 142
  520. 0xc0, # ...End Collection 144
  521. 0xc0, # ..End Collection 145
  522. 0xc0, # .End Collection 146
  523. 0xc0, # End Collection 147
  524. ]
  525. # fmt: on
  526. def __init__(self, rdesc=report_descriptor, name=None, input_info=None):
  527. super().__init__(rdesc, name, input_info)
  528. self.default_reportID = 0x1A
  529. # Feature Report 12, multiplier Feature value must be set to 0b0101,
  530. # i.e. 5. We should extract that from the descriptor instead
  531. # of hardcoding it here, but meanwhile this will do.
  532. self.set_feature_report = [0x12, 0x5]
  533. def set_report(self, req, rnum, rtype, data):
  534. super().set_report(req, rnum, rtype, data)
  535. self.wheel_multiplier = 12
  536. self.hwheel_multiplier = 12
  537. return 0
  538. class BaseTest:
  539. class TestMouse(base.BaseTestCase.TestUhid):
  540. def test_buttons(self):
  541. """check for button reliability."""
  542. uhdev = self.uhdev
  543. evdev = uhdev.get_evdev()
  544. syn_event = self.syn_event
  545. r = uhdev.event(0, 0, (None, True, None))
  546. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
  547. events = uhdev.next_sync_events()
  548. self.debug_reports(r, uhdev, events)
  549. self.assertInputEventsIn((syn_event, expected_event), events)
  550. assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
  551. r = uhdev.event(0, 0, (None, False, None))
  552. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
  553. events = uhdev.next_sync_events()
  554. self.debug_reports(r, uhdev, events)
  555. self.assertInputEventsIn((syn_event, expected_event), events)
  556. assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
  557. r = uhdev.event(0, 0, (None, None, True))
  558. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 1)
  559. events = uhdev.next_sync_events()
  560. self.debug_reports(r, uhdev, events)
  561. self.assertInputEventsIn((syn_event, expected_event), events)
  562. assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 1
  563. r = uhdev.event(0, 0, (None, None, False))
  564. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_MIDDLE, 0)
  565. events = uhdev.next_sync_events()
  566. self.debug_reports(r, uhdev, events)
  567. self.assertInputEventsIn((syn_event, expected_event), events)
  568. assert evdev.value[libevdev.EV_KEY.BTN_MIDDLE] == 0
  569. r = uhdev.event(0, 0, (True, None, None))
  570. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
  571. events = uhdev.next_sync_events()
  572. self.debug_reports(r, uhdev, events)
  573. self.assertInputEventsIn((syn_event, expected_event), events)
  574. assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
  575. r = uhdev.event(0, 0, (False, None, None))
  576. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
  577. events = uhdev.next_sync_events()
  578. self.debug_reports(r, uhdev, events)
  579. self.assertInputEventsIn((syn_event, expected_event), events)
  580. assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
  581. r = uhdev.event(0, 0, (True, True, None))
  582. expected_event0 = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 1)
  583. expected_event1 = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 1)
  584. events = uhdev.next_sync_events()
  585. self.debug_reports(r, uhdev, events)
  586. self.assertInputEventsIn(
  587. (syn_event, expected_event0, expected_event1), events
  588. )
  589. assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
  590. assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 1
  591. r = uhdev.event(0, 0, (False, None, None))
  592. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_LEFT, 0)
  593. events = uhdev.next_sync_events()
  594. self.debug_reports(r, uhdev, events)
  595. self.assertInputEventsIn((syn_event, expected_event), events)
  596. assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 1
  597. assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
  598. r = uhdev.event(0, 0, (None, False, None))
  599. expected_event = libevdev.InputEvent(libevdev.EV_KEY.BTN_RIGHT, 0)
  600. events = uhdev.next_sync_events()
  601. self.debug_reports(r, uhdev, events)
  602. self.assertInputEventsIn((syn_event, expected_event), events)
  603. assert evdev.value[libevdev.EV_KEY.BTN_RIGHT] == 0
  604. assert evdev.value[libevdev.EV_KEY.BTN_LEFT] == 0
  605. def test_relative(self):
  606. """Check for relative events."""
  607. uhdev = self.uhdev
  608. syn_event = self.syn_event
  609. r = uhdev.event(0, -1)
  610. expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_Y, -1)
  611. events = uhdev.next_sync_events()
  612. self.debug_reports(r, uhdev, events)
  613. self.assertInputEvents((syn_event, expected_event), events)
  614. r = uhdev.event(1, 0)
  615. expected_event = libevdev.InputEvent(libevdev.EV_REL.REL_X, 1)
  616. events = uhdev.next_sync_events()
  617. self.debug_reports(r, uhdev, events)
  618. self.assertInputEvents((syn_event, expected_event), events)
  619. r = uhdev.event(-1, 2)
  620. expected_event0 = libevdev.InputEvent(libevdev.EV_REL.REL_X, -1)
  621. expected_event1 = libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2)
  622. events = uhdev.next_sync_events()
  623. self.debug_reports(r, uhdev, events)
  624. self.assertInputEvents(
  625. (syn_event, expected_event0, expected_event1), events
  626. )
  627. class TestSimpleMouse(BaseTest.TestMouse):
  628. def create_device(self):
  629. return ButtonMouse()
  630. def test_rdesc(self):
  631. """Check that the testsuite actually manages to format the
  632. reports according to the report descriptors.
  633. No kernel device is used here"""
  634. uhdev = self.uhdev
  635. event = (0, 0, (None, None, None))
  636. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  637. event = (0, 0, (None, True, None))
  638. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  639. event = (0, 0, (True, True, None))
  640. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  641. event = (0, 0, (False, False, False))
  642. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  643. event = (1, 0, (True, False, True))
  644. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  645. event = (-1, 0, (True, False, True))
  646. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  647. event = (-5, 5, (True, False, True))
  648. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  649. event = (-127, 127, (True, False, True))
  650. assert uhdev.fake_report(*event) == uhdev.create_report(*event)
  651. event = (0, -128, (True, False, True))
  652. with pytest.raises(hidtools.hid.RangeError):
  653. uhdev.create_report(*event)
  654. class TestWheelMouse(BaseTest.TestMouse):
  655. def create_device(self):
  656. return WheelMouse()
  657. def is_wheel_highres(self, uhdev):
  658. evdev = uhdev.get_evdev()
  659. assert evdev.has(libevdev.EV_REL.REL_WHEEL)
  660. return evdev.has(libevdev.EV_REL.REL_WHEEL_HI_RES)
  661. def test_wheel(self):
  662. uhdev = self.uhdev
  663. # check if the kernel is high res wheel compatible
  664. high_res_wheel = self.is_wheel_highres(uhdev)
  665. syn_event = self.syn_event
  666. # The Resolution Multiplier is applied to the HID reports, so we
  667. # need to pre-multiply too.
  668. mult = uhdev.wheel_multiplier
  669. r = uhdev.event(0, 0, wheels=1 * mult)
  670. expected = [syn_event]
  671. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
  672. if high_res_wheel:
  673. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120))
  674. events = uhdev.next_sync_events()
  675. self.debug_reports(r, uhdev, events)
  676. self.assertInputEvents(expected, events)
  677. r = uhdev.event(0, 0, wheels=-1 * mult)
  678. expected = [syn_event]
  679. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -1))
  680. if high_res_wheel:
  681. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120))
  682. events = uhdev.next_sync_events()
  683. self.debug_reports(r, uhdev, events)
  684. self.assertInputEvents(expected, events)
  685. r = uhdev.event(-1, 2, wheels=3 * mult)
  686. expected = [syn_event]
  687. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
  688. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
  689. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 3))
  690. if high_res_wheel:
  691. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 360))
  692. events = uhdev.next_sync_events()
  693. self.debug_reports(r, uhdev, events)
  694. self.assertInputEvents(expected, events)
  695. class TestTwoWheelMouse(TestWheelMouse):
  696. def create_device(self):
  697. return TwoWheelMouse()
  698. def is_hwheel_highres(self, uhdev):
  699. evdev = uhdev.get_evdev()
  700. assert evdev.has(libevdev.EV_REL.REL_HWHEEL)
  701. return evdev.has(libevdev.EV_REL.REL_HWHEEL_HI_RES)
  702. def test_ac_pan(self):
  703. uhdev = self.uhdev
  704. # check if the kernel is high res wheel compatible
  705. high_res_wheel = self.is_wheel_highres(uhdev)
  706. high_res_hwheel = self.is_hwheel_highres(uhdev)
  707. assert high_res_wheel == high_res_hwheel
  708. syn_event = self.syn_event
  709. # The Resolution Multiplier is applied to the HID reports, so we
  710. # need to pre-multiply too.
  711. hmult = uhdev.hwheel_multiplier
  712. vmult = uhdev.wheel_multiplier
  713. r = uhdev.event(0, 0, wheels=(0, 1 * hmult))
  714. expected = [syn_event]
  715. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
  716. if high_res_hwheel:
  717. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120))
  718. events = uhdev.next_sync_events()
  719. self.debug_reports(r, uhdev, events)
  720. self.assertInputEvents(expected, events)
  721. r = uhdev.event(0, 0, wheels=(0, -1 * hmult))
  722. expected = [syn_event]
  723. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, -1))
  724. if high_res_hwheel:
  725. expected.append(
  726. libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120)
  727. )
  728. events = uhdev.next_sync_events()
  729. self.debug_reports(r, uhdev, events)
  730. self.assertInputEvents(expected, events)
  731. r = uhdev.event(-1, 2, wheels=(0, 3 * hmult))
  732. expected = [syn_event]
  733. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
  734. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
  735. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 3))
  736. if high_res_hwheel:
  737. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 360))
  738. events = uhdev.next_sync_events()
  739. self.debug_reports(r, uhdev, events)
  740. self.assertInputEvents(expected, events)
  741. r = uhdev.event(-1, 2, wheels=(-3 * vmult, 4 * hmult))
  742. expected = [syn_event]
  743. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, -1))
  744. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, 2))
  745. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, -3))
  746. if high_res_wheel:
  747. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -360))
  748. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 4))
  749. if high_res_wheel:
  750. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 480))
  751. events = uhdev.next_sync_events()
  752. self.debug_reports(r, uhdev, events)
  753. self.assertInputEvents(expected, events)
  754. class TestResolutionMultiplierMouse(TestTwoWheelMouse):
  755. def create_device(self):
  756. return ResolutionMultiplierMouse()
  757. def is_wheel_highres(self, uhdev):
  758. high_res = super().is_wheel_highres(uhdev)
  759. if not high_res:
  760. # the kernel doesn't seem to support the high res wheel mice,
  761. # make sure we haven't triggered the feature
  762. assert uhdev.wheel_multiplier == 1
  763. return high_res
  764. def test_resolution_multiplier_wheel(self):
  765. uhdev = self.uhdev
  766. if not self.is_wheel_highres(uhdev):
  767. pytest.skip("Kernel not compatible, we can not trigger the conditions")
  768. assert uhdev.wheel_multiplier > 1
  769. assert 120 % uhdev.wheel_multiplier == 0
  770. def test_wheel_with_multiplier(self):
  771. uhdev = self.uhdev
  772. if not self.is_wheel_highres(uhdev):
  773. pytest.skip("Kernel not compatible, we can not trigger the conditions")
  774. assert uhdev.wheel_multiplier > 1
  775. syn_event = self.syn_event
  776. mult = uhdev.wheel_multiplier
  777. r = uhdev.event(0, 0, wheels=1)
  778. expected = [syn_event]
  779. expected.append(
  780. libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
  781. )
  782. events = uhdev.next_sync_events()
  783. self.debug_reports(r, uhdev, events)
  784. self.assertInputEvents(expected, events)
  785. r = uhdev.event(0, 0, wheels=-1)
  786. expected = [syn_event]
  787. expected.append(
  788. libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, -120 / mult)
  789. )
  790. events = uhdev.next_sync_events()
  791. self.debug_reports(r, uhdev, events)
  792. self.assertInputEvents(expected, events)
  793. expected = [syn_event]
  794. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
  795. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
  796. expected.append(
  797. libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL_HI_RES, 120 / mult)
  798. )
  799. for _ in range(mult - 1):
  800. r = uhdev.event(1, -2, wheels=1)
  801. events = uhdev.next_sync_events()
  802. self.debug_reports(r, uhdev, events)
  803. self.assertInputEvents(expected, events)
  804. r = uhdev.event(1, -2, wheels=1)
  805. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_WHEEL, 1))
  806. events = uhdev.next_sync_events()
  807. self.debug_reports(r, uhdev, events)
  808. self.assertInputEvents(expected, events)
  809. class TestBadResolutionMultiplierMouse(TestTwoWheelMouse):
  810. def create_device(self):
  811. return BadResolutionMultiplierMouse()
  812. def is_wheel_highres(self, uhdev):
  813. high_res = super().is_wheel_highres(uhdev)
  814. assert uhdev.wheel_multiplier == 1
  815. return high_res
  816. def test_resolution_multiplier_wheel(self):
  817. uhdev = self.uhdev
  818. assert uhdev.wheel_multiplier == 1
  819. class TestResolutionMultiplierHWheelMouse(TestResolutionMultiplierMouse):
  820. def create_device(self):
  821. return ResolutionMultiplierHWheelMouse()
  822. def is_hwheel_highres(self, uhdev):
  823. high_res = super().is_hwheel_highres(uhdev)
  824. if not high_res:
  825. # the kernel doesn't seem to support the high res wheel mice,
  826. # make sure we haven't triggered the feature
  827. assert uhdev.hwheel_multiplier == 1
  828. return high_res
  829. def test_resolution_multiplier_ac_pan(self):
  830. uhdev = self.uhdev
  831. if not self.is_hwheel_highres(uhdev):
  832. pytest.skip("Kernel not compatible, we can not trigger the conditions")
  833. assert uhdev.hwheel_multiplier > 1
  834. assert 120 % uhdev.hwheel_multiplier == 0
  835. def test_ac_pan_with_multiplier(self):
  836. uhdev = self.uhdev
  837. if not self.is_hwheel_highres(uhdev):
  838. pytest.skip("Kernel not compatible, we can not trigger the conditions")
  839. assert uhdev.hwheel_multiplier > 1
  840. syn_event = self.syn_event
  841. hmult = uhdev.hwheel_multiplier
  842. r = uhdev.event(0, 0, wheels=(0, 1))
  843. expected = [syn_event]
  844. expected.append(
  845. libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
  846. )
  847. events = uhdev.next_sync_events()
  848. self.debug_reports(r, uhdev, events)
  849. self.assertInputEvents(expected, events)
  850. r = uhdev.event(0, 0, wheels=(0, -1))
  851. expected = [syn_event]
  852. expected.append(
  853. libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, -120 / hmult)
  854. )
  855. events = uhdev.next_sync_events()
  856. self.debug_reports(r, uhdev, events)
  857. self.assertInputEvents(expected, events)
  858. expected = [syn_event]
  859. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_X, 1))
  860. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_Y, -2))
  861. expected.append(
  862. libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL_HI_RES, 120 / hmult)
  863. )
  864. for _ in range(hmult - 1):
  865. r = uhdev.event(1, -2, wheels=(0, 1))
  866. events = uhdev.next_sync_events()
  867. self.debug_reports(r, uhdev, events)
  868. self.assertInputEvents(expected, events)
  869. r = uhdev.event(1, -2, wheels=(0, 1))
  870. expected.append(libevdev.InputEvent(libevdev.EV_REL.REL_HWHEEL, 1))
  871. events = uhdev.next_sync_events()
  872. self.debug_reports(r, uhdev, events)
  873. self.assertInputEvents(expected, events)
  874. class TestMiMouse(TestWheelMouse):
  875. def create_device(self):
  876. return MIDongleMIWirelessMouse()
  877. def assertInputEvents(self, expected_events, effective_events):
  878. # Buttons and x/y are spread over two HID reports, so we can get two
  879. # event frames for this device.
  880. remaining = self.assertInputEventsIn(expected_events, effective_events)
  881. try:
  882. remaining.remove(libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT, 0))
  883. except ValueError:
  884. # If there's no SYN_REPORT in the list, continue and let the
  885. # assert below print out the real error
  886. pass
  887. assert remaining == []
  888. class TestBadReportDescriptorMouse(base.BaseTestCase.TestUhid):
  889. def create_device(self):
  890. return BadReportDescriptorMouse()
  891. def assertName(self, uhdev):
  892. pass