brintos

brintos / linux-shallow public Read only

0
0
Text · 19.6 KiB · b3b2bdb Raw
486 lines · python
1#!/bin/env python32# SPDX-License-Identifier: GPL-2.03# -*- coding: utf-8 -*-4#5# Copyright (c) 2018 Benjamin Tissoires <benjamin.tissoires@gmail.com>6# Copyright (c) 2018 Red Hat, Inc.7#8 9from . import base10import hidtools.hid11import libevdev12import logging13 14logger = logging.getLogger("hidtools.test.keyboard")15 16 17class InvalidHIDCommunication(Exception):18    pass19 20 21class KeyboardData(object):22    pass23 24 25class BaseKeyboard(base.UHIDTestDevice):26    def __init__(self, rdesc, name=None, input_info=None):27        assert rdesc is not None28        super().__init__(name, "Key", input_info=input_info, rdesc=rdesc)29        self.keystates = {}30 31    def _update_key_state(self, keys):32        """33        Update the internal state of keys with the new state given.34 35        :param key: a tuple of chars for the currently pressed keys.36        """37        # First remove the already released keys38        unused_keys = [k for k, v in self.keystates.items() if not v]39        for key in unused_keys:40            del self.keystates[key]41 42        # self.keystates contains now the list of currently pressed keys,43        # release them...44        for key in self.keystates.keys():45            self.keystates[key] = False46 47        # ...and press those that are in parameter48        for key in keys:49            self.keystates[key] = True50 51    def _create_report_data(self):52        keyboard = KeyboardData()53        for key, value in self.keystates.items():54            key = key.replace(" ", "").lower()55            setattr(keyboard, key, value)56        return keyboard57 58    def create_array_report(self, keys, reportID=None, application=None):59        """60        Return an input report for this device.61 62        :param keys: a tuple of chars for the pressed keys. The class maintains63            the list of currently pressed keys, so to release a key, the caller64            needs to call again this function without the key in this tuple.65        :param reportID: the numeric report ID for this report, if needed66        """67        self._update_key_state(keys)68        reportID = reportID or self.default_reportID69 70        keyboard = self._create_report_data()71        return self.create_report(keyboard, reportID=reportID, application=application)72 73    def event(self, keys, reportID=None, application=None):74        """75        Send an input event on the default report ID.76 77        :param keys: a tuple of chars for the pressed keys. The class maintains78            the list of currently pressed keys, so to release a key, the caller79            needs to call again this function without the key in this tuple.80        """81        r = self.create_array_report(keys, reportID, application)82        self.call_input_event(r)83        return [r]84 85 86class PlainKeyboard(BaseKeyboard):87    # fmt: off88    report_descriptor = [89        0x05, 0x01,                    # Usage Page (Generic Desktop)90        0x09, 0x06,                    # Usage (Keyboard)91        0xa1, 0x01,                    # Collection (Application)92        0x85, 0x01,                    # .Report ID (1)93        0x05, 0x07,                    # .Usage Page (Keyboard)94        0x19, 0xe0,                    # .Usage Minimum (224)95        0x29, 0xe7,                    # .Usage Maximum (231)96        0x15, 0x00,                    # .Logical Minimum (0)97        0x25, 0x01,                    # .Logical Maximum (1)98        0x75, 0x01,                    # .Report Size (1)99        0x95, 0x08,                    # .Report Count (8)100        0x81, 0x02,                    # .Input (Data,Var,Abs)101        0x19, 0x00,                    # .Usage Minimum (0)102        0x29, 0x97,                    # .Usage Maximum (151)103        0x15, 0x00,                    # .Logical Minimum (0)104        0x25, 0x01,                    # .Logical Maximum (1)105        0x75, 0x01,                    # .Report Size (1)106        0x95, 0x98,                    # .Report Count (152)107        0x81, 0x02,                    # .Input (Data,Var,Abs)108        0xc0,                          # End Collection109    ]110    # fmt: on111 112    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):113        super().__init__(rdesc, name, input_info)114        self.default_reportID = 1115 116 117class ArrayKeyboard(BaseKeyboard):118    # fmt: off119    report_descriptor = [120        0x05, 0x01,                    # Usage Page (Generic Desktop)121        0x09, 0x06,                    # Usage (Keyboard)122        0xa1, 0x01,                    # Collection (Application)123        0x05, 0x07,                    # .Usage Page (Keyboard)124        0x19, 0xe0,                    # .Usage Minimum (224)125        0x29, 0xe7,                    # .Usage Maximum (231)126        0x15, 0x00,                    # .Logical Minimum (0)127        0x25, 0x01,                    # .Logical Maximum (1)128        0x75, 0x01,                    # .Report Size (1)129        0x95, 0x08,                    # .Report Count (8)130        0x81, 0x02,                    # .Input (Data,Var,Abs)131        0x95, 0x06,                    # .Report Count (6)132        0x75, 0x08,                    # .Report Size (8)133        0x15, 0x00,                    # .Logical Minimum (0)134        0x26, 0xa4, 0x00,              # .Logical Maximum (164)135        0x05, 0x07,                    # .Usage Page (Keyboard)136        0x19, 0x00,                    # .Usage Minimum (0)137        0x29, 0xa4,                    # .Usage Maximum (164)138        0x81, 0x00,                    # .Input (Data,Arr,Abs)139        0xc0,                          # End Collection140    ]141    # fmt: on142 143    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):144        super().__init__(rdesc, name, input_info)145 146    def _create_report_data(self):147        data = KeyboardData()148        array = []149 150        hut = hidtools.hut.HUT151 152        # strip modifiers from the array153        for k, v in self.keystates.items():154            # we ignore depressed keys155            if not v:156                continue157 158            usage = hut[0x07].from_name[k].usage159            if usage >= 224 and usage <= 231:160                # modifier161                setattr(data, k.lower(), 1)162            else:163                array.append(k)164 165        # if array length is bigger than 6, report ErrorRollOver166        if len(array) > 6:167            array = ["ErrorRollOver"] * 6168 169        data.keyboard = array170        return data171 172 173class LEDKeyboard(ArrayKeyboard):174    # fmt: off175    report_descriptor = [176        0x05, 0x01,                    # Usage Page (Generic Desktop)177        0x09, 0x06,                    # Usage (Keyboard)178        0xa1, 0x01,                    # Collection (Application)179        0x05, 0x07,                    # .Usage Page (Keyboard)180        0x19, 0xe0,                    # .Usage Minimum (224)181        0x29, 0xe7,                    # .Usage Maximum (231)182        0x15, 0x00,                    # .Logical Minimum (0)183        0x25, 0x01,                    # .Logical Maximum (1)184        0x75, 0x01,                    # .Report Size (1)185        0x95, 0x08,                    # .Report Count (8)186        0x81, 0x02,                    # .Input (Data,Var,Abs)187        0x95, 0x01,                    # .Report Count (1)188        0x75, 0x08,                    # .Report Size (8)189        0x81, 0x01,                    # .Input (Cnst,Arr,Abs)190        0x95, 0x05,                    # .Report Count (5)191        0x75, 0x01,                    # .Report Size (1)192        0x05, 0x08,                    # .Usage Page (LEDs)193        0x19, 0x01,                    # .Usage Minimum (1)194        0x29, 0x05,                    # .Usage Maximum (5)195        0x91, 0x02,                    # .Output (Data,Var,Abs)196        0x95, 0x01,                    # .Report Count (1)197        0x75, 0x03,                    # .Report Size (3)198        0x91, 0x01,                    # .Output (Cnst,Arr,Abs)199        0x95, 0x06,                    # .Report Count (6)200        0x75, 0x08,                    # .Report Size (8)201        0x15, 0x00,                    # .Logical Minimum (0)202        0x26, 0xa4, 0x00,              # .Logical Maximum (164)203        0x05, 0x07,                    # .Usage Page (Keyboard)204        0x19, 0x00,                    # .Usage Minimum (0)205        0x29, 0xa4,                    # .Usage Maximum (164)206        0x81, 0x00,                    # .Input (Data,Arr,Abs)207        0xc0,                          # End Collection208    ]209    # fmt: on210 211    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):212        super().__init__(rdesc, name, input_info)213 214 215# Some Primax manufactured keyboards set the Usage Page after having defined216# some local Usages. It relies on the fact that the specification states that217# Usages are to be concatenated with Usage Pages upon finding a Main item (see218# 6.2.2.8). This test covers this case.219class PrimaxKeyboard(ArrayKeyboard):220    # fmt: off221    report_descriptor = [222        0x05, 0x01,                    # Usage Page (Generic Desktop)223        0x09, 0x06,                    # Usage (Keyboard)224        0xA1, 0x01,                    # Collection (Application)225        0x05, 0x07,                    # .Usage Page (Keyboard)226        0x19, 0xE0,                    # .Usage Minimum (224)227        0x29, 0xE7,                    # .Usage Maximum (231)228        0x15, 0x00,                    # .Logical Minimum (0)229        0x25, 0x01,                    # .Logical Maximum (1)230        0x75, 0x01,                    # .Report Size (1)231        0x95, 0x08,                    # .Report Count (8)232        0x81, 0x02,                    # .Input (Data,Var,Abs)233        0x75, 0x08,                    # .Report Size (8)234        0x95, 0x01,                    # .Report Count (1)235        0x81, 0x01,                    # .Input (Data,Var,Abs)236        0x05, 0x08,                    # .Usage Page (LEDs)237        0x19, 0x01,                    # .Usage Minimum (1)238        0x29, 0x03,                    # .Usage Maximum (3)239        0x75, 0x01,                    # .Report Size (1)240        0x95, 0x03,                    # .Report Count (3)241        0x91, 0x02,                    # .Output (Data,Var,Abs)242        0x95, 0x01,                    # .Report Count (1)243        0x75, 0x05,                    # .Report Size (5)244        0x91, 0x01,                    # .Output (Constant)245        0x15, 0x00,                    # .Logical Minimum (0)246        0x26, 0xFF, 0x00,              # .Logical Maximum (255)247        0x19, 0x00,                    # .Usage Minimum (0)248        0x2A, 0xFF, 0x00,              # .Usage Maximum (255)249        0x05, 0x07,                    # .Usage Page (Keyboard)250        0x75, 0x08,                    # .Report Size (8)251        0x95, 0x06,                    # .Report Count (6)252        0x81, 0x00,                    # .Input (Data,Arr,Abs)253        0xC0,                          # End Collection254    ]255    # fmt: on256 257    def __init__(self, rdesc=report_descriptor, name=None, input_info=None):258        super().__init__(rdesc, name, input_info)259 260 261class BaseTest:262    class TestKeyboard(base.BaseTestCase.TestUhid):263        def test_single_key(self):264            """check for key reliability."""265            uhdev = self.uhdev266            evdev = uhdev.get_evdev()267            syn_event = self.syn_event268 269            r = uhdev.event(["a and A"])270            expected = [syn_event]271            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 1))272            events = uhdev.next_sync_events()273            self.debug_reports(r, uhdev, events)274            self.assertInputEventsIn(expected, events)275            assert evdev.value[libevdev.EV_KEY.KEY_A] == 1276 277            r = uhdev.event([])278            expected = [syn_event]279            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 0))280            events = uhdev.next_sync_events()281            self.debug_reports(r, uhdev, events)282            self.assertInputEventsIn(expected, events)283            assert evdev.value[libevdev.EV_KEY.KEY_A] == 0284 285        def test_two_keys(self):286            uhdev = self.uhdev287            evdev = uhdev.get_evdev()288            syn_event = self.syn_event289 290            r = uhdev.event(["a and A", "q and Q"])291            expected = [syn_event]292            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 1))293            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_Q, 1))294            events = uhdev.next_sync_events()295            self.debug_reports(r, uhdev, events)296            self.assertInputEventsIn(expected, events)297            assert evdev.value[libevdev.EV_KEY.KEY_A] == 1298 299            r = uhdev.event([])300            expected = [syn_event]301            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 0))302            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_Q, 0))303            events = uhdev.next_sync_events()304            self.debug_reports(r, uhdev, events)305            self.assertInputEventsIn(expected, events)306            assert evdev.value[libevdev.EV_KEY.KEY_A] == 0307            assert evdev.value[libevdev.EV_KEY.KEY_Q] == 0308 309            r = uhdev.event(["c and C"])310            expected = [syn_event]311            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_C, 1))312            events = uhdev.next_sync_events()313            self.debug_reports(r, uhdev, events)314            self.assertInputEventsIn(expected, events)315            assert evdev.value[libevdev.EV_KEY.KEY_C] == 1316 317            r = uhdev.event(["c and C", "Spacebar"])318            expected = [syn_event]319            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_SPACE, 1))320            events = uhdev.next_sync_events()321            self.debug_reports(r, uhdev, events)322            assert libevdev.InputEvent(libevdev.EV_KEY.KEY_C) not in events323            self.assertInputEventsIn(expected, events)324            assert evdev.value[libevdev.EV_KEY.KEY_C] == 1325            assert evdev.value[libevdev.EV_KEY.KEY_SPACE] == 1326 327            r = uhdev.event(["Spacebar"])328            expected = [syn_event]329            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_C, 0))330            events = uhdev.next_sync_events()331            self.debug_reports(r, uhdev, events)332            assert libevdev.InputEvent(libevdev.EV_KEY.KEY_SPACE) not in events333            self.assertInputEventsIn(expected, events)334            assert evdev.value[libevdev.EV_KEY.KEY_C] == 0335            assert evdev.value[libevdev.EV_KEY.KEY_SPACE] == 1336 337            r = uhdev.event([])338            expected = [syn_event]339            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_SPACE, 0))340            events = uhdev.next_sync_events()341            self.debug_reports(r, uhdev, events)342            self.assertInputEventsIn(expected, events)343            assert evdev.value[libevdev.EV_KEY.KEY_SPACE] == 0344 345        def test_modifiers(self):346            # ctrl-alt-del would be very nice :)347            uhdev = self.uhdev348            syn_event = self.syn_event349 350            r = uhdev.event(["LeftControl", "LeftShift", "= and +"])351            expected = [syn_event]352            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_LEFTCTRL, 1))353            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_LEFTSHIFT, 1))354            expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_EQUAL, 1))355            events = uhdev.next_sync_events()356            self.debug_reports(r, uhdev, events)357            self.assertInputEventsIn(expected, events)358 359 360class TestPlainKeyboard(BaseTest.TestKeyboard):361    def create_device(self):362        return PlainKeyboard()363 364    def test_10_keys(self):365        uhdev = self.uhdev366        syn_event = self.syn_event367 368        r = uhdev.event(369            [370                "1 and !",371                "2 and @",372                "3 and #",373                "4 and $",374                "5 and %",375                "6 and ^",376                "7 and &",377                "8 and *",378                "9 and (",379                "0 and )",380            ]381        )382        expected = [syn_event]383        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_0, 1))384        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 1))385        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 1))386        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 1))387        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 1))388        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 1))389        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 1))390        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_7, 1))391        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_8, 1))392        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_9, 1))393        events = uhdev.next_sync_events()394        self.debug_reports(r, uhdev, events)395        self.assertInputEventsIn(expected, events)396 397        r = uhdev.event([])398        expected = [syn_event]399        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_0, 0))400        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 0))401        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 0))402        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 0))403        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 0))404        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 0))405        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 0))406        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_7, 0))407        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_8, 0))408        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_9, 0))409        events = uhdev.next_sync_events()410        self.debug_reports(r, uhdev, events)411        self.assertInputEventsIn(expected, events)412 413 414class TestArrayKeyboard(BaseTest.TestKeyboard):415    def create_device(self):416        return ArrayKeyboard()417 418    def test_10_keys(self):419        uhdev = self.uhdev420        syn_event = self.syn_event421 422        r = uhdev.event(423            [424                "1 and !",425                "2 and @",426                "3 and #",427                "4 and $",428                "5 and %",429                "6 and ^",430            ]431        )432        expected = [syn_event]433        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 1))434        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 1))435        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 1))436        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 1))437        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 1))438        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 1))439        events = uhdev.next_sync_events()440 441        self.debug_reports(r, uhdev, events)442        self.assertInputEventsIn(expected, events)443 444        # ErrRollOver445        r = uhdev.event(446            [447                "1 and !",448                "2 and @",449                "3 and #",450                "4 and $",451                "5 and %",452                "6 and ^",453                "7 and &",454                "8 and *",455                "9 and (",456                "0 and )",457            ]458        )459        events = uhdev.next_sync_events()460 461        self.debug_reports(r, uhdev, events)462 463        assert len(events) == 0464 465        r = uhdev.event([])466        expected = [syn_event]467        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 0))468        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 0))469        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 0))470        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 0))471        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 0))472        expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 0))473        events = uhdev.next_sync_events()474        self.debug_reports(r, uhdev, events)475        self.assertInputEventsIn(expected, events)476 477 478class TestLEDKeyboard(BaseTest.TestKeyboard):479    def create_device(self):480        return LEDKeyboard()481 482 483class TestPrimaxKeyboard(BaseTest.TestKeyboard):484    def create_device(self):485        return PrimaxKeyboard()486