source: linux/osd/SimpleXkbWrapper.py

Letzte Änderung dieser Datei war 2352, erstellt von martinZuther, vor 4 Jahren

OSDneo2: Skript sucht sich jetzt die richtige Library heraus

  • Eigenschaft svn:eol-style auf native gesetzt
  • Eigenschaft svn:executable auf * gesetzt
  • Eigenschaft svn:mime-type auf text/plain gesetzt
Dateigröße: 19.4 KB
Zeile 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""OSD Neo2
5   ========
6   On screen display for learning the keyboard layout Neo2
7
8   Copyright (c) 2009-2010 Martin Zuther (http://www.mzuther.de/)
9
10   This program is free software: you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation, either version 3 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23   Thank you for using free software!
24
25"""
26
27# Here follows a plea in German to keep the comments in English so
28# that you may understand them, dear visitor ...
29#
30# Meine Kommentare in den Quellcodes sind absichtlich auf Englisch
31# gehalten, damit Leute, die im Internet nach Lösungen suchen, den
32# Code nachvollziehen können.  Daher bitte ich darum, zusätzliche
33# Kommentare ebenfalls auf Englisch zu schreiben.  Vielen Dank!
34
35import ctypes
36import ctypes.util
37import gettext
38import os
39import types
40
41# initialise localisation settings
42module_path = os.path.dirname(os.path.realpath(__file__))
43gettext.bindtextdomain('OSDneo2', os.path.join(module_path, 'po/'))
44gettext.textdomain('OSDneo2')
45_ = gettext.lgettext
46
47class SimpleXkbWrapper:
48    """
49    Far from complete wrapper for the "X Keyboard Extension" (well, to
50    be honest, it just wraps what I need using Python's "ctypes"
51    library <g>).
52    """
53
54    # set this to true to get lots of debugging information (and
55    # considerably slow things down)
56    DEBUG_XKB = False
57
58    # "C defines" from file /usr/include/X11/extensions/XKB.h (Ubuntu 9.04):
59    # $XFree86: xc/include/extensions/XKB.h,v 1.5tsi Exp $
60    #
61    # XkbUseCoreKbd is used to specify the core keyboard without having to
62    # look up its X input extension identifier.
63
64    XkbUseCoreKbd            = 0x0100
65
66
67
68    # "C defines" from file /usr/include/X11/XKBlib.h (Ubuntu 9.04):
69    # $XFree86: xc/lib/X11/XKBlib.h,v 3.5 2003/04/17 02:06:31 dawes Exp $ #
70    #
71    # XkbOpenDisplay error codes
72
73    XkbOD_Success            = 0
74    XkbOD_BadLibraryVersion  = 1
75    XkbOD_ConnectionRefused  = 2
76    XkbOD_NonXkbServer       = 3
77    XkbOD_BadServerVersion   = 4
78
79
80
81    # "C typedef" from file /usr/include/X11/extensions/XKBstr.h (Ubuntu 9.04):
82    # $Xorg: XKBstr.h,v 1.3 2000/08/18 04:05:45 coskrey Exp $
83    #
84    # Common data structures and access macros
85    #
86    # typedef struct _XkbStateRec {
87    #         unsigned char   group;
88    #         unsigned char   locked_group;
89    #         unsigned short  base_group;
90    #         unsigned short  latched_group;
91    #         unsigned char   mods;
92    #         unsigned char   base_mods;
93    #         unsigned char   latched_mods;
94    #         unsigned char   locked_mods;
95    #         unsigned char   compat_state;
96    #         unsigned char   grab_mods;
97    #         unsigned char   compat_grab_mods;
98    #         unsigned char   lookup_mods;
99    #         unsigned char   compat_lookup_mods;
100    #         unsigned short  ptr_buttons;
101    # } XkbStateRec,*XkbStatePtr;
102
103    class XkbStateRec(ctypes.Structure):
104        _fields_ = [
105                        ('group',              ctypes.c_ubyte), \
106                        ('locked_group',       ctypes.c_ubyte), \
107                        ('base_group',         ctypes.c_ushort), \
108                        ('latched_group',      ctypes.c_ushort), \
109                        ('mods',               ctypes.c_ubyte), \
110                        ('base_mods',          ctypes.c_ubyte), \
111                        ('latched_mods',       ctypes.c_ubyte), \
112                        ('locked_mods',        ctypes.c_ubyte), \
113                        ('compat_state',       ctypes.c_ubyte), \
114                        ('grab_mods',          ctypes.c_ubyte), \
115                        ('compat_grab_mods',   ctypes.c_ubyte), \
116                        ('lookup_mods',        ctypes.c_ubyte), \
117                        ('compat_lookup_mods', ctypes.c_ubyte), \
118                        ('ptr_buttons',        ctypes.c_ushort) \
119                   ]
120
121
122
123    # "C defines" from file /usr/include/X11/X.h (Ubuntu 9.04):
124    # $XFree86: xc/include/X.h,v 1.6 2003/07/09 15:27:28 tsi Exp $
125    #
126    # Key masks. Used as modifiers to GrabButton and GrabKey, results of
127    # QueryPointer, state in various key-, mouse-, and button-related
128    # events.
129
130    ShiftMask                = 1
131    LockMask                 = 2
132    ControlMask              = 4
133    Mod1Mask                 = 8
134    Mod2Mask                 = 16
135    Mod3Mask                 = 32
136    Mod4Mask                 = 64
137    Mod5Mask                 = 128
138
139
140
141    def __init__(self):
142        # dynamically link to "X Keyboard Extension" library while at
143        # the same time checking which library to use
144        xkbd_library_location = ctypes.util.find_library('Xxf86misc')
145        if not xkbd_library_location:
146            xkbd_library_location = ctypes.util.find_library('X11')
147
148        xkbd_library = ctypes.CDLL(xkbd_library_location)
149
150        # print debugging information if requested
151        if self.DEBUG_XKB:
152            print
153            print '  %s' % xkbd_library
154
155
156
157        # define "ctypes" prototype for the function
158        #
159        # Display *XkbOpenDisplay(display_name, event_rtrn, error_rtrn,
160        #                             major_in_out, minor_in_out, reason_rtrn)
161        #
162        #    char * display_name;
163        #    int * event_rtrn;
164        #    int * error_rtrn;
165        #    int * major_in_out;
166        #    int * minor_in_out;
167        #    int * reason_rtrn;
168
169        paramflags_xkbopendisplay = \
170            (1, 'display_name'), \
171            (2, 'event_rtrn'), \
172            (2, 'error_rtrn'), \
173            (3, 'major_in_out'), \
174            (3, 'minor_in_out'), \
175            (2, 'reason_rtrn')
176
177        prototype_xkbopendisplay = ctypes.CFUNCTYPE( \
178            ctypes.c_uint, \
179                ctypes.c_char_p, \
180                ctypes.POINTER(ctypes.c_int), \
181                ctypes.POINTER(ctypes.c_int), \
182                ctypes.POINTER(ctypes.c_int), \
183                ctypes.POINTER(ctypes.c_int), \
184                ctypes.POINTER(ctypes.c_int) \
185                )
186
187        # set-up function (low-level)
188        self.__XkbOpenDisplay__ = prototype_xkbopendisplay( \
189            ('XkbOpenDisplay', xkbd_library), \
190                paramflags_xkbopendisplay \
191                )
192
193        # define error handler
194        def errcheck_xkbopendisplay(result, func, args):
195            # print debugging information if requested
196            if self.DEBUG_XKB:
197                print
198                print '  [XkbOpenDisplay]'
199                print '  Display:       %#010x' % result
200                print '  display_name:  %s' % args[0].value
201                print '  event_rtrn:    %d' % args[1].value
202                print '  error_rtrn:    %d' % args[2].value
203                print '  major_in_out:  %d' % args[3].value
204                print '  minor_in_out:  %d' % args[4].value
205                print '  reason_rt:     %d' % args[5].value
206
207            # function didn't return display handle, so let's see why
208            # not
209            if result == 0:
210                # values were taken from file /usr/include/X11/XKBlib.h (Ubuntu 9.04):
211                # $XFree86: xc/lib/X11/XKBlib.h,v 3.5 2003/04/17 02:06:31 dawes Exp $ #
212                error_id = args[5].value
213                if error_id == self.XkbOD_Success:
214                    error_name = 'XkbOD_Success'
215                elif error_id == self.XkbOD_BadLibraryVersion:
216                    error_name = 'XkbOD_BadLibraryVersion'
217                elif error_id == self.XkbOD_ConnectionRefused:
218                    error_name = 'XkbOD_ConnectionRefused'
219                elif error_id == self.XkbOD_NonXkbServer:
220                    error_name = 'XkbOD_NonXkbServer'
221                elif error_id == self.XkbOD_BadServerVersion:
222                    error_name = 'XkbOD_BadServerVersion'
223                else:
224                    error_name = _('undefined')
225
226                error_message = \
227                    _('"XkbOpenDisplay" reported an error (%(error_name)s).') % \
228                    {'error_name': error_name}
229                raise OSError(error_message)
230
231            # return display handle and all function arguments
232            return (ctypes.c_uint(result), args)
233
234        # connect error handler to function
235        self.__XkbOpenDisplay__.errcheck = errcheck_xkbopendisplay
236
237
238
239        # define "ctypes" prototype for the function
240        #
241        # Bool XkbGetState(display, device_spec, state_return)
242        #
243        #     Display *             display;
244        #     unsigned int          device_spec;
245        #     XkbStatePtr           state_return;
246
247        paramflags_xkbgetstate = \
248            (1, 'display'), \
249            (1, 'device_spec'), \
250            (3, 'state_return')
251
252        prototype_xkbgetstate = ctypes.CFUNCTYPE( \
253            ctypes.c_int, # Python 2.5 doesn't yet know c_bool \
254                ctypes.c_uint, \
255                ctypes.c_uint, \
256                ctypes.POINTER(self.XkbStateRec) \
257                )
258
259        # set-up function (low-level)
260        self.__XkbGetState__ = prototype_xkbgetstate( \
261            ('XkbGetState', xkbd_library), \
262                paramflags_xkbgetstate \
263                )
264
265        # define error handler
266        def errcheck_xkbgetstate(result, func, args):
267            # print debugging information if requested
268            if self.DEBUG_XKB:
269                print
270                print '  [XkbGetState]'
271                print '  Status:        %s' % result
272                print '  display:       %#010x' % args[0].value
273                print '  device_spec:   %d\n' % args[1].value
274
275                print '  state_return.group:               %d' % \
276                    args[2].group
277                print '  state_return.locked_group:        %d' % \
278                    args[2].locked_group
279                print '  state_return.base_group:          %d' % \
280                    args[2].base_group
281                print '  state_return.latched_group:       %d' % \
282                    args[2].latched_group
283                print '  state_return.mods:                %d' % \
284                    args[2].mods
285                print '  state_return.base_mods:           %d' % \
286                    args[2].base_mods
287                print '  state_return.latched_mods:        %d' % \
288                    args[2].latched_mods
289                print '  state_return.locked_mods:         %d' % \
290                    args[2].locked_mods
291                print '  state_return.compat_state:        %d' % \
292                    args[2].compat_state
293                print '  state_return.grab_mods:           %d' % \
294                    args[2].grab_mods
295                print '  state_return.compat_grab_mods:    %d' % \
296                    args[2].compat_grab_mods
297                print '  state_return.lookup_mods:         %d' % \
298                    args[2].lookup_mods
299                print '  state_return.compat_lookup_mods:  %d' % \
300                    args[2].compat_lookup_mods
301                print '  state_return.ptr_buttons:         %d\n' % \
302                    args[2].ptr_buttons
303
304                print '  Mask          mods   base_mods   latched_mods   locked_mods   compat_state'
305                print '  --------------------------------------------------------------------------'
306                print '  ShiftMask     %-5s  %-5s       %-5s          %-5s         %-5s' % \
307                    ((args[2].mods         & self.ShiftMask) != 0, \
308                     (args[2].base_mods    & self.ShiftMask) != 0, \
309                     (args[2].latched_mods & self.ShiftMask) != 0, \
310                     (args[2].locked_mods  & self.ShiftMask) != 0, \
311                     (args[2].compat_state & self.ShiftMask) != 0)
312
313                print '  LockMask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
314                    ((args[2].mods         & self.LockMask) != 0, \
315                     (args[2].base_mods    & self.LockMask) != 0, \
316                     (args[2].latched_mods & self.LockMask) != 0, \
317                     (args[2].locked_mods  & self.LockMask) != 0, \
318                     (args[2].compat_state & self.LockMask) != 0)
319
320                print '  ControlMask   %-5s  %-5s       %-5s          %-5s         %-5s' % \
321                    ((args[2].mods         & self.ControlMask) != 0, \
322                     (args[2].base_mods    & self.ControlMask) != 0, \
323                     (args[2].latched_mods & self.ControlMask) != 0, \
324                     (args[2].locked_mods  & self.ControlMask) != 0, \
325                     (args[2].compat_state & self.ControlMask) != 0)
326
327                print '  Mod1Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
328                    ((args[2].mods         & self.Mod1Mask) != 0, \
329                     (args[2].base_mods    & self.Mod1Mask) != 0, \
330                     (args[2].latched_mods & self.Mod1Mask) != 0, \
331                     (args[2].locked_mods  & self.Mod1Mask) != 0, \
332                     (args[2].compat_state & self.Mod1Mask) != 0)
333
334                print '  Mod2Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
335                    ((args[2].mods         & self.Mod2Mask) != 0, \
336                     (args[2].base_mods    & self.Mod2Mask) != 0, \
337                     (args[2].latched_mods & self.Mod2Mask) != 0, \
338                     (args[2].locked_mods  & self.Mod2Mask) != 0, \
339                     (args[2].compat_state & self.Mod2Mask) != 0)
340
341                print '  Mod3Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
342                    ((args[2].mods         & self.Mod3Mask) != 0, \
343                     (args[2].base_mods    & self.Mod3Mask) != 0, \
344                     (args[2].latched_mods & self.Mod3Mask) != 0, \
345                     (args[2].locked_mods  & self.Mod3Mask) != 0, \
346                     (args[2].compat_state & self.Mod3Mask) != 0)
347
348                print '  Mod4Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
349                    ((args[2].mods         & self.Mod4Mask) != 0, \
350                     (args[2].base_mods    & self.Mod4Mask) != 0, \
351                     (args[2].latched_mods & self.Mod4Mask) != 0, \
352                     (args[2].locked_mods  & self.Mod4Mask) != 0, \
353                     (args[2].compat_state & self.Mod4Mask) != 0)
354
355                print '  Mod5Mask      %-5s  %-5s       %-5s          %-5s         %-5s' % \
356                    ((args[2].mods         & self.Mod5Mask) != 0, \
357                     (args[2].base_mods    & self.Mod5Mask) != 0, \
358                     (args[2].latched_mods & self.Mod5Mask) != 0, \
359                     (args[2].locked_mods  & self.Mod5Mask) != 0, \
360                     (args[2].compat_state & self.Mod5Mask) != 0)
361
362            # return function return value and all function arguments
363            return (result, args)
364
365        # connect error handler to function
366        self.__XkbGetState__.errcheck = errcheck_xkbgetstate
367
368
369    # define high-level version of "XkbOpenDisplay"
370    def XkbOpenDisplay(self, display_name, major_in_out, minor_in_out):
371        # if we don't do type checking, nobody ever will
372        assert (type(display_name) == types.NoneType) or \
373            (type(display_name) == types.StringType)
374        assert type(major_in_out) == types.IntType
375        assert type(minor_in_out) == types.IntType
376
377        # convert function arguments to "ctypes", ...
378        __display_name__ = ctypes.c_char_p(display_name)
379        __major_in_out__ = ctypes.c_int(major_in_out)
380        __minor_in_out__ = ctypes.c_int(minor_in_out)
381
382        # ... call low-level function ...
383        ret = self.__XkbOpenDisplay__(__display_name__, __major_in_out__, \
384                                         __minor_in_out__)
385
386        # ... and return converted return value and function arguments
387        return {'display_handle': ret[0].value, \
388                    'server_major_version': ret[1][3].value, \
389                    'server_minor_version': ret[1][4].value}
390
391
392    # define high-level version of "XkbGetState"
393    def XkbGetState(self, display_handle, device_spec):
394        # if we don't do type checking, nobody ever will
395        assert type(display_handle) == types.LongType
396        assert type(device_spec) == types.IntType
397
398        # convert function arguments to "ctypes", ...
399        __display_handle__ = ctypes.c_uint(display_handle)
400        __device_spec__ = ctypes.c_uint(device_spec)
401        __xkbstaterec__ = self.XkbStateRec()
402
403        # ... call low-level function ...
404        ret = self.__XkbGetState__(__display_handle__, __device_spec__, \
405                                  __xkbstaterec__)
406
407        # ... and return converted function argument
408        xkbstaterec = ret[1][2]
409        return xkbstaterec
410
411
412    # extract modifier status using bitmasks
413    def ExtractLocks(self, xkbstaterec):
414        return {'group': xkbstaterec.group, \
415                'shift': \
416                    (xkbstaterec.base_mods & self.ShiftMask) != 0, \
417                'shift_lock': \
418                    (xkbstaterec.locked_mods & self.ShiftMask) != 0, \
419                'lock': \
420                    (xkbstaterec.base_mods & self.LockMask) != 0, \
421                'lock_lock': \
422                    (xkbstaterec.locked_mods & self.LockMask) != 0, \
423                'control': \
424                    (xkbstaterec.base_mods & self.ControlMask) != 0, \
425                'control_lock': \
426                    (xkbstaterec.locked_mods & self.ControlMask) != 0, \
427                'mod1': \
428                    (xkbstaterec.base_mods & self.Mod1Mask) != 0, \
429                'mod1_lock': \
430                    (xkbstaterec.locked_mods & self.Mod1Mask) != 0, \
431                'mod2': \
432                    (xkbstaterec.base_mods & self.Mod2Mask) != 0, \
433                'mod2_lock': \
434                    (xkbstaterec.locked_mods & self.Mod2Mask) != 0, \
435                'mod3': \
436                    (xkbstaterec.base_mods & self.Mod3Mask) != 0, \
437                'mod3_lock': \
438                    (xkbstaterec.locked_mods & self.Mod3Mask) != 0, \
439                'mod4': \
440                    (xkbstaterec.base_mods & self.Mod4Mask) != 0, \
441                'mod4_lock': \
442                    (xkbstaterec.locked_mods & self.Mod4Mask) != 0, \
443                'mod5': \
444                    (xkbstaterec.base_mods & self.Mod5Mask) != 0, \
445                'mod5_lock': \
446                    (xkbstaterec.locked_mods & self.Mod5Mask) != 0}
447
448
449if __name__ == '__main__':
450    # simple demonstration of this wrapper
451    xkb = SimpleXkbWrapper()
452
453    # initialise wrapper for the X Keyboard Extension (v1.0) and
454    # open connection to default X display
455    display_name = None
456    major_in_out = 1
457    minor_in_out = 0
458
459    try:
460        ret = xkb.XkbOpenDisplay(display_name, major_in_out, minor_in_out)
461    except OSError, error:
462        print
463        print '  Error: %s' % error
464        print
465        exit(1)
466
467    # ... get modifier state of core keyboard ...
468    display_handle = ret['display_handle']
469    device_spec = xkb.XkbUseCoreKbd
470    xkbstaterec = xkb.XkbGetState(display_handle, device_spec)
471
472    # ... and extract and the information we need
473    mod_states = xkb.ExtractLocks(xkbstaterec)
474    print
475    for mod in mod_states:
476        print '  %-13s  %s' % (mod + ':', mod_states[mod])
477    print
Hinweis: Hilfe zum Repository-Browser finden Sie in TracBrowser.