问题
My application for X System stays in background (and in panel as indicator) and should popup whenever user hits a key, no matter whatever be the active window. Similar to Menu app.
Tried the following:
- Listening for global key-combinations in python on Linux But can't find how to integrate this Gtk main loop.
- Global keybinding on X using Python gtk3 The only answer for this question is Python 2 and doesn't work.
Mixing the above two, I got the following code:
from Xlib.display import Display
from Xlib import X, error
from Xlib.ext import record
from Xlib.protocol import rq
from gi.repository import Gtk, GObject, Gdk
import threading
class GlobalKeyBinding(GObject.GObject, threading.Thread):
def __init__(self):
GObject.GObject.__init__(self)
threading.Thread.__init__(self)
self.setDaemon(True)
self.display = Display()
self.Win = Gtk.Window()
self.Win.add(Gtk.Label("Hello"))
self.root = self.display.screen().root
ctx = self.display.record_create_context(
0,
[record.AllClients],
[{
'core_requests': (0, 0),
'core_replies': (0, 0),
'ext_requests': (0, 0, 0, 0),
'ext_replies': (0, 0, 0, 0),
'delivered_events': (0, 0),
'device_events': (X.KeyReleaseMask,
X.ButtonReleaseMask),
'errors': (0, 0),
'client_started': False,
'client_died': False,
}])
self.state = 0
self.display.record_enable_context(ctx, self.handler)
self.display.record_free_context(ctx)
def handler(self, reply):
data = reply.data
wait_for_release = False
while len(data):
event, data = rq.EventField(None).parse_binary_value(
data, self.display.display, None, None)
# KEYCODE IS FOUND USERING event.detail
print(event.detail)
if event.type == X.KeyPress:
# BUTTON PRESSED
print("pressed")
if not self.state:
self.Win.show_all()
self.state = 1
else:
self.Win.hide()
self.state = 0
elif event.type == X.KeyRelease:
# BUTTON RELEASED
print("released")
def run(self):
self.running = True
while self.running:
event = self.display.next_event () # registered keycode(or probably rather event) has been received.
while Gtk.main_iteration():
Gtk.main_iteration_do(True)
def main():
print("starting...")
Gdk.threads_init ()
keybindings=GlobalKeyBinding()
keybindings.start ()
Gtk.main ()
main()
Though this catches my input, it never shows the window. Please help : )
回答1:
So using XLib is not needed. Global Hotkey can be achieved using keybinder module. Example:
import gi
gi.require_versions({"Gtk": "3.0", "Gdk": "3.0", "Keybinder": "3.0"})
from gi.repository import Gtk, Keybinder
class A:
def __init__(self):
self.win = Gtk.Window()
self.lab = Gtk.Label(label="Hello")
self.win.add(self.lab)
self.win.connect("destroy", Gtk.main_quit)
self.win.show_all()
# Basic setup of a window with a label
self.count = 0
key = Keybinder # The module to bind keys
key.bind("<control>m", self.say, "Hello")
# key.bind(KEYCOMBINATION, FUNC, ARG)
key.init() # Call the mainloop something like Gtk.main()
def say(self, key, msg):
print(msg)
self.lab.set_label(f"Pressed {key} {self.count} times")
self.count += 1
A() # Call the object
Gtk.main() # Call the main loop
You can find more about this module here : https://github.com/engla/keybinder
来源:https://stackoverflow.com/questions/56517261/global-hotkey-in-python3-using-gtk-and-xlib