1
2 """
3 Handles raw input using AT-SPI event generation.
4
5 Note: Think of keyvals as keysyms, and keynames as keystrings.
6
7 Authors: David Malcolm <dmalcolm@redhat.com>, Zack Cerza <zcerza@redhat.com>
8 """
9
10 __author__ = """
11 David Malcolm <dmalcolm@redhat.com>,
12 Zack Cerza <zcerza@redhat.com>
13 """
14 import gi
15
16 gi.require_version('Gtk', '3.0')
17 gi.require_version('Gdk', '3.0')
18
19 from gi.repository import Gdk
20 from config import config
21 from utils import doDelay
22 from logging import debugLogger as logger
23 from pyatspi import Registry as registry
24 from pyatspi import (KEY_SYM, KEY_PRESS, KEY_PRESSRELEASE, KEY_RELEASE)
25 from exceptions import ValueError
26 from __builtin__ import unicode, unichr
27
28
31
32
34 if x < 0 or y < 0:
35 raise ValueError(
36 "Attempting to generate a mouse event at negative coordinates: (%s,%s)" % (x, y))
37
38
39 -def click(x, y, button=1, check=True):
48
49
51 """
52 Synthesize a mouse button double-click at (x,y)
53 """
54 if check:
55 checkCoordinates(x, y)
56 logger.log("Mouse button %s doubleclick at (%s,%s)" % (button, x, y))
57 registry.generateMouseEvent(x, y, 'b%sd' % button)
58 doDelay()
59
60
61 -def press(x, y, button=1, check=True):
62 """
63 Synthesize a mouse button press at (x,y)
64 """
65 if check:
66 checkCoordinates(x, y)
67 logger.log("Mouse button %s press at (%s,%s)" % (button, x, y))
68 registry.generateMouseEvent(x, y, 'b%sp' % button)
69 doDelay()
70
71
72 -def release(x, y, button=1, check=True):
73 """
74 Synthesize a mouse button release at (x,y)
75 """
76 if check:
77 checkCoordinates(x, y)
78 logger.log("Mouse button %s release at (%s,%s)" % (button, x, y))
79 registry.generateMouseEvent(x, y, 'b%sr' % button)
80 doDelay()
81
82
84 """
85 Synthesize mouse absolute motion to (x,y)
86 """
87 if check:
88 checkCoordinates(x, y)
89 logger.log("Mouse absolute motion to (%s,%s)" % (x, y))
90 registry.generateMouseEvent(x, y, 'abs')
91 if mouseDelay:
92 doDelay(mouseDelay)
93 else:
94 doDelay()
95
96
98 logger.log("Mouse relative motion of (%s,%s)" % (x, y))
99 registry.generateMouseEvent(x, y, 'rel')
100 if mouseDelay:
101 doDelay(mouseDelay)
102 else:
103 doDelay()
104
105
106 -def drag(fromXY, toXY, button=1, check=True):
107 """
108 Synthesize a mouse press, drag, and release on the screen.
109 """
110 logger.log("Mouse button %s drag from %s to %s" % (button, fromXY, toXY))
111
112 (x, y) = fromXY
113 press(x, y, button, check)
114
115
116 (x, y) = toXY
117 absoluteMotion(x, y, check=check)
118 doDelay()
119
120 release(x, y, button, check)
121 doDelay()
122
123
124 -def typeText(string):
125 """
126 Types the specified string, one character at a time.
127 Please note, you may have to set a higher typing delay,
128 if your machine misses/switches the characters typed.
129 Needed sometimes on slow setups/VMs typing non-ASCII utf8 chars.
130 """
131 if not isinstance(string, unicode):
132 string = string.decode('utf-8')
133 for char in string:
134 pressKey(char)
135
136 keyNameAliases = {
137 'enter': 'Return',
138 'esc': 'Escape',
139 'alt': 'Alt_L',
140 'control': 'Control_L',
141 'ctrl': 'Control_L',
142 'shift': 'Shift_L',
143 'del': 'Delete',
144 'ins': 'Insert',
145 'pageup': 'Page_Up',
146 'pagedown': 'Page_Down',
147 ' ': 'space',
148 '\t': 'Tab',
149 '\n': 'Return'
150 }
151
152
153
155 i = Gdk.keyval_to_unicode(keySym)
156 if i:
157 UniChar = unichr(i)
158 else:
159 UniChar = ''
160 return UniChar
161
162
164
165 if not isinstance(uniChar, unicode):
166 uniChar = unicode(uniChar, 'utf-8')
167 i = ord(uniChar)
168 keySym = Gdk.unicode_to_keyval(i)
169 return keySym
170
171
172
174 return Gdk.keyval_name(keySym)
175
176
178 keyName = keyNameAliases.get(keyName.lower(), keyName)
179 keySym = Gdk.keyval_from_name(keyName)
180
181 if keySym == 0xffffff or keySym == 0x0 or keySym is None:
182 try:
183 keySym = uniCharToKeySym(keyName)
184 except:
185 try:
186 keySym = getattr(Gdk, 'KEY_' + keyName)
187 except AttributeError:
188 raise KeyError(keyName)
189 return keySym
190
191
193 """
194 Use GDK to get the keycode for a given keystring.
195
196 Note that the keycode returned by this function is often incorrect when
197 the requested keystring is obtained by holding down the Shift key.
198
199 Generally you should use uniCharToKeySym() and should only need this
200 function for nonprintable keys anyway.
201 """
202 keymap = Gdk.Keymap.get_for_display(Gdk.Display.get_default())
203 entries = keymap.get_entries_for_keyval(
204 Gdk.keyval_from_name(keyName))
205 try:
206 return entries[1][0].keycode
207 except TypeError:
208 pass
209
210
212 """
213 Presses (and releases) the key specified by keyName.
214 keyName is the English name of the key as seen on the keyboard. Ex: 'enter'
215 Names are looked up in Gdk.KEY_ If they are not found there, they are
216 looked up by uniCharToKeySym().
217 """
218 keySym = keyNameToKeySym(keyName)
219 registry.generateKeyboardEvent(keySym, None, KEY_SYM)
220 doTypingDelay()
221
222
224 """
225 Generates the appropriate keyboard events to simulate a user pressing the
226 specified key combination.
227
228 comboString is the representation of the key combo to be generated.
229 e.g. '<Control><Alt>p' or '<Control><Shift>PageUp' or '<Control>q'
230 """
231 strings = []
232 for s in comboString.split('<'):
233 if s:
234 for S in s.split('>'):
235 if S:
236 S = keyNameAliases.get(S.lower(), S)
237 strings.append(S)
238 for s in strings:
239 if not hasattr(Gdk, s):
240 if not hasattr(Gdk, 'KEY_' + s):
241 raise ValueError("Cannot find key %s" % s)
242 modifiers = strings[:-1]
243 finalKey = strings[-1]
244 for modifier in modifiers:
245 code = keyNameToKeyCode(modifier)
246 registry.generateKeyboardEvent(code, None, KEY_PRESS)
247 code = keyNameToKeyCode(finalKey)
248 registry.generateKeyboardEvent(code, None, KEY_PRESSRELEASE)
249 for modifier in modifiers:
250 code = keyNameToKeyCode(modifier)
251 registry.generateKeyboardEvent(code, None, KEY_RELEASE)
252 doDelay()
253