mirror of
https://github.com/sezanzeb/input-remapper
synced 2024-11-18 03:25:52 +00:00
wip
This commit is contained in:
parent
ed5726f761
commit
ba929fce23
@ -8,25 +8,26 @@ Tool to change the mapping of your input device buttons.
|
|||||||
|
|
||||||
# Running
|
# Running
|
||||||
|
|
||||||
First, install the package:
|
Installation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/sezanzeb/key-mapper.git
|
git clone https://github.com/sezanzeb/key-mapper.git
|
||||||
cd key-mapper
|
cd key-mapper
|
||||||
sudo python3 setup.py install
|
sudo python3 setup.py install
|
||||||
|
usermod -a -G input $USER
|
||||||
```
|
```
|
||||||
|
|
||||||
To keep injecting the mapping after closing the window, the daemon needs to
|
To keep injecting the mapping after closing the window, the daemon needs to
|
||||||
be running:
|
be running. If it doesn't already after logging in, you can use:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo key-mapper-service -d
|
sudo key-mapper-service
|
||||||
```
|
```
|
||||||
|
|
||||||
To open the UI to modify the mappings, use:
|
To open the UI to modify the mappings, use:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo key-mapper-gtk -d
|
sudo key-mapper-gtk
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also start it via your applications menu.
|
You can also start it via your applications menu.
|
||||||
|
@ -33,7 +33,8 @@ from gi.repository import GLib
|
|||||||
import dbus.mainloop.glib
|
import dbus.mainloop.glib
|
||||||
from dbus.mainloop.glib import DBusGMainLoop
|
from dbus.mainloop.glib import DBusGMainLoop
|
||||||
|
|
||||||
from keymapper.logger import logger, update_verbosity, log_info
|
from keymapper.logger import logger, update_verbosity, log_info, \
|
||||||
|
add_filehandler
|
||||||
from keymapper.daemon import Daemon
|
from keymapper.daemon import Daemon
|
||||||
|
|
||||||
|
|
||||||
@ -47,13 +48,14 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
options = parser.parse_args(sys.argv[1:])
|
options = parser.parse_args(sys.argv[1:])
|
||||||
update_verbosity(options.debug)
|
update_verbosity(options.debug)
|
||||||
|
add_filehandler()
|
||||||
log_info()
|
log_info()
|
||||||
|
|
||||||
if getpass.getuser() != 'root' and 'unittest' not in sys.modules.keys():
|
if getpass.getuser() != 'root' and 'unittest' not in sys.modules.keys():
|
||||||
logger.warning('Without sudo, your devices may not be visible')
|
logger.warning('Without sudo, your devices may not be visible')
|
||||||
|
|
||||||
session_bus = dbus.SessionBus(mainloop=DBusGMainLoop())
|
session_bus = dbus.SessionBus(mainloop=DBusGMainLoop())
|
||||||
name = dbus.service.BusName('com.keymapper.Control', session_bus)
|
name = dbus.service.BusName('keymapper.Control', session_bus)
|
||||||
daemon = Daemon(session_bus, '/')
|
daemon = Daemon(session_bus, '/')
|
||||||
|
|
||||||
atexit.register(daemon.stop)
|
atexit.register(daemon.stop)
|
||||||
|
8
data/key-mapper-service.desktop
Normal file
8
data/key-mapper-service.desktop
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Key Mapper Service
|
||||||
|
Icon=mouse
|
||||||
|
Exec=key-mapper-service
|
||||||
|
Terminal=false
|
||||||
|
Categories=Settings;
|
||||||
|
Comment=The Key Mapper service to keep mappings alive after closing the UI
|
@ -601,6 +601,7 @@
|
|||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
|
<property name="width_request">250</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
@ -608,16 +609,15 @@
|
|||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="homogeneous">True</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel">
|
<object class="GtkLabel">
|
||||||
|
<property name="width_request">50</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="tooltip_text" translatable="yes">Click on a cell below and hit a key on your device. If you have your preset active, the reported keycodes may be wrong.</property>
|
<property name="tooltip_text" translatable="yes">Click on a cell below and hit a key on your device. If you have your preset active, the reported keycodes may be wrong.</property>
|
||||||
<property name="margin_top">5</property>
|
<property name="margin_top">5</property>
|
||||||
<property name="margin_bottom">5</property>
|
<property name="margin_bottom">5</property>
|
||||||
<property name="label" translatable="yes">Key</property>
|
<property name="label" translatable="yes">Key</property>
|
||||||
<property name="width_chars">10</property>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@ -637,16 +637,16 @@
|
|||||||
<property name="margin_top">5</property>
|
<property name="margin_top">5</property>
|
||||||
<property name="margin_bottom">5</property>
|
<property name="margin_bottom">5</property>
|
||||||
<property name="label" translatable="yes">Mapping</property>
|
<property name="label" translatable="yes">Mapping</property>
|
||||||
<property name="width_chars">10</property>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">True</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel">
|
<object class="GtkLabel">
|
||||||
|
<property name="width_request">50</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
</object>
|
</object>
|
||||||
@ -656,6 +656,9 @@
|
|||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="table-header"/>
|
||||||
|
</style>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@ -700,7 +703,7 @@
|
|||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">True</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
>
|
>
|
||||||
<policyconfig>
|
<policyconfig>
|
||||||
<icon_name>mouse</icon_name>
|
<icon_name>mouse</icon_name>
|
||||||
<action id="org.key-mapper">
|
<action id="keymapper">
|
||||||
<description>Run Key Mapper as root</description>
|
<description>Run Key Mapper as root</description>
|
||||||
<message>Authentication is required to discover devices.</message>
|
<message>Authentication is required to discover devices.</message>
|
||||||
<defaults>
|
<defaults>
|
12
data/key-mapper.service
Normal file
12
data/key-mapper.service
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# https://wiki.archlinux.org/index.php/Systemd
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Service to inject keycodes without the GUI application
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=keymapper.Control
|
||||||
|
ExecStart=/usr/bin/key-mapper-service -d
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
@ -1,3 +1,11 @@
|
|||||||
|
row {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header, .row-box {
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.changed {
|
.changed {
|
||||||
background: @selected_bg_color;
|
background: @selected_bg_color;
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,8 @@ from dbus import service
|
|||||||
import dbus.mainloop.glib
|
import dbus.mainloop.glib
|
||||||
|
|
||||||
from keymapper.logger import logger
|
from keymapper.logger import logger
|
||||||
from keymapper.config import config
|
|
||||||
from keymapper.injector import KeycodeInjector
|
from keymapper.injector import KeycodeInjector
|
||||||
from keymapper.mapping import Mapping
|
from keymapper.mapping import Mapping
|
||||||
from keymapper.paths import get_config_path
|
|
||||||
|
|
||||||
|
|
||||||
# TODO service file in data for a root daemon
|
# TODO service file in data for a root daemon
|
||||||
@ -59,13 +57,13 @@ def get_dbus_interface():
|
|||||||
'The daemon "key-mapper-service" is not running, mapping keys '
|
'The daemon "key-mapper-service" is not running, mapping keys '
|
||||||
'only works as long as the window is open.'
|
'only works as long as the window is open.'
|
||||||
)
|
)
|
||||||
return Daemon(autoload=False)
|
return Daemon()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.debug('Found the daemon process')
|
logger.debug('Found the daemon process')
|
||||||
bus = dbus.SessionBus()
|
bus = dbus.SessionBus()
|
||||||
remote_object = bus.get_object('com.keymapper.Control', '/')
|
remote_object = bus.get_object('keymapper.Control', '/')
|
||||||
interface = dbus.Interface(remote_object, 'com.keymapper.Interface')
|
interface = dbus.Interface(remote_object, 'keymapper.Interface')
|
||||||
logger.debug('Connected to dbus')
|
logger.debug('Connected to dbus')
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
logger.error(
|
||||||
@ -74,7 +72,7 @@ def get_dbus_interface():
|
|||||||
'key-mapper processes not running as root?'
|
'key-mapper processes not running as root?'
|
||||||
)
|
)
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
return Daemon(autoload=False)
|
return Daemon()
|
||||||
|
|
||||||
return interface
|
return interface
|
||||||
|
|
||||||
@ -83,20 +81,19 @@ class Daemon(service.Object):
|
|||||||
"""Starts injecting keycodes based on the configuration.
|
"""Starts injecting keycodes based on the configuration.
|
||||||
|
|
||||||
Can be talked to either over dbus or by instantiating it.
|
Can be talked to either over dbus or by instantiating it.
|
||||||
|
|
||||||
|
The Daemon may not have any knowledge about the logged in user, so it
|
||||||
|
can't read any config files. It has to be told what to do and will
|
||||||
|
continue to do so afterwards, but it can't decide to start injecting
|
||||||
|
on its own.
|
||||||
"""
|
"""
|
||||||
def __init__(self, *args, autoload=True, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Constructs the daemon. You still need to run the GLib mainloop."""
|
"""Constructs the daemon. You still need to run the GLib mainloop."""
|
||||||
self.injectors = {}
|
self.injectors = {}
|
||||||
if autoload:
|
|
||||||
for device, preset in config.iterate_autoload_presets():
|
|
||||||
mapping = Mapping()
|
|
||||||
mapping.load(get_config_path(device, preset))
|
|
||||||
self.injectors[device] = KeycodeInjector(device, mapping)
|
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
'com.keymapper.Interface',
|
'keymapper.Interface',
|
||||||
in_signature='s'
|
in_signature='s'
|
||||||
)
|
)
|
||||||
def stop_injecting(self, device):
|
def stop_injecting(self, device):
|
||||||
@ -113,7 +110,7 @@ class Daemon(service.Object):
|
|||||||
# TODO if ss is the correct signature for multiple parameters, add an
|
# TODO if ss is the correct signature for multiple parameters, add an
|
||||||
# example to https://gitlab.freedesktop.org/dbus/dbus-python/-/blob/master/doc/tutorial.txt # noqa pylint: disable=line-too-long
|
# example to https://gitlab.freedesktop.org/dbus/dbus-python/-/blob/master/doc/tutorial.txt # noqa pylint: disable=line-too-long
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
'com.keymapper.Interface',
|
'keymapper.Interface',
|
||||||
in_signature='ss'
|
in_signature='ss'
|
||||||
)
|
)
|
||||||
def start_injecting(self, device, path):
|
def start_injecting(self, device, path):
|
||||||
@ -143,9 +140,9 @@ class Daemon(service.Object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
'com.keymapper.Interface'
|
'keymapper.Interface'
|
||||||
)
|
)
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Properly stop the daemon."""
|
"""Stop all mapping injections."""
|
||||||
for injector in self.injectors.values():
|
for injector in self.injectors.values():
|
||||||
injector.stop_injecting()
|
injector.stop_injecting()
|
||||||
|
@ -132,10 +132,10 @@ class Row(Gtk.ListBoxRow):
|
|||||||
'button-press-event',
|
'button-press-event',
|
||||||
self.on_delete_button_clicked
|
self.on_delete_button_clicked
|
||||||
)
|
)
|
||||||
delete_button.set_margin_start(5)
|
delete_button.set_size_request(50, -1)
|
||||||
delete_button.set_margin_end(5)
|
|
||||||
|
|
||||||
keycode_input = Gtk.ToggleButton()
|
keycode_input = Gtk.ToggleButton()
|
||||||
|
keycode_input.set_size_request(50, -1)
|
||||||
|
|
||||||
if keycode is not None:
|
if keycode is not None:
|
||||||
keycode_input.set_label(str(keycode))
|
keycode_input.set_label(str(keycode))
|
||||||
@ -159,12 +159,13 @@ class Row(Gtk.ListBoxRow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
||||||
box.set_homogeneous(True)
|
box.set_homogeneous(False)
|
||||||
box.set_spacing(2)
|
box.set_spacing(0)
|
||||||
box.pack_start(keycode_input, expand=True, fill=True, padding=0)
|
box.pack_start(keycode_input, expand=False, fill=True, padding=0)
|
||||||
box.pack_start(character_input, expand=True, fill=True, padding=0)
|
box.pack_start(character_input, expand=True, fill=True, padding=0)
|
||||||
box.pack_start(delete_button, expand=True, fill=False, padding=0)
|
box.pack_start(delete_button, expand=False, fill=True, padding=0)
|
||||||
box.show_all()
|
box.show_all()
|
||||||
|
box.get_style_context().add_class('row-box')
|
||||||
|
|
||||||
self.add(box)
|
self.add(box)
|
||||||
self.show_all()
|
self.show_all()
|
||||||
|
@ -105,7 +105,6 @@ def update_verbosity(debug):
|
|||||||
|
|
||||||
def add_filehandler():
|
def add_filehandler():
|
||||||
"""Clear the existing logfile and start logging to it."""
|
"""Clear the existing logfile and start logging to it."""
|
||||||
# jack also logs to ~/.log
|
|
||||||
log_path = os.path.expanduser('~/.log/key-mapper')
|
log_path = os.path.expanduser('~/.log/key-mapper')
|
||||||
log_file = os.path.join(log_path, 'log')
|
log_file = os.path.join(log_path, 'log')
|
||||||
|
|
||||||
@ -118,4 +117,7 @@ def add_filehandler():
|
|||||||
|
|
||||||
file_handler = logging.FileHandler(log_file)
|
file_handler = logging.FileHandler(log_file)
|
||||||
file_handler.setFormatter(Formatter())
|
file_handler.setFormatter(Formatter())
|
||||||
|
|
||||||
|
logger.info('Logging to "%s"', log_file)
|
||||||
|
|
||||||
logger.addHandler(file_handler)
|
logger.addHandler(file_handler)
|
||||||
|
8
setup.py
8
setup.py
@ -34,7 +34,7 @@ class Install(DistUtilsExtra.auto.install_auto):
|
|||||||
executable = os.path.join(self.install_data, 'bin/key-mapper-gtk')
|
executable = os.path.join(self.install_data, 'bin/key-mapper-gtk')
|
||||||
assert os.path.exists(executable)
|
assert os.path.exists(executable)
|
||||||
|
|
||||||
policy_path = '/usr/share/polkit-1/actions/org.key-mapper.policy'
|
policy_path = '/usr/share/polkit-1/actions/key-mapper.policy'
|
||||||
|
|
||||||
with open(policy_path, 'r') as file:
|
with open(policy_path, 'r') as file:
|
||||||
contents = file.read()
|
contents = file.read()
|
||||||
@ -45,7 +45,7 @@ class Install(DistUtilsExtra.auto.install_auto):
|
|||||||
with open(policy_path, 'w') as file:
|
with open(policy_path, 'w') as file:
|
||||||
print(
|
print(
|
||||||
f'Inserting the correct path "{executable}" into '
|
f'Inserting the correct path "{executable}" into '
|
||||||
'org.key-mapper.policy'
|
'keymapper.policy'
|
||||||
)
|
)
|
||||||
file.write(contents.format(
|
file.write(contents.format(
|
||||||
executable=executable
|
executable=executable
|
||||||
@ -59,7 +59,9 @@ DistUtilsExtra.auto.setup(
|
|||||||
license='GPL-3.0',
|
license='GPL-3.0',
|
||||||
data_files=[
|
data_files=[
|
||||||
('share/applications/', ['data/key-mapper.desktop']),
|
('share/applications/', ['data/key-mapper.desktop']),
|
||||||
('/usr/share/polkit-1/actions/', ['data/org.key-mapper.policy']),
|
('/usr/share/polkit-1/actions/', ['data/key-mapper.policy']),
|
||||||
|
('/usr/lib/systemd/system', ['data/key-mapper.service']),
|
||||||
|
('/etc/xdg/autostart/', ['data/key-mapper-autoload']),
|
||||||
],
|
],
|
||||||
cmdclass={
|
cmdclass={
|
||||||
'install': Install
|
'install': Install
|
||||||
|
Loading…
Reference in New Issue
Block a user