2012-05-17 3 views
2

나는 gtk3에서 작동하는 python xlib 전역 키 바인딩의 예를 찾고 있는데, 이는 gtk2에 대해 http://www.siafoo.net/snippet/239에서 수행 한 것과 같습니다. 여기에 매우 비슷한 코드 : 파이썬을 사용하는 X에 대한 전역 키 바인딩

from Xlib.display import Display 
from Xlib import X 
import gtk.gdk 
import threading 
import gobject 

class GlobalKeyBinding (gobject.GObject, threading.Thread): 
    __gsignals__ = { 
      'activate': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,()), 
     } 


    def __init__ (self): 
     gobject.GObject.__init__ (self) 
     threading.Thread.__init__ (self) 
     self.setDaemon (True) 

     self.keymap = gtk.gdk.keymap_get_default() 
     self.display = Display() 
     self.screen = self.display.screen() 
     self.root = self.screen.root 

     self.map_modifiers() 
     self.keybindings={} 
     self.current_signal=None 

    def map_modifiers (self): 
     gdk_modifiers = (gtk.gdk.CONTROL_MASK, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD1_MASK, 
         gtk.gdk.MOD3_MASK, gtk.gdk.MOD4_MASK, gtk.gdk.MOD5_MASK, 
         gtk.gdk.SUPER_MASK, gtk.gdk.HYPER_MASK) 
     self.known_modifiers_mask = 0 
     for modifier in gdk_modifiers: 
      self.known_modifiers_mask |= modifier 

    def add_grab_key(self,accelerator,signal): 
     if not accelerator: 
      return 
     keyval,modifiers=gtk.accelerator_parse(accelerator) 
     if not keyval or not modifiers: 
      return 
     keycode=self.keymap.get_entries_for_keyval(keyval)[0][0] 
     self.keybindings[signal]=[accelerator, 
      keycode, 
      int (modifiers)] 
       #grab_key operation forces X to exclusivelly send given keycode (like apostrophe char) to current X client (unless other X client grabbed it before). 
       #`X.AnyModifier' parameter tells to register the keycode for all modifiers, thus Ctrl-', Alt-', Shift-', ' will all be sent to this X client. 
       # given keyval is grabbed by current X client until `ungrab_key' is called. 
     return self.root.grab_key (keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync) 



    def ungrab (self): 
     for signal in self.keybindings: 
        # ungrab_key ungrabs given keycode, that was grabbed by `grab_key'. 
      self.root.ungrab_key (self.keybindings[signal][1],X.AnyModifier, self.root) 
     self.keybindings={} 

    def idle (self): 
     if self.current_signal: 
      gtk.gdk.threads_enter() 
      self.emit (self.current_signal) 
      self.current_signal=None 
      gtk.gdk.threads_leave() 
     return False 

     #threading.Thread.start() method invokes this method. 
    def run (self): 
     self.running = True 
     wait_for_release = False 
     while self.running: 
      event = self.display.next_event() # registered keycode(or probably rather event) has been received. 
      if self.current_signal: 
       self.display.allow_events (X.ReplayKeyboard, event.time) 
       continue 

      try: 
       if not wait_for_release and event.type == X.KeyPress: 
        modifiers = event.state & self.known_modifiers_mask 
             print modifiers, event.detail 
        for signal in self.keybindings: 
         if self.keybindings[signal][1] == event.detail and self.keybindings[signal][2] == modifiers: 
          self.this_signal=signal 
          this_keycode = self.keybindings[signal][1] 
          wait_for_release=True 
          break 
        if wait_for_release: 
         self.display.allow_events (X.AsyncKeyboard, event.time) 
        else: 
         self.display.allow_events (X.ReplayKeyboard, event.time) 
        continue 
       elif wait_for_release and event.detail == this_keycode and event.type == X.KeyRelease: 
        wait_for_release = False 
        self.current_signal=self.this_signal 
        self.event_window=event.window 
        gobject.idle_add (self.idle) 
        self.display.allow_events (X.AsyncKeyboard, event.time) 
       else: 
        self.display.allow_events (X.ReplayKeyboard, event.time) 
      except: 
       self.display.allow_events (X.ReplayKeyboard, event.time) 
    def stop (self): 
     print "stopping keybindings thread..." 
     self.running = False 
     self.ungrab() 
     self.display.close() 

# SAMPLE USAGE 
def callback (keybinding): 
    print 'Callback!' 
    keybinding.stop() 
    gtk.main_quit() 

def main(): 
    print "starting..." 
    gtk.gdk.threads_init() 
    keybindings=GlobalKeyBinding() 
    keybindings.add_grab_key('<Control>apostrophe','activate') 
    keybindings.connect('activate',callback) 
    keybindings.start() # let's thart the thread 
    gtk.main() 

main() 

불행히도 나는 하나를 찾을 수 없습니다, 따라서 나는 (12.04 우분투) gtk3를 사용하도록 다시 구현하기로 결정했다. 아래는 결과입니다. 런타임 오류는 없지만 불행히도 입력을받지 않습니다.

from Xlib.display import Display 
from Xlib import X 
from gi.repository import Gtk, Gdk, GObject 
import threading 

class GlobalKeyBinding (GObject.GObject, threading.Thread): 
    __gsignals__ = { 
      'activate': (GObject.SignalFlags.RUN_LAST, None,()), 
     } 


    def __init__ (self): 
     GObject.GObject.__init__ (self) 
     threading.Thread.__init__ (self) 
     self.setDaemon (True) 

     self.keymap = Gdk.Keymap.get_default() 
     self.display = Display() 
     self.screen = self.display.screen() 
     self.root = self.screen.root 

     self.map_modifiers() 
     self.keybindings={} 
     self.current_signal=None 

    def map_modifiers (self): 
     gdk_modifiers = (Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.SHIFT_MASK, Gdk.ModifierType.MOD1_MASK, 
         Gdk.ModifierType.MOD3_MASK, Gdk.ModifierType.MOD4_MASK, Gdk.ModifierType.MOD5_MASK, 
         Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK) 
     self.known_modifiers_mask = 0 
     for modifier in gdk_modifiers: 
      #print modifier,modifier+0 
      self.known_modifiers_mask |= modifier 

    def add_grab_key(self,accelerator,signal): 
     if not accelerator: 
      return 
     keyval,modifiers=Gtk.accelerator_parse(accelerator) 
     if not keyval or not modifiers: 
      return 
     #keycode=self.keymap.get_entries_for_keyval(keyval)[0][0] 
       success, entries = self.keymap.get_entries_for_keyval(keyval) 
       entry = [(int(i.keycode), i.group, i.level) for i in entries] 
       if not entry: 
        raise TypeError("Invalid key name") 

       keycode=entry[0][0] 
     self.keybindings[signal]=[accelerator, 
      keycode, 
      int (modifiers)] 
     return self.root.grab_key (keycode, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeSync) 



    def ungrab (self): 
     for signal in self.keybindings: 
      self.root.ungrab_key (self.keybindings[signal][1],X.AnyModifier, self.root) 
     self.keybindings={} 

    def idle (self): 
     if self.current_signal: 
      Gdk.threads_enter() 
      self.emit (self.current_signal) 
      self.current_signal=None 
      Gdk.threads_leave() 
     return False 

    def run (self): 
     self.running = True 
     wait_for_release = False 
     while self.running: 
      event = self.display.next_event() 
      if self.current_signal: 
       self.display.allow_events (X.ReplayKeyboard, event.time) 
       continue 

      try: 
       if not wait_for_release and event.type == X.KeyPress: 
        modifiers = event.get_state() & self.known_modifiers_mask 
        print modifiers,event.get_state() 
        for signal in self.keybindings: 
         if self.keybindings[signal][1] == event.detail and self.keybindings[signal][2] == modifiers: 
          self.this_signal=signal 
          this_keycode = self.keybindings[signal][1] 
          wait_for_release=True 
          break 
        if wait_for_release: 
         self.display.allow_events (X.AsyncKeyboard, event.time) 
        else: 
         self.display.allow_events (X.ReplayKeyboard, event.time) 
        continue 
       elif wait_for_release and event.detail == this_keycode and event.type == X.KeyRelease: 
        wait_for_release = False 
        self.current_signal=self.this_signal 
        self.event_window=event.window 
        GObject.idle_add (self.idle) 
        self.display.allow_events (X.AsyncKeyboard, event.time) 
       else: 
        self.display.allow_events (X.ReplayKeyboard, event.time) 
      except: 
       self.display.allow_events (X.ReplayKeyboard, event.time) 
    def stop (self): 
     self.running = False 
     self.ungrab() 
     self.display.close() 

# SAMPLE USAGE 
def callback (keybinding): 
    print 'Callback!' 
    keybinding.stop() 
    Gtk.main_quit() 

def main(): 
    print "starting..." 
    Gdk.threads_init() 
    keybindings=GlobalKeyBinding() 
    keybindings.add_grab_key('<Control>apostrophe','activate') 
    keybindings.connect('activate',callback) 
    print "keybindings go" 
    keybindings.start() # let's thart the thread 
    print "gtk go" 
    Gtk.main() 

main() 

어쩌면 몇 가지 아이디어가 있습니까?

안부, 폴

답변

2

이봐, 내가 동일한 코드와 큰 작업을 구현, 당신이 시도 할 수 있습니다. 그러나 아무 보증도 없다. 누락 된 부품을 발견하면 알려주십시오.

# -*- coding: utf-8; -*- 
# Copyright (C) 2013 Özcan Esen <[email protected]> 
# Copyright (C) 2008 Luca Bruno <[email protected]> 
# 
# This a slightly modified version of the globalkeybinding.py file which is part of FreeSpeak. 
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions: 
# 
# The above copyright notice and this permission notice shall be included in 
# all copies or substantial portions of the Software. 
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  
# DEALINGS IN THE SOFTWARE. 

from Xlib.display import Display 
from Xlib import X, error 
#import GObject 
#import gtk.gdk 
from gi.repository import Gtk, Gdk, GObject, GLib 
import threading 
from config import ConfigManager 

class GlobalKeyBinding(GObject.GObject, threading.Thread): 
    __gsignals__ = { 
     'activate':(GObject.SIGNAL_RUN_LAST, None,()), 
     } 

    def __init__(self): 
     GObject.GObject.__init__(self) 
     threading.Thread.__init__(self) 
     self.setDaemon(True) 

     self.keymap = Gdk.Keymap.get_default() 
     self.display = Display() 
     self.screen = self.display.screen() 
     self.root = self.screen.root 
     self.ignored_masks = self.get_mask_combinations(X.LockMask | X.Mod2Mask | X.Mod5Mask) 
     self.map_modifiers() 

    def map_modifiers(self): 
     gdk_modifiers =(Gdk.ModifierType.CONTROL_MASK, Gdk.ModifierType.SHIFT_MASK, Gdk.ModifierType.MOD1_MASK, 
         Gdk.ModifierType.MOD2_MASK, Gdk.ModifierType.MOD3_MASK, Gdk.ModifierType.MOD4_MASK, Gdk.ModifierType.MOD5_MASK, 
         Gdk.ModifierType.SUPER_MASK, Gdk.ModifierType.HYPER_MASK) 
     self.known_modifiers_mask = 0 
     for modifier in gdk_modifiers: 
      if "Mod" not in Gtk.accelerator_name(0, modifier): 
       self.known_modifiers_mask |= modifier 

    def grab(self): 
     Gdk.threads_enter() 
     accelerator = ConfigManager.get_conf('global-key') 
     Gdk.threads_leave() 
     keyval, modifiers = Gtk.accelerator_parse(accelerator) 
     if not accelerator or(not keyval and not modifiers): 
      self.keycode = None 
      self.modifiers = None 
      return 

     self.keycode= self.keymap.get_entries_for_keyval(keyval)[1][0].keycode 
     self.modifiers = int(modifiers) 

     catch = error.CatchError(error.BadAccess) 
     for ignored_mask in self.ignored_masks: 
      mod = modifiers | ignored_mask 
      result = self.root.grab_key(self.keycode, mod, True, X.GrabModeAsync, X.GrabModeSync, onerror=catch) 
     self.display.sync() 
     if catch.get_error(): 
      return False 
     return True 

    def ungrab(self): 
     if self.keycode: 
      self.root.ungrab_key(self.keycode, X.AnyModifier, self.root) 

    def get_mask_combinations(self, mask): 
     return [x for x in xrange(mask+1) if not (x & ~mask)] 

    def idle(self): 
     Gdk.threads_enter() 
     self.emit("activate") 
     Gdk.threads_leave() 
     return False 

    def run(self): 
     self.running = True 
     wait_for_release = False 
     while self.running: 
      event = self.display.next_event() 
      self.current_event_time = event.time 
      if event.detail == self.keycode and event.type == X.KeyPress and not wait_for_release: 
       modifiers = event.state & self.known_modifiers_mask 
       if modifiers == self.modifiers: 
        wait_for_release = True 
        self.display.allow_events(X.AsyncKeyboard, event.time) 
       else: 
        self.display.allow_events(X.ReplayKeyboard, event.time) 
      elif event.detail == self.keycode and wait_for_release: 
       if event.type == X.KeyRelease: 
        wait_for_release = False 
        GLib.idle_add(self.idle) 
       self.display.allow_events(X.AsyncKeyboard, event.time) 
      else: 
       self.display.allow_events(X.ReplayKeyboard, event.time) 

    def stop(self): 
     self.running = False 
     self.ungrab() 
     self.display.close()