I just mapped my mouse key

first
sezanzeb 4 years ago
parent 5a499f6467
commit 7a86dfa179

@ -34,9 +34,9 @@ sudo python3 setup.py install && sudo python3 tests/test.py
- [x] show a dropdown to select an arbitrary device from `xinput list` - [x] show a dropdown to select an arbitrary device from `xinput list`
- [x] creating presets per device - [x] creating presets per device
- [ ] renaming presets - [x] renaming presets
- [x] show a list that can be extended with a `[+]` button - [x] show a list that can be extended with a `[+]` button
- [ ] The list shows `[keycode, current key for that keycode -> target]` - [ ] The list shows `[keycode, current key for that keycode -> target]`
- [ ] generate a file for /usr/share/X11/xkb/symbols/ for each preset, (symlink to home .config/?) - [x] generate a file for /usr/share/X11/xkb/symbols/ for each preset, (symlink to home .config/?)
- [x] load that file with `setxkbmap` - [x] load that file with `setxkbmap`
- [ ] automatically load the preset (on startup?, udev on mouse connect?) - [ ] automatically load the preset (on startup?, udev on mouse connect?)

@ -54,7 +54,6 @@ class SingleKeyMapping:
def put_together(self): def put_together(self):
"""Create all GTK widgets.""" """Create all GTK widgets."""
delete_button = Gtk.Button() delete_button = Gtk.Button()
destroy_icon = Gtk.Image.new_from_icon_name( destroy_icon = Gtk.Image.new_from_icon_name(
'window-close', Gtk.IconSize.BUTTON 'window-close', Gtk.IconSize.BUTTON
@ -145,9 +144,24 @@ class Window:
# and select the newest one (on the top) # and select the newest one (on the top)
preset_selection.set_active(0) preset_selection.set_active(0)
def clear_mapping_table(self):
"""Remove all rows from the mappings table."""
key_list = self.get('key_list')
for i in range(self.rows):
key_list.remove_row(i + 1)
self.rows = 0
def update_mappings(self): def update_mappings(self):
"""Construct the mapping from the inputs without saving or applying.""" """Construct the mapping from the inputs without saving or applying."""
self.mappings = [(10, 'c')] key_list = self.get('key_list')
mappings = []
for i in range(self.rows):
code = key_list.get_child_at(1, i + 1).get_text()
character = key_list.get_child_at(2, i + 1).get_text()
if code == '' or character == '':
continue
mappings.append((int(code), character))
self.mappings = mappings
def on_save_preset_clicked(self, button): def on_save_preset_clicked(self, button):
"""Save changes to a preset to the file system.""" """Save changes to a preset to the file system."""
@ -201,22 +215,15 @@ class Window:
self.selected_preset = preset self.selected_preset = preset
self.mappings = [] self.mappings = []
# prepare one empty input to add stuff, and to get the grid to
# the correct column width, otherwise it may jump if the user adds
# the first row.
key_list = self.get('key_list')
for i in range(self.rows):
# don't remove the header
key_list.remove_row(i + 1)
self.rows = 0
# TODO show all mapped keys from config # TODO show all mapped keys from config
self.clear_mapping_table()
self.on_add_key_clicked() self.on_add_key_clicked()
def on_add_key_clicked(self, button=None): def on_add_key_clicked(self, button=None):
"""Add a mapping to the list of mappings.""" """Add a mapping to the list of mappings."""
# TODO automatically add a line when no line is empty anymore # TODO automatically add a line when no line is empty anymore,
# making the add button obsolete
single_key_mapping = SingleKeyMapping(self.on_row_removed) single_key_mapping = SingleKeyMapping(self.on_row_removed)
key_list = self.get('key_list') key_list = self.get('key_list')
key_list.insert_row(1) key_list.insert_row(1)

@ -40,7 +40,7 @@ from keymapper.paths import get_home_path, get_usr_path, KEYCODES_PATH, \
from keymapper.logger import logger from keymapper.logger import logger
from keymapper.data import get_data_path from keymapper.data import get_data_path
from keymapper.presets import get_presets from keymapper.presets import get_presets
from keymapper.linux import get_devices from keymapper.linux import get_devices, can_grab
def get_keycode(device, letter): def get_keycode(device, letter):
@ -63,7 +63,7 @@ def create_preset(device, name=None):
i += 1 i += 1
name = f'{name} {i}' name = f'{name} {i}'
create_setxkbmap_config(device, name, []) os.mknod(get_home_path(device, name))
return name return name
@ -76,7 +76,18 @@ def create_setxkbmap_config(device, preset, mappings):
/usr/share/X11/xkb/symbols/key-mapper/<device>/<preset> to point to it. /usr/share/X11/xkb/symbols/key-mapper/<device>/<preset> to point to it.
The file in home doesn't have underscore to be more beautiful on the The file in home doesn't have underscore to be more beautiful on the
frontend, while the symlink doesn't contain any whitespaces. frontend, while the symlink doesn't contain any whitespaces.
Parameters
----------
device : string
preset : string
mappings : list
List of (keycode, character) tuples
""" """
if len(mappings) == 0:
logger.debug('Got empty mappings')
return None
create_identity_mapping() create_identity_mapping()
home_device_path = get_home_path(device) home_device_path = get_home_path(device)
@ -98,27 +109,34 @@ def create_setxkbmap_config(device, preset, mappings):
logger.info('Writing key mappings') logger.info('Writing key mappings')
with open(home_preset_path, 'w') as f: with open(home_preset_path, 'w') as f:
f.write(generate_symbols_file_content(device, preset, mappings)) contents = generate_symbols_file_content(device, preset, mappings)
if contents is not None:
f.write(contents)
def apply_preset(device, preset): def apply_preset(device, preset):
"""Apply a preset to the device.""" """Apply a preset to the device."""
group = get_devices()[device]
# apply it to every device that hangs on the same usb port, because I # apply it to every device that hangs on the same usb port, because I
# have no idea how to figure out which one of those 3 devices that are # have no idea how to figure out which one of those 3 devices that are
# all named after my mouse to use. # all named after my mouse to use.
device_underscored = device.replace(' ', '_')
preset_underscored = preset.replace(' ', '_')
group = get_devices()[device]
for xinput_name, xinput_id in get_xinput_id_mapping(): for xinput_name, xinput_id in get_xinput_id_mapping():
if xinput_name not in group['devices']: if xinput_name not in group['devices']:
# only all virtual devices of the same hardware device
continue continue
layout_name = (
'key-mapper' """# get the path in /dev for that
f'/{device_underscored}' path = [
f'/{preset_underscored}' path for name, path
) in zip(group['devices'], group['paths'])
if name == xinput_name
][0]
if not can_grab(path):
logger.error('Something else is')"""
symbols = '/usr/share/X11/xkb/symbols/'
layout_name = get_usr_path(device, preset)[len(symbols):]
cmd = [ cmd = [
'setxkbmap', 'setxkbmap',
'-layout', layout_name, '-layout', layout_name,
@ -188,6 +206,9 @@ def generate_symbols_file_content(device, preset, mappings):
if f'<{code}>' not in keycodes: if f'<{code}>' not in keycodes:
logger.error(f'Unknown keycode <{code}> for "{character}"') logger.error(f'Unknown keycode <{code}> for "{character}"')
xkb_symbols.append(f'key <{code}> {{ [ {character} ] }};') xkb_symbols.append(f'key <{code}> {{ [ {character} ] }};')
if len(xkb_symbols) == 0:
logger.error('Failed to populate xkb_symbols')
return None
template_path = get_data_path('xkb_symbols_template') template_path = get_data_path('xkb_symbols_template')
with open(template_path, 'r') as template_file: with open(template_path, 'r') as template_file:

Loading…
Cancel
Save