Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Unified Diff: tools/accessibility/nvda/winapi.py

Issue 660633002: Fixed IAccessibleText::TextAtOffset with IA2_TEXT_BOUNDARY_WORD to return text that spans from the … (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Broke up different boundary tests in their own test cases. Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/accessibility/nvda/winapi.py
diff --git a/tools/accessibility/nvda/winapi.py b/tools/accessibility/nvda/winapi.py
new file mode 100644
index 0000000000000000000000000000000000000000..aeb5e4e11e51a4b79987a6f2498d4026dc850e38
--- /dev/null
+++ b/tools/accessibility/nvda/winapi.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Windows API functions required by tests of Chrome with NVDA."""
+
+
+from ctypes import wintypes
+
+import ctypes
+
+_user = ctypes.windll.user32
+# Argument types for Windows API functions.
+_user.VkKeyScanW.argtypes = [wintypes.WCHAR]
+_user.VkKeyScanW.restype = wintypes.SHORT
+_ENUM_WINDOWS_CALLBACK = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
+_user.EnumWindows.argtypes = [_ENUM_WINDOWS_CALLBACK, wintypes.LPARAM]
+_user.GetWindowThreadProcessId.argtypes = [wintypes.HWND, ctypes.POINTER(wintypes.DWORD)]
+# Flags required by some API calls.
+_MAP_VKCODE_TO_SCAN_CODE = 0
+_PRESS_KEY = 0
+_RELEASE_KEY = 2
+
+_MODIFIER_KEYS = {
+ 'shift': 0x10,
+ 'control': 0x11,
+ 'alt': 0x12,
+ 'windows': 0x5B,
+
+ # Screen reader modifiers.
+ 'insert': 0x2D,
+ 'capslock': 0x14,
+}
+
+_SPECIAL_KEYS = {
+ 'enter': 0x0D,
+ 'space': 0x20,
+ 'tab': 0x09,
+ 'applications': 0x5D, # Context menu key.
+ 'escape': 0x1B,
+ 'backspace': 0x08,
+ 'delete': 0x2E,
+
+ # Navigation keys.
+ 'pageup': 0x21,
+ 'pagedown': 0x22,
+ 'end': 0x23,
+ 'home': 0x24,
+ 'left': 0x25,
+ 'up': 0x26,
+ 'right': 0x27,
+ 'down': 0x28,
+
+ # Browser keys.
+ 'back': 0xA6,
+ 'forward': 0xA7,
+ 'refresh': 0xA8,
+ 'home': 0xAC,
+}
+
+def _getKeyAndScanCode(key):
+ if key[0] == '{' and key[-1] == '}':
+ # This is a modifier or a special key.
+ key = key[1:-1]
+ keyCode = dict(_MODIFIER_KEYS.items() + _SPECIAL_KEYS.items()).get(key)
+ if keyCode is not None:
+ return keyCode, _user.MapVirtualKeyW(keyCode, _MAP_VKCODE_TO_SCAN_CODE)
+ else:
+ raise ValueError, key
+ else:
+ # This is a character to be typed.
+ keyCodes = []
+ retVal = _user.VkKeyScanW(key)
+ modifiers = retVal >> 8 # Upper byte only.
+ keyCode = retVal & 0xFF # Lower byte only.
+ if modifiers == -1 or keyCode == -1:
+ raise ValueError, key
+ if modifiers & 0x1: # Shift key.
+ keyCodes.append(_getKeyAndScanCode('{shift}'))
+ if modifiers & 0x2: # Control key.
+ keyCodes.append(_getKeyAndScanCode('{control}'))
+ if modifiers & 0x4: # Alt key.
+ keyCodes.append(_getKeyAndScanCode('{alt}'))
+ keyCodes.append((keyCode, _user.MapVirtualKeyW(keyCode, _MAP_VKCODE_TO_SCAN_CODE)))
+ return keyCodes
+
+def typeKeys(keys):
+ """Enters the given keys in the active application's input queue.
+
+ The argument to this function should be a string containing a sequence of
+ keys to be pressed. Keys are separated using '+'. Special keys like control
+ should be placed in braces.
+ Examples:
+ Open the Task Manager: winapi.typeKeys('{control}+{shift}{escape}')
+ Read the current line using NVDA: winapi.typeKeys('{insert}{up}')
+ Type a combination of capital and small letters: winapi.typeKeys('TeStIng')
+ """
+ try:
+ pressedModifiers = []
+ for key in keys.split('+'):
+ if key[0] == '{' and key[-1] == '}':
+ # This is a modifier or a special key.
+ keyCode, scanCode = _getKeyAndScanCode(key)
+ _user.keybd_event(keyCode, scanCode, _PRESS_KEY)
+ if key[1:-1] in _MODIFIER_KEYS:
+ pressedModifiers.append((keyCode, scanCode))
+ else:
+ # Key is a sequence of one or more characters.
+ textCodes = [_getKeyAndScanCode(c) for c in key]
+ for charCodes in textCodes:
+ for keyCode, scanCode in charCodes:
+ _user.keybd_event(keyCode, scanCode, _PRESS_KEY)
+ for keyCode, scanCode in reversed(charCodes):
+ _user.keybd_event(keyCode, scanCode, _RELEASE_KEY)
+ except ValueError:
+ raise
+ finally:
+ # Release any modifiers in reverse order.
+ for keyCode, scanCode in reversed(pressedModifiers):
+ _user.keybd_event(keyCode, scanCode, _RELEASE_KEY)
+
+def _getWindowHandleFromProcessId(processId):
+ hWnds = []
+ def enumWindowsCallback(hWnd, lParam):
+ if _isWindowHandleOwnedByProcess(processId, hWnd):
+ hWnds.append(hWnd)
+ return True # Continue enumerating.
+ _user.EnumWindows(_ENUM_WINDOWS_CALLBACK(enumWindowsCallback), 0)
+ return hWnds[0] if len(hWnds) > 0 else None
+
+def _isWindowHandleOwnedByProcess(processId, hWnd):
+ windowProcessId = wintypes.DWORD()
+ if _user.GetWindowThreadProcessId(hWnd, ctypes.byref(windowProcessId)):
+ if windowProcessId.value == processId:
+ return True
+ return False
+
+def focusWindow(processId):
+ hWnd = _getWindowHandleFromProcessId(processId)
+ if hWnd is None:
+ raise ValueError, processId
+ _user.SwitchToThisWindow(hWnd)
+

Powered by Google App Engine
This is Rietveld 408576698