4

キーボードの Super (または WinKey) を押すたびにイベントを実行する必要がある Python スクリプトを作成しました。

イベントを実行するためにキーが押されるのを待っているバックグラウンドで実行されているため、Pythonプロセスが「フォーカス」されずにこれを達成するにはどうすればよいですか?

入力を読み取る方法を示すWeb上の投稿をたくさん見ましたが、それらはすべてプロセスを「集中」させる必要があり、Pythonスクリプトを使用してスーパー(またはWinKey)をキャプチャする方法を示したものはありません。

Ubuntu 9.10 を実行しています。

4

4 に答える 4

5

これにより、 *nixシステムで修飾キーの状態を取得できます。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""OSD Neo2
   ========
   On screen display for learning the keyboard layout Neo2
   Copyright (c) 2009 Martin Zuther (http://www.mzuther.de/)
   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
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   Thank you for using free software!
"""
# Here follows a plea in German to keep the comments in English so
# that you may understand them, dear visitor ...
#
# Meine Kommentare in den Quellcodes sind absichtlich auf Englisch
# gehalten, damit Leute, die im Internet nach Lösungen suchen, den
# Code nachvollziehen können.  Daher bitte ich darum, zusätzliche
# Kommentare ebenfalls auf Englisch zu schreiben.  Vielen Dank!
import ctypes
import ctypes.util
import gettext
import os
import types
# initialise localisation settings
module_path = os.path.dirname(os.path.realpath(__file__))
gettext.bindtextdomain('OSDneo2', os.path.join(module_path, 'po/'))
gettext.textdomain('OSDneo2')
_ = gettext.lgettext
class SimpleXkbWrapper:
    """
    Far from complete wrapper for the "X Keyboard Extension" (well, to
    be honest, it just wraps what I need using Python's "ctypes"
    library <g>).
    """
    # set this to true to get lots of debugging information (and
    # considerably slow things down)
    DEBUG_XKB = False
    # "C defines" from file /usr/include/X11/extensions/XKB.h (Ubuntu 9.04):
    # $XFree86: xc/include/extensions/XKB.h,v 1.5tsi Exp $
    #
    # XkbUseCoreKbd is used to specify the core keyboard without having to
    # look up its X input extension identifier.
    XkbUseCoreKbd            = 0x0100
    # "C defines" from file /usr/include/X11/XKBlib.h (Ubuntu 9.04):
    # $XFree86: xc/lib/X11/XKBlib.h,v 3.5 2003/04/17 02:06:31 dawes Exp $ #
    #
    # XkbOpenDisplay error codes
    XkbOD_Success            = 0
    XkbOD_BadLibraryVersion  = 1
    XkbOD_ConnectionRefused  = 2
    XkbOD_NonXkbServer       = 3
    XkbOD_BadServerVersion   = 4
    # "C typedef" from file /usr/include/X11/extensions/XKBstr.h (Ubuntu 9.04):
    # $Xorg: XKBstr.h,v 1.3 2000/08/18 04:05:45 coskrey Exp $
    #
    # Common data structures and access macros
    #
    # typedef struct _XkbStateRec {
    #         unsigned char   group;
    #         unsigned char   locked_group;
    #         unsigned short  base_group;
    #         unsigned short  latched_group;
    #         unsigned char   mods;
    #         unsigned char   base_mods;
    #         unsigned char   latched_mods;
    #         unsigned char   locked_mods;
    #         unsigned char   compat_state;
    #         unsigned char   grab_mods;
    #         unsigned char   compat_grab_mods;
    #         unsigned char   lookup_mods;
    #         unsigned char   compat_lookup_mods;
    #         unsigned short  ptr_buttons;
    # } XkbStateRec,*XkbStatePtr;
    class XkbStateRec(ctypes.Structure):
        _fields_ = [
                        ('group',              ctypes.c_ubyte), \
                        ('locked_group',       ctypes.c_ubyte), \
                        ('base_group',         ctypes.c_ushort), \
                        ('latched_group',      ctypes.c_ushort), \
                        ('mods',               ctypes.c_ubyte), \
                        ('base_mods',          ctypes.c_ubyte), \
                        ('latched_mods',       ctypes.c_ubyte), \
                        ('locked_mods',        ctypes.c_ubyte), \
                        ('compat_state',       ctypes.c_ubyte), \
                        ('grab_mods',          ctypes.c_ubyte), \
                        ('compat_grab_mods',   ctypes.c_ubyte), \
                        ('lookup_mods',        ctypes.c_ubyte), \
                        ('compat_lookup_mods', ctypes.c_ubyte), \
                        ('ptr_buttons',        ctypes.c_ushort) \
                   ]
    # "C defines" from file /usr/include/X11/X.h (Ubuntu 9.04):
    # $XFree86: xc/include/X.h,v 1.6 2003/07/09 15:27:28 tsi Exp $
    #
    # Key masks. Used as modifiers to GrabButton and GrabKey, results of
    # QueryPointer, state in various key-, mouse-, and button-related
    # events.
    ShiftMask                = 1
    LockMask                 = 2
    ControlMask              = 4
    Mod1Mask                 = 8
    Mod2Mask                 = 16
    Mod3Mask                 = 32
    Mod4Mask                 = 64
    Mod5Mask                 = 128
    def __init__(self):
        # dynamically link to "X Keyboard Extension" library
        library_xf86misc = ctypes.CDLL(ctypes.util.find_library('Xxf86misc'))
        # print debugging information if requested
        if self.DEBUG_XKB:
            print
            print '  %s' % library_xf86misc
        # define "ctypes" prototype for the function
        #
        # Display *XkbOpenDisplay(display_name, event_rtrn, error_rtrn,
        #                             major_in_out, minor_in_out, reason_rtrn)
        #
        #    char * display_name;
        #    int * event_rtrn;
        #    int * error_rtrn;
        #    int * major_in_out;
        #    int * minor_in_out;
        #    int * reason_rtrn;
        paramflags_xkbopendisplay = \
            (1, 'display_name'), \
            (2, 'event_rtrn'), \
            (2, 'error_rtrn'), \
            (3, 'major_in_out'), \
            (3, 'minor_in_out'), \
            (2, 'reason_rtrn')
        prototype_xkbopendisplay = ctypes.CFUNCTYPE( \
            ctypes.c_uint, \
                ctypes.c_char_p, \
                ctypes.POINTER(ctypes.c_int), \
                ctypes.POINTER(ctypes.c_int), \
                ctypes.POINTER(ctypes.c_int), \
                ctypes.POINTER(ctypes.c_int), \
                ctypes.POINTER(ctypes.c_int) \
                )
        # set-up function (low-level)
        self.__XkbOpenDisplay__ = prototype_xkbopendisplay( \
            ('XkbOpenDisplay', library_xf86misc), \
                paramflags_xkbopendisplay \
                )
        # define error handler
        def errcheck_xkbopendisplay(result, func, args):
            # print debugging information if requested
            if self.DEBUG_XKB:
                print
                print '  [XkbOpenDisplay]'
                print '  Display:       %#010x' % result
                print '  display_name:  %s' % args[0].value
                print '  event_rtrn:    %d' % args[1].value
                print '  error_rtrn:    %d' % args[2].value
                print '  major_in_out:  %d' % args[3].value
                print '  minor_in_out:  %d' % args[4].value
                print '  reason_rt:     %d' % args[5].value
            # function didn't return display handle, so let's see why
            # not
            if result == 0:
                # values were taken from file /usr/include/X11/XKBlib.h (Ubuntu 9.04):
                # $XFree86: xc/lib/X11/XKBlib.h,v 3.5 2003/04/17 02:06:31 dawes Exp $ #
                error_id = args[5].value
                if error_id == self.XkbOD_Success:
                    error_name = 'XkbOD_Success'
                elif error_id == self.XkbOD_BadLibraryVersion:
                    error_name = 'XkbOD_BadLibraryVersion'
                elif error_id == self.XkbOD_ConnectionRefused:
                    error_name = 'XkbOD_ConnectionRefused'
                elif error_id == self.XkbOD_NonXkbServer:
                    error_name = 'XkbOD_NonXkbServer'
                elif error_id == self.XkbOD_BadServerVersion:
                    error_name = 'XkbOD_BadServerVersion'
                else:
                    error_name = _('undefined')
                error_message = \
                    _('"XkbOpenDisplay" reported an error (%(error_name)s).') % \
                    {'error_name': error_name}
                raise OSError(error_message)
            # return display handle and all function arguments
            return (ctypes.c_uint(result), args)
        # connect error handler to function
        self.__XkbOpenDisplay__.errcheck = errcheck_xkbopendisplay
        # define "ctypes" prototype for the function
        #
        # Bool XkbGetState(display, device_spec, state_return)
        #
        #     Display *             display;
        #     unsigned int          device_spec;
        #     XkbStatePtr           state_return;
        paramflags_xkbgetstate = \
            (1, 'display'), \
            (1, 'device_spec'), \
            (3, 'state_return')
        prototype_xkbgetstate = ctypes.CFUNCTYPE( \
            ctypes.c_int, # Python 2.5 doesn't yet know c_bool \
                ctypes.c_uint, \
                ctypes.c_uint, \
                ctypes.POINTER(self.XkbStateRec) \
                )
        # set-up function (low-level)
        self.__XkbGetState__ = prototype_xkbgetstate( \
            ('XkbGetState', library_xf86misc), \
                paramflags_xkbgetstate \
                )
        # define error handler
        def errcheck_xkbgetstate(result, func, args):
            # print debugging information if requested
            if self.DEBUG_XKB:
                print
                print '  [XkbGetState]'
                print '  Status:        %s' % result
                print '  display:       %#010x' % args[0].value
                print '  device_spec:   %d\n' % args[1].value
                print '  state_return.group:               %d' % \
                    args[2].group
                print '  state_return.locked_group:        %d' % \
                    args[2].locked_group
                print '  state_return.base_group:          %d' % \
                    args[2].base_group
                print '  state_return.latched_group:       %d' % \
                    args[2].latched_group
                print '  state_return.mods:                %d' % \
                    args[2].mods
                print '  state_return.base_mods:           %d' % \
                    args[2].base_mods
                print '  state_return.latched_mods:        %d' % \
                    args[2].latched_mods
                print '  state_return.locked_mods:         %d' % \
                    args[2].locked_mods
                print '  state_return.compat_state:        %d' % \
                    args[2].compat_state
                print '  state_return.grab_mods:           %d' % \
                    args[2].grab_mods
                print '  state_return.compat_grab_mods:    %d' % \
                    args[2].compat_grab_mods
                print '  state_return.lookup_mods:         %d' % \
                    args[2].lookup_mods
                print '  state_return.compat_lookup_mods:  %d' % \
                    args[2].compat_lookup_mods
                print '  state_return.ptr_buttons:         %d\n' % \
                    args[2].ptr_buttons
                print '  Mask          mods   base_mods   latched_mods   locked_mods   compat_state'
                print '  --------------------------------------------------------------------------'
                print '  ShiftMask     %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.ShiftMask) != 0, \
                     (args[2].base_mods    & self.ShiftMask) != 0, \
                     (args[2].latched_mods & self.ShiftMask) != 0, \
                     (args[2].locked_mods  & self.ShiftMask) != 0, \
                     (args[2].compat_state & self.ShiftMask) != 0)
                print '  LockMask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.LockMask) != 0, \
                     (args[2].base_mods    & self.LockMask) != 0, \
                     (args[2].latched_mods & self.LockMask) != 0, \
                     (args[2].locked_mods  & self.LockMask) != 0, \
                     (args[2].compat_state & self.LockMask) != 0)
                print '  ControlMask   %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.ControlMask) != 0, \
                     (args[2].base_mods    & self.ControlMask) != 0, \
                     (args[2].latched_mods & self.ControlMask) != 0, \
                     (args[2].locked_mods  & self.ControlMask) != 0, \
                     (args[2].compat_state & self.ControlMask) != 0)
                print '  Mod1Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.Mod1Mask) != 0, \
                     (args[2].base_mods    & self.Mod1Mask) != 0, \
                     (args[2].latched_mods & self.Mod1Mask) != 0, \
                     (args[2].locked_mods  & self.Mod1Mask) != 0, \
                     (args[2].compat_state & self.Mod1Mask) != 0)
                print '  Mod2Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.Mod2Mask) != 0, \
                     (args[2].base_mods    & self.Mod2Mask) != 0, \
                     (args[2].latched_mods & self.Mod2Mask) != 0, \
                     (args[2].locked_mods  & self.Mod2Mask) != 0, \
                     (args[2].compat_state & self.Mod2Mask) != 0)
                print '  Mod3Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.Mod3Mask) != 0, \
                     (args[2].base_mods    & self.Mod3Mask) != 0, \
                     (args[2].latched_mods & self.Mod3Mask) != 0, \
                     (args[2].locked_mods  & self.Mod3Mask) != 0, \
                     (args[2].compat_state & self.Mod3Mask) != 0)
                print '  Mod4Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.Mod4Mask) != 0, \
                     (args[2].base_mods    & self.Mod4Mask) != 0, \
                     (args[2].latched_mods & self.Mod4Mask) != 0, \
                     (args[2].locked_mods  & self.Mod4Mask) != 0, \
                     (args[2].compat_state & self.Mod4Mask) != 0)
                print '  Mod5Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
                    ((args[2].mods         & self.Mod5Mask) != 0, \
                     (args[2].base_mods    & self.Mod5Mask) != 0, \
                     (args[2].latched_mods & self.Mod5Mask) != 0, \
                     (args[2].locked_mods  & self.Mod5Mask) != 0, \
                     (args[2].compat_state & self.Mod5Mask) != 0)
            # return function return value and all function arguments
            return (result, args)
        # connect error handler to function
        self.__XkbGetState__.errcheck = errcheck_xkbgetstate
    # define high-level version of "XkbOpenDisplay"
    def XkbOpenDisplay(self, display_name, major_in_out, minor_in_out):
        # if we don't do type checking, nobody ever will
        assert (type(display_name) == types.NoneType) or \
            (type(display_name) == types.StringType)
        assert type(major_in_out) == types.IntType
        assert type(minor_in_out) == types.IntType
        # convert function arguments to "ctypes", ...
        __display_name__ = ctypes.c_char_p(display_name)
        __major_in_out__ = ctypes.c_int(major_in_out)
        __minor_in_out__ = ctypes.c_int(minor_in_out)
        # ... call low-level function ...
        ret = self.__XkbOpenDisplay__(__display_name__, __major_in_out__, \
                                         __minor_in_out__)
        # ... and return converted return value and function arguments
        return {'display_handle': ret[0].value, \
                    'server_major_version': ret[1][3].value, \
                    'server_minor_version': ret[1][4].value}
    # define high-level version of "XkbGetState"
    def XkbGetState(self, display_handle, device_spec):
        # if we don't do type checking, nobody ever will
        assert type(display_handle) == types.LongType
        assert type(device_spec) == types.IntType
        # convert function arguments to "ctypes", ...
        __display_handle__ = ctypes.c_uint(display_handle)
        __device_spec__ = ctypes.c_uint(device_spec)
        __xkbstaterec__ = self.XkbStateRec()
        # ... call low-level function ...
        ret = self.__XkbGetState__(__display_handle__, __device_spec__, \
                                  __xkbstaterec__)
        # ... and return converted function argument
        xkbstaterec = ret[1][2]
        return xkbstaterec
    # extract modifier status using bitmasks
    def ExtractLocks(self, xkbstaterec):
        return {'group': xkbstaterec.group, \
                'shift': \
                    (xkbstaterec.base_mods & self.ShiftMask) != 0, \
                'shift_lock': \
                    (xkbstaterec.locked_mods & self.ShiftMask) != 0, \
                'lock': \
                    (xkbstaterec.base_mods & self.LockMask) != 0, \
                'lock_lock': \
                    (xkbstaterec.locked_mods & self.LockMask) != 0, \
                'control': \
                    (xkbstaterec.base_mods & self.ControlMask) != 0, \
                'control_lock': \
                    (xkbstaterec.locked_mods & self.ControlMask) != 0, \
                'mod1': \
                    (xkbstaterec.base_mods & self.Mod1Mask) != 0, \
                'mod1_lock': \
                    (xkbstaterec.locked_mods & self.Mod1Mask) != 0, \
                'mod2': \
                    (xkbstaterec.base_mods & self.Mod2Mask) != 0, \
                'mod2_lock': \
                    (xkbstaterec.locked_mods & self.Mod2Mask) != 0, \
                'mod3': \
                    (xkbstaterec.base_mods & self.Mod3Mask) != 0, \
                'mod3_lock': \
                    (xkbstaterec.locked_mods & self.Mod3Mask) != 0, \
                'mod4': \
                    (xkbstaterec.base_mods & self.Mod4Mask) != 0, \
                'mod4_lock': \
                    (xkbstaterec.locked_mods & self.Mod4Mask) != 0, \
                'mod5': \
                    (xkbstaterec.base_mods & self.Mod5Mask) != 0, \
                'mod5_lock': \
                    (xkbstaterec.locked_mods & self.Mod5Mask) != 0}

別のファイルから状態を辞書に呼び出すfrom FILENAME import *には、次のように呼び出して実行します。

# simple demonstration of this wrapper
xkb = SimpleXkbWrapper()
# initialise wrapper for the X Keyboard Extension (v1.0) and
# open connection to default X display
display_name = None
major_in_out = 1
minor_in_out = 0
try:
    ret = xkb.XkbOpenDisplay(display_name, major_in_out, minor_in_out)
except OSError, error:
    print
    print '  Error: %s' % error
    print
    exit(1)
# ... get modifier state of core keyboard ...
display_handle = ret['display_handle']
device_spec = xkb.XkbUseCoreKbd
xkbstaterec = xkb.XkbGetState(display_handle, device_spec)
# ... and extract and the information we need
print xkb.ExtractLocks(xkbstaterec)

ここでコードを見つけることができる作成者と、私の注意を引いてくれたJason Orendorfflに乾杯します。

于 2010-04-04T03:49:37.787 に答える
2

私の以前の回答は完全に間違っていたようです、申し訳ありません。/dev/input/event1 (?) から読み取るのが正しいアプローチだと思います。

この短いテストでは、端末にフォーカスがない場合でも、スキャンコードが表示されました。

from struct import unpack
port = open("/dev/input/event1","rb")    

while 1:    
  a,b,c,d = unpack("4B",port.read(4))    
  print a,b,c,d

/dev/input/event1 が常にキーボードかどうか、またはどれがキーボードであるかを判断する方法はわかりませんが、少なくとも私にとってはうまくいきました

于 2009-12-07T13:54:26.790 に答える
0

Linux で作業する必要がある場合は、何らかの方法で X イベントを監視する必要があると思います。

コマンド「xev」を実行すると、すべてのイベントを表示できます。したがって、X がすべてのイベントへのインターフェイスを提供していると確信しています。簡単なグーグル検索で、おそらく必要なものを提供するPython X ライブラリが見つかります。

ここからダウンロードできます。

于 2009-12-07T12:07:13.810 に答える