config, more renaming, some glade prototype

first
sezanzeb 4 years ago
parent ab1aca7939
commit 5c41d2ae2e

2
.gitignore vendored

@ -1,3 +1,5 @@
*.glade~
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

@ -1,6 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GTK based GUI for device specific keyboard mappings
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
@ -31,8 +31,8 @@ gi.require_version('Gtk', '3.0')
gi.require_version('GLib', '2.0')
from gi.repository import Gtk, GLib
from setxkbmapgtk.util import find_devices
from setxkbmapgtk.logger import logger, update_verbosity, log_info
from keymapper.util import find_devices
from keymapper.logger import logger, update_verbosity, log_info
class Window:
@ -44,10 +44,14 @@ class Window:
builder.connect_signals(self)
self.builder = builder
window = builder.get_object('setxkbmap-gtk_window')
window = builder.get_object('key-mapper-gtk_window')
window.show()
self.window = window
def get(self, name):
"""Get a widget from the window"""
return self.builder.get_object(name)
if __name__ == '__main__':
parser = ArgumentParser()

@ -2,7 +2,7 @@
Type=Application
Name=key-mapper
Icon=mouse
Exec=setxkbmapgtk-gtk
Exec=key-mapper-gtk
Terminal=false
Categories=Settings
Comment=GTK based GUI for device specific keyboard mappings
Comment=GUI for device specific keyboard mappings

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkWindow">
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">10</property>
<child>
<object class="GtkLabel">
<property name="width_request">50</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Device</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="device_selection">
<property name="width_request">200</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">10</property>
<child>
<object class="GtkLabel">
<property name="width_request">50</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Profile</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="profile_selection">
<property name="width_request">200</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">10</property>
<child>
<object class="GtkLabel">
<property name="width_request">50</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Mapping</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="add_key">
<property name="label" translatable="yes">Add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="key_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
</interface>

@ -0,0 +1,196 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
#
# key-mapper 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,
# 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/>.
"""Query settings, parse and write config files."""
import os
from keymapper.logger import logger
_config = None
_defaults = {
'pcm_input': 'null',
'input_use_dsnoop': True,
'input_use_softvol': True,
'input_plugin': 'hw',
'pcm_output': 'null',
'output_use_dmix': True,
'output_use_softvol': True,
'output_channels': 2,
'output_plugin': 'hw'
}
def _modify_config(config_contents, key, value):
"""Return a string representing the modified contents of the config file.
Parameters
----------
config_contents : string
Contents of the config file in ~/.config/key-mapper/config.
It is not edited in place and the config file is not overwritten.
key : string
Settings key that should be modified
value : string, int
Value to write
"""
logger.info('Setting "%s" to "%s"', key, value)
split = config_contents.split('\n')
if split[-1] == '':
split = split[:-1]
found = False
setting = f'{key}={value}'
for i, line in enumerate(split):
strip = line.strip()
if strip.startswith('#'):
continue
if strip.startswith(f'{key}='):
# replace the setting
logger.debug('Overwriting "%s=%s" in config', key, value)
split[i] = setting
found = True
break
if not found:
logger.debug('Adding "%s=%s" to config', key, value)
split.append(setting)
return '\n'.join(split)
class Config:
"""Read and set config values."""
def __init__(self, path=None):
"""Initialize the interface to the config file.
Parameters
----------
path : string or None
If none, will default to '~/.config/key-mapper/config'
"""
if path is None:
path = os.path.expanduser('~/.config/key-mapper/config')
logger.debug('Using config file at %s', path)
self._path = path
self._config = {}
self.mtime = 0
self.create_config_file()
self.load_config()
def create_config_file(self):
"""Create an empty config if it doesn't exist."""
if not os.path.exists(os.path.dirname(self._path)):
os.makedirs(os.path.dirname(self._path))
if not os.path.exists(self._path):
logger.info('Creating config file "%s"', self._path)
os.mknod(self._path)
def load_config(self):
"""Read the config file."""
logger.debug('Loading configuration')
self._config = {}
# load config
self.mtime = os.path.getmtime(self._path)
with open(self._path, 'r') as config_file:
for line in config_file:
line = line.strip()
if not line.startswith('#'):
split = line.split('=', 1)
if len(split) == 2:
key = split[0]
value = split[1]
else:
key = split[0]
value = None
if value.isdigit():
value = int(value)
else:
try:
value = float(value)
except ValueError:
pass
if value == 'True':
value = True
if value == 'False':
value = False
self._config[key] = value
def check_mtime(self):
"""Check if the config file has been modified and reload if needed."""
if os.path.getmtime(self._path) != self.mtime:
logger.info('Config changed, reloading')
self.load_config()
def get(self, key):
"""Read a value from the configuration or get the default."""
self.check_mtime()
if key not in _defaults:
logger.error('Unknown setting %s', key)
return None
return self._config.get(key, _defaults[key])
def set(self, key, value):
"""Write a setting into memory and ~/.config/key-mapper/config."""
if key not in _defaults:
logger.error('Unknown setting %s', key)
return None
self.check_mtime()
if key in self._config and self._config[key] == value:
logger.debug('Setting "%s" is already "%s"', key, value)
return False
self._config[key] = value
with open(self._path, 'r+') as config_file:
config_contents = config_file.read()
config_contents = _modify_config(config_contents, key, value)
# overwrite completely
with open(self._path, 'w') as config_file:
if not config_contents.endswith('\n'):
config_contents += '\n'
config_file.write(config_contents)
self.mtime = os.path.getmtime(self._path)
return True
def get_config(*args, **kwargs):
"""Ask for the config. Initialize it if not yet done so.
Will pass any parameters to the config constructor. Only needed in tests
to avoid writing the users config.
"""
# don't initialize it right away in the global scope, to avoid having
# the wrong logging verbosity.
global _config
if _config is None:
_config = Config(*args, **kwargs)
return _config

@ -1,6 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GTK based GUI for device specific keyboard mappings
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
@ -66,8 +66,8 @@ logger.setLevel(logging.INFO)
def log_info():
"""Log version and name to the console"""
# read values from setup.py
version = pkg_resources.require('setxkbmapgtk')[0].version
name = pkg_resources.require('setxkbmapgtk')[0].project_name
version = pkg_resources.require('key-mapper')[0].version
name = pkg_resources.require('key-mapper')[0].project_name
logger.info('%s %s', version, name)
@ -86,7 +86,7 @@ def debug_log_on():
def add_filehandler():
"""Clear the existing logfile and start logging to it."""
# jack also logs to ~/.log
log_path = os.path.expanduser('~/.log/setxkbmapgtk')
log_path = os.path.expanduser('~/.log/key-mapper')
log_file = os.path.join(log_path, 'log')
if not os.path.exists(log_path):

@ -1,6 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GTK based GUI for device specific keyboard mappings
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
@ -22,7 +22,7 @@
"""Helperfunctions to find device ids, names, and to load configs."""
from setxkbmapgtk.logger import logger
from keymapper.logger import logger
def find_devices():

@ -1,6 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GTK based GUI for device specific keyboard mappings
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
@ -23,11 +23,11 @@ import DistUtilsExtra.auto
DistUtilsExtra.auto.setup(
name='setxkbmapgtk',
name='key-mapper',
version='0.1.0',
description='GTK based GUI for device specific keyboard mappings',
description='GUI for device specific keyboard mappings',
license='GPL-3.0',
data_files=[
('share/applications/', ['data/setxkbmapgtk.desktop']),
('share/applications/', ['data/key-mapper.desktop']),
],
)

@ -1,6 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GTK based GUI for device specific keyboard mappings
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.

@ -1,6 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# key-mapper - GTK based GUI for device specific keyboard mappings
# key-mapper - GUI for device specific keyboard mappings
# Copyright (C) 2020 sezanzeb <proxima@hip70890b.de>
#
# This file is part of key-mapper.
@ -21,10 +21,24 @@
import unittest
from keymapper.config import _modify_config
class ConfigTest(unittest.TestCase):
def test_nothing(self):
pass
def test_first_line(self):
contents = """a=1\n # test=3\n abc=123"""
contents = _modify_config(contents, 'a', 3)
self.assertEqual(contents, """a=3\n # test=3\n abc=123""")
def test_last_line(self):
contents = """a=1\n # test=3\n abc=123"""
contents = _modify_config(contents, 'abc', 'foo')
self.assertEqual(contents, """a=1\n # test=3\nabc=foo""")
def test_new_line(self):
contents = """a=1\n # test=3\n abc=123"""
contents = _modify_config(contents, 'test', '1234')
self.assertEqual(contents, """a=1\n # test=3\n abc=123\ntest=1234""")
if __name__ == "__main__":
Loading…
Cancel
Save