mirror of
https://github.com/sezanzeb/input-remapper
synced 2024-11-04 12:00:16 +00:00
some more tests
This commit is contained in:
parent
e54a08f3be
commit
d75082bdf7
@ -32,8 +32,8 @@ Documentation:
|
|||||||
|
|
||||||
##### Names
|
##### Names
|
||||||
|
|
||||||
For a list of supported keystrokes and their names, check the output of
|
For a list of supported keystrokes and their names for the middle column,
|
||||||
`xmodmap -pke`
|
check the output of `xmodmap -pke`
|
||||||
|
|
||||||
- Alphanumeric `a` to `z` and `0` to `9`
|
- Alphanumeric `a` to `z` and `0` to `9`
|
||||||
- Modifiers `Alt_L` `Control_L` `Control_R` `Shift_L` `Shift_R`
|
- Modifiers `Alt_L` `Control_L` `Control_R` `Shift_L` `Shift_R`
|
||||||
@ -42,6 +42,7 @@ If you can't find what you need, consult
|
|||||||
[linux/input-event-codes.h](https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h)
|
[linux/input-event-codes.h](https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h)
|
||||||
|
|
||||||
- Mouse buttons `BTN_LEFT` `BTN_RIGHT` `BTN_MIDDLE` `BTN_SIDE`
|
- Mouse buttons `BTN_LEFT` `BTN_RIGHT` `BTN_MIDDLE` `BTN_SIDE`
|
||||||
|
- Multimedia keys `KEY_NEXTSONG`, `KEY_PLAYPAUSE`, ...
|
||||||
- Macro special keys `KEY_MACRO1` `KEY_MACRO2` ...
|
- Macro special keys `KEY_MACRO1` `KEY_MACRO2` ...
|
||||||
|
|
||||||
##### Gamepads
|
##### Gamepads
|
||||||
|
@ -143,7 +143,6 @@ class KeycodeInjector:
|
|||||||
|
|
||||||
needed = False
|
needed = False
|
||||||
for (ev_type, keycode), _ in self.mapping:
|
for (ev_type, keycode), _ in self.mapping:
|
||||||
# TODO test ev_type
|
|
||||||
if keycode in capabilities.get(ev_type, []):
|
if keycode in capabilities.get(ev_type, []):
|
||||||
needed = True
|
needed = True
|
||||||
break
|
break
|
||||||
@ -161,13 +160,13 @@ class KeycodeInjector:
|
|||||||
|
|
||||||
attempts = 0
|
attempts = 0
|
||||||
while True:
|
while True:
|
||||||
device = evdev.InputDevice(path)
|
|
||||||
try:
|
try:
|
||||||
# grab to avoid e.g. the disabled keycode of 10 to confuse
|
# grab to avoid e.g. the disabled keycode of 10 to confuse
|
||||||
# X, especially when one of the buttons of your mouse also
|
# X, especially when one of the buttons of your mouse also
|
||||||
# uses 10. This also avoids having to load an empty xkb
|
# uses 10. This also avoids having to load an empty xkb
|
||||||
# symbols file to prevent writing any unwanted keys.
|
# symbols file to prevent writing any unwanted keys.
|
||||||
device.grab()
|
device.grab()
|
||||||
|
logger.debug('Grab %s', path)
|
||||||
break
|
break
|
||||||
except IOError:
|
except IOError:
|
||||||
attempts += 1
|
attempts += 1
|
||||||
@ -224,7 +223,6 @@ class KeycodeInjector:
|
|||||||
capabilities[ecodes.EV_KEY] = []
|
capabilities[ecodes.EV_KEY] = []
|
||||||
# for reasons I don't know, it is also required to have
|
# for reasons I don't know, it is also required to have
|
||||||
# any keyboard button in capabilities.
|
# any keyboard button in capabilities.
|
||||||
# TODO test that this is always present when abs_to_rel
|
|
||||||
capabilities[ecodes.EV_KEY].append(ecodes.KEY_0)
|
capabilities[ecodes.EV_KEY].append(ecodes.KEY_0)
|
||||||
|
|
||||||
# just like what python-evdev does in from_device
|
# just like what python-evdev does in from_device
|
||||||
|
@ -43,7 +43,6 @@ def should_map_event_as_btn(type, code):
|
|||||||
code : int
|
code : int
|
||||||
linux keycode
|
linux keycode
|
||||||
"""
|
"""
|
||||||
# TODO test
|
|
||||||
if type == evdev.events.EV_KEY:
|
if type == evdev.events.EV_KEY:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -108,8 +108,6 @@ class _KeycodeReader:
|
|||||||
logger.debug('Pipe closed, reader stops.')
|
logger.debug('Pipe closed, reader stops.')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# TODO write a test to map event `type 3 (EV_ABS), code 16
|
|
||||||
# (ABS_HAT0X), value 0` to a button
|
|
||||||
if should_map_event_as_btn(event.type, event.code):
|
if should_map_event_as_btn(event.type, event.code):
|
||||||
logger.spam(
|
logger.spam(
|
||||||
'got code:%s value:%s type:%s',
|
'got code:%s value:%s type:%s',
|
||||||
|
@ -38,7 +38,6 @@ CTX_KEYCODE = 2
|
|||||||
|
|
||||||
def to_string(ev_type, code):
|
def to_string(ev_type, code):
|
||||||
"""A nice to show description of the pressed key."""
|
"""A nice to show description of the pressed key."""
|
||||||
# TODO test
|
|
||||||
try:
|
try:
|
||||||
name = evdev.ecodes.bytype[ev_type][code]
|
name = evdev.ecodes.bytype[ev_type][code]
|
||||||
if isinstance(name, list):
|
if isinstance(name, list):
|
||||||
|
@ -86,7 +86,7 @@ class Mapping:
|
|||||||
prev_keycode = int(prev_keycode)
|
prev_keycode = int(prev_keycode)
|
||||||
if prev_type is not None:
|
if prev_type is not None:
|
||||||
prev_type = int(prev_type)
|
prev_type = int(prev_type)
|
||||||
except ValueError:
|
except (TypeError, ValueError):
|
||||||
logger.error('Can only use numbers in the tuples')
|
logger.error('Can only use numbers in the tuples')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -100,9 +100,6 @@ class Mapping:
|
|||||||
if code_changed and prev_keycode is not None:
|
if code_changed and prev_keycode is not None:
|
||||||
# clear previous mapping of that code, because the line
|
# clear previous mapping of that code, because the line
|
||||||
# representing that one will now represent a different one.
|
# representing that one will now represent a different one.
|
||||||
# TODO test that None won't reach the clear function.
|
|
||||||
# TODO test that overwriting an entry with a different type
|
|
||||||
# works
|
|
||||||
self.clear(prev_type, prev_keycode)
|
self.clear(prev_type, prev_keycode)
|
||||||
self.changed = True
|
self.changed = True
|
||||||
return True
|
return True
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import copy
|
||||||
import unittest
|
import unittest
|
||||||
import subprocess
|
import subprocess
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
@ -99,7 +100,16 @@ fixtures = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'/dev/input/event30': {
|
'/dev/input/event30': {
|
||||||
'capabilities': {evdev.ecodes.EV_SYN: [], evdev.ecodes.EV_ABS: [0, 1]},
|
# this device is expected to not have EV_KEY capabilities in tests
|
||||||
|
# yet. Only when the injector is running EV_KEY stuff is added
|
||||||
|
'capabilities': {
|
||||||
|
evdev.ecodes.EV_SYN: [],
|
||||||
|
evdev.ecodes.EV_ABS: [
|
||||||
|
evdev.ecodes.ABS_X,
|
||||||
|
evdev.ecodes.ABS_Y,
|
||||||
|
evdev.ecodes.ABS_HAT0X
|
||||||
|
]
|
||||||
|
},
|
||||||
'phys': 'usb-0000:03:00.0-3/input1',
|
'phys': 'usb-0000:03:00.0-3/input1',
|
||||||
'name': 'gamepad'
|
'name': 'gamepad'
|
||||||
},
|
},
|
||||||
@ -252,7 +262,7 @@ def patch_evdev():
|
|||||||
await asyncio.sleep(0.01)
|
await asyncio.sleep(0.01)
|
||||||
|
|
||||||
def capabilities(self, absinfo=True):
|
def capabilities(self, absinfo=True):
|
||||||
return fixtures[self.path]['capabilities']
|
return copy.deepcopy(fixtures[self.path]['capabilities'])
|
||||||
|
|
||||||
class UInput:
|
class UInput:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -288,6 +298,7 @@ def clear_write_history():
|
|||||||
while uinput_write_history_pipe[0].poll():
|
while uinput_write_history_pipe[0].poll():
|
||||||
uinput_write_history_pipe[0].recv()
|
uinput_write_history_pipe[0].recv()
|
||||||
|
|
||||||
|
|
||||||
# quickly fake some stuff before any other file gets a chance to import
|
# quickly fake some stuff before any other file gets a chance to import
|
||||||
# the original versions
|
# the original versions
|
||||||
patch_paths()
|
patch_paths()
|
||||||
|
@ -24,7 +24,7 @@ import unittest
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
import evdev
|
import evdev
|
||||||
from evdev.ecodes import EV_REL, EV_KEY, EV_ABS
|
from evdev.ecodes import EV_REL, EV_KEY, EV_ABS, ABS_HAT0X
|
||||||
|
|
||||||
from keymapper.dev.injector import is_numlock_on, toggle_numlock,\
|
from keymapper.dev.injector import is_numlock_on, toggle_numlock,\
|
||||||
ensure_numlock, KeycodeInjector
|
ensure_numlock, KeycodeInjector
|
||||||
@ -65,6 +65,7 @@ class TestInjector(unittest.TestCase):
|
|||||||
for key in keys:
|
for key in keys:
|
||||||
del pending_events[key]
|
del pending_events[key]
|
||||||
clear_write_history()
|
clear_write_history()
|
||||||
|
custom_mapping.empty()
|
||||||
|
|
||||||
def test_modify_capabilities(self):
|
def test_modify_capabilities(self):
|
||||||
class FakeDevice:
|
class FakeDevice:
|
||||||
@ -108,6 +109,15 @@ class TestInjector(unittest.TestCase):
|
|||||||
# success on the third try
|
# success on the third try
|
||||||
device.name = fixtures[path]['name']
|
device.name = fixtures[path]['name']
|
||||||
|
|
||||||
|
def test_prepare_device_1(self):
|
||||||
|
# according to the fixtures, /dev/input/event30 can do ABS_HAT0X
|
||||||
|
custom_mapping.change((EV_ABS, ABS_HAT0X), 'a')
|
||||||
|
self.injector = KeycodeInjector('foobar', custom_mapping)
|
||||||
|
|
||||||
|
_prepare_device = self.injector._prepare_device
|
||||||
|
self.assertIsNone(_prepare_device('/dev/input/event10')[0])
|
||||||
|
self.assertIsNotNone(_prepare_device('/dev/input/event30')[0])
|
||||||
|
|
||||||
def test_gamepad_capabilities(self):
|
def test_gamepad_capabilities(self):
|
||||||
self.injector = KeycodeInjector('gamepad', custom_mapping)
|
self.injector = KeycodeInjector('gamepad', custom_mapping)
|
||||||
|
|
||||||
@ -119,6 +129,11 @@ class TestInjector(unittest.TestCase):
|
|||||||
self.assertNotIn(evdev.ecodes.EV_ABS, capabilities)
|
self.assertNotIn(evdev.ecodes.EV_ABS, capabilities)
|
||||||
self.assertIn(evdev.ecodes.EV_REL, capabilities)
|
self.assertIn(evdev.ecodes.EV_REL, capabilities)
|
||||||
|
|
||||||
|
# for some reason, having any EV_KEY capability is needed to
|
||||||
|
# be able to control the mouse
|
||||||
|
self.assertIn(evdev.ecodes.EV_KEY, capabilities)
|
||||||
|
self.assertEqual(len(capabilities[evdev.ecodes.EV_KEY]), 1)
|
||||||
|
|
||||||
def test_skip_unused_device(self):
|
def test_skip_unused_device(self):
|
||||||
# skips a device because its capabilities are not used in the mapping
|
# skips a device because its capabilities are not used in the mapping
|
||||||
custom_mapping.change((EV_KEY, 10), 'a')
|
custom_mapping.change((EV_KEY, 10), 'a')
|
||||||
@ -282,7 +297,7 @@ class TestInjector(unittest.TestCase):
|
|||||||
|
|
||||||
def test_injector(self):
|
def test_injector(self):
|
||||||
custom_mapping.change((EV_KEY, 8), 'k(KEY_Q).k(w)')
|
custom_mapping.change((EV_KEY, 8), 'k(KEY_Q).k(w)')
|
||||||
custom_mapping.change((EV_KEY, 9), 'a')
|
custom_mapping.change((EV_ABS, ABS_HAT0X), 'a')
|
||||||
# one mapping that is unknown in the system_mapping on purpose
|
# one mapping that is unknown in the system_mapping on purpose
|
||||||
input_b = 10
|
input_b = 10
|
||||||
custom_mapping.change((EV_KEY, input_b), 'b')
|
custom_mapping.change((EV_KEY, input_b), 'b')
|
||||||
@ -301,9 +316,9 @@ class TestInjector(unittest.TestCase):
|
|||||||
# should execute a macro
|
# should execute a macro
|
||||||
Event(EV_KEY, 8, 1),
|
Event(EV_KEY, 8, 1),
|
||||||
Event(EV_KEY, 8, 0),
|
Event(EV_KEY, 8, 0),
|
||||||
# normal keystroke
|
# normal keystrokes
|
||||||
Event(EV_KEY, 9, 1),
|
Event(EV_ABS, ABS_HAT0X, 1),
|
||||||
Event(EV_KEY, 9, 0),
|
Event(EV_ABS, ABS_HAT0X, 0),
|
||||||
# just pass those over without modifying
|
# just pass those over without modifying
|
||||||
Event(EV_KEY, 10, 1),
|
Event(EV_KEY, 10, 1),
|
||||||
Event(EV_KEY, 10, 0),
|
Event(EV_KEY, 10, 0),
|
||||||
|
@ -40,6 +40,7 @@ from keymapper.state import custom_mapping, system_mapping, \
|
|||||||
from keymapper.paths import CONFIG, get_config_path
|
from keymapper.paths import CONFIG, get_config_path
|
||||||
from keymapper.config import config
|
from keymapper.config import config
|
||||||
from keymapper.dev.reader import keycode_reader
|
from keymapper.dev.reader import keycode_reader
|
||||||
|
from keymapper.gtk.row import to_string
|
||||||
|
|
||||||
from tests.test import tmp, pending_events, Event, uinput_write_history_pipe, \
|
from tests.test import tmp, pending_events, Event, uinput_write_history_pipe, \
|
||||||
clear_write_history
|
clear_write_history
|
||||||
@ -176,6 +177,11 @@ class TestIntegration(unittest.TestCase):
|
|||||||
self.assertIsNotNone(self.window)
|
self.assertIsNotNone(self.window)
|
||||||
self.assertTrue(self.window.window.get_visible())
|
self.assertTrue(self.window.window.get_visible())
|
||||||
|
|
||||||
|
def test_row_keycode_to_string(self):
|
||||||
|
# not an integration test, but I have all the row tests here already
|
||||||
|
self.assertEqual(to_string(EV_KEY, 10), '9')
|
||||||
|
self.assertEqual(to_string(EV_KEY, 39), 'SEMICOLON')
|
||||||
|
|
||||||
def test_row_simple(self):
|
def test_row_simple(self):
|
||||||
rows = self.window.get('key_list').get_children()
|
rows = self.window.get('key_list').get_children()
|
||||||
self.assertEqual(len(rows), 1)
|
self.assertEqual(len(rows), 1)
|
||||||
@ -185,9 +191,15 @@ class TestIntegration(unittest.TestCase):
|
|||||||
row.set_new_keycode(None, None)
|
row.set_new_keycode(None, None)
|
||||||
self.assertIsNone(row.get_keycode())
|
self.assertIsNone(row.get_keycode())
|
||||||
self.assertEqual(len(custom_mapping), 0)
|
self.assertEqual(len(custom_mapping), 0)
|
||||||
|
self.assertEqual(row.keycode_input.get_label(), None)
|
||||||
|
|
||||||
row.set_new_keycode(EV_KEY, 30)
|
row.set_new_keycode(EV_KEY, 30)
|
||||||
self.assertEqual(len(custom_mapping), 0)
|
self.assertEqual(len(custom_mapping), 0)
|
||||||
self.assertEqual(row.get_keycode(), (EV_KEY, 30))
|
self.assertEqual(row.get_keycode(), (EV_KEY, 30))
|
||||||
|
# this is KEY_A in linux/input-event-codes.h,
|
||||||
|
# but KEY_ is removed from the text
|
||||||
|
self.assertEqual(row.keycode_input.get_label(), 'A')
|
||||||
|
|
||||||
row.set_new_keycode(EV_KEY, 30)
|
row.set_new_keycode(EV_KEY, 30)
|
||||||
self.assertEqual(len(custom_mapping), 0)
|
self.assertEqual(len(custom_mapping), 0)
|
||||||
self.assertEqual(row.get_keycode(), (EV_KEY, 30))
|
self.assertEqual(row.get_keycode(), (EV_KEY, 30))
|
||||||
@ -208,8 +220,20 @@ class TestIntegration(unittest.TestCase):
|
|||||||
self.assertEqual(row.get_keycode(), (EV_KEY, 30))
|
self.assertEqual(row.get_keycode(), (EV_KEY, 30))
|
||||||
|
|
||||||
def change_empty_row(self, code, char, code_first=True, success=True):
|
def change_empty_row(self, code, char, code_first=True, success=True):
|
||||||
"""Modify the one empty row that always exists."""
|
"""Modify the one empty row that always exists.
|
||||||
# this is not a test, it's a utility function for other tests.
|
|
||||||
|
Utility function for other tests.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
code_first : boolean
|
||||||
|
If True, the code is entered and then the character.
|
||||||
|
If False, the character is entered first.
|
||||||
|
success : boolean
|
||||||
|
If this change on the empty row is going to result in a change
|
||||||
|
in the mapping eventually. False if this change is going to
|
||||||
|
cause a duplicate.
|
||||||
|
"""
|
||||||
# wait for the window to create a new empty row if needed
|
# wait for the window to create a new empty row if needed
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
gtk_iteration()
|
gtk_iteration()
|
||||||
|
38
tests/testcases/test_keycode_mapper.py
Normal file
38
tests/testcases/test_keycode_mapper.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# key-mapper - GUI for device specific keyboard mappings
|
||||||
|
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
|
||||||
|
#
|
||||||
|
# This file is part of key-mapper.
|
||||||
|
#
|
||||||
|
# key-mapper is free software: you can redistribute it and/or modify
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# key-mapper is distributed in the hope that it will be useful,
|
||||||
|
# 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
|
||||||
|
# along with key-mapper. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from evdev.ecodes import EV_KEY, EV_ABS, ABS_HAT0X, KEY_A, ABS_X, EV_REL, REL_X
|
||||||
|
|
||||||
|
from keymapper.dev.keycode_mapper import should_map_event_as_btn
|
||||||
|
|
||||||
|
|
||||||
|
class TestKeycodeMapper(unittest.TestCase):
|
||||||
|
def test_should_map_event_as_btn(self):
|
||||||
|
self.assertTrue(should_map_event_as_btn(EV_ABS, ABS_HAT0X))
|
||||||
|
self.assertTrue(should_map_event_as_btn(EV_KEY, KEY_A))
|
||||||
|
self.assertFalse(should_map_event_as_btn(EV_ABS, ABS_X))
|
||||||
|
self.assertFalse(should_map_event_as_btn(EV_REL, REL_X))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from evdev.events import EV_KEY
|
from evdev.events import EV_KEY, EV_ABS
|
||||||
|
|
||||||
from keymapper.mapping import Mapping
|
from keymapper.mapping import Mapping
|
||||||
from keymapper.state import populate_system_mapping
|
from keymapper.state import populate_system_mapping
|
||||||
@ -81,15 +81,15 @@ class TestMapping(unittest.TestCase):
|
|||||||
self.assertEqual(self.mapping.get_character(EV_KEY, 2), 'a')
|
self.assertEqual(self.mapping.get_character(EV_KEY, 2), 'a')
|
||||||
self.assertEqual(len(self.mapping), 1)
|
self.assertEqual(len(self.mapping), 1)
|
||||||
|
|
||||||
# change 2 to 3 and change a to b
|
# change KEY 2 to ABS 16 and change a to b
|
||||||
self.mapping.change((EV_KEY, 3), 'b', (EV_KEY, 2))
|
self.mapping.change((EV_ABS, 16), 'b', (EV_KEY, 2))
|
||||||
self.assertIsNone(self.mapping.get_character(EV_KEY, 2))
|
self.assertIsNone(self.mapping.get_character(EV_KEY, 2))
|
||||||
self.assertEqual(self.mapping.get_character(EV_KEY, 3), 'b')
|
self.assertEqual(self.mapping.get_character(EV_ABS, 16), 'b')
|
||||||
self.assertEqual(len(self.mapping), 1)
|
self.assertEqual(len(self.mapping), 1)
|
||||||
|
|
||||||
# add 4
|
# add 4
|
||||||
self.mapping.change((EV_KEY, 4), 'c', (None, None))
|
self.mapping.change((EV_KEY, 4), 'c', (None, None))
|
||||||
self.assertEqual(self.mapping.get_character(EV_KEY, 3), 'b')
|
self.assertEqual(self.mapping.get_character(EV_ABS, 16), 'b')
|
||||||
self.assertEqual(self.mapping.get_character(EV_KEY, 4), 'c')
|
self.assertEqual(self.mapping.get_character(EV_KEY, 4), 'c')
|
||||||
self.assertEqual(len(self.mapping), 2)
|
self.assertEqual(len(self.mapping), 2)
|
||||||
|
|
||||||
@ -109,10 +109,23 @@ class TestMapping(unittest.TestCase):
|
|||||||
self.assertEqual(len(self.mapping), 2)
|
self.assertEqual(len(self.mapping), 2)
|
||||||
|
|
||||||
# non-int keycodes are ignored
|
# non-int keycodes are ignored
|
||||||
# TODO what about non-int types?
|
|
||||||
self.mapping.change((EV_KEY, 'b'), 'c', (EV_KEY, 'a'))
|
self.mapping.change((EV_KEY, 'b'), 'c', (EV_KEY, 'a'))
|
||||||
|
self.mapping.change((EV_KEY, 'b'), 'c')
|
||||||
|
self.mapping.change(('foo', 1), 'c', ('foo', 2))
|
||||||
|
self.mapping.change(('foo', 1), 'c')
|
||||||
self.assertEqual(len(self.mapping), 2)
|
self.assertEqual(len(self.mapping), 2)
|
||||||
|
|
||||||
|
def test_change_2(self):
|
||||||
|
self.mapping.change((EV_KEY, 2), 'a')
|
||||||
|
|
||||||
|
self.mapping.change((None, 2), 'b', (EV_KEY, 2))
|
||||||
|
self.assertEqual(self.mapping.get_character(EV_KEY, 2), 'a')
|
||||||
|
|
||||||
|
self.mapping.change((EV_KEY, None), 'c', (EV_KEY, 2))
|
||||||
|
self.assertEqual(self.mapping.get_character(EV_KEY, 2), 'a')
|
||||||
|
|
||||||
|
self.assertEqual(len(self.mapping), 1)
|
||||||
|
|
||||||
def test_clear(self):
|
def test_clear(self):
|
||||||
# does nothing
|
# does nothing
|
||||||
self.mapping.clear(EV_KEY, 40)
|
self.mapping.clear(EV_KEY, 40)
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from evdev.events import EV_KEY
|
from evdev.ecodes import EV_KEY, EV_ABS, ABS_HAT0X
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from keymapper.dev.reader import keycode_reader
|
from keymapper.dev.reader import keycode_reader
|
||||||
@ -34,6 +34,17 @@ CODE_2 = 101
|
|||||||
CODE_3 = 102
|
CODE_3 = 102
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
class TestReader(unittest.TestCase):
|
class TestReader(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# verify that tearDown properly cleared the reader
|
# verify that tearDown properly cleared the reader
|
||||||
@ -45,10 +56,10 @@ class TestReader(unittest.TestCase):
|
|||||||
for key in keys:
|
for key in keys:
|
||||||
del pending_events[key]
|
del pending_events[key]
|
||||||
|
|
||||||
def test_reading(self):
|
def test_reading_1(self):
|
||||||
pending_events['device 1'] = [
|
pending_events['device 1'] = [
|
||||||
Event(EV_KEY, CODE_1, 1),
|
Event(EV_KEY, CODE_1, 1),
|
||||||
Event(EV_KEY, CODE_2, 1),
|
Event(EV_ABS, ABS_HAT0X, 1),
|
||||||
Event(EV_KEY, CODE_3, 1)
|
Event(EV_KEY, CODE_3, 1)
|
||||||
]
|
]
|
||||||
keycode_reader.start_reading('device 1')
|
keycode_reader.start_reading('device 1')
|
||||||
@ -56,10 +67,18 @@ class TestReader(unittest.TestCase):
|
|||||||
# sending anything arbitrary does not stop the pipe
|
# sending anything arbitrary does not stop the pipe
|
||||||
keycode_reader._pipe[0].send((EV_KEY, 1234))
|
keycode_reader._pipe[0].send((EV_KEY, 1234))
|
||||||
|
|
||||||
time.sleep(EVENT_READ_TIMEOUT * 5)
|
wait(keycode_reader._pipe[0].poll, 0.5)
|
||||||
|
|
||||||
self.assertEqual(keycode_reader.read(), (EV_KEY, CODE_3))
|
self.assertEqual(keycode_reader.read(), (EV_KEY, CODE_3))
|
||||||
self.assertEqual(keycode_reader.read(), (None, None))
|
self.assertEqual(keycode_reader.read(), (None, None))
|
||||||
|
|
||||||
|
def test_reading_2(self):
|
||||||
|
pending_events['device 1'] = [Event(EV_ABS, ABS_HAT0X, 1)]
|
||||||
|
keycode_reader.start_reading('device 1')
|
||||||
|
wait(keycode_reader._pipe[0].poll, 0.5)
|
||||||
|
self.assertEqual(keycode_reader.read(), (EV_ABS, ABS_HAT0X))
|
||||||
|
self.assertEqual(keycode_reader.read(), (None, None))
|
||||||
|
|
||||||
def test_wrong_device(self):
|
def test_wrong_device(self):
|
||||||
pending_events['device 1'] = [
|
pending_events['device 1'] = [
|
||||||
Event(EV_KEY, CODE_1, 1),
|
Event(EV_KEY, CODE_1, 1),
|
||||||
|
Loading…
Reference in New Issue
Block a user