Skip to content

Commit 3932596

Browse files
authored
Merge 724dae7 into 81d81dc
2 parents 81d81dc + 724dae7 commit 3932596

7 files changed

Lines changed: 62 additions & 133 deletions

File tree

source/NVDAObjects/IAccessible/MSHTML.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from .. import InvalidNVDAObject
2828
from ..window import Window
2929
from NVDAObjects.UIA import UIA, UIATextInfo
30-
from locationHelper import RectLTRB, Point
30+
from locationHelper import RectLTRB
3131
from typing import Dict
3232

3333
IID_IHTMLElement=comtypes.GUID('{3050F1FF-98B5-11CF-BB82-00AA00BDCE0B}')
@@ -487,20 +487,14 @@ def kwargsFromSuper(cls,kwargs,relation=None):
487487

488488
elif isinstance(relation,tuple):
489489
windowHandle=kwargs.get('windowHandle')
490-
if not windowHandle:
491-
log.debugWarning("Error converting point to client coordinates, no window handle")
492-
return False
493-
try:
494-
point = Point(*relation).toClient(windowHandle)
495-
except WindowsError:
496-
log.debugWarning("Error converting point to client coordinates", exc_info=True)
497-
return False
490+
p=ctypes.wintypes.POINT(x=relation[0],y=relation[1])
491+
ctypes.windll.user32.ScreenToClient(windowHandle,ctypes.byref(p))
498492
# #3494: MSHTML's internal coordinates are always at a hardcoded DPI (usually 96) no matter the system DPI or zoom level.
499493
xFactor,yFactor=getZoomFactorsFromHTMLDocument(HTMLNode.document)
500494
try:
501-
HTMLNode = HTMLNode.document.elementFromPoint(point.x // xFactor, point.y // yFactor)
495+
HTMLNode=HTMLNode.document.elementFromPoint(p.x // xFactor, p.y // yFactor)
502496
except:
503-
HTMLNode = None
497+
HTMLNode=None
504498
if not HTMLNode:
505499
log.debugWarning("Error getting HTMLNode with elementFromPoint")
506500
return False

source/NVDAObjects/window/__init__.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,18 +202,12 @@ def _get_displayText(self):
202202

203203
def redraw(self):
204204
"""Redraw the display for this object.
205-
@raise WindowsError: If redrawing fails.
206205
"""
207-
# Conversion to client coordinates may fail if the window handle of this object is incorrect.
208-
# This will most likely be caused by a died window.
209-
location = self.location.toClient(self.windowHandle)
210-
if not winUser.RedrawWindow(
211-
self.windowHandle,
212-
location.toRECT(),
213-
None,
214-
winUser.RDW_INVALIDATE | winUser.RDW_UPDATENOW
215-
):
216-
raise ctypes.WinError()
206+
left, top, width, height = self.location
207+
left, top = winUser.ScreenToClient(self.windowHandle, left, top)
208+
winUser.RedrawWindow(self.windowHandle,
209+
winUser.RECT(left, top, left + width, top + height), None,
210+
winUser.RDW_INVALIDATE | winUser.RDW_UPDATENOW)
217211

218212
def _get_windowText(self):
219213
textLength=watchdog.cancellableSendMessage(self.windowHandle,winUser.WM_GETTEXTLENGTH,0,0)
@@ -410,8 +404,6 @@ class DisplayModelLiveText(LiveText, Window):
410404

411405
def startMonitoring(self):
412406
# Force the window to be redrawn, as our display model might be out of date.
413-
# Do not catch exceptions caused by redraw, as when redrawing fails,
414-
# it is most likely that the window died, and we don't want to monitor in that case.
415407
self.redraw()
416408
displayModel.requestTextChangeNotifications(self, True)
417409
super(DisplayModelLiveText, self).startMonitoring()

source/NVDAObjects/window/edit.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,18 +180,11 @@ def _getPointFromOffset(self,offset):
180180
if point.x <0 or point.y <0:
181181
raise LookupError("Point with client coordinates x=%d, y=%d not within client area of object" %
182182
(point.x, point.y))
183-
try:
184-
return point.toScreen(self.obj.windowHandle)
185-
except WindowsError as e:
186-
raise LookupError(
187-
f"Couldn't convert point at offset {offset} to screen coordinates: {e.strerror}"
188-
)
183+
return point.toScreen(self.obj.windowHandle)
184+
189185

190186
def _getOffsetFromPoint(self,x,y):
191-
try:
192-
x, y = winUser.ScreenToClient(self.obj.windowHandle, x, y)
193-
except WindowsError as e:
194-
raise LookupError(f"Couldn't convert point ({x},{y}) to client coordinates: {e.strerror}")
187+
x, y = winUser.ScreenToClient(self.obj.windowHandle, x, y)
195188
if self.obj.editAPIVersion>=1:
196189
processHandle=self.obj.processHandle
197190
internalP=winKernel.virtualAllocEx(processHandle,None,ctypes.sizeof(PointLStruct),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)

source/displayModel.py

Lines changed: 24 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import watchdog
2222
from logHandler import log
2323
import windowUtils
24-
from locationHelper import RectLTRB, RectLTWH, Point
24+
from locationHelper import RectLTRB, RectLTWH
2525
import textUtils
2626
from typing import Union, List, Tuple
2727

@@ -300,31 +300,23 @@ def _get__storyFieldsAndRects(self) -> Tuple[
300300
List[int]
301301
]:
302302
# All returned coordinates are logical coordinates.
303-
location = self._location if self._location else self.obj.location
304-
if location is None or not any(location):
305-
# No location; nothing we can do.
306-
return [], [], [], []
303+
if self._location:
304+
left, top, right, bottom = self._location
305+
else:
306+
try:
307+
left, top, width, height = self.obj.location
308+
except TypeError:
309+
# No location; nothing we can do.
310+
return [], [], [], []
311+
right = left + width
312+
bottom = top + height
307313
bindingHandle=self.obj.appModule.helperLocalBindingHandle
308314
if not bindingHandle:
309315
log.debugWarning("AppModule does not have a binding handle")
310316
return [], [], [], []
311-
try:
312-
location = location.toLogical(self.obj.windowHandle)
313-
except RuntimeError:
314-
log.exception()
315-
return [], [], [], []
316-
text, rects = getWindowTextInRect(
317-
bindingHandle,
318-
self.obj.windowHandle,
319-
location.left,
320-
location.top,
321-
location.right,
322-
location.bottom,
323-
self.minHorizontalWhitespace,
324-
self.minVerticalWhitespace,
325-
self.stripOuterWhitespace,
326-
self.includeDescendantWindows
327-
)
317+
left,top=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,left,top)
318+
right,bottom=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,right,bottom)
319+
text,rects=getWindowTextInRect(bindingHandle, self.obj.windowHandle, left, top, right, bottom, self.minHorizontalWhitespace, self.minVerticalWhitespace,self.stripOuterWhitespace,self.includeDescendantWindows)
328320
if not text:
329321
return [], [], [], []
330322
text="<control>%s</control>"%text
@@ -452,29 +444,15 @@ def _normalizeFormatField(self,field):
452444

453445
def _getOffsetFromPoint(self, x, y):
454446
# Accepts physical coordinates.
455-
try:
456-
x, y = windowUtils.physicalToLogicalPoint(
457-
self.obj.windowHandle,
458-
x,
459-
y
460-
)
461-
except RuntimeError:
462-
raise LookupError("physicalToLogicalPoint failed")
447+
x,y=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,x,y)
463448
for charOffset, (charLeft, charTop, charRight, charBottom) in enumerate(self._storyFieldsAndRects[1]):
464449
if charLeft<=x<charRight and charTop<=y<charBottom:
465450
return charOffset
466451
raise LookupError
467452

468453
def _getClosestOffsetFromPoint(self,x,y):
469454
# Accepts physical coordinates.
470-
try:
471-
x, y = windowUtils.physicalToLogicalPoint(
472-
self.obj.windowHandle,
473-
x,
474-
y
475-
)
476-
except RuntimeError:
477-
raise LookupError("physicalToLogicalPoint failed")
455+
x,y=windowUtils.physicalToLogicalPoint(self.obj.windowHandle,x,y)
478456
#Enumerate the character rectangles
479457
a=enumerate(self._storyFieldsAndRects[1])
480458
#Convert calculate center points for all the rectangles
@@ -492,14 +470,7 @@ def _getBoundingRectFromOffset(self, offset):
492470
rects=self._storyFieldsAndRects[1]
493471
if not rects or offset>=len(rects):
494472
raise LookupError
495-
rect = rects[offset].toLTWH()
496-
try:
497-
rect = rect.toPhysical(self.obj.windowHandle)
498-
except RuntimeError:
499-
raise LookupError(
500-
f"Couldn't convert character rectangle at offset {offset} to physical coordinates"
501-
)
502-
return rect
473+
return rects[offset].toPhysical(self.obj.windowHandle).toLTWH()
503474

504475
def _getNVDAObjectFromOffset(self,offset):
505476
try:
@@ -591,15 +562,7 @@ def _get_boundingRects(self):
591562
for lineEndOffset in lineEndOffsets:
592563
startOffset=endOffset
593564
endOffset=lineEndOffset
594-
lineRect = RectLTWH.fromCollection(*self._storyFieldsAndRects[1][startOffset:endOffset])
595-
try:
596-
lineRect = lineRect.toPhysical(self.obj.windowHandle)
597-
except RuntimeError:
598-
raise LookupError(
599-
f"Couldn't convert line rectangle at offsets {startOffset} to {endOffset} "
600-
"to physical coordinates"
601-
)
602-
rects.append(lineRect)
565+
rects.append(RectLTWH.fromCollection(*self._storyFieldsAndRects[1][startOffset:endOffset]).toPhysical(self.obj.windowHandle))
603566
return rects
604567

605568
def _getFirstVisibleOffset(self):
@@ -643,12 +606,7 @@ def _findCaretOffsetFromLocation(
643606
def _getCaretOffset(self):
644607
caretRect = getCaretRect(self.obj)
645608
objLocation = self.obj.location
646-
try:
647-
objRect = objLocation.toLTRB().toLogical(self.obj.windowHandle)
648-
except RuntimeError:
649-
raise RuntimeError(
650-
"Couldn't convert object location to logical coordinates when getting caret offset"
651-
)
609+
objRect = objLocation.toLTRB().toLogical(self.obj.windowHandle)
652610
caretRect = caretRect.intersection(objRect)
653611
if not any(caretRect):
654612
raise RuntimeError("The caret rectangle does not overlap with the window")
@@ -673,14 +631,11 @@ def _setCaretOffset(self,offset):
673631
if offset>=len(rects):
674632
raise RuntimeError("offset %d out of range")
675633
rect = rects[offset]
676-
# Place the cursor at the left coordinate of the character, vertically centered.
677-
point = Point(rect.left, rect.center.y)
678-
try:
679-
point = point.toPhysical(self.obj.windowHandle)
680-
except RuntimeError:
681-
raise RuntimeError("Conversion to physical coordinates failed when setting caret offset")
682-
oldX, oldY = winUser.getCursorPos()
683-
winUser.setCursorPos(*point)
634+
x = rect.left
635+
y= rect.center.y
636+
x,y=windowUtils.logicalToPhysicalPoint(self.obj.windowHandle,x,y)
637+
oldX,oldY=winUser.getCursorPos()
638+
winUser.setCursorPos(x,y)
684639
mouseHandler.executeMouseEvent(winUser.MOUSEEVENTF_LEFTDOWN,0,0)
685640
mouseHandler.executeMouseEvent(winUser.MOUSEEVENTF_LEFTUP,0,0)
686641
winUser.setCursorPos(oldX,oldY)

source/locationHelper.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -254,24 +254,18 @@ def toRECT(self):
254254
return RECT(self.left,self.top,self.right,self.bottom)
255255

256256
def toLogical(self, hwnd):
257-
try:
258-
left, top = self.topLeft.toLogical(hwnd)
259-
right, bottom = self.bottomRight.toLogical(hwnd)
260-
except RuntimeError:
261-
raise RuntimeError(f"Couldn't convert {self} to logical coordinates")
257+
left,top=self.topLeft.toLogical(hwnd)
258+
right,bottom=self.bottomRight.toLogical(hwnd)
262259
if isinstance(self, RectLTWH):
263-
return RectLTWH(left, top, right - left, bottom - top)
264-
return RectLTRB(left, top, right, bottom)
260+
return RectLTWH(left,top,right-left,bottom-top)
261+
return RectLTRB(left,top,right,bottom)
265262

266263
def toPhysical(self, hwnd):
267-
try:
268-
left, top = self.topLeft.toPhysical(hwnd)
269-
right, bottom = self.bottomRight.toPhysical(hwnd)
270-
except RuntimeError:
271-
raise RuntimeError(f"Couldn't convert {self} to physical coordinates")
264+
left,top=self.topLeft.toPhysical(hwnd)
265+
right,bottom=self.bottomRight.toPhysical(hwnd)
272266
if isinstance(self, RectLTWH):
273-
return RectLTWH(left, top, right - left, bottom - top)
274-
return RectLTRB(left, top, right, bottom)
267+
return RectLTWH(left,top,right-left,bottom-top)
268+
return RectLTRB(left,top,right,bottom)
275269

276270
def toClient(self, hwnd):
277271
left, top =self.topLeft.toClient(hwnd)
@@ -280,7 +274,7 @@ def toClient(self, hwnd):
280274
return RectLTRB(left, top, left+self.width, top+self.height)
281275

282276
def toScreen(self, hwnd):
283-
left, top = self.topLeft.toScreen(hwnd)
277+
left,top=self.topLeft.toScreen(hwnd)
284278
if isinstance(self, RectLTWH):
285279
return RectLTWH(left, top, self.width, self.height)
286280
return RectLTRB(left, top, left+self.width, top+self.height)

source/winUser.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -609,14 +609,12 @@ def VkKeyScanEx(ch, hkl):
609609

610610
def ScreenToClient(hwnd, x, y):
611611
point = POINT(x, y)
612-
if not user32.ScreenToClient(hwnd, byref(point)):
613-
raise WinError()
612+
user32.ScreenToClient(hwnd, byref(point))
614613
return point.x, point.y
615614

616615
def ClientToScreen(hwnd, x, y):
617616
point = POINT(x, y)
618-
if not user32.ClientToScreen(hwnd, byref(point)):
619-
raise WinError()
617+
user32.ClientToScreen(hwnd, byref(point))
620618
return point.x, point.y
621619

622620
def NotifyWinEvent(event, hwnd, idObject, idChild):

source/windowUtils.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,14 @@ def callback(window, data):
5454
_logicalToPhysicalPoint = ctypes.windll.user32.LogicalToPhysicalPointForPerMonitorDPI
5555
_physicalToLogicalPoint = ctypes.windll.user32.PhysicalToLogicalPointForPerMonitorDPI
5656
except AttributeError:
57-
# Windows Vista..Windows 8
58-
_logicalToPhysicalPoint = ctypes.windll.user32.LogicalToPhysicalPoint
59-
_physicalToLogicalPoint = ctypes.windll.user32.PhysicalToLogicalPoint
57+
try:
58+
# Windows Vista..Windows 8
59+
_logicalToPhysicalPoint = ctypes.windll.user32.LogicalToPhysicalPoint
60+
_physicalToLogicalPoint = ctypes.windll.user32.PhysicalToLogicalPoint
61+
except AttributeError:
62+
# Windows <= XP
63+
_logicalToPhysicalPoint = None
64+
_physicalToLogicalPoint = None
6065

6166
def logicalToPhysicalPoint(window, x, y):
6267
"""Converts the logical coordinates of a point in a window to physical coordinates.
@@ -69,11 +74,10 @@ def logicalToPhysicalPoint(window, x, y):
6974
@return: The physical x and y coordinates.
7075
@rtype: tuple of (int, int)
7176
"""
77+
if not _logicalToPhysicalPoint:
78+
return x, y
7279
point = ctypes.wintypes.POINT(x, y)
73-
if not _logicalToPhysicalPoint(window, ctypes.byref(point)):
74-
raise RuntimeError(
75-
f"Couldn't convert point(x={x}, y={y}) from logical to physical coordinates for window {window}"
76-
)
80+
_logicalToPhysicalPoint(window, ctypes.byref(point))
7781
return point.x, point.y
7882

7983
def physicalToLogicalPoint(window, x, y):
@@ -87,11 +91,10 @@ def physicalToLogicalPoint(window, x, y):
8791
@return: The logical x and y coordinates.
8892
@rtype: tuple of (int, int)
8993
"""
94+
if not _physicalToLogicalPoint:
95+
return x, y
9096
point = ctypes.wintypes.POINT(x, y)
91-
if not _physicalToLogicalPoint(window, ctypes.byref(point)):
92-
raise RuntimeError(
93-
f"Couldn't convert point(x={x}, y={y}) from physical to logical coordinates for window {window}"
94-
)
97+
_physicalToLogicalPoint(window, ctypes.byref(point))
9598
return point.x, point.y
9699

97100
DEFAULT_DPI_LEVEL = 96.0

0 commit comments

Comments
 (0)