Check if key is pressed using python (a daemon in the background)

こ雲淡風輕ζ 提交于 2019-12-17 23:22:42

问题


I've created a python script in which an event needs to be executed each time I press the Super (or WinKey) on my keyboard.

How can one achieve this without the python process being "focused" - as it is running in the background waiting for the key to be pressed to execute the event?

I've seen a lot of posts around the web showing me how to read input - but they have all required one to have the process "focused" and none have showed me how to capture the Super (or WinKey) using a python script.

I'm running Ubuntu 9.10.


回答1:


This allows me to get the state of modifier keys on my *nix system.

#!/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}

To call state to a dictionary,from another file, just call from FILENAME import * and do the following:

# 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)

Cheers to the creator whose code can be found here, and to Jason Orendorffl for drawing my attention to it.




回答2:


My previous answer apparently was completely wrong, sorry. I think the correct approach would be to read from /dev/input/event1 (?)

This short test showed scancodes for me, even if the terminal did not have focus:

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

I do not know if /dev/input/event1 is always the keyboard or how to determine which one is, but at least for me it worked




回答3:


You can use PyUserInput for this purpose, which is a cross-platform solution, compatible, in your case, with X11.

Example with Super:

from pykeyboard import PyKeyboardEvent

class MonitorSuper(PyKeyboardEvent):
    def tap(self, keycode, character, press):
        '''Monitor Super key.'''
        if character == 'Super_L':
            if press:
                print('Super pressed')
            else:
                print('Super released')
mon = MonitorSuper()
mon.run()



回答4:


If you need to work on Linux, I think you need to somehow monitor for X events.

You can see all events if you run the command "xev" - so I am sure that X provides an interface to all events. A quick googling finds Python X library that probably gives you the stuff you need.

You can download it here.



来源:https://stackoverflow.com/questions/1859049/check-if-key-is-pressed-using-python-a-daemon-in-the-background

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!