Skip to content

Commit

Permalink
Merge pull request #9 from acro5piano/feature/multi-keyboards
Browse files Browse the repository at this point in the history
breaking: support multiple keyboards (like USB keyboard)
  • Loading branch information
acro5piano committed Feb 19, 2022
2 parents 74057d5 + b124f30 commit 01755ef
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 71 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,28 @@ sudo pip3 install git+https://github.com/acro5piano/wayremap

# Run

For Wayland security model, we have to do execute the key remapping as root.
For Wayland security model, we have to run keyboard remapping tools as root permission.

Simply write your own service and run it as a python script:

```python
# /etc/wayremap.config.py

from wayremap.config import WayremapConfig, Binding
from wayremap.main import run
from wayremap import ecodes as e
from wayremap import ecodes as e, run, WayremapConfig, Binding
import uinput as k

wayremap_config = WayremapConfig(
# Note that `'/dev/input/event4'` varies among system.
input_path='/dev/input/event4',

# Filter applications which remap will be applied
applications=[
'Chromium',
'Brave-browser',
'Leafpad',
'firefoxdeveloperedition',
],

bindings=[
# To see all available binding keys, please see
# https://github.com/acro5piano/wayremap/blob/06d27c9bb86b766d7fd1e4230f3a16827785519e/wayremap/ecodes.py
Expand Down Expand Up @@ -88,8 +90,7 @@ wayremap_config = WayremapConfig(
])

# Finally, run wayremap.
# Note that `'/dev/input/event4'` varies among system.
run(wayremap_config, '/dev/input/event4')
run(wayremap_config)

```

Expand Down
20 changes: 20 additions & 0 deletions example/multiple-keyboards.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import uinput as k
from wayremap import ecodes as e, WayremapConfig, Binding, run

applications = [
'Brave-browser',
]

bindings = [
Binding([e.KEY_LEFTCTRL, e.KEY_S], [[k.KEY_LEFTCTRL, k.KEY_F]]),
]

run(
WayremapConfig(input_identifier=
'Lenovo TrackPoint Keyboard II usb-0000:00:14.0-1/input0',
applications=applications,
bindings=bindings),
WayremapConfig(input_path='/dev/input/event4',
applications=applications,
bindings=bindings),
)
3 changes: 3 additions & 0 deletions example/print-inputs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from wayremap import list_devices

list_devices()
44 changes: 44 additions & 0 deletions example/remap-like-osx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import uinput as k
from wayremap import ecodes as e, WayremapConfig, Binding, run

config = WayremapConfig(
input_identifier='Lenovo TrackPoint Keyboard II usb-0000:00:14.0-1/input0',
applications=[
'Brave-browser',
'chromium',
'firefoxdeveloperedition',
],
bindings=[
# Emacs-like key binding
Binding([e.KEY_LEFTCTRL, e.KEY_LEFTALT, e.KEY_A],
[[k.KEY_LEFTCTRL, k.KEY_HOME]]),
Binding([e.KEY_LEFTCTRL, e.KEY_LEFTALT, e.KEY_E],
[[k.KEY_LEFTCTRL, k.KEY_END]]),
Binding([e.KEY_LEFTCTRL, e.KEY_LEFTALT, e.KEY_H],
[[k.KEY_LEFTCTRL, k.KEY_BACKSPACE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_F], [[k.KEY_RIGHT]]),
Binding([e.KEY_LEFTCTRL, e.KEY_B], [[k.KEY_LEFT]]),
Binding([e.KEY_LEFTCTRL, e.KEY_P], [[k.KEY_UP]]),
Binding([e.KEY_LEFTCTRL, e.KEY_N], [[k.KEY_DOWN]]),
Binding([e.KEY_LEFTCTRL, e.KEY_K],
[[k.KEY_LEFTSHIFT, k.KEY_END], [k.KEY_LEFTCTRL, k.KEY_X]]),
Binding([e.KEY_LEFTCTRL, e.KEY_A], [[k.KEY_HOME]]),
Binding([e.KEY_LEFTCTRL, e.KEY_E], [[k.KEY_END]]),
Binding([e.KEY_LEFTCTRL, e.KEY_Y], [[k.KEY_LEFTCTRL, k.KEY_V]]),
Binding([e.KEY_LEFTALT, e.KEY_F], [[k.KEY_LEFTCTRL, k.KEY_RIGHT]]),
Binding([e.KEY_LEFTALT, e.KEY_B], [[k.KEY_LEFTCTRL, k.KEY_LEFT]]),
Binding([e.KEY_LEFTALT, e.KEY_D], [[k.KEY_LEFTCTRL, k.KEY_DELETE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_H], [[k.KEY_BACKSPACE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_D], [[k.KEY_DELETE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_S], [[k.KEY_LEFTCTRL, k.KEY_F]]),

# OSX-like key binding
Binding([e.KEY_LEFTALT, e.KEY_A], [[k.KEY_LEFTCTRL, k.KEY_A]]),
Binding([e.KEY_LEFTALT, e.KEY_C], [[k.KEY_LEFTCTRL, k.KEY_C]]),
Binding([e.KEY_LEFTALT, e.KEY_V], [[k.KEY_LEFTCTRL, k.KEY_V]]),

# Slack helm!
Binding([e.KEY_LEFTALT, e.KEY_X], [[k.KEY_LEFTCTRL, k.KEY_K]]),
])

run(config)
4 changes: 0 additions & 4 deletions test-module.py

This file was deleted.

45 changes: 3 additions & 42 deletions wayremap/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from dataclasses import dataclass
import uinput as k
from wayremap import ecodes as e
from typing import Optional
from wayremap import constants


Expand Down Expand Up @@ -41,43 +40,5 @@ def require_ctrl_alt(self) -> bool:
class WayremapConfig:
applications: list[str]
bindings: list[Binding]


example_config = WayremapConfig(
applications=[
'Brave-browser',
'chromium',
'firefoxdeveloperedition',
],
bindings=[
# Emacs-like key binding
Binding([e.KEY_LEFTCTRL, e.KEY_LEFTALT, e.KEY_A],
[[k.KEY_LEFTCTRL, k.KEY_HOME]]),
Binding([e.KEY_LEFTCTRL, e.KEY_LEFTALT, e.KEY_E],
[[k.KEY_LEFTCTRL, k.KEY_END]]),
Binding([e.KEY_LEFTCTRL, e.KEY_LEFTALT, e.KEY_H],
[[k.KEY_LEFTCTRL, k.KEY_BACKSPACE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_F], [[k.KEY_RIGHT]]),
Binding([e.KEY_LEFTCTRL, e.KEY_B], [[k.KEY_LEFT]]),
Binding([e.KEY_LEFTCTRL, e.KEY_P], [[k.KEY_UP]]),
Binding([e.KEY_LEFTCTRL, e.KEY_N], [[k.KEY_DOWN]]),
Binding([e.KEY_LEFTCTRL, e.KEY_K],
[[k.KEY_LEFTSHIFT, k.KEY_END], [k.KEY_LEFTCTRL, k.KEY_X]]),
Binding([e.KEY_LEFTCTRL, e.KEY_A], [[k.KEY_HOME]]),
Binding([e.KEY_LEFTCTRL, e.KEY_E], [[k.KEY_END]]),
Binding([e.KEY_LEFTCTRL, e.KEY_Y], [[k.KEY_LEFTCTRL, k.KEY_V]]),
Binding([e.KEY_LEFTALT, e.KEY_F], [[k.KEY_LEFTCTRL, k.KEY_RIGHT]]),
Binding([e.KEY_LEFTALT, e.KEY_B], [[k.KEY_LEFTCTRL, k.KEY_LEFT]]),
Binding([e.KEY_LEFTALT, e.KEY_D], [[k.KEY_LEFTCTRL, k.KEY_DELETE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_H], [[k.KEY_BACKSPACE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_D], [[k.KEY_DELETE]]),
Binding([e.KEY_LEFTCTRL, e.KEY_S], [[k.KEY_LEFTCTRL, k.KEY_F]]),

# OSX-like key binding
Binding([e.KEY_LEFTALT, e.KEY_A], [[k.KEY_LEFTCTRL, k.KEY_A]]),
Binding([e.KEY_LEFTALT, e.KEY_C], [[k.KEY_LEFTCTRL, k.KEY_C]]),
Binding([e.KEY_LEFTALT, e.KEY_V], [[k.KEY_LEFTCTRL, k.KEY_V]]),

# Slack helm!
Binding([e.KEY_LEFTALT, e.KEY_X], [[k.KEY_LEFTCTRL, k.KEY_K]]),
])
input_path: Optional[str] = None
input_identifier: Optional[str] = None
3 changes: 3 additions & 0 deletions wayremap/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,4 +432,7 @@
uinput.KEY_KBDINPUTASSIST_CANCEL,
uinput.KEY_MIN_INTERESTING,
uinput.KEY_MAX,
uinput.BTN_MIDDLE,
uinput.BTN_LEFT,
uinput.BTN_RIGHT,
]
57 changes: 38 additions & 19 deletions wayremap/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@
from threading import Thread
import traceback

from wayremap import config
from wayremap import constants
from wayremap import config, constants

is_remap_enabled = True


def get_identifier(device: evdev.InputDevice):
return f'{device.name} {device.phys}'


def is_pressed(value: int) -> bool:
Expand All @@ -18,7 +23,26 @@ def is_pressed(value: int) -> bool:
def list_devices():
devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
for device in devices:
print(device.path, device.name, device.phys)
identifier = get_identifier(device)
print(f'{device.path}: {identifier}')


def find_input_path_from_name(device_identifier: str):
devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
for device in devices:
if get_identifier(device) == device_identifier:
return device.path
raise Exception(f"Cannot find device named {device_identifier}")


def get_input_path(config: config.WayremapConfig):
if config.input_path:
return config.input_path
elif config.input_identifier:
return find_input_path_from_name(config.input_identifier)
else:
raise Exception(
'You must specify either input_path or input_name to config.')


def find_sway_ipc_path() -> str:
Expand All @@ -29,9 +53,6 @@ def find_sway_ipc_path() -> str:
raise Exception('Cannot find sway socket under /run/user/')


is_remap_enabled = True


def subscribe_sway(apps: list[str]):
if apps is None or len(apps) == 0:
print(
Expand Down Expand Up @@ -73,6 +94,7 @@ def remap(bindings: list[config.Binding], path: str):
real_input.grab()

for event in real_input.read_loop():
print(event)
if event.type == constants.EV_KEY:
if event.code in constants.CTRL_KEYS:
is_ctrl = is_pressed(event.value)
Expand Down Expand Up @@ -110,22 +132,19 @@ def remap(bindings: list[config.Binding], path: str):
print(traceback.format_exc())


def run(config: config.WayremapConfig, path: str):
def run(*configs: config.WayremapConfig):
threads = list()

thread_remap = Thread(target=remap, args=(config.bindings, path))
threads.append(thread_remap)
thread_remap.start()
for config in configs:
thread_remap = Thread(target=remap,
args=(config.bindings, get_input_path(config)))
threads.append(thread_remap)
thread_remap.start()

thread_subscribe_sway = Thread(target=subscribe_sway,
args=(config.applications, ))
threads.append(thread_subscribe_sway)
thread_subscribe_sway.start()
thread_subscribe_sway = Thread(target=subscribe_sway,
args=(config.applications, ))
threads.append(thread_subscribe_sway)
thread_subscribe_sway.start()

for t in threads:
t.join()


if __name__ == '__main__':
# list_devices()
run(config.example_config, '/dev/input/event4')

0 comments on commit 01755ef

Please sign in to comment.