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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With