Skip to content

Commit

Permalink
winmmkeys: Use pynput; remove support for other modules (#848)
Browse files Browse the repository at this point in the history
Fixes: #830
  • Loading branch information
sjohannes committed Feb 23, 2023
1 parent 8e9e915 commit 87ff77c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 62 deletions.
4 changes: 2 additions & 2 deletions plugins/winmmkeys/PLUGININFO
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Version='4.1.2'
Name=_('Multimedia keys for Windows')
Authors=['Johannes Sasongko <sasongko@gmail.com>']
Description=_('Adds support for multimedia keys (present on most new keyboards) when running Exaile in Microsoft Windows.\n\nRequires: pyHook (%s) or keyboard (%s)') % ('https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyhook', 'https://github.com/boppreh/keyboard')
Description=_('Adds support for keyboard multimedia keys on Windows.\n\nRequires: pynput (%s) (included in the Exaile installer)\n\nWarning: When this plugin is enabled, Exaile will process every key event in the Windows session, which may cause some security software to detect Exaile as a keylogger.') % 'https://github.com/moses-palmer/pynput'
Category=_('External Control')
RequiredModules=['pyHook']
RequiredModules=['pynput']
Platforms=['win32']
83 changes: 24 additions & 59 deletions plugins/winmmkeys/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# winmmkeys - Adds support for multimedia keys in Win32.
# Copyright (C) 2007, 2010, 2016 Johannes Sasongko <sasongko@gmail.com>
# winmmkeys - Adds support for multimedia keys on Windows
# Copyright (C) 2007, 2010, 2016, 2022 Johannes Sasongko <sasongko@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
Expand All @@ -20,10 +20,7 @@ def enable(self, exaile):
self.exaile = exaile

def on_gui_loaded(self):
try:
self.handler = HotkeyHandler_PyHook(self.exaile)
except ImportError:
self.handler = HotkeyHandler_Keyboard(self.exaile)
self.handler = HotkeyHandler_Pynput(self.exaile)

def disable(self, exaile):
if hasattr(self, 'handler'):
Expand All @@ -35,68 +32,36 @@ def disable(self, exaile):
plugin_class = WinmmkeysPlugin


class HotkeyHandler_PyHook:
class HotkeyHandler_Pynput:
def __init__(self, exaile):
import pyHook
from pynput import keyboard

from xl.player import PLAYER, QUEUE

# https://learn.microsoft.com/windows/win32/inputdev/virtual-key-codes
key_map = {
'Launch_Media_Select': exaile.gui.main.window.present,
'Media_Stop': PLAYER.stop,
'Media_Play_Pause': PLAYER.toggle_pause,
'Media_Next_Track': QUEUE.next,
'Media_Prev_Track': QUEUE.prev,
0xB0: QUEUE.next,
0xB1: QUEUE.prev,
0xB2: PLAYER.stop,
0xB3: PLAYER.toggle_pause,
0xB5: exaile.gui.main.window.present,
}

def on_key_down(event):
# NOTE: Because we capture every single key in the system, the
# following test will fail almost 100% of the time. That's why we
# use a very simple test that fails fast rather than a try-except
# block.
if event.Key in key_map:
key_map[event.Key]()
return False # Indicate that we've handled the key.
return True

self.hook_manager = man = pyHook.HookManager()
man.KeyDown = on_key_down
man.HookKeyboard()

def __del__(self):
self.disable()

def disable(self):
if hasattr(self, 'hook_manager'):
self.hook_manager.UnhookKeyboard()
del self.hook_manager


class HotkeyHandler_Keyboard:
def __init__(self, exaile):
import keyboard
from xl.player import PLAYER, QUEUE
# NOTE: This runs on every key event in the system, so it should exit as
# fast as possible when the key or event type doesn't match.
def on_event(msg, data):
# WM_KEYDOWN = 0x0100
if data.vkCode in key_map and msg == 0x0100:
key_map[data.vkCode]()
listener.suppress_event()

self.handlers = [
# use lambda here because gi function isn't hashable
keyboard.add_hotkey(
'select media', lambda: exaile.gui.main.window.present()
),
keyboard.add_hotkey('stop media', PLAYER.stop),
keyboard.add_hotkey('play/pause media', PLAYER.toggle_pause),
keyboard.add_hotkey('next track', QUEUE.next),
keyboard.add_hotkey('previous track', QUEUE.prev),
]
self.listener = listener = keyboard.Listener(win32_event_filter=on_event)
listener.start()

def __del__(self):
self.disable()

def disable(self):
if hasattr(self, 'handlers'):
import keyboard

for handler in self.handlers:
keyboard.remove_hotkey(handler)
del self.handlers


# vi: et sts=4 sw=4 tw=80
if hasattr(self, 'listener'):
self.listener.stop()
del self.listener
2 changes: 1 addition & 1 deletion tools/installer/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ musicbrainzngs==0.6
mutagen==1.40
pylast==1.8.0
feedparser==6.0.8
keyboard==0.13.2
pynput==1.7.6
discid

0 comments on commit 87ff77c

Please sign in to comment.