input-remapper
input-remapper copied to clipboard
Led test
see https://github.com/sezanzeb/key-mapper/issues/160
some difficulties that is the magic of asyncio
asyncio is indeed a bit more difficult than for example async/await in javascript. In javascript there is always one single event loop present, and in python you have to create them yourself first.
Just in case you haven't used async/await before, a brief introduction:
Each time you await
something, asyncio will continue at a different place in your code that has previously stopped at an await
. Await is kindof like saying "while we wait for input, lets do something else". Its just another method of concurrency.
Ok, I believe this is complete.
I foresee the possibility to send to other devices (like in your earlier question: if I program a button on "Brand XYZ mouse" I may want to set a led or beep "Brand UVW keyboard", so the device parameter can also be something else then a bool, like a search string. But for now, it will only work if "Brand XYZ mouse" has its own LED's
Eventually, it should even be extended to EV_FF force feedback, for which this device specification could really be important. but I believe that is a bit more complex then merely sending events. If it is as simple as sending event triplets, it may already work when on the same device.
Let me know. If you accept the PR, I will also work on the documentation, and maybe even add some test cases.
and maybe even add some test cases.
we will absolutely do that, I'll help you out on that and point you to where to do that later
Eventually, it should even be extended to EV_FF force feedback
please explain what EV_FF does
In test_macros.py
there is
def test_event_1(self):
macro = parse('e(EV_KEY, KEY_A, 1)', self.mapping)
a_code = system_mapping.get('a')
self.assertSetEqual(macro.get_capabilities()[EV_KEY], {a_code})
self.assertSetEqual(macro.get_capabilities()[EV_REL], set())
self.loop.run_until_complete(macro.run(self.handler))
self.assertListEqual(self.result, [(EV_KEY, a_code, 1)])
self.assertEqual(len(macro.child_macros), 0)
You could start with this as a template. self.handler
needs to be modified so that the assertListEqual
can check events written back to the device.
same for the led(...)
macro function
In order to test device_write
you could write one in test_keycode_mapper.py
since it is in that class.
maybe something like
def test_device_write(self):
context = Context(...)
# note that there is a fake `class InputDevice` in `test.py` that is patched into evdev via `patch_evdev`.
# It probably has to be extended with a `write` function.
# to have each inputDevice get different capabilities, take a look at the `fixtures` in `test.py`
context.sources = [evdev.InputDevice(...), ...]
keycode_mapper = KeycodeMapper(...)
keycode_mapper.device_write(...)
# assert stuff, maybe the patched `InputDevice` can keep track of written events,
# just like the `write_history` of the `UInput` patch.
You can run tests via python3 tests/test.py test_keycode_mapper
FF stands for force feedback. Not a gamer myself, but I believe it is where the game controller vibrates in your hand when you take a hit.
I suspect soon there will be a user that complains that his vibration does not work anymore when key-mapper sits in the middle. Then again, I suspect hard-core gamers turn this off anyway, at it distracts and shaves milliseconds of their response times.
Anyway, I do not know how to use or test it, but I foresee if ever that is implemented, it will also pass through this todevice() function.
I should ignore the errors that the python3 tests/test.py test_keycode_mapper
already give before I modify anything?
======================================================================
ERROR: test_macro_writes_to_context_uinput (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 509, in test_macro_writes_to_context_uinput
keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1))
File "/usr/lib/python3/dist-packages/keymapper/injection/keycode_mapper.py", line 441, in handle_keycode
macro.press_key()
AttributeError: 'NoneType' object has no attribute 'press_key'
======================================================================
ERROR: test_macro_writes_to_context_uinput (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 83, in tearDown
if macro.is_holding():
AttributeError: 'NoneType' object has no attribute 'is_holding'
======================================================================
ERROR: test_not_forward (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 83, in tearDown
if macro.is_holding():
AttributeError: 'NoneType' object has no attribute 'is_holding'
======================================================================
ERROR: test_release_joystick_button (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 83, in tearDown
if macro.is_holding():
AttributeError: 'NoneType' object has no attribute 'is_holding'
======================================================================
ERROR: test_subsets (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 83, in tearDown
if macro.is_holding():
AttributeError: 'NoneType' object has no attribute 'is_holding'
======================================================================
ERROR: test_two_d_pad_macros (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 83, in tearDown
if macro.is_holding():
AttributeError: 'NoneType' object has no attribute 'is_holding'
======================================================================
ERROR: test_wheel_combination_release_failure (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 83, in tearDown
if macro.is_holding():
AttributeError: 'NoneType' object has no attribute 'is_holding'
======================================================================
FAIL: test_not_forward (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 202, in test_not_forward
self.assertEqual(len(unreleased), 1)
AssertionError: 2 != 1
======================================================================
FAIL: test_wheel_combination_release_failure (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 1293, in test_wheel_combination_release_failure
self.assertEqual(uinput_write_history[0].t, btn_down)
AssertionError: Tuples differ: (1, 73, 1) != (1, 276, 1)
First differing element 1:
73
276
- (1, 73, 1)
? ^
+ (1, 276, 1)
? + ^
----------------------------------------------------------------------
Ran 22 tests in 5.540s
FAILED (failures=2, errors=7)
Please run python3 tests/test.py test_keycode_mapper.TestKeycodeMapper.test_macro_writes_to_context_uinput
and share the complete log. They pass on my computer, I'll see if I can fix them for yours
Ok. Just for sake to correctness, I first moved to the main branch rather then the LED branch, but it did not matter much Please note this is running on a Raspberry Pi. Also, all function I use seem to work.
pi@RasPi4SSD:~/key-mapper $ python3 tests/test.py test_keycode_mapper.TestKeycodeMapper.test_macro_writes_to_context_uinput
1363 0.02780 DEBUG groups.py:328: Discovering device paths
1363 0.02898 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-0", "/dev/input/event1", "Foo Device", type: keyboard
1363 0.02934 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-1", "/dev/input/event11", "Foo Device foo", type: mouse
1363 0.03054 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-1", "/dev/input/event10", "Foo Device", type: keyboard
1363 0.03084 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-1", "/dev/input/event13", "Foo Device", type: unknown
1363 0.03219 SPAM groups.py:362: Found "2_1_2_usb-0000:03:00.0-2", "/dev/input/event20", "Bar Device", type: keyboard
1363 0.03261 SPAM groups.py:362: Found "3_1_3_-", "/dev/input/event30", "gamepad", type: gamepad
1363 0.03395 SPAM groups.py:362: Found "5_1_5_key-mapper", "/dev/input/event40", "key-mapper Bar Device", type: keyboard
1363 0.03621 INFO groups.py:434: Found "Foo Device", "Foo Device 2", "Bar Device", "gamepad", "key-mapper Bar Device"
1363 0.04235 DEBUG state.py:64: Gathering available keycodes
1363 0.05295 INFO paths.py:50: Creating file "/tmp/key-mapper-test/xmodmap.json"
1363 0.05464 DEBUG state.py:85: Writing "/tmp/key-mapper-test/xmodmap.json"
1363 0.07304 SPAM pipe.py:64: Creating new pipe for "/tmp/key-mapper/results"
1363 0.07485 SPAM pipe.py:64: Creating new pipe for "/tmp/key-mapper/commands"
cleanup
1363 0.17613 DEBUG reader.py:194: Sending close msg to helper
1367 0.17998 SPAM macros.py:84: SharedDict got ('stop',)
1363 0.20993 INFO paths.py:50: Creating file "/tmp/key-mapper-test/config.json"
1363 0.21228 INFO config.py:269: Saved config to /tmp/key-mapper-test/config.json
1363 0.21301 DEBUG state.py:64: Gathering available keycodes
1363 0.22502 INFO paths.py:50: Creating file "/tmp/key-mapper-test/xmodmap.json"
1363 0.22613 DEBUG state.py:85: Writing "/tmp/key-mapper-test/xmodmap.json"
1363 0.23365 DEBUG reader.py:203: Clearing reader
1372 0.23619 SPAM macros.py:84: SharedDict got ('ping',)
1363 0.33935 DEBUG groups.py:328: Discovering device paths
1363 0.34015 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-0", "/dev/input/event1", "Foo Device", type: keyboard
1363 0.34051 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-1", "/dev/input/event11", "Foo Device foo", type: mouse
1363 0.34182 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-1", "/dev/input/event10", "Foo Device", type: keyboard
1363 0.34211 SPAM groups.py:362: Found "1_1_1_usb-0000:03:00.0-1", "/dev/input/event13", "Foo Device", type: unknown
1363 0.34335 SPAM groups.py:362: Found "2_1_2_usb-0000:03:00.0-2", "/dev/input/event20", "Bar Device", type: keyboard
1363 0.34371 SPAM groups.py:362: Found "3_1_3_-", "/dev/input/event30", "gamepad", type: gamepad
1363 0.34492 SPAM groups.py:362: Found "5_1_5_key-mapper", "/dev/input/event40", "key-mapper Bar Device", type: keyboard
1363 0.34750 INFO groups.py:434: Found "Foo Device", "Foo Device 2", "Bar Device", "gamepad", "key-mapper Bar Device"
test_macro_writes_to_context_uinput (testcases.test_keycode_mapper.TestKeycodeMapper) ...
1363 0.38732 SPAM macros.py:721: preparing macro k(a) for later execution
1363 0.38832 SPAM macros.py:617: calls k with ['a']
1363 0.38872 SPAM macros.py:658: <class 'str'> a
1363 0.38898 SPAM macros.py:624: add call to k with ['a']
1363 0.38931 ERROR macros.py:727: Failed to parse macro "k(a)": KeyError('Unknown key "a"')
1363 0.39055 DEBUG macros.py:729: File "/usr/lib/python3/dist-packages/keymapper/injection/macros.py", line 724, in parse
macro_object = _parse_recurse(macro, mapping)
File "/usr/lib/python3/dist-packages/keymapper/injection/macros.py", line 640, in _parse_recurse
function[0](*params)
File "/usr/lib/python3/dist-packages/keymapper/injection/macros.py", line 371, in keycode
raise KeyError(f'Unknown key "{symbol}"')
1363 0.39115 DEBUG context.py:96: Parsing macros
1363 0.39143 DEBUG context.py:108: No macros configured
ERROR
ERROR
======================================================================
ERROR: test_macro_writes_to_context_uinput (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 509, in test_macro_writes_to_context_uinput
keycode_mapper.handle_keycode(new_event(EV_KEY, 1, 1))
File "/usr/lib/python3/dist-packages/keymapper/injection/keycode_mapper.py", line 429, in handle_keycode
macro.press_key()
AttributeError: 'NoneType' object has no attribute 'press_key'
======================================================================
ERROR: test_macro_writes_to_context_uinput (testcases.test_keycode_mapper.TestKeycodeMapper)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/pi/key-mapper/tests/testcases/test_keycode_mapper.py", line 83, in tearDown
if macro.is_holding():
AttributeError: 'NoneType' object has no attribute 'is_holding'
----------------------------------------------------------------------
Ran 1 test in 0.010s
FAILED (errors=2)
1372 0.39833 SPAM macros.py:84: SharedDict got ('stop',)
pi@RasPi4SSD:~/key-mapper $
are you running the test from a tty or ssh? the issue is probably that xmodmap -pke
doesn't yield any output, but the test expects it to do
please pull the latest main and try again
From ssh indeed, sorry Even without your fixes, it indeed ran OK from tty
With your fixes, it runs OK from ssh as well. Is that now fixed and ssh as good to run the test as tty, or should I best always use the latter.
I think ssh should be fine now too. Obviously tests that require the gui to run would still fail, but those are just in test_integration.py
Is that now fixed and ssh as good to run the test as tty, or should I best always use the latter.
There is also test_numlock
in test_injector.py which will probably fail, but anyways, for this only test_macros.py and test_keycode_mapper.py are of interest
I just saw your request for contributor. Please understand I am also busy, but more importantly I ran into some trouble with writing the test routines. I started a few times, but got stuck on how to write a test routine for the 'todevice()' function, or rather, its underlying device_write()
function.
I may need some additional hints on this.
Don't worry I'm not blaming you. Your work is greatly appreciated!
where are you stuck? If you have questions you can always ask. Maintaining key-mapper and communicating with people works quite well even though my focus is currently a different one.
I think I'll dedicate one really intense week for key-mapper programming each winter/spring during semester break and see how far I can get. The really big problems have already been solved after all.
I just merged the latest main into led_test: https://github.com/sezanzeb/key-mapper/tree/led_test_merge
There have been some conflicts because I changed the architecture around a bit, but I haven't tried if led and to_device it still works properly after the merge.
This was closed automatically when I was tinkering around with the branches, sorry
there will be a lot of changes once beta is merged in, because the architecture is completely different. If this is still relevant, it needs to be rewritten, sorry. Idk how easy/hard it is with the new architecture
Ok noted. If I ever have a need to update my Pi, I guess I am in for some work. But as it stands, the Pi and mini-keyboard is working. Thanks for letting me know.
PS in all this time, no one else has requested or used LED's?
PS in all this time, no one else has requested or used LED's?
no