root/projects/WinDictator/trunk/windictator/linux/keycodes.py

Revision 19, 6.2 kB (checked in by edsuom, 1 year ago)

Importing windictator into the global FOSS repo

Line 
1 # WinDictator:
2 # Dictate in Windows, have the text typed in Linux via X faked keystroke events
3 #
4 # Copyright (C) 2005-2006 by Edwin A. Suominen, http://www.eepatents.com
5 #
6 # This program is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
9 # version.
10 #
11 # This program is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE.  See the file COPYING for more details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # this program; if not, write to the Free Software Foundation, Inc., 51
17 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18
19
20 """
21 Conversions to and from keycodes
22 """
23
24 import re
25 from os import environ
26 from twisted.internet import utils
27
28
29 class KeyCoder:
30     """
31     I take care of conversions from text to sequences of fake keystrokes.
32     """
33     def __init__(self):
34         self.specialSingles = {
35             ' '  : ('space',),
36             '.'  : ('period',),
37             '!'  : ('Shift_L', '1'),
38             '@'  : ('Shift_L', '2'),
39             '#'  : ('Shift_L', '3'),
40             '$'  : ('Shift_L', '4'),
41             '%'  : ('Shift_L', '5'),
42             '^'  : ('Shift_L', '6'),
43             '&'  : ('Shift_L', '7'),
44             '('  : ('Shift_L', '9'),
45             ')'  : ('Shift_L', '0'),
46             '*'  : ('Shift_L', '8'),
47             '+'  : ('Shift_L', 'plus'),
48             ','  : ('comma',),
49             '-'  : ('minus',),
50             "'"  : ('apostrophe',),
51             '"'  : ('Shift_L', 'apostrophe'),
52             '/'  : ('slash',),
53             '='  : ('plus',),
54             '`'  : ('grave',),
55             '~'  : ('Shift_L', 'grave'),
56             ';'  : ('semicolon',),
57             ':'  : ('Shift_L', 'semicolon'),
58             '?'  : ('Shift_L', 'slash'),
59             '['  : ('bracketleft',),
60             ']'  : ('bracketright',),
61             '_'  : ('Shift_L', 'minus'),
62             '|'  : ('Shift_L', 'backslash'),
63             '<'  : ('Shift_L', 'comma'),
64             '>'  : ('Shift_L', 'period'),
65             '{'  : ('Shift_L', 'bracketleft'),
66             '}'  : ('Shift_L', 'bracketright'),
67
68             '\n' : ('Return',),
69             '\t' : ('Tab',),
70             '\\' : ('backslash',)
71             }
72         upperCases = {}
73         for char in 'abcdefghijklmnopqrstuvwxyz':
74             upperCases[char.capitalize()] = ('Shift_L', char)
75         self.upperCases = upperCases
76
77     def textToKeys(self, text):
78         """
79         Consumes text from left to right, converting each matching character
80         pair or single character to a sequence of keycode strings and returning
81         a list of all such sequences in the order they are to be entered as
82         faked keystrokes.
83         """
84         k = 0
85         keyList = []
86         while k < len(text):
87             singleCandidate = text[k]
88             k += 1
89             if singleCandidate in self.specialSingles:
90                 keyList.append(self.specialSingles[singleCandidate])
91             elif singleCandidate in self.upperCases:
92                 keyList.append(self.upperCases[singleCandidate])
93             else:
94                 keyList.append((singleCandidate,))
95         return keyList
96
97
98 class KeyDecoder:
99     """
100     I take care of conversions from combinations of keycodes to text.
101     """
102     reLine = re.compile(r'keycode\s+(\d+)\s*\=\s*(\w+)\s+(\w+)')
103     keycodes = {}
104     specialSingles = {
105         'exclam':                   '!',
106         'at':                       '@',
107         'numbersign':               '#',
108         'dollar':                   '$',
109         'percent':                  '%',
110         'asciicircum':              '%',
111         'ampersand':                '&',
112         'asterisk':                 '*',
113         'parenleft':                '(',
114         'parenright':               ')',
115         'minus':                    '-',
116         'underscore':               '_',
117         'equal':                    '=',
118         'plus':                     '+',
119         'Tab':                      chr(9),
120         'bracketleft':              chr(91),
121         'braceleft':                chr(123),
122         'bracketright':             chr(93),
123         'braceright':               chr(125),
124         'Return':                   chr(10),
125         'semicolon':                ';',
126         'colon':                    ':',
127         'apostrophe':               chr(39),
128         'quotedbl':                 chr(34),
129         'grave':                    '`',
130         'asciitilde':               '~',
131         'backslash':                chr(92),
132         'bar':                      '|',
133         'comma':                    ',',
134         'less':                     '<',
135         'period':                   '.',
136         'greater':                  '>',
137         'slash':                    '/',
138         'question':                 '?',
139         'space':                    chr(32)
140         }
141
142     def startup(self):
143         """
144         """
145         d = utils.getProcessOutputAndValue(
146             '/usr/bin/xmodmap', args=("-pke",), env=environ)
147         d.addCallback(self._parse)
148         return d
149
150     def _parse(self, lines):
151         """
152         Parses the output of I{xmodmap} to build up a keycode dictionary
153         """
154         self.table = {}
155         for line in lines:
156             match = self.reLine.search(line)
157             if match:
158                 keycode, keyLower, keyUpper = match.groups()
159                 self.keycodes[keycode] = (keyLower, keyUpper)
160    
161     def decode(self, *keycodeList):
162         """
163         Converts the combination of I{keycodeList} supplied as one or more
164         arguments into a text character.
165
166         Currently the args can only be a single keycode, with or without the
167         code for the left or right shift key. There's probably no need to go
168         beyond that.
169         """
170         shiftKeys = [x for x in (50, 62) if x in keycodeList]
171         if shiftKeys:
172             keycodeList.remove(shiftKeys[0])
173             k = 1
174         else:
175             k = 0
176         symTuple = self.keycodes.get(keycodeList[0], ('',''))
177         keySym = symTuple[k]
178         return self.specialSingles.get(keySym, keySym)
179    
180        
181        
Note: See TracBrowser for help on using the browser.