From nobody Mon Dec 15 21:26:24 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2F02BC64ED6 for ; Fri, 17 Feb 2023 16:20:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231181AbjBQQUU (ORCPT ); Fri, 17 Feb 2023 11:20:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52340 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230049AbjBQQUM (ORCPT ); Fri, 17 Feb 2023 11:20:12 -0500 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 72E3925E16 for ; Fri, 17 Feb 2023 08:18:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1676650731; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MMnn0z4iV4PJ/axzkiucRlAm/k7ZZcvfPJCs1gXrpHQ=; b=PEAHPJw7Qn713FxMzlo15ND1ylRQhtGxNIiNAqlDWBKEN6vl2uE/8FYzKXkQfEzQfdEcQU j2KWngeqHRbMm2RJEmN2zCgpdrfVCX9A8n7znpK/77H4J3bldqQd8sYIdIcVwNWU5TxAph Oz9MsUgwZkiUhSQtUwvsQezYRao/dJk= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-468-SEijkpmEPBKIXmMe_8uLOQ-1; Fri, 17 Feb 2023 11:18:48 -0500 X-MC-Unique: SEijkpmEPBKIXmMe_8uLOQ-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BED57101B42B; Fri, 17 Feb 2023 16:18:47 +0000 (UTC) Received: from xps-13.local (unknown [10.39.193.224]) by smtp.corp.redhat.com (Postfix) with ESMTP id 41AE4C15BA0; Fri, 17 Feb 2023 16:18:46 +0000 (UTC) From: Benjamin Tissoires Date: Fri, 17 Feb 2023 17:17:58 +0100 Subject: [PATCH 04/11] selftests: hid: import hid-tools hid-keyboards tests MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20230217-import-hid-tools-tests-v1-4-d1c48590d0ee@redhat.com> References: <20230217-import-hid-tools-tests-v1-0-d1c48590d0ee@redhat.com> In-Reply-To: <20230217-import-hid-tools-tests-v1-0-d1c48590d0ee@redhat.com> To: Jiri Kosina , Shuah Khan Cc: linux-input@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Benjamin Tissoires , Peter Hutterer , Roderick Colenbrander , Nicolas Saenz Julienne X-Developer-Signature: v=1; a=ed25519-sha256; t=1676650715; l=22934; i=benjamin.tissoires@redhat.com; s=20230215; h=from:subject:message-id; bh=KK0MRAuOIROX7h7CQ9r1zTW58y1MCSjT9UIs2lXhrSA=; b=TVrsHjtNufCb2nH8HJ/tp2S+aor6TkZvtTks2mY7hamMf61BoYyfr+JuU17B7QIM1KoCX2pJ0 PwfzALIs66xAatBUYjGSvzAv43wjh/l+6vujP2of5np/7LYGG40tNdl X-Developer-Key: i=benjamin.tissoires@redhat.com; a=ed25519; pk=7D1DyAVh6ajCkuUTudt/chMuXWIJHlv2qCsRkIizvFw= X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org These tests have been developed in the hid-tools[0] tree for a while. Now that we have a proper selftests/hid kernel entry and that the tests are more reliable, it is time to directly include those in the kernel tree. [0] https://gitlab.freedesktop.org/libevdev/hid-tools Cc: Nicolas Saenz Julienne Cc: Peter Hutterer Cc: Roderick Colenbrander Signed-off-by: Benjamin Tissoires --- tools/testing/selftests/hid/Makefile | 1 + tools/testing/selftests/hid/hid-keyboard.sh | 7 + tools/testing/selftests/hid/tests/test_keyboard.py | 485 +++++++++++++++++= ++++ 3 files changed, 493 insertions(+) diff --git a/tools/testing/selftests/hid/Makefile b/tools/testing/selftests= /hid/Makefile index d16a22477140..181a594ffe92 100644 --- a/tools/testing/selftests/hid/Makefile +++ b/tools/testing/selftests/hid/Makefile @@ -7,6 +7,7 @@ include ../../../scripts/Makefile.include =20 TEST_PROGS :=3D hid-core.sh TEST_PROGS +=3D hid-gamepad.sh +TEST_PROGS +=3D hid-keyboard.sh =20 CXX ?=3D $(CROSS_COMPILE)g++ =20 diff --git a/tools/testing/selftests/hid/hid-keyboard.sh b/tools/testing/se= lftests/hid/hid-keyboard.sh new file mode 100755 index 000000000000..55368f17d1d5 --- /dev/null +++ b/tools/testing/selftests/hid/hid-keyboard.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# Runs tests for the HID subsystem + +export TARGET=3Dtest_keyboard.py + +bash ./run-hid-tools-tests.sh diff --git a/tools/testing/selftests/hid/tests/test_keyboard.py b/tools/tes= ting/selftests/hid/tests/test_keyboard.py new file mode 100644 index 000000000000..b3b2bdbf63b7 --- /dev/null +++ b/tools/testing/selftests/hid/tests/test_keyboard.py @@ -0,0 +1,485 @@ +#!/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018 Benjamin Tissoires +# Copyright (c) 2018 Red Hat, Inc. +# + +from . import base +import hidtools.hid +import libevdev +import logging + +logger =3D logging.getLogger("hidtools.test.keyboard") + + +class InvalidHIDCommunication(Exception): + pass + + +class KeyboardData(object): + pass + + +class BaseKeyboard(base.UHIDTestDevice): + def __init__(self, rdesc, name=3DNone, input_info=3DNone): + assert rdesc is not None + super().__init__(name, "Key", input_info=3Dinput_info, rdesc=3Drde= sc) + self.keystates =3D {} + + def _update_key_state(self, keys): + """ + Update the internal state of keys with the new state given. + + :param key: a tuple of chars for the currently pressed keys. + """ + # First remove the already released keys + unused_keys =3D [k for k, v in self.keystates.items() if not v] + for key in unused_keys: + del self.keystates[key] + + # self.keystates contains now the list of currently pressed keys, + # release them... + for key in self.keystates.keys(): + self.keystates[key] =3D False + + # ...and press those that are in parameter + for key in keys: + self.keystates[key] =3D True + + def _create_report_data(self): + keyboard =3D KeyboardData() + for key, value in self.keystates.items(): + key =3D key.replace(" ", "").lower() + setattr(keyboard, key, value) + return keyboard + + def create_array_report(self, keys, reportID=3DNone, application=3DNon= e): + """ + Return an input report for this device. + + :param keys: a tuple of chars for the pressed keys. The class main= tains + the list of currently pressed keys, so to release a key, the c= aller + needs to call again this function without the key in this tupl= e. + :param reportID: the numeric report ID for this report, if needed + """ + self._update_key_state(keys) + reportID =3D reportID or self.default_reportID + + keyboard =3D self._create_report_data() + return self.create_report(keyboard, reportID=3DreportID, applicati= on=3Dapplication) + + def event(self, keys, reportID=3DNone, application=3DNone): + """ + Send an input event on the default report ID. + + :param keys: a tuple of chars for the pressed keys. The class main= tains + the list of currently pressed keys, so to release a key, the c= aller + needs to call again this function without the key in this tupl= e. + """ + r =3D self.create_array_report(keys, reportID, application) + self.call_input_event(r) + return [r] + + +class PlainKeyboard(BaseKeyboard): + # fmt: off + report_descriptor =3D [ + 0x05, 0x01, # Usage Page (Generic Desktop) + 0x09, 0x06, # Usage (Keyboard) + 0xa1, 0x01, # Collection (Application) + 0x85, 0x01, # .Report ID (1) + 0x05, 0x07, # .Usage Page (Keyboard) + 0x19, 0xe0, # .Usage Minimum (224) + 0x29, 0xe7, # .Usage Maximum (231) + 0x15, 0x00, # .Logical Minimum (0) + 0x25, 0x01, # .Logical Maximum (1) + 0x75, 0x01, # .Report Size (1) + 0x95, 0x08, # .Report Count (8) + 0x81, 0x02, # .Input (Data,Var,Abs) + 0x19, 0x00, # .Usage Minimum (0) + 0x29, 0x97, # .Usage Maximum (151) + 0x15, 0x00, # .Logical Minimum (0) + 0x25, 0x01, # .Logical Maximum (1) + 0x75, 0x01, # .Report Size (1) + 0x95, 0x98, # .Report Count (152) + 0x81, 0x02, # .Input (Data,Var,Abs) + 0xc0, # End Collection + ] + # fmt: on + + def __init__(self, rdesc=3Dreport_descriptor, name=3DNone, input_info= =3DNone): + super().__init__(rdesc, name, input_info) + self.default_reportID =3D 1 + + +class ArrayKeyboard(BaseKeyboard): + # fmt: off + report_descriptor =3D [ + 0x05, 0x01, # Usage Page (Generic Desktop) + 0x09, 0x06, # Usage (Keyboard) + 0xa1, 0x01, # Collection (Application) + 0x05, 0x07, # .Usage Page (Keyboard) + 0x19, 0xe0, # .Usage Minimum (224) + 0x29, 0xe7, # .Usage Maximum (231) + 0x15, 0x00, # .Logical Minimum (0) + 0x25, 0x01, # .Logical Maximum (1) + 0x75, 0x01, # .Report Size (1) + 0x95, 0x08, # .Report Count (8) + 0x81, 0x02, # .Input (Data,Var,Abs) + 0x95, 0x06, # .Report Count (6) + 0x75, 0x08, # .Report Size (8) + 0x15, 0x00, # .Logical Minimum (0) + 0x26, 0xa4, 0x00, # .Logical Maximum (164) + 0x05, 0x07, # .Usage Page (Keyboard) + 0x19, 0x00, # .Usage Minimum (0) + 0x29, 0xa4, # .Usage Maximum (164) + 0x81, 0x00, # .Input (Data,Arr,Abs) + 0xc0, # End Collection + ] + # fmt: on + + def __init__(self, rdesc=3Dreport_descriptor, name=3DNone, input_info= =3DNone): + super().__init__(rdesc, name, input_info) + + def _create_report_data(self): + data =3D KeyboardData() + array =3D [] + + hut =3D hidtools.hut.HUT + + # strip modifiers from the array + for k, v in self.keystates.items(): + # we ignore depressed keys + if not v: + continue + + usage =3D hut[0x07].from_name[k].usage + if usage >=3D 224 and usage <=3D 231: + # modifier + setattr(data, k.lower(), 1) + else: + array.append(k) + + # if array length is bigger than 6, report ErrorRollOver + if len(array) > 6: + array =3D ["ErrorRollOver"] * 6 + + data.keyboard =3D array + return data + + +class LEDKeyboard(ArrayKeyboard): + # fmt: off + report_descriptor =3D [ + 0x05, 0x01, # Usage Page (Generic Desktop) + 0x09, 0x06, # Usage (Keyboard) + 0xa1, 0x01, # Collection (Application) + 0x05, 0x07, # .Usage Page (Keyboard) + 0x19, 0xe0, # .Usage Minimum (224) + 0x29, 0xe7, # .Usage Maximum (231) + 0x15, 0x00, # .Logical Minimum (0) + 0x25, 0x01, # .Logical Maximum (1) + 0x75, 0x01, # .Report Size (1) + 0x95, 0x08, # .Report Count (8) + 0x81, 0x02, # .Input (Data,Var,Abs) + 0x95, 0x01, # .Report Count (1) + 0x75, 0x08, # .Report Size (8) + 0x81, 0x01, # .Input (Cnst,Arr,Abs) + 0x95, 0x05, # .Report Count (5) + 0x75, 0x01, # .Report Size (1) + 0x05, 0x08, # .Usage Page (LEDs) + 0x19, 0x01, # .Usage Minimum (1) + 0x29, 0x05, # .Usage Maximum (5) + 0x91, 0x02, # .Output (Data,Var,Abs) + 0x95, 0x01, # .Report Count (1) + 0x75, 0x03, # .Report Size (3) + 0x91, 0x01, # .Output (Cnst,Arr,Abs) + 0x95, 0x06, # .Report Count (6) + 0x75, 0x08, # .Report Size (8) + 0x15, 0x00, # .Logical Minimum (0) + 0x26, 0xa4, 0x00, # .Logical Maximum (164) + 0x05, 0x07, # .Usage Page (Keyboard) + 0x19, 0x00, # .Usage Minimum (0) + 0x29, 0xa4, # .Usage Maximum (164) + 0x81, 0x00, # .Input (Data,Arr,Abs) + 0xc0, # End Collection + ] + # fmt: on + + def __init__(self, rdesc=3Dreport_descriptor, name=3DNone, input_info= =3DNone): + super().__init__(rdesc, name, input_info) + + +# Some Primax manufactured keyboards set the Usage Page after having defin= ed +# some local Usages. It relies on the fact that the specification states t= hat +# Usages are to be concatenated with Usage Pages upon finding a Main item = (see +# 6.2.2.8). This test covers this case. +class PrimaxKeyboard(ArrayKeyboard): + # fmt: off + report_descriptor =3D [ + 0x05, 0x01, # Usage Page (Generic Desktop) + 0x09, 0x06, # Usage (Keyboard) + 0xA1, 0x01, # Collection (Application) + 0x05, 0x07, # .Usage Page (Keyboard) + 0x19, 0xE0, # .Usage Minimum (224) + 0x29, 0xE7, # .Usage Maximum (231) + 0x15, 0x00, # .Logical Minimum (0) + 0x25, 0x01, # .Logical Maximum (1) + 0x75, 0x01, # .Report Size (1) + 0x95, 0x08, # .Report Count (8) + 0x81, 0x02, # .Input (Data,Var,Abs) + 0x75, 0x08, # .Report Size (8) + 0x95, 0x01, # .Report Count (1) + 0x81, 0x01, # .Input (Data,Var,Abs) + 0x05, 0x08, # .Usage Page (LEDs) + 0x19, 0x01, # .Usage Minimum (1) + 0x29, 0x03, # .Usage Maximum (3) + 0x75, 0x01, # .Report Size (1) + 0x95, 0x03, # .Report Count (3) + 0x91, 0x02, # .Output (Data,Var,Abs) + 0x95, 0x01, # .Report Count (1) + 0x75, 0x05, # .Report Size (5) + 0x91, 0x01, # .Output (Constant) + 0x15, 0x00, # .Logical Minimum (0) + 0x26, 0xFF, 0x00, # .Logical Maximum (255) + 0x19, 0x00, # .Usage Minimum (0) + 0x2A, 0xFF, 0x00, # .Usage Maximum (255) + 0x05, 0x07, # .Usage Page (Keyboard) + 0x75, 0x08, # .Report Size (8) + 0x95, 0x06, # .Report Count (6) + 0x81, 0x00, # .Input (Data,Arr,Abs) + 0xC0, # End Collection + ] + # fmt: on + + def __init__(self, rdesc=3Dreport_descriptor, name=3DNone, input_info= =3DNone): + super().__init__(rdesc, name, input_info) + + +class BaseTest: + class TestKeyboard(base.BaseTestCase.TestUhid): + def test_single_key(self): + """check for key reliability.""" + uhdev =3D self.uhdev + evdev =3D uhdev.get_evdev() + syn_event =3D self.syn_event + + r =3D uhdev.event(["a and A"]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 1)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_A] =3D=3D 1 + + r =3D uhdev.event([]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 0)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_A] =3D=3D 0 + + def test_two_keys(self): + uhdev =3D self.uhdev + evdev =3D uhdev.get_evdev() + syn_event =3D self.syn_event + + r =3D uhdev.event(["a and A", "q and Q"]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_Q, 1)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_A] =3D=3D 1 + + r =3D uhdev.event([]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_A, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_Q, 0)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_A] =3D=3D 0 + assert evdev.value[libevdev.EV_KEY.KEY_Q] =3D=3D 0 + + r =3D uhdev.event(["c and C"]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_C, 1)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_C] =3D=3D 1 + + r =3D uhdev.event(["c and C", "Spacebar"]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_SPACE,= 1)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + assert libevdev.InputEvent(libevdev.EV_KEY.KEY_C) not in events + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_C] =3D=3D 1 + assert evdev.value[libevdev.EV_KEY.KEY_SPACE] =3D=3D 1 + + r =3D uhdev.event(["Spacebar"]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_C, 0)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + assert libevdev.InputEvent(libevdev.EV_KEY.KEY_SPACE) not in e= vents + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_C] =3D=3D 0 + assert evdev.value[libevdev.EV_KEY.KEY_SPACE] =3D=3D 1 + + r =3D uhdev.event([]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_SPACE,= 0)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + assert evdev.value[libevdev.EV_KEY.KEY_SPACE] =3D=3D 0 + + def test_modifiers(self): + # ctrl-alt-del would be very nice :) + uhdev =3D self.uhdev + syn_event =3D self.syn_event + + r =3D uhdev.event(["LeftControl", "LeftShift", "=3D and +"]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_LEFTCT= RL, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_LEFTSH= IFT, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_EQUAL,= 1)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + + +class TestPlainKeyboard(BaseTest.TestKeyboard): + def create_device(self): + return PlainKeyboard() + + def test_10_keys(self): + uhdev =3D self.uhdev + syn_event =3D self.syn_event + + r =3D uhdev.event( + [ + "1 and !", + "2 and @", + "3 and #", + "4 and $", + "5 and %", + "6 and ^", + "7 and &", + "8 and *", + "9 and (", + "0 and )", + ] + ) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_0, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_7, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_8, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_9, 1)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + + r =3D uhdev.event([]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_0, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_7, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_8, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_9, 0)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + + +class TestArrayKeyboard(BaseTest.TestKeyboard): + def create_device(self): + return ArrayKeyboard() + + def test_10_keys(self): + uhdev =3D self.uhdev + syn_event =3D self.syn_event + + r =3D uhdev.event( + [ + "1 and !", + "2 and @", + "3 and #", + "4 and $", + "5 and %", + "6 and ^", + ] + ) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 1)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 1)) + events =3D uhdev.next_sync_events() + + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + + # ErrRollOver + r =3D uhdev.event( + [ + "1 and !", + "2 and @", + "3 and #", + "4 and $", + "5 and %", + "6 and ^", + "7 and &", + "8 and *", + "9 and (", + "0 and )", + ] + ) + events =3D uhdev.next_sync_events() + + self.debug_reports(r, uhdev, events) + + assert len(events) =3D=3D 0 + + r =3D uhdev.event([]) + expected =3D [syn_event] + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_1, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_2, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_3, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_4, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_5, 0)) + expected.append(libevdev.InputEvent(libevdev.EV_KEY.KEY_6, 0)) + events =3D uhdev.next_sync_events() + self.debug_reports(r, uhdev, events) + self.assertInputEventsIn(expected, events) + + +class TestLEDKeyboard(BaseTest.TestKeyboard): + def create_device(self): + return LEDKeyboard() + + +class TestPrimaxKeyboard(BaseTest.TestKeyboard): + def create_device(self): + return PrimaxKeyboard() --=20 2.39.1