Renamed to Input Remapper
parent
d3d1d9124f
commit
a2ed3696ca
@ -1,8 +1,8 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = /usr/lib/python3.9/site-packages/keymapper
|
||||
source = /usr/lib/python3.9/site-packages/inputremapper
|
||||
concurrency = multiprocessing
|
||||
debug = multiproc
|
||||
omit =
|
||||
# not used currently due to problems
|
||||
/usr/lib/python3.9/site-packages/keymapper/ipc/socket.py
|
||||
/usr/lib/python3.9/site-packages/inputremapper/ipc/socket.py
|
||||
|
@ -1,7 +1,8 @@
|
||||
Package: key-mapper
|
||||
Package: input-remapper
|
||||
Version: 1.2.2
|
||||
Architecture: all
|
||||
Maintainer: Sezanzeb <proxima@sezanzeb.de>
|
||||
Depends: build-essential, libpython3-dev, libdbus-1-dev, python3, python3-setuptools, python3-evdev, python3-pydbus, python3-gi, gettext, python3-cairo, libgtk-3-0
|
||||
Description: A tool to change the mapping of your input device buttons
|
||||
Replaces: python3-key-mapper
|
||||
Replaces: python3-key-mapper, key-mapper
|
||||
Conflicts: python3-key-mapper, key-mapper
|
||||
|
@ -1,6 +1,11 @@
|
||||
#!/bin/bash
|
||||
if [ -d "/run/systemd/system/" ]; then
|
||||
pkill -f key-mapper-service # might have been started by the gui previously
|
||||
systemctl enable key-mapper
|
||||
systemctl start key-mapper
|
||||
# old name, those lines should at some point be removed from postinst
|
||||
pkill -f key-mapper-service
|
||||
systemctl disable key-mapper
|
||||
systemctl stop key-mapper
|
||||
|
||||
pkill -f input-remapper-service # might have been started by the gui previously
|
||||
systemctl enable input-remapper
|
||||
systemctl start input-remapper
|
||||
fi
|
||||
|
@ -1,4 +0,0 @@
|
||||
# for /scripts/build.sh
|
||||
recursive-include data *
|
||||
include bin/key-mapper-gtk
|
||||
include bin/key-mapper-service
|
@ -0,0 +1,295 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# input-remapper 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.
|
||||
#
|
||||
# input-remapper 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 input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Control the dbus service from the command line."""
|
||||
|
||||
|
||||
import os
|
||||
import grp
|
||||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from inputremapper.logger import logger, update_verbosity, log_info, add_filehandler
|
||||
from inputremapper.config import config
|
||||
|
||||
# import inputremapper modules as late as possible to make sure the correct
|
||||
# log level is applied before anything is logged
|
||||
|
||||
|
||||
AUTOLOAD = 'autoload'
|
||||
START = 'start'
|
||||
STOP = 'stop'
|
||||
STOP_ALL = 'stop-all'
|
||||
HELLO = 'hello'
|
||||
|
||||
# internal stuff that the gui uses
|
||||
START_DAEMON = 'start-daemon'
|
||||
HELPER = 'helper'
|
||||
|
||||
|
||||
def run(cmd):
|
||||
"""Run and log a command."""
|
||||
logger.info('Running `%s`...', cmd)
|
||||
code = os.system(cmd)
|
||||
if code != 0:
|
||||
logger.error('Failed. exit code %d', code)
|
||||
|
||||
|
||||
def group_exists(name):
|
||||
"""Check if a group with that name exists."""
|
||||
try:
|
||||
grp.getgrnam(name)
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
COMMANDS = [AUTOLOAD, START, STOP, HELLO, STOP_ALL]
|
||||
|
||||
INTERNALS = [START_DAEMON, HELPER]
|
||||
|
||||
|
||||
def utils(options):
|
||||
"""Listing names, tasks that don't require a running daemon."""
|
||||
if options.list_devices:
|
||||
logger.setLevel(logging.ERROR)
|
||||
from inputremapper.groups import groups
|
||||
for group in groups:
|
||||
print(group.key)
|
||||
|
||||
if options.key_names:
|
||||
from inputremapper.system_mapping import system_mapping
|
||||
print('\n'.join(system_mapping.list_names()))
|
||||
|
||||
|
||||
def communicate(options, daemon):
|
||||
"""Commands that require a running daemon"""
|
||||
# import stuff late to make sure the correct log level is applied
|
||||
# before anything is logged
|
||||
from inputremapper.groups import groups
|
||||
from inputremapper.paths import USER
|
||||
|
||||
def require_group():
|
||||
if options.device is None:
|
||||
logger.error('--device missing')
|
||||
sys.exit(1)
|
||||
|
||||
if options.device.startswith('/dev'):
|
||||
group = groups.find(path=options.device)
|
||||
else:
|
||||
group = groups.find(key=options.device)
|
||||
|
||||
if group is None:
|
||||
logger.error(
|
||||
'Device "%s" is unknown or not an appropriate input device',
|
||||
options.device
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
return group
|
||||
|
||||
if daemon is None:
|
||||
# probably broken tests
|
||||
logger.error('Daemon missing')
|
||||
sys.exit(1)
|
||||
|
||||
if options.config_dir is not None:
|
||||
path = os.path.abspath(os.path.expanduser(os.path.join(
|
||||
options.config_dir,
|
||||
'config.json'
|
||||
)))
|
||||
if not os.path.exists(path):
|
||||
logger.error('"%s" does not exist', path)
|
||||
sys.exit(1)
|
||||
|
||||
logger.info('Using config from "%s" instead', path)
|
||||
config.load_config(path)
|
||||
|
||||
if USER != 'root':
|
||||
# Might be triggered by udev, so skip the root user.
|
||||
# This will also refresh the config of the daemon if the user changed
|
||||
# it in the meantime.
|
||||
# config_dir is either the cli arg or the default path in home
|
||||
config_dir = os.path.dirname(config.path)
|
||||
daemon.set_config_dir(config_dir)
|
||||
|
||||
if options.command == AUTOLOAD:
|
||||
# if device was specified, autoload for that one. if None autoload
|
||||
# for all devices.
|
||||
if options.device is None:
|
||||
logger.info('Autoloading all')
|
||||
# timeout is not documented, for more info see
|
||||
# https://github.com/LEW21/pydbus/blob/master/pydbus/proxy_method.py
|
||||
daemon.autoload(timeout=10)
|
||||
else:
|
||||
group = require_group()
|
||||
logger.info('Asking daemon to autoload for %s', options.device)
|
||||
daemon.autoload_single(group.key, timeout=2)
|
||||
|
||||
if options.command == START:
|
||||
group = require_group()
|
||||
|
||||
logger.info(
|
||||
'Starting injection: "%s", "%s"',
|
||||
options.device, options.preset
|
||||
)
|
||||
|
||||
daemon.start_injecting(group.key, options.preset)
|
||||
|
||||
if options.command == STOP:
|
||||
group = require_group()
|
||||
daemon.stop_injecting(group.key)
|
||||
|
||||
if options.command == STOP_ALL:
|
||||
daemon.stop_all()
|
||||
|
||||
if options.command == HELLO:
|
||||
response = daemon.hello('hello')
|
||||
logger.info('Daemon answered with "%s"', response)
|
||||
|
||||
|
||||
def internals(options):
|
||||
"""Methods that are needed to get the gui to work and that require root.
|
||||
|
||||
input-remapper-control should be started with sudo or pkexec for this.
|
||||
"""
|
||||
debug = ' -d' if options.debug else ''
|
||||
|
||||
if options.command == HELPER:
|
||||
cmd = f'input-remapper-helper{debug}'
|
||||
elif options.command == START_DAEMON:
|
||||
cmd = f'input-remapper-service --hide-info{debug}'
|
||||
else:
|
||||
return
|
||||
|
||||
# daemonize
|
||||
cmd = f'{cmd} &'
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
def systemd_finished():
|
||||
"""Check if systemd finished booting."""
|
||||
try:
|
||||
systemd_analyze = subprocess.run(['systemd-analyze'], stdout=subprocess.PIPE)
|
||||
except FileNotFoundError:
|
||||
# probably not systemd, lets assume true to not block input-remapper for good
|
||||
# on certain installations
|
||||
return True
|
||||
|
||||
if 'finished' in systemd_analyze.stdout.decode():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main(options):
|
||||
if options.debug:
|
||||
update_verbosity(True)
|
||||
|
||||
add_filehandler('/var/log/input-remapper-control')
|
||||
|
||||
if options.version:
|
||||
log_info()
|
||||
return
|
||||
|
||||
logger.debug('Call for "%s"', sys.argv)
|
||||
|
||||
from inputremapper.paths import USER
|
||||
boot_finished = systemd_finished()
|
||||
is_root = USER == "root"
|
||||
is_autoload = options.command == AUTOLOAD
|
||||
config_dir_set = options.config_dir is not None
|
||||
if is_autoload and not boot_finished and is_root and not config_dir_set:
|
||||
# this is probably happening during boot time and got
|
||||
# triggered by udev. There is no need to try to inject anything if the
|
||||
# service doesn't know where to look for a config file. This avoids a lot
|
||||
# of confusing service logs. And also avoids potential for problems when
|
||||
# input-remapper-control stresses about evdev, dbus and multiprocessing already
|
||||
# while the system hasn't even booted completely.
|
||||
logger.warning('Skipping autoload command without a logged in user')
|
||||
return
|
||||
|
||||
if options.command is not None:
|
||||
if options.command in INTERNALS:
|
||||
internals(options)
|
||||
elif options.command in COMMANDS:
|
||||
from inputremapper.daemon import Daemon
|
||||
daemon = Daemon.connect(fallback=False)
|
||||
communicate(options, daemon)
|
||||
else:
|
||||
logger.error('Unknown command "%s"', options.command)
|
||||
else:
|
||||
utils(options)
|
||||
|
||||
if options.command:
|
||||
logger.info('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--command', action='store', dest='command', help=(
|
||||
'Communicate with the daemon. Available commands are start, '
|
||||
'stop, autoload, hello or stop-all'
|
||||
), default=None, metavar='NAME'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--config-dir', action='store', dest='config_dir',
|
||||
help=(
|
||||
'path to the config directory containing config.json, '
|
||||
'xmodmap.json and the presets folder. '
|
||||
'defaults to ~/.config/input-remapper/'
|
||||
),
|
||||
default=None, metavar='PATH',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--preset', action='store', dest='preset',
|
||||
help='The filename of the preset without the .json extension.',
|
||||
default=None, metavar='NAME',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--device', action='store', dest='device',
|
||||
help='One of the device keys from --list-devices',
|
||||
default=None, metavar='NAME'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--list-devices', action='store_true', dest='list_devices',
|
||||
help='List available device keys and exit',
|
||||
default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--symbol-names', action='store_true', dest='key_names',
|
||||
help='Print all available names for the mapping',
|
||||
default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'-d', '--debug', action='store_true', dest='debug',
|
||||
help='Displays additional debug information',
|
||||
default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'-v', '--version', action='store_true', dest='version',
|
||||
help='Print the version and exit', default=False
|
||||
)
|
||||
|
||||
main(parser.parse_args(sys.argv[1:]))
|
@ -0,0 +1,86 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# input-remapper 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.
|
||||
#
|
||||
# input-remapper 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 input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Starts the user interface."""
|
||||
|
||||
|
||||
import sys
|
||||
import atexit
|
||||
import gettext
|
||||
import locale
|
||||
from inputremapper.data import get_data_path
|
||||
import os.path
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GLib', '2.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
APP_NAME = 'input-remapper'
|
||||
LOCALE_DIR = os.path.join(get_data_path(), 'lang')
|
||||
|
||||
locale.bindtextdomain(APP_NAME, LOCALE_DIR)
|
||||
locale.textdomain(APP_NAME)
|
||||
|
||||
translate = gettext.translation(APP_NAME, LOCALE_DIR, fallback=True)
|
||||
_ = translate.gettext
|
||||
|
||||
|
||||
# https://github.com/Nuitka/Nuitka/issues/607#issuecomment-650217096
|
||||
Gtk.init()
|
||||
|
||||
from inputremapper.logger import logger, update_verbosity, log_info
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument(
|
||||
'-d', '--debug', action='store_true', dest='debug',
|
||||
help=_('Displays additional debug information'),
|
||||
default=False
|
||||
)
|
||||
|
||||
options = parser.parse_args(sys.argv[1:])
|
||||
update_verbosity(options.debug)
|
||||
log_info('input-remapper-gtk')
|
||||
logger.debug('Using locale directory: {}'.format(LOCALE_DIR))
|
||||
|
||||
# import input-remapper stuff after setting the log verbosity
|
||||
from inputremapper.gui.window import Window
|
||||
from inputremapper.daemon import Daemon
|
||||
from inputremapper.daemon import config
|
||||
|
||||
config.load_config()
|
||||
|
||||
window = Window()
|
||||
|
||||
def stop():
|
||||
if isinstance(window.dbus, Daemon):
|
||||
# it created its own temporary daemon inside the process
|
||||
# because none was running
|
||||
window.dbus.stop_all()
|
||||
|
||||
window.on_close()
|
||||
|
||||
atexit.register(stop)
|
||||
|
||||
Gtk.main()
|
@ -0,0 +1,55 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# input-remapper 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.
|
||||
#
|
||||
# input-remapper 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 input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Starts injecting keycodes based on the configuration."""
|
||||
|
||||
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from inputremapper.logger import update_verbosity, log_info, add_filehandler
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument(
|
||||
'-d', '--debug', action='store_true', dest='debug',
|
||||
help='Displays additional debug information', default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--hide-info', action='store_true', dest='hide_info',
|
||||
help='Don\'t display version information', default=False
|
||||
)
|
||||
|
||||
options = parser.parse_args(sys.argv[1:])
|
||||
|
||||
update_verbosity(options.debug)
|
||||
|
||||
# import input-remapper stuff after setting the log verbosity
|
||||
from inputremapper.daemon import Daemon
|
||||
|
||||
add_filehandler()
|
||||
if not options.hide_info:
|
||||
log_info('input-remapper-service')
|
||||
|
||||
daemon = Daemon()
|
||||
daemon.publish()
|
||||
daemon.run()
|
@ -1,295 +1,30 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
print('key-mapper-control is deprecated, please use input-remapper-control instead')
|
||||
|
||||
"""Control the dbus service from the command line."""
|
||||
from importlib.util import spec_from_loader, module_from_spec
|
||||
from importlib.machinery import SourceFileLoader
|
||||
|
||||
|
||||
import os
|
||||
import grp
|
||||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from keymapper.logger import logger, update_verbosity, log_info, add_filehandler
|
||||
from keymapper.config import config
|
||||
|
||||
# import keymapper modules as late as possible to make sure the correct
|
||||
# log level is applied before anything is logged
|
||||
|
||||
|
||||
AUTOLOAD = 'autoload'
|
||||
START = 'start'
|
||||
STOP = 'stop'
|
||||
STOP_ALL = 'stop-all'
|
||||
HELLO = 'hello'
|
||||
|
||||
# internal stuff that the gui uses
|
||||
START_DAEMON = 'start-daemon'
|
||||
HELPER = 'helper'
|
||||
|
||||
|
||||
def run(cmd):
|
||||
"""Run and log a command."""
|
||||
logger.info('Running `%s`...', cmd)
|
||||
code = os.system(cmd)
|
||||
if code != 0:
|
||||
logger.error('Failed. exit code %d', code)
|
||||
|
||||
|
||||
def group_exists(name):
|
||||
"""Check if a group with that name exists."""
|
||||
try:
|
||||
grp.getgrnam(name)
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
COMMANDS = [AUTOLOAD, START, STOP, HELLO, STOP_ALL]
|
||||
|
||||
INTERNALS = [START_DAEMON, HELPER]
|
||||
|
||||
|
||||
def utils(options):
|
||||
"""Listing names, tasks that don't require a running daemon."""
|
||||
if options.list_devices:
|
||||
logger.setLevel(logging.ERROR)
|
||||
from keymapper.groups import groups
|
||||
for group in groups:
|
||||
print(group.key)
|
||||
|
||||
if options.key_names:
|
||||
from keymapper.system_mapping import system_mapping
|
||||
print('\n'.join(system_mapping.list_names()))
|
||||
|
||||
|
||||
def communicate(options, daemon):
|
||||
"""Commands that require a running daemon"""
|
||||
# import stuff late to make sure the correct log level is applied
|
||||
# before anything is logged
|
||||
from keymapper.groups import groups
|
||||
from keymapper.paths import USER
|
||||
|
||||
def require_group():
|
||||
if options.device is None:
|
||||
logger.error('--device missing')
|
||||
sys.exit(1)
|
||||
|
||||
if options.device.startswith('/dev'):
|
||||
group = groups.find(path=options.device)
|
||||
else:
|
||||
group = groups.find(key=options.device)
|
||||
|
||||
if group is None:
|
||||
logger.error(
|
||||
'Device "%s" is unknown or not an appropriate input device',
|
||||
options.device
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
return group
|
||||
|
||||
if daemon is None:
|
||||
# probably broken tests
|
||||
logger.error('Daemon missing')
|
||||
sys.exit(1)
|
||||
|
||||
if options.config_dir is not None:
|
||||
path = os.path.abspath(os.path.expanduser(os.path.join(
|
||||
options.config_dir,
|
||||
'config.json'
|
||||
)))
|
||||
if not os.path.exists(path):
|
||||
logger.error('"%s" does not exist', path)
|
||||
sys.exit(1)
|
||||
|
||||
logger.info('Using config from "%s" instead', path)
|
||||
config.load_config(path)
|
||||
|
||||
if USER != 'root':
|
||||
# Might be triggered by udev, so skip the root user.
|
||||
# This will also refresh the config of the daemon if the user changed
|
||||
# it in the meantime.
|
||||
# config_dir is either the cli arg or the default path in home
|
||||
config_dir = os.path.dirname(config.path)
|
||||
daemon.set_config_dir(config_dir)
|
||||
|
||||
if options.command == AUTOLOAD:
|
||||
# if device was specified, autoload for that one. if None autoload
|
||||
# for all devices.
|
||||
if options.device is None:
|
||||
logger.info('Autoloading all')
|
||||
# timeout is not documented, for more info see
|
||||
# https://github.com/LEW21/pydbus/blob/master/pydbus/proxy_method.py
|
||||
daemon.autoload(timeout=10)
|
||||
else:
|
||||
group = require_group()
|
||||
logger.info('Asking daemon to autoload for %s', options.device)
|
||||
daemon.autoload_single(group.key, timeout=2)
|
||||
|
||||
if options.command == START:
|
||||
group = require_group()
|
||||
|
||||
logger.info(
|
||||
'Starting injection: "%s", "%s"',
|
||||
options.device, options.preset
|
||||
)
|
||||
|
||||
daemon.start_injecting(group.key, options.preset)
|
||||
|
||||
if options.command == STOP:
|
||||
group = require_group()
|
||||
daemon.stop_injecting(group.key)
|
||||
|
||||
if options.command == STOP_ALL:
|
||||
daemon.stop_all()
|
||||
|
||||
if options.command == HELLO:
|
||||
response = daemon.hello('hello')
|
||||
logger.info('Daemon answered with "%s"', response)
|
||||
|
||||
|
||||
def internals(options):
|
||||
"""Methods that are needed to get the gui to work and that require root.
|
||||
|
||||
key-mapper-control should be started with sudo or pkexec for this.
|
||||
"""
|
||||
debug = ' -d' if options.debug else ''
|
||||
|
||||
if options.command == HELPER:
|
||||
cmd = f'key-mapper-helper{debug}'
|
||||
elif options.command == START_DAEMON:
|
||||
cmd = f'key-mapper-service --hide-info{debug}'
|
||||
else:
|
||||
return
|
||||
|
||||
# daemonize
|
||||
cmd = f'{cmd} &'
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
def systemd_finished():
|
||||
"""Check if systemd finished booting."""
|
||||
try:
|
||||
systemd_analyze = subprocess.run(['systemd-analyze'], stdout=subprocess.PIPE)
|
||||
except FileNotFoundError:
|
||||
# probably not systemd, lets assume true to not block key-mapper for good
|
||||
# on certain installations
|
||||
return True
|
||||
|
||||
if 'finished' in systemd_analyze.stdout.decode():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main(options):
|
||||
if options.debug:
|
||||
update_verbosity(True)
|
||||
|
||||
add_filehandler('/var/log/key-mapper-control')
|
||||
|
||||
if options.version:
|
||||
log_info()
|
||||
return
|
||||
|
||||
logger.debug('Call for "%s"', sys.argv)
|
||||
|
||||
from keymapper.paths import USER
|
||||
boot_finished = systemd_finished()
|
||||
is_root = USER == "root"
|
||||
is_autoload = options.command == AUTOLOAD
|
||||
config_dir_set = options.config_dir is not None
|
||||
if is_autoload and not boot_finished and is_root and not config_dir_set:
|
||||
# this is probably happening during boot time and got
|
||||
# triggered by udev. There is no need to try to inject anything if the
|
||||
# service doesn't know where to look for a config file. This avoids a lot
|
||||
# of confusing service logs. And also avoids potential for problems when
|
||||
# key-mapper-control stresses about evdev, dbus and multiprocessing already
|
||||
# while the system hasn't even booted completely.
|
||||
logger.warning('Skipping autoload command without a logged in user')
|
||||
return
|
||||
|
||||
if options.command is not None:
|
||||
if options.command in INTERNALS:
|
||||
internals(options)
|
||||
elif options.command in COMMANDS:
|
||||
from keymapper.daemon import Daemon
|
||||
daemon = Daemon.connect(fallback=False)
|
||||
communicate(options, daemon)
|
||||
else:
|
||||
logger.error('Unknown command "%s"', options.command)
|
||||
else:
|
||||
utils(options)
|
||||
|
||||
if options.command:
|
||||
logger.info('Done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--command', action='store', dest='command', help=(
|
||||
'Communicate with the daemon. Available commands are start, '
|
||||
'stop, autoload, hello or stop-all'
|
||||
), default=None, metavar='NAME'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--config-dir', action='store', dest='config_dir',
|
||||
help=(
|
||||
'path to the config directory containing config.json, '
|
||||
'xmodmap.json and the presets folder. '
|
||||
'defaults to ~/.config/key-mapper/'
|
||||
),
|
||||
default=None, metavar='PATH',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--preset', action='store', dest='preset',
|
||||
help='The filename of the preset without the .json extension.',
|
||||
default=None, metavar='NAME',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--device', action='store', dest='device',
|
||||
help='One of the device keys from --list-devices',
|
||||
default=None, metavar='NAME'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--list-devices', action='store_true', dest='list_devices',
|
||||
help='List available device keys and exit',
|
||||
default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--symbol-names', action='store_true', dest='key_names',
|
||||
help='Print all available names for the mapping',
|
||||
default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'-d', '--debug', action='store_true', dest='debug',
|
||||
help='Displays additional debug information',
|
||||
default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'-v', '--version', action='store_true', dest='version',
|
||||
help='Print the version and exit', default=False
|
||||
)
|
||||
|
||||
main(parser.parse_args(sys.argv[1:]))
|
||||
bin_path = "/bin/input-remapper-control"
|
||||
loader = SourceFileLoader("__main__", bin_path)
|
||||
spec = spec_from_loader("__main__", loader)
|
||||
module = module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
@ -1,86 +1,30 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
print('key-mapper-gtk is deprecated, please use input-remapper-gtk instead')
|
||||
|
||||
"""Starts the user interface."""
|
||||
from importlib.util import spec_from_loader, module_from_spec
|
||||
from importlib.machinery import SourceFileLoader
|
||||
|
||||
|
||||
import sys
|
||||
import atexit
|
||||
import gettext
|
||||
import locale
|
||||
from keymapper.data import get_data_path
|
||||
import os.path
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GLib', '2.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
APP_NAME = 'key-mapper'
|
||||
LOCALE_DIR = os.path.join(get_data_path(), 'lang')
|
||||
|
||||
locale.bindtextdomain(APP_NAME, LOCALE_DIR)
|
||||
locale.textdomain(APP_NAME)
|
||||
|
||||
translate = gettext.translation(APP_NAME, LOCALE_DIR, fallback=True)
|
||||
_ = translate.gettext
|
||||
|
||||
|
||||
# https://github.com/Nuitka/Nuitka/issues/607#issuecomment-650217096
|
||||
Gtk.init()
|
||||
|
||||
from keymapper.logger import logger, update_verbosity, log_info
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument(
|
||||
'-d', '--debug', action='store_true', dest='debug',
|
||||
help=_('Displays additional debug information'),
|
||||
default=False
|
||||
)
|
||||
|
||||
options = parser.parse_args(sys.argv[1:])
|
||||
update_verbosity(options.debug)
|
||||
log_info('key-mapper-gtk')
|
||||
logger.debug('Using locale directory: {}'.format(LOCALE_DIR))
|
||||
|
||||
# import key-mapper stuff after setting the log verbosity
|
||||
from keymapper.gui.window import Window
|
||||
from keymapper.daemon import Daemon
|
||||
from keymapper.daemon import config
|
||||
|
||||
config.load_config()
|
||||
|
||||
window = Window()
|
||||
|
||||
def stop():
|
||||
if isinstance(window.dbus, Daemon):
|
||||
# it created its own temporary daemon inside the process
|
||||
# because none was running
|
||||
window.dbus.stop_all()
|
||||
|
||||
window.on_close()
|
||||
|
||||
atexit.register(stop)
|
||||
|
||||
Gtk.main()
|
||||
bin_path = "/bin/input-remapper-gtk"
|
||||
loader = SourceFileLoader("__main__", bin_path)
|
||||
spec = spec_from_loader("__main__", loader)
|
||||
module = module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
@ -1,55 +1,30 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
print('key-mapper-service is deprecated, please use input-remapper-service instead')
|
||||
|
||||
"""Starts injecting keycodes based on the configuration."""
|
||||
from importlib.util import spec_from_loader, module_from_spec
|
||||
from importlib.machinery import SourceFileLoader
|
||||
|
||||
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from keymapper.logger import update_verbosity, log_info, add_filehandler
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument(
|
||||
'-d', '--debug', action='store_true', dest='debug',
|
||||
help='Displays additional debug information', default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
'--hide-info', action='store_true', dest='hide_info',
|
||||
help='Don\'t display version information', default=False
|
||||
)
|
||||
|
||||
options = parser.parse_args(sys.argv[1:])
|
||||
|
||||
update_verbosity(options.debug)
|
||||
|
||||
# import key-mapper stuff after setting the log verbosity
|
||||
from keymapper.daemon import Daemon
|
||||
|
||||
add_filehandler()
|
||||
if not options.hide_info:
|
||||
log_info('key-mapper-service')
|
||||
|
||||
daemon = Daemon()
|
||||
daemon.publish()
|
||||
daemon.run()
|
||||
bin_path = "/bin/input-remapper-service"
|
||||
loader = SourceFileLoader("__main__", bin_path)
|
||||
spec = spec_from_loader("__main__", loader)
|
||||
module = module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
|
@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=bash -c "input-remapper-control --command stop-all && input-remapper-control --command autoload"
|
||||
Name=input-remapper-autoload
|
||||
Icon=/usr/share/input-remapper/input-remapper.svg
|
||||
Comment=Starts injecting all presets that are set to automatically load for the user
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
@ -1,8 +1,8 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=key-mapper
|
||||
Icon=/usr/share/key-mapper/key-mapper.svg
|
||||
Exec=key-mapper-gtk
|
||||
Name=input-remapper
|
||||
Icon=/usr/share/input-remapper/input-remapper.svg
|
||||
Exec=input-remapper-gtk
|
||||
Terminal=false
|
||||
Categories=Settings
|
||||
Comment=GUI for device specific key mappings
|
@ -1,14 +1,14 @@
|
||||
[Unit]
|
||||
Description=Service to inject keycodes without the GUI application
|
||||
# dbus is required for ipc between gui and key-mapper-control
|
||||
# dbus is required for ipc between gui and input-remapper-control
|
||||
Requires=dbus.service
|
||||
After=dbus.service
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=keymapper.Control
|
||||
ExecStart=/usr/bin/key-mapper-service
|
||||
BusName=inputremapper.Control
|
||||
ExecStart=/usr/bin/input-remapper-service
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
Alias=key-mapper.service
|
||||
Alias=input-remapper.service
|
@ -1,6 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=bash -c "key-mapper-control --command stop-all && key-mapper-control --command autoload"
|
||||
Name=key-mapper-autoload
|
||||
Icon=/usr/share/key-mapper/key-mapper.svg
|
||||
Comment=Starts injecting all presets that are set to automatically load for the user
|
@ -1,28 +1,28 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""One mapping object for the GUI application."""
|
||||
|
||||
|
||||
from keymapper.mapping import Mapping
|
||||
from inputremapper.mapping import Mapping
|
||||
|
||||
|
||||
custom_mapping = Mapping()
|
@ -1,22 +1,22 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""The injection process.
|
||||
|
@ -1,22 +1,22 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""Consumers
|
||||
|
@ -1,22 +1,22 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Consumer base class.
|
@ -1,31 +1,31 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Stores injection-process wide information."""
|
||||
|
||||
|
||||
from keymapper.logger import logger
|
||||
from keymapper.injection.macros.parse import parse, is_this_a_macro
|
||||
from keymapper.system_mapping import system_mapping
|
||||
from keymapper.config import NONE, MOUSE, WHEEL, BUTTONS
|
||||
from inputremapper.logger import logger
|
||||
from inputremapper.injection.macros.parse import parse, is_this_a_macro
|
||||
from inputremapper.system_mapping import system_mapping
|
||||
from inputremapper.config import NONE, MOUSE, WHEEL, BUTTONS
|
||||
|
||||
|
||||
class Context:
|
@ -1,22 +1,22 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""Since I'm not forking, I can't use multiprocessing.Pipe.
|
||||
|
@ -1,22 +1,22 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# key-mapper - GUI for device specific keyboard mappings
|
||||
# input-remapper - GUI for device specific keyboard mappings
|
||||
# Copyright (C) 2021 sezanzeb <proxima@sezanzeb.de>
|
||||
#
|
||||
# This file is part of key-mapper.
|
||||
# This file is part of input-remapper.
|
||||
#
|
||||
# key-mapper is free software: you can redistribute it and/or modify
|
||||
# input-remapper 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,
|
||||
# input-remapper 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/>.
|
||||
# along with input-remapper. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""A button or a key combination."""
|
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Loading…
Reference in New Issue