2020-11-22 14:14:43 +00:00
|
|
|
#!/usr/bin/python3
|
|
|
|
# -*- coding: utf-8 -*-
|
2022-01-01 12:00:49 +00:00
|
|
|
# input-remapper - GUI for device specific keyboard mappings
|
2022-01-01 12:52:33 +00:00
|
|
|
# Copyright (C) 2022 sezanzeb <proxima@sezanzeb.de>
|
2020-11-22 14:14:43 +00:00
|
|
|
#
|
2022-01-01 12:00:49 +00:00
|
|
|
# This file is part of input-remapper.
|
2020-11-22 14:14:43 +00:00
|
|
|
#
|
2022-01-01 12:00:49 +00:00
|
|
|
# input-remapper is free software: you can redistribute it and/or modify
|
2020-11-22 14:14:43 +00:00
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
2022-01-01 12:00:49 +00:00
|
|
|
# input-remapper is distributed in the hope that it will be useful,
|
2020-11-22 14:14:43 +00:00
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
2022-01-01 12:00:49 +00:00
|
|
|
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
2022-07-23 08:53:41 +00:00
|
|
|
import json
|
|
|
|
from typing import List
|
|
|
|
|
2022-10-16 12:56:21 +00:00
|
|
|
from inputremapper.gui.messages.message_types import MessageType
|
|
|
|
from inputremapper.gui.messages.message_broker import (
|
2022-07-23 08:53:41 +00:00
|
|
|
MessageBroker,
|
|
|
|
Signal,
|
|
|
|
)
|
2022-10-16 12:56:21 +00:00
|
|
|
from inputremapper.gui.messages.message_data import CombinationRecorded
|
2022-03-03 22:42:37 +00:00
|
|
|
from tests.test import (
|
|
|
|
new_event,
|
|
|
|
push_events,
|
|
|
|
EVENT_READ_TIMEOUT,
|
|
|
|
START_READING_DELAY,
|
|
|
|
quick_cleanup,
|
|
|
|
MAX_ABS,
|
2022-07-23 08:53:41 +00:00
|
|
|
MIN_ABS,
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures,
|
|
|
|
push_event,
|
2022-03-03 22:42:37 +00:00
|
|
|
)
|
|
|
|
|
2020-11-22 14:14:43 +00:00
|
|
|
import unittest
|
2020-11-30 17:59:34 +00:00
|
|
|
import time
|
2020-12-31 22:16:46 +00:00
|
|
|
import multiprocessing
|
2020-11-22 14:14:43 +00:00
|
|
|
|
2021-09-26 10:44:56 +00:00
|
|
|
from evdev.ecodes import (
|
|
|
|
EV_KEY,
|
|
|
|
EV_ABS,
|
|
|
|
ABS_HAT0X,
|
|
|
|
KEY_COMMA,
|
|
|
|
BTN_TOOL_DOUBLETAP,
|
|
|
|
ABS_Z,
|
|
|
|
ABS_Y,
|
|
|
|
KEY_A,
|
|
|
|
EV_REL,
|
|
|
|
REL_WHEEL,
|
|
|
|
REL_X,
|
|
|
|
ABS_X,
|
|
|
|
ABS_RZ,
|
2022-07-23 08:53:41 +00:00
|
|
|
REL_HWHEEL,
|
2021-09-26 10:44:56 +00:00
|
|
|
)
|
2020-12-26 18:36:47 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
from inputremapper.gui.reader import Reader
|
2022-01-31 19:58:37 +00:00
|
|
|
from inputremapper.event_combination import EventCombination
|
2022-01-01 12:00:49 +00:00
|
|
|
from inputremapper.gui.helper import RootHelper
|
2022-07-23 08:53:41 +00:00
|
|
|
from inputremapper.groups import _Groups, DeviceType
|
2020-11-22 14:14:43 +00:00
|
|
|
|
|
|
|
CODE_1 = 100
|
|
|
|
CODE_2 = 101
|
|
|
|
CODE_3 = 102
|
|
|
|
|
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
class Listener:
|
|
|
|
def __init__(self):
|
|
|
|
self.calls: List = []
|
|
|
|
|
|
|
|
def __call__(self, data):
|
|
|
|
self.calls.append(data)
|
|
|
|
|
|
|
|
|
2020-12-03 19:03:53 +00:00
|
|
|
def wait(func, timeout=1.0):
|
|
|
|
"""Wait for func to return True."""
|
|
|
|
iterations = 0
|
|
|
|
sleepytime = 0.1
|
|
|
|
while not func():
|
|
|
|
time.sleep(sleepytime)
|
|
|
|
iterations += 1
|
|
|
|
if iterations * sleepytime > timeout:
|
|
|
|
break
|
|
|
|
|
|
|
|
|
2020-11-22 14:14:43 +00:00
|
|
|
class TestReader(unittest.TestCase):
|
2020-11-30 17:59:34 +00:00
|
|
|
def setUp(self):
|
2021-03-21 18:15:20 +00:00
|
|
|
self.helper = None
|
2022-07-23 08:53:41 +00:00
|
|
|
self.groups = _Groups()
|
|
|
|
self.message_broker = MessageBroker()
|
|
|
|
self.reader = Reader(self.message_broker, self.groups)
|
2020-11-30 17:59:34 +00:00
|
|
|
|
2020-11-22 14:14:43 +00:00
|
|
|
def tearDown(self):
|
2021-02-12 20:43:40 +00:00
|
|
|
quick_cleanup()
|
2022-07-23 08:53:41 +00:00
|
|
|
try:
|
|
|
|
self.reader.terminate()
|
|
|
|
except (BrokenPipeError, OSError):
|
|
|
|
pass
|
|
|
|
|
2021-03-21 18:15:20 +00:00
|
|
|
if self.helper is not None:
|
|
|
|
self.helper.join()
|
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
def create_helper(self, groups: _Groups = None):
|
2021-03-21 18:15:20 +00:00
|
|
|
# this will cause pending events to be copied over to the helper
|
|
|
|
# process
|
2022-07-23 08:53:41 +00:00
|
|
|
if not groups:
|
|
|
|
groups = self.groups
|
|
|
|
|
2021-03-21 18:15:20 +00:00
|
|
|
def start_helper():
|
2022-07-23 08:53:41 +00:00
|
|
|
helper = RootHelper(groups)
|
2021-03-21 18:15:20 +00:00
|
|
|
helper.run()
|
|
|
|
|
|
|
|
self.helper = multiprocessing.Process(target=start_helper)
|
|
|
|
self.helper.start()
|
|
|
|
time.sleep(0.1)
|
2020-11-22 14:14:43 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
def test_reading(self):
|
|
|
|
l1 = Listener()
|
|
|
|
l2 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
self.message_broker.subscribe(MessageType.recording_finished, l2)
|
|
|
|
self.create_helper()
|
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_gamepad, [new_event(EV_ABS, ABS_HAT0X, 1)])
|
|
|
|
# we need to sleep because we have two different fixtures,
|
|
|
|
# which will lead to race conditions
|
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
|
|
|
|
# relative axis events should be released automagically after 0.3s
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_mouse, [new_event(EV_REL, REL_X, 5)])
|
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
# read all pending events. Having a glib mainloop would be better,
|
|
|
|
# as it would call read automatically periodically
|
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(
|
|
|
|
[
|
|
|
|
CombinationRecorded(EventCombination.from_string("3,16,1")),
|
|
|
|
CombinationRecorded(EventCombination.from_string("3,16,1+2,0,1")),
|
|
|
|
],
|
|
|
|
l1.calls,
|
|
|
|
)
|
|
|
|
|
|
|
|
# release the hat switch should emit the recording finished event
|
|
|
|
# as both the hat and relative axis are released by now
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_gamepad, [new_event(EV_ABS, ABS_HAT0X, 0)])
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.3)
|
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual([Signal(MessageType.recording_finished)], l2.calls)
|
|
|
|
|
|
|
|
def test_should_release_relative_axis(self):
|
|
|
|
# the timeout is set to 0.3s
|
|
|
|
l1 = Listener()
|
|
|
|
l2 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
self.message_broker.subscribe(MessageType.recording_finished, l2)
|
|
|
|
self.create_helper()
|
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
|
|
|
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_mouse, [new_event(EV_REL, REL_X, -5)])
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
[CombinationRecorded(EventCombination.from_string("2,0,-1"))],
|
|
|
|
l1.calls,
|
|
|
|
)
|
|
|
|
self.assertEqual([], l2.calls) # no stop recording yet
|
|
|
|
|
|
|
|
time.sleep(0.3)
|
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual([Signal(MessageType.recording_finished)], l2.calls)
|
|
|
|
|
|
|
|
def test_should_not_trigger_at_low_speed_for_rel_axis(self):
|
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
self.create_helper()
|
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
|
|
|
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_mouse, [new_event(EV_REL, REL_X, -1)])
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(0, len(l1.calls))
|
|
|
|
|
|
|
|
def test_should_trigger_wheel_at_low_speed(self):
|
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
self.create_helper()
|
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
|
|
|
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_mouse,
|
2022-07-23 08:53:41 +00:00
|
|
|
[new_event(EV_REL, REL_WHEEL, -1), new_event(EV_REL, REL_HWHEEL, 1)],
|
|
|
|
)
|
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
2020-12-31 20:46:57 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
self.assertEqual(
|
|
|
|
[
|
|
|
|
CombinationRecorded(EventCombination.from_string("2,8,-1")),
|
|
|
|
CombinationRecorded(EventCombination.from_string("2,8,-1+2,6,1")),
|
|
|
|
],
|
|
|
|
l1.calls,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_wont_emit_the_same_combination_twice(self):
|
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
2021-03-21 18:15:20 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
|
|
|
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_keyboard, [new_event(EV_KEY, KEY_A, 1)])
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
|
|
|
# the duplicate event should be ignored
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_keyboard, [new_event(EV_KEY, KEY_A, 1)])
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
[CombinationRecorded(EventCombination.from_string("1,30,1"))],
|
|
|
|
l1.calls,
|
2022-04-17 10:19:23 +00:00
|
|
|
)
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
def test_should_read_absolut_axis(self):
|
|
|
|
l1 = Listener()
|
|
|
|
l2 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
self.message_broker.subscribe(MessageType.recording_finished, l2)
|
|
|
|
self.create_helper()
|
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
# over 30% should trigger
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(
|
|
|
|
fixtures.foo_device_2_gamepad,
|
|
|
|
[new_event(EV_ABS, ABS_X, int(MAX_ABS * 0.4))],
|
|
|
|
)
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
2022-01-31 19:58:37 +00:00
|
|
|
self.assertEqual(
|
2022-07-23 08:53:41 +00:00
|
|
|
[CombinationRecorded(EventCombination.from_string("3,0,1"))],
|
|
|
|
l1.calls,
|
2022-01-31 19:58:37 +00:00
|
|
|
)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.assertEqual([], l2.calls) # no stop recording yet
|
|
|
|
|
|
|
|
# less the 30% should release
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(
|
|
|
|
fixtures.foo_device_2_gamepad,
|
|
|
|
[new_event(EV_ABS, ABS_X, int(MAX_ABS * 0.2))],
|
|
|
|
)
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(
|
|
|
|
[CombinationRecorded(EventCombination.from_string("3,0,1"))],
|
|
|
|
l1.calls,
|
|
|
|
)
|
|
|
|
self.assertEqual([Signal(MessageType.recording_finished)], l2.calls)
|
|
|
|
|
|
|
|
def test_should_change_direction(self):
|
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
2021-03-21 18:56:15 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
|
|
|
|
2022-08-28 10:38:40 +00:00
|
|
|
push_event(fixtures.foo_device_2_keyboard, new_event(EV_KEY, KEY_A, 1))
|
|
|
|
time.sleep(0.1)
|
|
|
|
push_event(
|
|
|
|
fixtures.foo_device_2_gamepad, new_event(EV_ABS, ABS_X, int(MAX_ABS * 0.4))
|
|
|
|
)
|
|
|
|
time.sleep(0.1)
|
|
|
|
push_event(fixtures.foo_device_2_keyboard, new_event(EV_KEY, KEY_COMMA, 1))
|
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_gamepad,
|
2022-07-23 08:53:41 +00:00
|
|
|
[
|
|
|
|
new_event(EV_ABS, ABS_X, int(MAX_ABS * 0.1)),
|
|
|
|
new_event(EV_ABS, ABS_X, int(MIN_ABS * 0.4)),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
time.sleep(0.1)
|
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(
|
|
|
|
[
|
|
|
|
CombinationRecorded(EventCombination.from_string("1,30,1")),
|
|
|
|
CombinationRecorded(EventCombination.from_string("1,30,1+3,0,1")),
|
|
|
|
CombinationRecorded(
|
|
|
|
EventCombination.from_string("1,30,1+3,0,1+1,51,1")
|
|
|
|
),
|
|
|
|
CombinationRecorded(
|
|
|
|
EventCombination.from_string("1,30,1+3,0,-1+1,51,1")
|
|
|
|
),
|
|
|
|
],
|
|
|
|
l1.calls,
|
|
|
|
)
|
2021-03-21 18:15:20 +00:00
|
|
|
|
|
|
|
def test_change_device(self):
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_keyboard,
|
2021-09-26 10:44:56 +00:00
|
|
|
[
|
|
|
|
new_event(EV_KEY, 1, 1),
|
|
|
|
]
|
2022-07-23 08:53:41 +00:00
|
|
|
* 10,
|
2021-09-26 10:44:56 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.bar_device,
|
2021-09-26 10:44:56 +00:00
|
|
|
[
|
|
|
|
new_event(EV_KEY, 2, 1),
|
2022-07-23 08:53:41 +00:00
|
|
|
new_event(EV_KEY, 2, 0),
|
2021-09-26 10:44:56 +00:00
|
|
|
]
|
2022-07-23 08:53:41 +00:00
|
|
|
* 3,
|
2021-09-26 10:44:56 +00:00
|
|
|
)
|
2021-03-21 18:15:20 +00:00
|
|
|
|
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
2021-03-21 18:15:20 +00:00
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(l1.calls[0].combination, EventCombination((EV_KEY, 1, 1)))
|
2021-03-21 18:15:20 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(name="Bar Device"))
|
2021-01-07 16:15:12 +00:00
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
2021-03-21 18:15:20 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
# we did not get the event from the "Bar Device" because the group change
|
|
|
|
# stopped the recording
|
|
|
|
self.assertEqual(len(l1.calls), 1)
|
|
|
|
|
|
|
|
self.reader.start_recorder()
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.bar_device, [new_event(EV_KEY, 2, 1)])
|
2021-01-07 16:15:12 +00:00
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(l1.calls[1].combination, EventCombination((EV_KEY, 2, 1)))
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2020-12-31 20:46:57 +00:00
|
|
|
def test_reading_2(self):
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
2020-12-31 20:46:57 +00:00
|
|
|
# a combination of events
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_keyboard,
|
2021-09-26 10:44:56 +00:00
|
|
|
[
|
|
|
|
new_event(EV_KEY, CODE_1, 1, 10000.1234),
|
|
|
|
new_event(EV_KEY, CODE_3, 1, 10001.1234),
|
|
|
|
],
|
|
|
|
)
|
2021-04-23 09:51:21 +00:00
|
|
|
|
|
|
|
pipe = multiprocessing.Pipe()
|
|
|
|
|
|
|
|
def refresh():
|
|
|
|
# from within the helper process notify this test that
|
|
|
|
# refresh was called as expected
|
2021-09-26 10:44:56 +00:00
|
|
|
pipe[1].send("refreshed")
|
2021-04-23 09:51:21 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
groups = _Groups()
|
|
|
|
groups.refresh = refresh
|
|
|
|
self.create_helper(groups)
|
2021-04-23 09:51:21 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
2020-12-01 22:53:32 +00:00
|
|
|
|
2021-03-21 18:15:20 +00:00
|
|
|
# sending anything arbitrary does not stop the helper
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._commands.send(856794)
|
2021-03-21 18:15:20 +00:00
|
|
|
time.sleep(0.2)
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(
|
|
|
|
fixtures.foo_device_2_gamepad,
|
|
|
|
[new_event(EV_ABS, ABS_HAT0X, -1, 10002.1234)],
|
|
|
|
)
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1)
|
2021-04-23 09:51:21 +00:00
|
|
|
# but it makes it look for new devices because maybe its list of
|
2022-07-23 08:53:41 +00:00
|
|
|
# self.groups is not up-to-date
|
2021-04-23 09:51:21 +00:00
|
|
|
self.assertTrue(pipe[0].poll())
|
2021-09-26 10:44:56 +00:00
|
|
|
self.assertEqual(pipe[0].recv(), "refreshed")
|
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
2021-09-26 10:44:56 +00:00
|
|
|
self.assertEqual(
|
2022-07-23 08:53:41 +00:00
|
|
|
l1.calls[-1].combination,
|
2021-09-29 18:17:45 +00:00
|
|
|
((EV_KEY, CODE_1, 1), (EV_KEY, CODE_3, 1), (EV_ABS, ABS_HAT0X, -1)),
|
2021-09-26 10:44:56 +00:00
|
|
|
)
|
2021-01-25 23:15:30 +00:00
|
|
|
|
2021-04-23 09:51:21 +00:00
|
|
|
def test_blacklisted_events(self):
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_mouse,
|
2021-09-26 10:44:56 +00:00
|
|
|
[
|
|
|
|
new_event(EV_KEY, BTN_TOOL_DOUBLETAP, 1),
|
|
|
|
new_event(EV_KEY, CODE_2, 1),
|
|
|
|
new_event(EV_KEY, BTN_TOOL_DOUBLETAP, 1),
|
|
|
|
],
|
2022-08-28 10:38:40 +00:00
|
|
|
force=True,
|
2021-09-26 10:44:56 +00:00
|
|
|
)
|
2021-03-21 18:15:20 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
2020-12-27 12:09:28 +00:00
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(
|
|
|
|
l1.calls[-1].combination, EventCombination((EV_KEY, CODE_2, 1))
|
|
|
|
)
|
2020-12-31 20:46:57 +00:00
|
|
|
|
|
|
|
def test_ignore_value_2(self):
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
2020-12-31 20:46:57 +00:00
|
|
|
# this is not a combination, because (EV_KEY CODE_3, 2) is ignored
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_gamepad,
|
2021-09-26 10:44:56 +00:00
|
|
|
[new_event(EV_ABS, ABS_HAT0X, 1), new_event(EV_KEY, CODE_3, 2)],
|
2022-08-28 10:38:40 +00:00
|
|
|
force=True,
|
2021-09-26 10:44:56 +00:00
|
|
|
)
|
2021-03-21 18:15:20 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
2021-03-21 18:15:20 +00:00
|
|
|
time.sleep(0.2)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(
|
|
|
|
l1.calls[-1].combination, EventCombination((EV_ABS, ABS_HAT0X, 1))
|
|
|
|
)
|
2020-12-27 12:09:28 +00:00
|
|
|
|
2020-12-19 15:04:07 +00:00
|
|
|
def test_reading_ignore_up(self):
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_keyboard,
|
2021-09-26 10:44:56 +00:00
|
|
|
[
|
|
|
|
new_event(EV_KEY, CODE_1, 0, 10),
|
|
|
|
new_event(EV_KEY, CODE_2, 1, 11),
|
|
|
|
new_event(EV_KEY, CODE_3, 0, 12),
|
|
|
|
],
|
|
|
|
)
|
2021-03-21 18:15:20 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
|
|
|
self.reader.start_recorder()
|
2020-12-19 15:04:07 +00:00
|
|
|
time.sleep(0.1)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(
|
|
|
|
l1.calls[-1].combination, EventCombination((EV_KEY, CODE_2, 1))
|
|
|
|
)
|
2020-12-31 22:16:46 +00:00
|
|
|
|
2020-11-30 17:59:34 +00:00
|
|
|
def test_wrong_device(self):
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
|
|
|
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.foo_device_2_keyboard,
|
2021-09-26 10:44:56 +00:00
|
|
|
[
|
|
|
|
new_event(EV_KEY, CODE_1, 1),
|
|
|
|
new_event(EV_KEY, CODE_2, 1),
|
|
|
|
new_event(EV_KEY, CODE_3, 1),
|
|
|
|
],
|
|
|
|
)
|
2021-03-21 18:15:20 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(name="Bar Device"))
|
|
|
|
self.reader.start_recorder()
|
2020-11-30 17:59:34 +00:00
|
|
|
time.sleep(EVENT_READ_TIMEOUT * 5)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(len(l1.calls), 0)
|
2020-11-22 14:14:43 +00:00
|
|
|
|
2022-01-01 12:00:49 +00:00
|
|
|
def test_inputremapper_devices(self):
|
|
|
|
# Don't read from inputremapper devices, their keycodes are not
|
2020-12-01 22:53:32 +00:00
|
|
|
# representative for the original key. As long as this is not
|
|
|
|
# intentionally programmed it won't even do that. But it was at some
|
|
|
|
# point.
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.combination_recorded, l1)
|
2021-09-26 10:44:56 +00:00
|
|
|
push_events(
|
2022-08-28 10:38:40 +00:00
|
|
|
fixtures.input_remapper_bar_device,
|
2021-09-26 10:44:56 +00:00
|
|
|
[
|
|
|
|
new_event(EV_KEY, CODE_1, 1),
|
|
|
|
new_event(EV_KEY, CODE_2, 1),
|
|
|
|
new_event(EV_KEY, CODE_3, 1),
|
|
|
|
],
|
|
|
|
)
|
2021-03-21 18:15:20 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(name="Bar Device"))
|
|
|
|
self.reader.start_recorder()
|
2020-11-30 17:59:34 +00:00
|
|
|
time.sleep(EVENT_READ_TIMEOUT * 5)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader._read()
|
|
|
|
self.assertEqual(len(l1.calls), 0)
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2021-03-21 18:15:20 +00:00
|
|
|
def test_terminate(self):
|
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.set_group(self.groups.find(key="Foo Device 2"))
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_keyboard, [new_event(EV_KEY, CODE_3, 1)])
|
2021-03-21 18:15:20 +00:00
|
|
|
time.sleep(START_READING_DELAY + EVENT_READ_TIMEOUT)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.assertTrue(self.reader._results.poll())
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.terminate()
|
2021-03-27 07:10:14 +00:00
|
|
|
time.sleep(EVENT_READ_TIMEOUT)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.assertFalse(self.reader._results.poll())
|
2021-01-07 16:15:12 +00:00
|
|
|
|
2021-03-21 18:15:20 +00:00
|
|
|
# no new events arrive after terminating
|
2022-08-28 10:38:40 +00:00
|
|
|
push_events(fixtures.foo_device_2_keyboard, [new_event(EV_KEY, CODE_3, 1)])
|
2021-03-21 18:15:20 +00:00
|
|
|
time.sleep(EVENT_READ_TIMEOUT * 3)
|
2022-07-23 08:53:41 +00:00
|
|
|
self.assertFalse(self.reader._results.poll())
|
2021-03-21 18:15:20 +00:00
|
|
|
|
2022-01-10 19:37:22 +00:00
|
|
|
def test_are_new_groups_available(self):
|
2022-07-23 08:53:41 +00:00
|
|
|
l1 = Listener()
|
|
|
|
self.message_broker.subscribe(MessageType.groups, l1)
|
2021-03-21 18:15:20 +00:00
|
|
|
self.create_helper()
|
2022-07-23 08:53:41 +00:00
|
|
|
self.reader.groups.set_groups({})
|
2021-03-21 18:15:20 +00:00
|
|
|
|
2022-07-23 08:53:41 +00:00
|
|
|
time.sleep(0.1) # let the helper send the groups
|
2021-03-21 18:15:20 +00:00
|
|
|
# read stuff from the helper, which includes the devices
|
2022-07-23 08:53:41 +00:00
|
|
|
self.assertEqual("[]", self.reader.groups.dumps())
|
|
|
|
self.reader._read()
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
self.reader.groups.dumps(),
|
|
|
|
json.dumps(
|
|
|
|
[
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"paths": [
|
|
|
|
"/dev/input/event1",
|
|
|
|
],
|
|
|
|
"names": ["Foo Device"],
|
|
|
|
"types": [DeviceType.KEYBOARD],
|
|
|
|
"key": "Foo Device",
|
|
|
|
}
|
|
|
|
),
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"paths": [
|
|
|
|
"/dev/input/event11",
|
|
|
|
"/dev/input/event10",
|
|
|
|
"/dev/input/event13",
|
|
|
|
"/dev/input/event15",
|
|
|
|
],
|
|
|
|
"names": [
|
|
|
|
"Foo Device foo",
|
|
|
|
"Foo Device",
|
|
|
|
"Foo Device",
|
|
|
|
"Foo Device bar",
|
|
|
|
],
|
|
|
|
"types": [
|
|
|
|
DeviceType.GAMEPAD,
|
|
|
|
DeviceType.KEYBOARD,
|
|
|
|
DeviceType.MOUSE,
|
|
|
|
],
|
|
|
|
"key": "Foo Device 2",
|
|
|
|
}
|
|
|
|
),
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"paths": ["/dev/input/event20"],
|
|
|
|
"names": ["Bar Device"],
|
|
|
|
"types": [DeviceType.KEYBOARD],
|
|
|
|
"key": "Bar Device",
|
|
|
|
}
|
|
|
|
),
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"paths": ["/dev/input/event30"],
|
|
|
|
"names": ["gamepad"],
|
|
|
|
"types": [DeviceType.GAMEPAD],
|
|
|
|
"key": "gamepad",
|
|
|
|
}
|
|
|
|
),
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"paths": ["/dev/input/event40"],
|
|
|
|
"names": ["input-remapper Bar Device"],
|
|
|
|
"types": [DeviceType.KEYBOARD],
|
|
|
|
"key": "input-remapper Bar Device",
|
|
|
|
}
|
|
|
|
),
|
|
|
|
]
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(len(l1.calls), 1) # ensure we got the event
|
2020-12-12 14:22:34 +00:00
|
|
|
|
2020-11-22 14:14:43 +00:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
unittest.main()
|