Module Keyboard
[hide private]
[frames] | no frames]

Source Code for Module Keyboard

  1  ''' 
  2  Defines a class representing a standard L{Keyboard} input device and action  
  3  code constants used to register filters on that device. 
  4   
  5  @var MAX_KEY_CHORD: Maximum number of actions that can be in a keyboard gesture 
  6  @type MAX_KEY_CHORD: integer 
  7  @var def_keymap: Default keymap for translation between key codes, keysyms, and 
  8    key names 
  9  @type def_keymap: gtk.gdk.Keymap 
 10   
 11  @author: Peter Parente 
 12  @author: Scott Haeger 
 13  @organization: IBM Corporation 
 14  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
 15   
 16  @author: Frank Zenker 
 17  @organization: IT Science Center Ruegen gGmbH, Germany 
 18  @copyright: Copyright (c) 2007, 2008 ITSC Ruegen 
 19   
 20  @license: I{The BSD License} 
 21  All rights reserved. This program and the accompanying materials are made 
 22  available under the terms of the BSD license which accompanies 
 23  this distribution, and is available at 
 24  U{http://www.opensource.org/licenses/bsd-license.php} 
 25  ''' 
 26  from AccessEngine import AEInput 
 27  from AccessEngine import AEConstants 
 28  import pyatspi 
 29  # need pygtk to map keycodes to keynames 
 30  import pygtk 
 31  pygtk.require('2.0') 
 32  import gtk.gdk as gdk 
 33  from Tools.i18n import _ 
 34   
 35  DEBUG = False 
 36   
 37  def_keymap = gdk.keymap_get_default() 
 38  MAX_KEY_CHORD = 4 
 39   
 40  __uie__ = dict(kind='device') 
 41   
42 -def _keyCodeToKeyName(code):
43 ''' 44 Gets the name of the given key code by using the default key map to lookup 45 its keysym value and then its localized name. If the code is not known, an 46 empty string is returned. 47 48 @param code: Hardware keycode 49 @type code: integer 50 @return: Name of the key 51 @rtype: string 52 ''' 53 entries = def_keymap.get_entries_for_keycode(code) 54 if entries and len(entries): 55 return gdk.keyval_name(entries[0][0]) 56 return ''
57
58 -class Keyboard(AEInput.SystemInput):
59 ''' 60 Basic keyboard input device. 61 62 Has a reference to the L{AEEventManager 63 <AccessEngine.AEEventManager._AEEventManager>} to register for system 64 wide keyboard key press and key release events. Matches key presses against a 65 collection of stored L{AEInput.Gesture}s representing key combinations that 66 should be filtered before they can reach the window with the input focus. 67 Observers of this device are notified about L{AEInput.Gesture}s when one or 68 more press events are received followed by a release. 69 70 Instances of L{Keyboard} impose some constraints on the filters that can be 71 registered. A filter can contain at most one L{AEInput.Gesture} and that 72 L{AEInput.Gesture} may have at most L{MAX_KEY_CHORD} key codes and at least 73 one. The filtered gesture may start with zero, one, or two modifiers 74 registered via L{SystemInput.addModifier 75 <AccessEngine.AEDevice.AEInput.SystemInput.SystemInput.addModifier>} and must 76 end with exactly one non-modifier. 77 78 The L{Keyboard} device is robust against typomatic repeats and more than 79 L{MAX_KEY_CHORD} sustained presses. Typomatic repeats are ignored so 80 that holding two modifier keys, holding a typomatic key, releasing one of the 81 modifiers, and then releasing the typomatic key does not result in two 82 notifications. Key presses beyond the maximum number are also ignored without 83 affecting the current state. 84 85 @ivar filters: Registered L{AEInput.GestureList} filters keyed by the one and 86 only one L{AEInput.Gesture} allowed in each filter 87 @type filters: dictionary keyed by L{AEInput.Gesture}s 88 @ivar acc_reg: Reference to the C{pyatspi.Registry} 89 @type acc_reg: C{pyatspi.Registry} 90 @ivar curr_gesture: Actions seen so far that might form a filtered 91 L{AEInput.Gesture} 92 @type curr_gesture: L{AEInput.Gesture} 93 @ivar synth_press: Ordered list of synthesized key presses that have been 94 sent for processing and should be ignored when detected 95 @type synth_press: list 96 @ivar synth_release: Ordered list of synthesized key releases that have been 97 sent for processing and should be ignored when detected 98 @type synth_release: list 99 @ivar state: Current state method for the key event handling state machine 100 @type state: callable 101 @ivar last_press: Was the last event a press (True) or release (False)? 102 @type last_press: boolean 103 @ivar LOCK_KEYS: Key codes for keys that can be locked in a particular state, 104 namely L{AEK_CAPS_LOCK}, L{AEK_SCROLL_LOCK}, and L{AEK_NUM_LOCK}. These 105 are constant. 106 @type LOCK_KEYS: list of integer 107 @ivar ACC_KEYS: Key codes for keys that should never be consumed because they 108 activate accessibility features such as slow keys or sticky keys 109 @type ACC_KEYS: list of integer 110 @ivar EATEN_GESTURES: List of gestures commonly eaten by a party higher than 111 this device in the AT-SPI event chain (e.g. the window manager). This 112 device should not synthesize these gestures when detected. 113 @type EATEN_GESTURES: list of L{AEInput.Gesture} 114 '''
115 - def init(self):
116 ''' 117 Initializes the empty filters dictionary and creates an empty L{AEInput.Gesture} that will be used to 118 buffer incoming keystrokes until the L{AEInput.Gesture} definitely matches 119 or does not match one of the held filters. Registers for key press and 120 release events via C{pyatspi}. Sets the filtering mode to handled by 121 default. Also registers for window activate events to account for missing 122 keys caused by system wide hotkey presses. 123 ''' 124 self.filters = {} 125 self.acc_reg = pyatspi.Registry 126 self.curr_gesture = AEInput.Gesture(self) 127 self.state = self._stateInvalid 128 self.synth_press = [] 129 self.synth_release = [] 130 self.last_press = False 131 self.LOCK_KEYS = [self.AEK_CAPS_LOCK, self.AEK_SCROLL_LOCK, 132 self.AEK_NUM_LOCK] 133 self.ACC_KEYS = [self.AEK_SHIFT_L, self.AEK_SHIFT_R] 134 self.EATEN_GESTURES = [ 135 AEInput.Gesture(self,[self.AEK_ALT_L, self.AEK_F4]), 136 AEInput.Gesture(self,[self.AEK_ALT_R, self.AEK_F4]) 137 ] 138 139 140 141 self.acc_reg.registerKeystrokeListener(self._onKeyPressed, mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,)) 142 self.acc_reg.registerKeystrokeListener(self._onKeyReleased, mask=None, kind=(pyatspi.KEY_RELEASED_EVENT,)) 143 self.acc_reg.registerEventListener(self._onForegroundChange, 'window:activate') 144 self.setFilterMode(AEConstants.FILTER_HANDLED)
145
146 - def close(self):
147 ''' 148 Informs the L{AccessEngine.AEEventManager} that notifications about keyboard events are no 149 longer of interest to this L{Keyboard} device. Sets the filtering mode to 150 none for good measure. Removes the request for focus events also. 151 ''' 152 AEInput.SystemInput.close(self) 153 self.acc_reg.deregisterKeystrokeListener(self._onKeyPressed, mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,)) 154 self.acc_reg.deregisterKeystrokeListener(self._onKeyReleased, mask=None, kind=(pyatspi.KEY_RELEASED_EVENT,)) 155 self.acc_reg.deregisterEventListener(self._onForegroundChange,'window:activate') 156 self.setFilterMode(AEConstants.FILTER_NONE)
157
158 - def getCapabilities(self):
159 ''' 160 Gets the list of capabilities provided by this device, namely 'keyboard.' 161 162 @return: 'keyboard' as the only capability of this device. 163 @rtype: list of string 164 ''' 165 return ['keyboard']
166
167 - def addFilter(self, key_filter):
168 ''' 169 Adds a L{AEInput.GestureList} to the collection of filters. The fire 170 L{AEInput.Gesture} in the L{AEInput.GestureList} will be used when the mode 171 is set to filter handled to prevent keys consumed by SUE from reaching the 172 foreground application. 173 174 The L{Keyboard} input device only supports one L{AEInput.Gesture} per 175 filter, not a sequence of L{AEInput.Gesture}s, and only one non-modifier 176 key code per L{AEInput.Gesture} chord. Any L{AEInput.GestureList} breaking 177 these rules will cause this method to raise a ValueError. 178 179 @param key_filter: Filter to add to the filter list 180 @type key_filter: L{AEInput.GestureList} 181 @raise ValueError: When the given L{AEInput.GestureList} does not conform 182 to the rules set forth above 183 ''' 184 # make sure there is only one Gesture in the list 185 if key_filter.getNumGestures() != 1: 186 raise ValueError('only one Gesture allowed in a Keyboard filter') 187 gesture = key_filter.getGestureAt(0) 188 # make sure there is at least one keystroke in the Gesture 189 if gesture.getNumActions() < 1: 190 raise ValueError('at least one key code required') 191 # make sure there is only one non-modifier key code 192 count = 0 193 for code in gesture: 194 try: 195 self.modifiers[code] 196 except KeyError: 197 count += 1 198 if count > 1: 199 raise ValueError('at most one non-modifier key allowed') 200 # add the filter to the filters dictionary indexed by the first Gesture 201 self.filters[gesture] = None
202
203 - def removeFilter(self, key_filter):
204 ''' 205 Removes a L{AEInput.GestureList} from the collection of filters. 206 207 @param key_filter: Filter to remove from the filter list 208 @type key_filter: L{AEInput.GestureList} 209 @raise KeyError: When the L{AEInput.GestureList} to remove is not found 210 @raise IndexError: When the L{AEInput.GestureList} is empty 211 ''' 212 del self.filters[key_filter.getGestureAt(0)]
213
214 - def clearFilters(self):
215 ''' 216 Removes all filters by destroying the dictionary and recreating it. 217 ''' 218 self.filters = {}
219
220 - def getMaxActions(self):
221 ''' 222 Gets the maximum L{AEInput.Gesture} chord length as defined by 223 L{MAX_KEY_CHORD}. 224 225 @return: Maximum L{AEInput.Gesture} chord length 226 @rtype: integer 227 ''' 228 return MAX_KEY_CHORD
229
230 - def getName(self):
231 ''' 232 Gets the name of this input device. 233 234 @return: Localized device name 235 @rtype: string 236 ''' 237 return _('Keyboard')
238
239 - def resetState(self):
240 ''' 241 Resets the state of the L{Keyboard} by clearing out the L{curr_gesture} and 242 returning to L{_stateInvalid}. 243 ''' 244 self.curr_gesture.clearActionCodes() 245 self.state = self._stateInvalid
246
247 - def _debug(self, header, code, event, press):
248 if DEBUG: 249 if press: 250 print 'press:', code 251 else: 252 print 'release:', code 253 print header 254 print 'next state:', self.state 255 print 'consumed:', event.consume 256 print 'curr key:', str(self.curr_gesture) 257 print 'synth pressed:', str(self.synth_press) 258 print 'synth released:', str(self.synth_release) 259 print '----------------------------'
260
261 - def _hasOneModifier(self, gesture):
262 ''' 263 Peeks in the given gestures to see if it contains at least one modifier. 264 265 @param gesture: Gesture to check for a modifier 266 @type gesture: L{AEInput.Gesture} 267 @return: Does the gesture contain at least one modifier? 268 @rtype: boolean 269 ''' 270 for code in gesture.peekActionCodes(): 271 if self.modifiers.has_key(code): 272 return True 273 return False
274
275 - def _hasOnlyModifiers(self, gesture):
276 ''' 277 Peeks in the given gesture to see if it contains only modifiers. 278 279 @param gesture: Gesture to check for a non-modifier 280 @type gesture: L{AEInput.Gesture} 281 @return: Does the gesture contain at least one non-modifier? 282 @rtype: boolean 283 ''' 284 for code in gesture.peekActionCodes(): 285 if not self.modifiers.has_key(code): 286 return False 287 return True #gesture.getNumActions() != 0
288
289 - def _sendGesture(self, gesture, press):
290 ''' 291 Synthesizes key strokes for the key codes in the given L{AEInput.Gesture}. 292 The presses are noted in L{synth_press} and L{synth_release} so that they 293 can be ignored when they are seen in L{_onKeyPressed} or L{_onKeyReleased} 294 to avoid duplicate processing. 295 296 @param press: Synthesize key presses (True) or releases (False)? 297 @type press: boolean 298 @param gesture: Gesture containing key codes to be pressed 299 @type gesture: L{AEInput.Gesture} 300 ''' 301 # see if the gesture is one of our eaten key combos 302 if gesture in self.EATEN_GESTURES: 303 # do nothing 304 return 305 306 # generate all events 307 for code in gesture.peekActionCodes(): 308 if code in self.LOCK_KEYS or code in self.ACC_KEYS: 309 continue 310 self._sendKey(code, press)
311
312 - def _sendKey(self, hw_code, press):
313 ''' 314 Synthesizes a single key stroke. The presses are noted in L{synth_press} 315 and L{synth_release} so that they can be ignored when they are seen in 316 L{_onKeyPressed} or L{_onKeyReleased} to avoid duplicate processing. 317 318 @param hw_code: Keycode of the key to generate 319 @type hw_code: integer 320 @param press: Synthesize key press (True) or releas (False)? 321 @type press: boolean 322 ''' 323 if press: 324 self.acc_reg.generateKeyboardEvent(hw_code, None, pyatspi.KEY_PRESS) 325 self.synth_press.append(hw_code) 326 else: 327 self.acc_reg.generateKeyboardEvent(hw_code, None, pyatspi.KEY_RELEASE) 328 self.synth_release.append(hw_code)
329
330 - def _consumeKey(self, event, press):
331 ''' 332 Consumes the given event as long as it is not a special key used by other 333 system services for accessibility purposes such as shift for slow keys 334 and sticky keys. 335 336 @param event: Keyboard event 337 @type event: C{pyatspi.event.DeviceEvent} 338 @param press: Press or release event? 339 @type press: boolean 340 ''' 341 #if not press or (event.hw_code not in self.ACC_KEYS): 342 event.consume = True 343 if press and (event.hw_code in self.ACC_KEYS): 344 # allow accessibility keys to pass, but as synthesized events so later 345 # release events can be paired properly by X and not generate a second 346 # press 347 self._sendKey(event.hw_code, True)
348
349 - def _handleStateful(self, event, press):
350 ''' 351 Handles the use of stateful keys such as caps lock, num lock, and scroll 352 lock as modifiers. When a lock key is pressed, this method immediately 353 sets it back to its former state. When a lock key is released, this method 354 allows the change to pass but only if all of the conditions are met: 355 356 - The lock key was the only key in the L{curr_gesture} since it was last 357 empty. 358 - The lock key is not a gesture itself. 359 - The lock key is currently the only key in the L{curr_gesture}. 360 361 @param event: Keyboard event 362 @type event: C{pyatspi.event.DeviceEvent} 363 @param press: Was the event a press (True) or release (False)? 364 @type press: boolean 365 ''' 366 hw_code = event.hw_code 367 if hw_code in self.LOCK_KEYS: 368 if press: 369 # deactive lock immediately after it has been pressed 370 self._sendKey(hw_code, True) 371 elif (self.last_press == True and 372 not self.filters.has_key(self.curr_gesture) and 373 len(self.curr_gesture) == 1): 374 # reactivate lock if it is the only key pressed, wasn't part of a combo 375 # where another key was pressed and released, and is not a filter key 376 # itself 377 self._sendKey(hw_code, True) 378 self._sendKey(hw_code, False)
379
380 - def _statePossible(self, event, press):
381 ''' 382 Represents a state where the current key codes in L{curr_gesture} and the 383 next key press may lead to a match on one of the registered L{filters}. 384 The actions in this state are as follows. 385 386 If the event is a press or release of one of the registered 387 L{SystemInput.modifiers 388 <AccessEngine.AEDevice.AEInput.SystemInput.SystemInput.modifiers>}, 389 the key is consumed and we remain in this state. 390 391 If the event is a press of a non-modifier and the L{curr_gesture} matches 392 one of the registered L{filters}, we consume the key and transition to 393 L{_stateMatch}. 394 395 If the event is anything else, we synthesize all keys in the 396 L{curr_gesture}, consume the current event, and transition to 397 L{_stateInvalid}. 398 399 @param event: Keyboard event 400 @type event: C{pyatspi.event.DeviceEvent} 401 @param press: Was the event a press (True) or release (False)? 402 @type press: boolean 403 @return: Method representing the next state 404 @rtype: callable 405 ''' 406 if self.modifiers.has_key(event.hw_code): 407 # stay in this state and consume the key 408 self._consumeKey(event, press) 409 return self._statePossible 410 elif self.filters.has_key(self.curr_gesture): 411 # move to the match state and consume the key 412 self._consumeKey(event, press) 413 return self._stateMatch 414 else: 415 # update the os key state 416 self._sendGesture(self.curr_gesture, True) 417 # move to the invalid state and consume the current key 418 self._consumeKey(event, press) 419 return self._stateInvalid
420
421 - def _stateInvalid(self, event, press):
422 ''' 423 Represents a state where the current key codes in L{curr_gesture} and the 424 next key event is not likely to match one of the registered L{filters}. 425 The actions in this state are as follows. 426 427 If the event is a press resulting in the L{curr_gesture} having only 428 L{SystemInput.modifiers 429 <AccessEngine.AEDevice.AEInput.SystemInput.SystemInput.modifiers>} in it, 430 we consume the press and transition to L{_statePossible}. 431 432 If the event is a press resulting in the L{curr_gesture} exactly matching 433 one of the registered L{filters}, we consume the press transition to 434 L{_stateMatch}. 435 436 If the event is anything else, we allow the event to pass and stay in this 437 state. 438 439 @param event: Keyboard event 440 @type event: C{pyatspi.event.DeviceEvent} 441 @param press: Was the event a press (True) or release (False)? 442 @type press: boolean 443 @return: Method representing the next state 444 @rtype: callable 445 ''' 446 if press: 447 if self._hasOnlyModifiers(self.curr_gesture): 448 # just a modifier, possibly a filter to match 449 self._consumeKey(event, press) 450 return self._statePossible 451 elif self.filters.has_key(self.curr_gesture): 452 # already a matched filter 453 self._consumeKey(event, press) 454 return self._stateMatch 455 elif len(self.synth_press): 456 # still waiting for presses to be synthesized, eat and synth 457 self._consumeKey(event, press) 458 self._sendKey(event.hw_code, True)
459
460 - def _stateMatch(self, event, press):
461 ''' 462 Represents a state where the current key codes in L{curr_gesture} matches 463 one of the L{filters} and the next event may determine if the key codes in 464 L{curr_gesture} are consumed forever or synthesized to be passed on to the 465 OS. The actions in this state are as follows. 466 467 If the event is a press and L{curr_gesture} matches one of the L{filters}, 468 we stay in this state. (This case is needed to handle repeating, typomatic 469 presses of non-modifier keys.) 470 471 If the event is a press and L{curr_gesture} no longer matches one of the 472 L{filters}, we synthesize key presses for all keys in L{curr_gesture}, 473 consume the current press, and transition to L{_stateInvalid}. 474 475 If the event is a release of one of the L{SystemInput.modifiers 476 <AccessEngine.AEDevice.AEInput.SystemInput.SystemInput.modifiers>}, we 477 consume the release and move to L{_stateAfterMatch}. 478 479 If the event is anything else (i.e. a non-modifier release), we consume the 480 key and transition to L{_statePossible}. 481 482 @param event: Keyboard event 483 @type event: C{pyatspi.event.DeviceEvent} 484 @param press: Was the event a press (True) or release (False)? 485 @type press: boolean 486 @return: Method representing the next state 487 @rtype: callable 488 ''' 489 if press: 490 if self.filters.has_key(self.curr_gesture): 491 # stay in this state and eat the key, typomatic 492 self._consumeKey(event, press) 493 return self._stateMatch 494 else: 495 # send all key presses 496 self._sendGesture(self.curr_gesture, True) 497 # move to the invalid state and eat the key 498 self._consumeKey(event, press) 499 return self._stateInvalid 500 elif self.modifiers.has_key(event.hw_code): 501 # move to the after match state and eat the key 502 self._consumeKey(event, press) 503 return self._stateAfterMatch 504 else: 505 # move to the possible state and eat the key 506 self._consumeKey(event, press) 507 return self._statePossible
508
509 - def _stateAfterMatch(self, event, press):
510 ''' 511 Represents a state where the the keys in L{curr_gesture} just matched one 512 of the L{filters} and the next event was a release of one of the modifier 513 keys instead of the non-modifier. This state is needed to avoid typomatic 514 repeat presses of the still held non-modifier key. The actions in this 515 state are as follows. 516 517 If the event is a release of a non-modifier and the L{curr_gesture} is now 518 empty, we consume the release and move to L{_stateInvalid}. 519 520 If the event is a release of one of the non-modifiers and the 521 L{curr_gesture} still contains key strokes (e.g. L{SystemInput.modifiers 522 <AccessEngine.AEDevice.AEInput.SystemInput.SystemInput.modifiers>}), we consume 523 the release and move to L{_statePossible}. 524 525 @param event: Keyboard event 526 @type event: C{pyatspi.event.DeviceEvent} 527 @param press: Was the event a press (True) or release (False)? 528 @type press: boolean 529 @return: Method representing the next state 530 @rtype: callable 531 ''' 532 if not press and not self.modifiers.has_key(event.hw_code): 533 # eat the key 534 self._consumeKey(event, press) 535 if self.curr_gesture.getNumActions() == 0: 536 # move to state invalid 537 return self._stateInvalid 538 else: 539 # move to state possible 540 return self._statePossible 541 else: 542 # stay in this state and eat the key 543 self._consumeKey(event, press)
544
545 - def _onKeyPressed(self, event):
546 ''' 547 Handles a key press event by acting on the hardware key code in 548 event.hw_code. If the key code is at the top of the L{synth_press} list, 549 then the press is ignored since it was synthesized and that code is removed 550 from the list. Otherwise, an attempt is made to add the key code to the 551 L{curr_gesture}. If the current gesture is full, the press is ignored and 552 the method returns immediately. If not, the event is dispatched to the 553 current state method (one of L{_statePossible}, L{_stateInvalid}, 554 L{_stateMatch}). The return value of the state method is set as the next 555 state and the L{last_press} flag is set to True. 556 557 @param event: Keyboard key press event 558 @type event: C{pyatspi.event.DeviceEvent} 559 ''' 560 hw_code = event.hw_code 561 if len(self.synth_press) and hw_code == self.synth_press[0]: 562 # ignore keys we know we synthesized 563 self.synth_press.pop(0) 564 self._debug('ignored our press', hw_code, event, True) 565 return 566 elif hw_code in self.synth_release: 567 # ignore presses for keys we're waiting to release 568 # do not account for ACC_KEYS, ignore everything 569 event.consume = True 570 self._debug('ignored our press before release', hw_code, event, True) 571 return 572 573 if hw_code not in self.curr_gesture: 574 # only count a non-typomatic press as a last press 575 self.last_press = True 576 # don't need to do the following if it was a typomatic press, repeats are 577 # ignored when trying to add to a Gesture 578 try: 579 # try to store the action code in the current gesture 580 self.curr_gesture.addActionCode(hw_code) 581 except ValueError: 582 # ignore the press if the gesture is full 583 self._debug('error adding', hw_code, event, True) 584 return 585 586 self._handleStateful(event, True) 587 588 self.state = self.state(event, True) or self.state 589 self._debug('state machine handled', hw_code, event, True)
590
591 - def _onKeyReleased(self, event):
592 ''' 593 Handles a key release event by acting on the hardware key code in 594 event.hw_code. If the key code is at the top of the L{synth_release} list, 595 then the release is ignored since it was synthesized and that code is 596 removed from the list. Otherwise, the L{last_press} flag is checked to see 597 if it is True indicating the last event was a key press. If so, the 598 L{curr_gesture} is copied into a new L{AEInput.Gesture} and sent to any 599 listeners via the L{AEInput.SystemInput}._notifyInputListeners method. Next 600 an attempt is made to remove the key code from the L{curr_gesture}. If the 601 key code does not exist, the release is ignored and the method returns 602 immediately. If not, the event is dispatched to the current state method 603 (one of L{_statePossible}, L{_stateInvalid}, L{_stateMatch}). The return 604 value of the state method is set as the next state and the L{last_press} 605 flag is set to False. 606 607 @param event: Keyboard key release event 608 @type event: C{pyatspi.event.DeviceEvent} 609 ''' 610 hw_code = event.hw_code 611 if len(self.synth_release) and hw_code == self.synth_release[0]: 612 # ignore keys we know we synthesized 613 self.synth_release.pop(0) 614 try: 615 # take the released key out of the gesture 616 self.curr_gesture.removeActionCode(hw_code) 617 except ValueError: 618 pass 619 self._debug('ignored our release', hw_code, event, False) 620 return 621 elif len(self.synth_press): 622 # ignore releases when we're waiting to synth presses 623 self._consumeKey(event, False) 624 # but make sure to synth our own release 625 self._sendKey(hw_code, False) 626 self._debug('ignored release before press', hw_code, event, False) 627 return 628 elif self.last_press: 629 # make a copy of the current gesture before we modify it 630 gesture = AEInput.Gesture(self, gesture=self.curr_gesture) 631 # notify listeners of the gesture and its timestamp 632 self._notifyInputListeners(gesture, event.timestamp) 633 634 # do special handling for stateful keys 635 self._handleStateful(event, False) 636 637 try: 638 # take the released key out of the gesture 639 self.curr_gesture.removeActionCode(hw_code) 640 except ValueError: 641 self._debug('error removing', hw_code, event, False) 642 return 643 644 self.state = self.state(event, False) or self.state 645 self._debug('state machine handled', hw_code, event, False) 646 self.last_press = False
647
648 - def _onForegroundChange(self, event):
649 ''' 650 Resets the internal key state on a window:activate event. This is needed to 651 resolve the problem of system wide hotkey releases going missing. 652 653 @see: U{http://bugzilla.gnome.org/show_bug.cgi?id=104058} 654 @param event: Keyboard key release event 655 @type event: C{pyatspi.event.DeviceEvent} 656 ''' 657 self.resetState()
658
659 - def asString(self, gesture):
660 ''' 661 Gets a string representation of all of the key codes in the given 662 L{AEInput.Gesture} using the L{_keyCodeToKeyName} function 663 664 @param gesture: L{AEInput.Gesture} to render as a string 665 @type gesture: L{AEInput.Gesture} 666 @return: String representation of the provided L{AEInput.Gesture} 667 @rtype: string 668 ''' 669 return ','.join([_keyCodeToKeyName(i) for i in gesture.getActionCodes()])
670 671 # action code constants specific to the Keyboard device (key codes) 672 AEK_ESCAPE = 9 673 AEK_QUESTION = 20 674 AEK_F1 = 67 675 AEK_F2 = 68 676 AEK_F3 = 69 677 AEK_F4 = 70 678 AEK_F5 = 71 679 AEK_F6 = 72 680 AEK_F7 = 73 681 AEK_F8 = 74 682 AEK_F9 = 75 683 AEK_F10 = 76 684 AEK_F11 = 95 685 AEK_F12 = 96 686 AEK_PRINT_SCREEN = 111 # PP: unconfirmed 687 AEK_SCROLL_LOCK = 78 688 AEK_PAUSE = 110 689 AEK_TILDE = 49 690 AEK_1 = 10 691 AEK_2 = 11 692 AEK_3 = 12 693 AEK_4 = 13 694 AEK_5 = 14 695 AEK_6 = 15 696 AEK_7 = 16 697 AEK_8 = 17 698 AEK_9 = 18 699 AEK_0 = 19 700 AEK_MINUS = 20 701 AEK_EQUALS = 21 702 AEK_BACK_SPACE = 22 703 AEK_TAB = 23 704 AEK_Q = 24 705 AEK_W = 25 706 AEK_E = 26 707 AEK_R = 27 708 AEK_T = 28 709 AEK_Y = 29 710 AEK_U = 30 711 AEK_I = 31 712 AEK_O = 32 713 AEK_P = 33 714 AEK_OPEN_BRACKET = 34 715 AEK_CLOSE_BRACKET = 35 716 AEK_BACK_SLASH = 51 717 AEK_CAPS_LOCK = 66 718 AEK_A = 38 719 AEK_S = 39 720 AEK_D = 40 721 AEK_F = 41 722 AEK_G = 42 723 AEK_H = 43 724 AEK_J = 44 725 AEK_K = 45 726 AEK_L = 46 727 AEK_SEMICOLON = 47 728 AEK_QUOTE = 48 729 AEK_ENTER = 36 730 AEK_SHIFT_L = 50 731 AEK_Z = 52 732 AEK_X = 53 733 AEK_C = 54 734 AEK_V = 55 735 AEK_B = 56 736 AEK_N = 57 737 AEK_M = 58 738 AEK_COMMA = 59 739 AEK_PERIOD = 60 740 AEK_SLASH = 61 741 AEK_SHIFT_R = 62 742 AEK_CONTROL_L = 37 743 AEK_ALT_L = 64 744 AEK_SPACE = 65 745 AEK_ALT_R = 113 746 AEK_MENU = 117 747 AEK_CONTROL_R = 109 748 AEK_LEFT = 100 749 AEK_RIGHT = 102 750 AEK_UP = 98 751 AEK_DOWN = 104 752 AEK_PAGE_DOWN = 105 753 AEK_PAGE_UP = 99 754 AEK_DELETE = 107 755 AEK_INSERT = 106 756 AEK_HOME = 97 757 AEK_END = 103 758 AEK_NUM_LOCK = 77 759 AEK_DIVIDE = 112 760 AEK_MULTIPLY = 63 761 AEK_ADD = 86 762 AEK_SUBTRACT = 82 763 AEK_DECIMAL = 91 764 AEK_NUMPAD0 = 90 765 AEK_NUMPAD1 = 87 766 AEK_NUMPAD2 = 88 767 AEK_NUMPAD3 = 89 768 AEK_NUMPAD4 = 83 769 AEK_NUMPAD5 = 84 770 AEK_NUMPAD6 = 85 771 AEK_NUMPAD7 = 79 772 AEK_NUMPAD8 = 80 773 AEK_NUMPAD9 = 81 774 AEK_NUMPAD_ENTER = 108 775 AEK_THINKPAD_FN = 227 776 AEK_THINKPAD_BACK = 234 777 AEK_THINKPAD_FORWARD = 233
778