diff --git a/README.rst b/README.rst index 3f64068..edacd29 100644 --- a/README.rst +++ b/README.rst @@ -58,6 +58,30 @@ to that group. E.g., Otherwise, just run mopidy as root to avoid any additional configuration requirements. + +You can define your own key using following options in configuration file:: + + + [evtdev] + #same configuration as before + ... + #define the play/pause button on key A + play_pause_btn = KEY_A + #define the stop button on key space + stop_btn = KEY_SPACE + #define mute button on key F12 + mute_btn = KEY_F12 + #define next track button on key '-' from the keypad + next_track_btn = KEY_KPPLUS + #define next track button on key '+' from the keypad + prev_track_btn = KEY_KPMINUS + #define volume up button on the page up key + volume_up_btn = KEY_PAGEUP + #define volume up button on the page down key + volume_down_btn = KEY_PAGEDOWN + +the list of available keys is defined in linux/input.h + Project resources ================= diff --git a/mopidy_evtdev/__init__.py b/mopidy_evtdev/__init__.py index 61c63f7..ff65742 100644 --- a/mopidy_evtdev/__init__.py +++ b/mopidy_evtdev/__init__.py @@ -23,6 +23,13 @@ def get_config_schema(self): schema['devices'] = config.List(optional=True) schema['refresh'] = config.Integer(minimum=1) schema['vol_step_size'] = config.Integer(minimum=1, maximum=25) + schema['play_pause_btn'] = config.String(optional=True) + schema['stop_btn'] = config.String(optional=True) + schema['next_track_btn'] = config.String(optional=True) + schema['prev_track_btn'] = config.String(optional=True) + schema['volume_up_btn'] = config.String(optional=True) + schema['volume_down_btn'] = config.String(optional=True) + schema['mute_btn'] = config.String(optional=True) return schema def validate_environment(self): diff --git a/mopidy_evtdev/agent.py b/mopidy_evtdev/agent.py index b4f8c2f..915af7a 100644 --- a/mopidy_evtdev/agent.py +++ b/mopidy_evtdev/agent.py @@ -13,7 +13,7 @@ class EvtDevAgent(object): MAX_TIME_INTERVAL = 5.0 # Maximum number of seconds between events - def __init__(self, core, dev_dir, devices, vol_step_size, refresh): + def __init__(self, core, dev_dir, devices, vol_step_size, refresh, btn): self.core = core self.dev_dir = dev_dir @@ -41,6 +41,27 @@ def __init__(self, core, dev_dir, devices, vol_step_size, refresh): evdev.ecodes.KEY_MUTE: self._mute } + for key, value in btn.iteritems(): + if value is None: + continue + code = getattr(evdev.ecodes, value, None) + if code is None: + continue + if key == 'play_pause_btn': + self.ecode_map[code] = self._play_pause + elif key == 'stop_btn': + self.ecode_map[code] = self._play_pause + elif key == 'next_track_btn': + self.ecode_map[code] = self._next_track + elif key == 'prev_track_btn': + self.ecode_map[code] = self._prev_track + elif key == 'volume_up_btn': + self.ecode_map[code] = self._volume_up + elif key == 'volume_down_btn': + self.ecode_map[code] = self._volume_down + elif key == 'mute_btn': + self.ecode_map[code] = self._mute + # This will initiate a refresh of all attached devices and # initiate timeouts self._refresh_timeout_callback() diff --git a/mopidy_evtdev/ext.conf b/mopidy_evtdev/ext.conf index 4820094..1f5466f 100644 --- a/mopidy_evtdev/ext.conf +++ b/mopidy_evtdev/ext.conf @@ -4,3 +4,10 @@ dev_dir = /dev/input devices = refresh = 10 vol_step_size = 10 +play_pause_btn = +prev_track_btn = +next_track_btn = +stop_btn = +volume_up_btn = +volume_down_btn = +mute_btn = \ No newline at end of file diff --git a/mopidy_evtdev/frontend.py b/mopidy_evtdev/frontend.py index 0cf5125..fca07c3 100644 --- a/mopidy_evtdev/frontend.py +++ b/mopidy_evtdev/frontend.py @@ -16,10 +16,19 @@ def __init__(self, config, core): vol_step_size = config['evtdev']['vol_step_size'] refresh = config['evtdev']['refresh'] + btn = {} + btn['play_pause_btn'] = config['evtdev']['play_pause_btn'] + btn['stop_btn'] = config['evtdev']['stop_btn'] + btn['next_track_btn'] = config['evtdev']['next_track_btn'] + btn['prev_track_btn'] = config['evtdev']['prev_track_btn'] + btn['volume_up_btn'] = config['evtdev']['volume_up_btn'] + btn['volume_down_btn'] = config['evtdev']['volume_down_btn'] + btn['mute_btn'] = config['evtdev']['mute_btn'] + # EvtDevAgent performs all the handling of device # key presses on our behalf self.agent = EvtDevAgent(core, dev_dir, devices, - vol_step_size, refresh) + vol_step_size, refresh, btn) logger.info('EvtDevAgent started') def on_stop(self): diff --git a/tests/test_agent_mocked_uinput.py b/tests/test_agent_mocked_uinput.py index 0dcd880..cc02ebd 100644 --- a/tests/test_agent_mocked_uinput.py +++ b/tests/test_agent_mocked_uinput.py @@ -50,7 +50,7 @@ def test_cleanup_on_stale_device(self, input_device, source_remove, mock_device.name = 'Mock Device' input_device.return_value = mock_device a = agent.EvtDevAgent(self.core, self.path, [], self.vol_step_size, - self.refresh_period) + self.refresh_period, {}) list_devices.assert_called_with(self.path) input_device.assert_called_with(self.dev) list_devices.return_value = [] @@ -73,7 +73,7 @@ def test_cleanup_on_stop(self, input_device, source_remove, mock_device.name = 'Mock Device' input_device.return_value = mock_device a = agent.EvtDevAgent(self.core, self.path, [], - self.vol_step_size, self.refresh_period) + self.vol_step_size, self.refresh_period, {}) input_device.assert_called_with(self.dev) a.stop() mock_device.close.assert_called_with() @@ -93,7 +93,7 @@ def test_fd_io_error(self, input_device, source_remove, mock_device.name = 'Mock Device' input_device.return_value = mock_device a = agent.EvtDevAgent(self.core, self.path, [], - self.vol_step_size, self.refresh_period) + self.vol_step_size, self.refresh_period, {}) io_add_watch.assert_called() io_callback = io_add_watch.call_args_list[0][0][2] io_exception = IOError('Mocked IO Error') @@ -125,7 +125,8 @@ def setUp(self): self.devices = map(ProxyInputDevice, self.device_names) self.agent = agent.EvtDevAgent(self.core, self.dev_dir, self.device_names, self.vol_step_size, - self.refresh) + self.refresh, + {}) def tearDown(self): self.agent.stop()