Skip to content

Commit

Permalink
make approach more robust
Browse files Browse the repository at this point in the history
  • Loading branch information
seanbudd committed Dec 8, 2022
1 parent 7070762 commit f8fb374
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 16 deletions.
1 change: 1 addition & 0 deletions source/nvda.pyw
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ def _serviceDebugEnabled() -> bool:
if winreg.QueryValueEx(k, "serviceDebug")[0]:
return True
except WindowsError:
# Expected state by default, serviceDebug parameter not set
pass
return False

Expand Down
40 changes: 33 additions & 7 deletions source/utils/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,29 @@ def isObjectAboveLockScreen(obj: "NVDAObjects.NVDAObject") -> bool:
return obj.isAboveLockScreen


def _checkWindowsForAppModules():
from ctypes import c_bool, WINFUNCTYPE, c_int, POINTER, windll # TODO move and order
from ctypes.wintypes import LPARAM
import appModuleHandler
# BOOL CALLBACK EnumWindowsProc _In_ HWND,_In_ LPARAM
# HWND as a pointer creates confusion, treat as an int
# http://makble.com/the-story-of-lpclong
@WINFUNCTYPE(c_bool, c_int, POINTER(c_int))
def _appModuleHandlerUpdate(hwnd: winUser.HWNDVal, _lParam: LPARAM) -> bool:
processID, _threadID = winUser.getWindowThreadProcessID(hwnd)
appModuleHandler.update(processID)
return True

if not windll.user32.EnumWindows(_appModuleHandlerUpdate, 0):
log.error("Failed search for lockapp App Module")


def _findLockAppModule() -> Optional["appModuleHandler.AppModule"]:
import appModuleHandler
runningAppModules = appModuleHandler.runningTable.values()
return next(filter(_isLockAppAndAlive, runningAppModules), None)


def _isObjectAboveLockScreen(obj: "NVDAObjects.NVDAObject") -> bool:
"""
When Windows is locked, the foreground Window is usually LockApp,
Expand All @@ -193,10 +216,10 @@ def _isObjectAboveLockScreen(obj: "NVDAObjects.NVDAObject") -> bool:
):
return True

import appModuleHandler
runningAppModules = appModuleHandler.runningTable.values()
lockAppModule = next(filter(_isLockAppAndAlive, runningAppModules), None)

lockAppModule = _findLockAppModule()
if lockAppModule is None:
_checkWindowsForAppModules()
lockAppModule = _findLockAppModule()
if lockAppModule is None:
# lockAppModule not running/registered by NVDA yet
log.debug(
Expand Down Expand Up @@ -253,14 +276,17 @@ def _isWindowAboveWindowMatchesCond(
"""
aboveWindow = winUser.getWindow(targetWindow, winUser.GW_HWNDPREV)
belowWindow = winUser.getWindow(targetWindow, winUser.GW_HWNDNEXT)
while aboveWindow or belowWindow:
while (
aboveWindow != winUser.GW_RESULT_NOT_FOUND
or belowWindow != winUser.GW_RESULT_NOT_FOUND
):
if matchCond(belowWindow): # target window is above the found window
return True
elif matchCond(aboveWindow): # found window is above the target window
return False
if aboveWindow:
if aboveWindow != winUser.GW_RESULT_NOT_FOUND:
aboveWindow = winUser.getWindow(aboveWindow, winUser.GW_HWNDPREV)
if belowWindow:
if belowWindow != winUser.GW_RESULT_NOT_FOUND:
belowWindow = winUser.getWindow(belowWindow, winUser.GW_HWNDNEXT)
raise _WindowNotFoundError(f"Window not found matching condition {matchCond}")

Expand Down
9 changes: 8 additions & 1 deletion source/winUser.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,17 @@ class GUITHREADINFO(Structure):
GWL_ID=-12
GWL_STYLE=-16
GWL_EXSTYLE=-20
#getWindow

# getWindow: TODO turn to enum
GW_HWNDNEXT=2
GW_HWNDPREV=3
GW_OWNER=4
GW_RESULT_NOT_FOUND = 0
"""
When GetWindow returns 0, it means the window has not been found.
For example the last window has been reached, or an error has occurred.
"""

# SetLayeredWindowAttributes
LWA_ALPHA = 2
LWA_COLORKEY = 1
Expand Down
10 changes: 2 additions & 8 deletions tests/unit/test_util/test_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,13 @@ def _getWindow_patched(self, hwnd: winUser.HWNDVal, relation: int) -> int:
"""Fetch current window, find adjacent window by relation."""
currentWindowIndex = self._windows.index(hwnd)
if relation == winUser.GW_HWNDNEXT:
try:
nextIndex = currentWindowIndex + 1
except IndexError:
return 0
elif relation == winUser.GW_HWNDPREV:
try:
nextIndex = currentWindowIndex - 1
except IndexError:
return 0
else:
return 0
return winUser.GW_RESULT_NOT_FOUND
if nextIndex >= len(self._windows) or nextIndex < 0:
return 0
return winUser.GW_RESULT_NOT_FOUND
return self._windows[nextIndex]

def _windowMatches(self, expectedWindow: int):
Expand Down

0 comments on commit f8fb374

Please sign in to comment.