1#!/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3# -*- coding: utf-8 -*-
4#
5# Copyright (c) 2019 Benjamin Tissoires <benjamin.tissoires@gmail.com>
6# Copyright (c) 2019 Red Hat, Inc.
7#
8
9from .test_keyboard import ArrayKeyboard, TestArrayKeyboard
10from hidtools.util import BusType
11
12import libevdev
13import logging
14
15logger = logging.getLogger("hidtools.test.apple-keyboard")
16
17KERNEL_MODULE = ("apple", "hid-apple")
18
19
20class KbdData(object):
21    pass
22
23
24class AppleKeyboard(ArrayKeyboard):
25    # fmt: off
26    report_descriptor = [
27        0x05, 0x01,         # Usage Page (Generic Desktop)
28        0x09, 0x06,         # Usage (Keyboard)
29        0xa1, 0x01,         # Collection (Application)
30        0x85, 0x01,         # .Report ID (1)
31        0x05, 0x07,         # .Usage Page (Keyboard)
32        0x19, 0xe0,         # .Usage Minimum (224)
33        0x29, 0xe7,         # .Usage Maximum (231)
34        0x15, 0x00,         # .Logical Minimum (0)
35        0x25, 0x01,         # .Logical Maximum (1)
36        0x75, 0x01,         # .Report Size (1)
37        0x95, 0x08,         # .Report Count (8)
38        0x81, 0x02,         # .Input (Data,Var,Abs)
39        0x75, 0x08,         # .Report Size (8)
40        0x95, 0x01,         # .Report Count (1)
41        0x81, 0x01,         # .Input (Cnst,Arr,Abs)
42        0x75, 0x01,         # .Report Size (1)
43        0x95, 0x05,         # .Report Count (5)
44        0x05, 0x08,         # .Usage Page (LEDs)
45        0x19, 0x01,         # .Usage Minimum (1)
46        0x29, 0x05,         # .Usage Maximum (5)
47        0x91, 0x02,         # .Output (Data,Var,Abs)
48        0x75, 0x03,         # .Report Size (3)
49        0x95, 0x01,         # .Report Count (1)
50        0x91, 0x01,         # .Output (Cnst,Arr,Abs)
51        0x75, 0x08,         # .Report Size (8)
52        0x95, 0x06,         # .Report Count (6)
53        0x15, 0x00,         # .Logical Minimum (0)
54        0x26, 0xff, 0x00,   # .Logical Maximum (255)
55        0x05, 0x07,         # .Usage Page (Keyboard)
56        0x19, 0x00,         # .Usage Minimum (0)
57        0x2a, 0xff, 0x00,   # .Usage Maximum (255)
58        0x81, 0x00,         # .Input (Data,Arr,Abs)
59        0xc0,               # End Collection
60        0x05, 0x0c,         # Usage Page (Consumer Devices)
61        0x09, 0x01,         # Usage (Consumer Control)
62        0xa1, 0x01,         # Collection (Application)
63        0x85, 0x47,         # .Report ID (71)
64        0x05, 0x01,         # .Usage Page (Generic Desktop)
65        0x09, 0x06,         # .Usage (Keyboard)
66        0xa1, 0x02,         # .Collection (Logical)
67        0x05, 0x06,         # ..Usage Page (Generic Device Controls)
68        0x09, 0x20,         # ..Usage (Battery Strength)
69        0x15, 0x00,         # ..Logical Minimum (0)
70        0x26, 0xff, 0x00,   # ..Logical Maximum (255)
71        0x75, 0x08,         # ..Report Size (8)
72        0x95, 0x01,         # ..Report Count (1)
73        0x81, 0x02,         # ..Input (Data,Var,Abs)
74        0xc0,               # .End Collection
75        0xc0,               # End Collection
76        0x05, 0x0c,         # Usage Page (Consumer Devices)
77        0x09, 0x01,         # Usage (Consumer Control)
78        0xa1, 0x01,         # Collection (Application)
79        0x85, 0x11,         # .Report ID (17)
80        0x15, 0x00,         # .Logical Minimum (0)
81        0x25, 0x01,         # .Logical Maximum (1)
82        0x75, 0x01,         # .Report Size (1)
83        0x95, 0x03,         # .Report Count (3)
84        0x81, 0x01,         # .Input (Cnst,Arr,Abs)
85        0x75, 0x01,         # .Report Size (1)
86        0x95, 0x01,         # .Report Count (1)
87        0x05, 0x0c,         # .Usage Page (Consumer Devices)
88        0x09, 0xb8,         # .Usage (Eject)
89        0x81, 0x02,         # .Input (Data,Var,Abs)
90        0x06, 0xff, 0x00,   # .Usage Page (Vendor Usage Page 0xff)
91        0x09, 0x03,         # .Usage (Vendor Usage 0x03)
92        0x81, 0x02,         # .Input (Data,Var,Abs)
93        0x75, 0x01,         # .Report Size (1)
94        0x95, 0x03,         # .Report Count (3)
95        0x81, 0x01,         # .Input (Cnst,Arr,Abs)
96        0x05, 0x0c,         # .Usage Page (Consumer Devices)
97        0x85, 0x12,         # .Report ID (18)
98        0x15, 0x00,         # .Logical Minimum (0)
99        0x25, 0x01,         # .Logical Maximum (1)
100        0x75, 0x01,         # .Report Size (1)
101        0x95, 0x01,         # .Report Count (1)
102        0x09, 0xcd,         # .Usage (Play/Pause)
103        0x81, 0x02,         # .Input (Data,Var,Abs)
104        0x09, 0xb3,         # .Usage (Fast Forward)
105        0x81, 0x02,         # .Input (Data,Var,Abs)
106        0x09, 0xb4,         # .Usage (Rewind)
107        0x81, 0x02,         # .Input (Data,Var,Abs)
108        0x09, 0xb5,         # .Usage (Scan Next Track)
109        0x81, 0x02,         # .Input (Data,Var,Abs)
110        0x09, 0xb6,         # .Usage (Scan Previous Track)
111        0x81, 0x02,         # .Input (Data,Var,Abs)
112        0x81, 0x01,         # .Input (Cnst,Arr,Abs)
113        0x81, 0x01,         # .Input (Cnst,Arr,Abs)
114        0x81, 0x01,         # .Input (Cnst,Arr,Abs)
115        0x85, 0x13,         # .Report ID (19)
116        0x15, 0x00,         # .Logical Minimum (0)
117        0x25, 0x01,         # .Logical Maximum (1)
118        0x75, 0x01,         # .Report Size (1)
119        0x95, 0x01,         # .Report Count (1)
120        0x06, 0x01, 0xff,   # .Usage Page (Vendor Usage Page 0xff01)
121        0x09, 0x0a,         # .Usage (Vendor Usage 0x0a)
122        0x81, 0x02,         # .Input (Data,Var,Abs)
123        0x06, 0x01, 0xff,   # .Usage Page (Vendor Usage Page 0xff01)
124        0x09, 0x0c,         # .Usage (Vendor Usage 0x0c)
125        0x81, 0x22,         # .Input (Data,Var,Abs,NoPref)
126        0x75, 0x01,         # .Report Size (1)
127        0x95, 0x06,         # .Report Count (6)
128        0x81, 0x01,         # .Input (Cnst,Arr,Abs)
129        0x85, 0x09,         # .Report ID (9)
130        0x09, 0x0b,         # .Usage (Vendor Usage 0x0b)
131        0x75, 0x08,         # .Report Size (8)
132        0x95, 0x01,         # .Report Count (1)
133        0xb1, 0x02,         # .Feature (Data,Var,Abs)
134        0x75, 0x08,         # .Report Size (8)
135        0x95, 0x02,         # .Report Count (2)
136        0xb1, 0x01,         # .Feature (Cnst,Arr,Abs)
137        0xc0,               # End Collection
138    ]
139    # fmt: on
140
141    def __init__(
142        self,
143        rdesc=report_descriptor,
144        name="Apple Wireless Keyboard",
145        input_info=(BusType.BLUETOOTH, 0x05AC, 0x0256),
146    ):
147        super().__init__(rdesc, name, input_info)
148        self.default_reportID = 1
149
150    def send_fn_state(self, state):
151        data = KbdData()
152        setattr(data, "0xff0003", state)
153        r = self.create_report(data, reportID=17)
154        self.call_input_event(r)
155        return [r]
156
157
158class TestAppleKeyboard(TestArrayKeyboard):
159    kernel_modules = [KERNEL_MODULE]
160
161    def create_device(self):
162        return AppleKeyboard()
163
164    def test_single_function_key(self):
165        """check for function key reliability."""
166        uhdev = self.uhdev
167        evdev = uhdev.get_evdev()
168        syn_event = self.syn_event
169
170        r = uhdev.event(["F4"])
171        expected = [syn_event]
172        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_ALL_APPLICATIONS, 1))
173        events = uhdev.next_sync_events()
174        self.debug_reports(r, uhdev, events)
175        self.assertInputEventsIn(expected, events)
176        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 1
177        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 0
178
179        r = uhdev.event([])
180        expected = [syn_event]
181        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_ALL_APPLICATIONS, 0))
182        events = uhdev.next_sync_events()
183        self.debug_reports(r, uhdev, events)
184        self.assertInputEventsIn(expected, events)
185        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 0
186
187    def test_single_fn_function_key(self):
188        """check for function key reliability with the fn key."""
189        uhdev = self.uhdev
190        evdev = uhdev.get_evdev()
191        syn_event = self.syn_event
192
193        r = uhdev.send_fn_state(1)
194        r.extend(uhdev.event(["F4"]))
195        expected = [syn_event]
196        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F4, 1))
197        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 1))
198        events = uhdev.next_sync_events()
199        self.debug_reports(r, uhdev, events)
200        self.assertInputEventsIn(expected, events)
201        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 1
202
203        r = uhdev.event([])
204        expected = [syn_event]
205        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F4, 0))
206        events = uhdev.next_sync_events()
207        self.debug_reports(r, uhdev, events)
208        self.assertInputEventsIn(expected, events)
209        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
210        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
211
212        r = uhdev.send_fn_state(0)
213        expected = [syn_event]
214        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 0))
215        events = uhdev.next_sync_events()
216        self.debug_reports(r, uhdev, events)
217        self.assertInputEventsIn(expected, events)
218
219    def test_single_fn_function_key_release_first(self):
220        """check for function key reliability with the fn key."""
221        uhdev = self.uhdev
222        evdev = uhdev.get_evdev()
223        syn_event = self.syn_event
224
225        r = uhdev.send_fn_state(1)
226        r.extend(uhdev.event(["F4"]))
227        expected = [syn_event]
228        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F4, 1))
229        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 1))
230        events = uhdev.next_sync_events()
231        self.debug_reports(r, uhdev, events)
232        self.assertInputEventsIn(expected, events)
233        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 1
234
235        r = uhdev.send_fn_state(0)
236        expected = [syn_event]
237        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 0))
238        events = uhdev.next_sync_events()
239        self.debug_reports(r, uhdev, events)
240        self.assertInputEventsIn(expected, events)
241
242        r = uhdev.event([])
243        expected = [syn_event]
244        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F4, 0))
245        events = uhdev.next_sync_events()
246        self.debug_reports(r, uhdev, events)
247        self.assertInputEventsIn(expected, events)
248        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
249
250    def test_single_fn_function_key_inverted(self):
251        """check for function key reliability with the fn key."""
252        uhdev = self.uhdev
253        evdev = uhdev.get_evdev()
254        syn_event = self.syn_event
255
256        r = uhdev.event(["F4"])
257        r.extend(uhdev.send_fn_state(1))
258        expected = [syn_event]
259        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_ALL_APPLICATIONS, 1))
260        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 1))
261        events = uhdev.next_sync_events()
262        self.debug_reports(r, uhdev, events)
263        self.assertInputEventsIn(expected, events)
264        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 1
265
266        r = uhdev.event([])
267        expected = [syn_event]
268        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_ALL_APPLICATIONS, 0))
269        events = uhdev.next_sync_events()
270        self.debug_reports(r, uhdev, events)
271        self.assertInputEventsIn(expected, events)
272        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 0
273        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
274
275        r = uhdev.send_fn_state(0)
276        expected = [syn_event]
277        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 0))
278        events = uhdev.next_sync_events()
279        self.debug_reports(r, uhdev, events)
280        self.assertInputEventsIn(expected, events)
281
282    def test_multiple_fn_function_key_release_first(self):
283        """check for function key reliability with the fn key."""
284        uhdev = self.uhdev
285        evdev = uhdev.get_evdev()
286        syn_event = self.syn_event
287
288        r = uhdev.send_fn_state(1)
289        r.extend(uhdev.event(["F4"]))
290        r.extend(uhdev.event(["F4", "F6"]))
291        expected = [syn_event]
292        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F4, 1))
293        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F6, 1))
294        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 1))
295        events = uhdev.next_sync_events()
296        self.debug_reports(r, uhdev, events)
297        self.assertInputEventsIn(expected, events)
298        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 1
299        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 1
300        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
301
302        r = uhdev.event(["F6"])
303        expected = [syn_event]
304        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F4, 0))
305        events = uhdev.next_sync_events()
306        self.debug_reports(r, uhdev, events)
307        self.assertInputEventsIn(expected, events)
308        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
309        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 1
310        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
311
312        r = uhdev.send_fn_state(0)
313        expected = [syn_event]
314        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 0))
315        events = uhdev.next_sync_events()
316        self.debug_reports(r, uhdev, events)
317        self.assertInputEventsIn(expected, events)
318        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
319        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 1
320        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 0
321
322        r = uhdev.event([])
323        expected = [syn_event]
324        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F6, 0))
325        events = uhdev.next_sync_events()
326        self.debug_reports(r, uhdev, events)
327        self.assertInputEventsIn(expected, events)
328        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
329        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 0
330        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 0
331
332    def test_multiple_fn_function_key_release_between(self):
333        """check for function key reliability with the fn key."""
334        uhdev = self.uhdev
335        evdev = uhdev.get_evdev()
336        syn_event = self.syn_event
337
338        # press F4
339        r = uhdev.event(["F4"])
340        expected = [syn_event]
341        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_ALL_APPLICATIONS, 1))
342        events = uhdev.next_sync_events()
343        self.debug_reports(r, uhdev, events)
344        self.assertInputEventsIn(expected, events)
345        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
346        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 1
347        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 0
348        assert evdev.value[libevdev.EV_KEY.KEY_KBDILLUMUP] == 0
349        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 0
350
351        # press Fn key
352        r = uhdev.send_fn_state(1)
353        expected = [syn_event]
354        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 1))
355        events = uhdev.next_sync_events()
356        self.debug_reports(r, uhdev, events)
357        self.assertInputEventsIn(expected, events)
358        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
359        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 1
360        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 0
361        assert evdev.value[libevdev.EV_KEY.KEY_KBDILLUMUP] == 0
362        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
363
364        # keep F4 and press F6
365        r = uhdev.event(["F4", "F6"])
366        expected = [syn_event]
367        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F6, 1))
368        events = uhdev.next_sync_events()
369        self.debug_reports(r, uhdev, events)
370        self.assertInputEventsIn(expected, events)
371        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
372        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 1
373        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 1
374        assert evdev.value[libevdev.EV_KEY.KEY_KBDILLUMUP] == 0
375        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
376
377        # keep F4 and F6
378        r = uhdev.event(["F4", "F6"])
379        expected = []
380        events = uhdev.next_sync_events()
381        self.debug_reports(r, uhdev, events)
382        self.assertInputEventsIn(expected, events)
383        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
384        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 1
385        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 1
386        assert evdev.value[libevdev.EV_KEY.KEY_KBDILLUMUP] == 0
387        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
388
389        # release Fn key and all keys
390        r = uhdev.send_fn_state(0)
391        r.extend(uhdev.event([]))
392        expected = [syn_event]
393        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_ALL_APPLICATIONS, 0))
394        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_F6, 0))
395        events = uhdev.next_sync_events()
396        self.debug_reports(r, uhdev, events)
397        self.assertInputEventsIn(expected, events)
398        assert evdev.value[libevdev.EV_KEY.KEY_F4] == 0
399        assert evdev.value[libevdev.EV_KEY.KEY_ALL_APPLICATIONS] == 0
400        assert evdev.value[libevdev.EV_KEY.KEY_F6] == 0
401        assert evdev.value[libevdev.EV_KEY.KEY_KBDILLUMUP] == 0
402        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 0
403
404    def test_single_pageup_key_release_first(self):
405        """check for function key reliability with the [page] up key."""
406        uhdev = self.uhdev
407        evdev = uhdev.get_evdev()
408        syn_event = self.syn_event
409
410        r = uhdev.send_fn_state(1)
411        r.extend(uhdev.event(["UpArrow"]))
412        expected = [syn_event]
413        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_PAGEUP, 1))
414        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 1))
415        events = uhdev.next_sync_events()
416        self.debug_reports(r, uhdev, events)
417        self.assertInputEventsIn(expected, events)
418        assert evdev.value[libevdev.EV_KEY.KEY_PAGEUP] == 1
419        assert evdev.value[libevdev.EV_KEY.KEY_UP] == 0
420        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 1
421
422        r = uhdev.send_fn_state(0)
423        expected = [syn_event]
424        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_FN, 0))
425        events = uhdev.next_sync_events()
426        self.debug_reports(r, uhdev, events)
427        self.assertInputEventsIn(expected, events)
428        assert evdev.value[libevdev.EV_KEY.KEY_PAGEUP] == 1
429        assert evdev.value[libevdev.EV_KEY.KEY_UP] == 0
430        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 0
431
432        r = uhdev.event([])
433        expected = [syn_event]
434        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_PAGEUP, 0))
435        events = uhdev.next_sync_events()
436        self.debug_reports(r, uhdev, events)
437        self.assertInputEventsIn(expected, events)
438        assert evdev.value[libevdev.EV_KEY.KEY_PAGEUP] == 0
439        assert evdev.value[libevdev.EV_KEY.KEY_UP] == 0
440        assert evdev.value[libevdev.EV_KEY.KEY_FN] == 0
441