def save(self, path): """Dump as JSON into home.""" logger.info('Saving preset to %s', path) touch(path) with open(path, 'w') as file: if self._config.get('mapping') is not None: logger.error( '"mapping" is reserved and cannot be used as config key') preset_dict = self._config # make sure to keep the option to add metadata if ever needed, # so put the mapping into a special key json_ready_mapping = {} # tuple keys are not possible in json, encode them as string for key, value in self._mapping.items(): new_key = '+'.join([ ','.join([str(value) for value in sub_key]) for sub_key in key ]) json_ready_mapping[new_key] = value preset_dict['mapping'] = json_ready_mapping json.dump(preset_dict, file, indent=4) file.write('\n') self.changed = False
def populate(self): """Get a mapping of all available names to their keycodes.""" logger.debug('Gathering available keycodes') self.clear() xmodmap_dict = {} try: xmodmap = subprocess.check_output( ['xmodmap', '-pke'], stderr=subprocess.STDOUT).decode() xmodmap = xmodmap self._xmodmap = re.findall(r'(\d+) = (.+)\n', xmodmap + '\n') xmodmap_dict = self._find_legit_mappings() except (subprocess.CalledProcessError, FileNotFoundError): # might be within a tty pass if USER != 'root': # write this stuff into the key-mapper config directory, because # the systemd service won't know the user sessions xmodmap path = get_config_path(XMODMAP_FILENAME) touch(path) with open(path, 'w') as file: logger.debug('Writing "%s"', path) json.dump(xmodmap_dict, file, indent=4) for name, code in xmodmap_dict.items(): self._set(name, code) for name, ecode in evdev.ecodes.ecodes.items(): if name.startswith('KEY') or name.startswith('BTN'): self._set(name, ecode) self._set(DISABLE_NAME, DISABLE_CODE)
def test_save_load(self): self.assertEqual(len(config.iterate_autoload_presets()), 0) config.load_config() self.assertEqual(len(config.iterate_autoload_presets()), 0) config.set_autoload_preset('d1', 'a') config.set_autoload_preset('d2.foo', 'b') config.save_config() # ignored after load config.set_autoload_preset('d3', 'c') config.load_config() self.assertListEqual(list(config.iterate_autoload_presets()), [('d1', 'a'), ('d2.foo', 'b')]) config_2 = os.path.join(tmp, 'config_2.json') touch(config_2) with open(config_2, 'w') as f: f.write('{"a":"b"}') config.load_config(config_2) self.assertEqual(config.get("a"), "b") self.assertEqual(config.get(["a"]), "b")
def save_config(self): """Save the config to the file system.""" touch(self.path) with open(self.path, 'w') as file: json.dump(self._config, file, indent=4) logger.info('Saved config to %s', self.path) shutil.chown(self.path, USER, USER) file.write('\n')
def test_migrate(self): old = os.path.join(CONFIG_PATH, 'config') new = os.path.join(CONFIG_PATH, 'config.json') os.remove(new) touch(old) with open(old, 'w') as f: f.write('{}') GlobalConfig() self.assertTrue(os.path.exists(new)) self.assertFalse(os.path.exists(old))
def save_config(self): """Save the config to the file system.""" if USER == 'root': logger.debug('Skipping config file creation for the root user') return touch(self.path) with open(self.path, 'w') as file: json.dump(self._config, file, indent=4) logger.info('Saved config to %s', self.path) file.write('\n')
def populate(self): """Get a mapping of all available names to their keycodes.""" logger.debug('Gathering available keycodes') self.clear() xmodmap_dict = {} try: xmodmap = subprocess.check_output(['xmodmap', '-pke']).decode() xmodmap = xmodmap.lower() mappings = re.findall(r'(\d+) = (.+)\n', xmodmap + '\n') for keycode, names in mappings: # there might be multiple, like: # keycode 64 = Alt_L Meta_L Alt_L Meta_L # keycode 204 = NoSymbol Alt_L NoSymbol Alt_L # Alt_L should map to code 64. Writing code 204 only works # if a modifier is applied at the same time. So take the first # one. name = names.split()[0] xmodmap_dict[name] = int(keycode) - XKB_KEYCODE_OFFSET for keycode, names in mappings: # but since KP may be mapped like KP_Home KP_7 KP_Home KP_7, # make another pass and add all of them if they don't already # exist. don't overwrite any keycodes. for name in names.split(): if xmodmap_dict.get(name) is None: xmodmap_dict[name] = int(keycode) - XKB_KEYCODE_OFFSET except (subprocess.CalledProcessError, FileNotFoundError): # might be within a tty pass if USER != 'root': # write this stuff into the key-mapper config directory, because # the systemd service won't know the user sessions xmodmap path = get_config_path(XMODMAP_FILENAME) touch(path) with open(path, 'w') as file: logger.info('Writing "%s"', path) json.dump(xmodmap_dict, file, indent=4) self._mapping.update(xmodmap_dict) for name, ecode in evdev.ecodes.ecodes.items(): if name.startswith('KEY') or name.startswith('BTN'): self._set(name, ecode) self._set(DISABLE_NAME, DISABLE_CODE)
def test_migrate(self): if os.path.exists(tmp): shutil.rmtree(tmp) touch(os.path.join(tmp, 'foo1', 'bar1.json')) touch(os.path.join(tmp, 'foo2', 'bar2.json')) migrate_path() self.assertFalse(os.path.exists(os.path.join(tmp, 'foo1', 'bar1.json'))) self.assertFalse(os.path.exists(os.path.join(tmp, 'foo2', 'bar2.json'))) self.assertTrue( os.path.exists(os.path.join(tmp, 'presets', 'foo1', 'bar1.json'))) self.assertTrue( os.path.exists(os.path.join(tmp, 'presets', 'foo2', 'bar2.json')))
def test_get_available_preset_name(self): # no filename conflict self.assertEqual(get_available_preset_name('_', 'qux 2'), 'qux 2') touch(get_preset_path('_', 'qux 5')) self.assertEqual(get_available_preset_name('_', 'qux 5'), 'qux 6') touch(get_preset_path('_', 'qux')) self.assertEqual(get_available_preset_name('_', 'qux'), 'qux 2') touch(get_preset_path('_', 'qux1')) self.assertEqual(get_available_preset_name('_', 'qux1'), 'qux1 2') touch(get_preset_path('_', 'qux 2 3')) self.assertEqual(get_available_preset_name('_', 'qux 2 3'), 'qux 2 4') touch(get_preset_path('_', 'qux 5')) self.assertEqual(get_available_preset_name('_', 'qux 5', True), 'qux 5 copy') touch(get_preset_path('_', 'qux 5 copy')) self.assertEqual(get_available_preset_name('_', 'qux 5', True), 'qux 5 copy 2') touch(get_preset_path('_', 'qux 5 copy 2')) self.assertEqual(get_available_preset_name('_', 'qux 5', True), 'qux 5 copy 3') touch(get_preset_path('_', 'qux 5copy')) self.assertEqual(get_available_preset_name('_', 'qux 5copy', True), 'qux 5copy copy') touch(get_preset_path('_', 'qux 5copy 2')) self.assertEqual(get_available_preset_name('_', 'qux 5copy 2', True), 'qux 5copy 2 copy') touch(get_preset_path('_', 'qux 5copy 2 copy')) self.assertEqual( get_available_preset_name('_', 'qux 5copy 2 copy', True), 'qux 5copy 2 copy 2')
def test_touch(self): touch('/tmp/a/b/c/d/e') self.assertTrue(os.path.exists('/tmp/a/b/c/d/e')) self.assertTrue(os.path.isfile('/tmp/a/b/c/d/e')) self.assertRaises(ValueError, lambda: touch('/tmp/a/b/c/d/f/'))