Skip to content

Commit 6ac8549

Browse files
authored
Merge 6bde16e into 178f19d
2 parents 178f19d + 6bde16e commit 6ac8549

5 files changed

Lines changed: 136 additions & 18 deletions

File tree

nvdaHelper/interfaces/nvdaInProcUtils/nvdaInProcUtils.acf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ interface NvdaInProcUtils {
2121
[fault_status,comm_status] winword_moveByLine();
2222
[fault_status,comm_status] sysListView32_getGroupInfo();
2323
[fault_status,comm_status] sysListView32_getColumnContent();
24+
[fault_status,comm_status] sysListView32_getColumnLocation();
25+
[fault_status,comm_status] sysListView32_getColumnHeader();
26+
[fault_status,comm_status] sysListView32_getColumnOrderArray();
2427
[fault_status,comm_status] getActiveObject();
2528
[fault_status,comm_status] dumpOnCrash();
2629
[fault_status,comm_status] IA2Text_findContentDescendant();

nvdaHelper/interfaces/nvdaInProcUtils/nvdaInProcUtils.idl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ interface NvdaInProcUtils {
6868

6969
error_status_t sysListView32_getColumnContent([in] const unsigned long windowHandle, [in] int item, [in] int subItem, [out,string] BSTR* text);
7070

71+
error_status_t sysListView32_getColumnLocation([in] const unsigned long windowHandle, [in] int item, [in] int subItem, [out] RECT* location);
72+
73+
error_status_t sysListView32_getColumnHeader([in] const unsigned long windowHandle, [in] int subItem, [out,string] BSTR* text);
74+
75+
error_status_t sysListView32_getColumnOrderArray([in] const unsigned long windowHandle, [in] const int columnCount, [out,size_is(columnCount)] int* coa);
76+
7177
error_status_t getActiveObject([in] handle_t bindingHandle, [in,string] const wchar_t* progid, [out] IUnknown** ppUnknown);
7278

7379
error_status_t dumpOnCrash([in] handle_t bindingHandle, [in,string] const wchar_t* minidumpPath);

nvdaHelper/local/nvdaHelperLocal.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ EXPORTS
1010
nvdaInProcUtils_unregisterNVDAProcess
1111
nvdaInProcUtils_sysListView32_getGroupInfo
1212
nvdaInProcUtils_sysListView32_getColumnContent
13+
nvdaInProcUtils_sysListView32_getColumnLocation
14+
nvdaInProcUtils_sysListView32_getColumnHeader
15+
nvdaInProcUtils_sysListView32_getColumnOrderArray
1316
nvdaInProcUtils_dumpOnCrash
1417
nvdaInProcUtils_IA2Text_findContentDescendant
1518
nvdaInProcUtils_getTextFromIAccessible

nvdaHelper/remote/sysListView32.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2020 NV Access Limited, Leonard de Ruijter.
4+
Copyright 2006-2022 NV Access Limited, Leonard de Ruijter.
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -59,3 +59,46 @@ error_status_t nvdaInProcUtils_sysListView32_getColumnContent(handle_t bindingHa
5959
*text = SysAllocString(lvItem.pszText);
6060
return 0;
6161
}
62+
63+
error_status_t nvdaInProcUtils_sysListView32_getColumnLocation(handle_t bindingHandle, const unsigned long windowHandle, int item, int subItem, RECT* location) {
64+
RECT localRect {
65+
// Returns the bounding rectangle of the entire item, including the icon and label.
66+
LVIR_LABEL, // left
67+
// According to Microsoft, top should be the one-based index of the subitem.
68+
// However, indexes coming from LVM_GETCOLUMNORDERARRAY are zero based.
69+
subItem // top
70+
};
71+
if (!SendMessage((HWND)UlongToHandle(windowHandle), LVM_GETSUBITEMRECT, (WPARAM)item, (LPARAM)&localRect)) {
72+
LOG_DEBUGWARNING(L"LVM_GETSUBITEMRECT failed");
73+
return 1;
74+
}
75+
*location = localRect;
76+
return 0;
77+
}
78+
79+
error_status_t nvdaInProcUtils_sysListView32_getColumnHeader(handle_t bindingHandle, const unsigned long windowHandle, int subItem, BSTR* text) {
80+
LVCOLUMN lvColumn = {0};
81+
lvColumn.mask = LVCF_TEXT;
82+
lvColumn.iSubItem = subItem;
83+
lvColumn.cchTextMax = CBEMAXSTRLEN;
84+
wchar_t textBuf[CBEMAXSTRLEN]{}; // Ensure that the array initialised with all zero values ('\0')
85+
lvColumn.pszText= textBuf;
86+
if (!SendMessage((HWND)UlongToHandle(windowHandle), LVM_GETCOLUMN, (WPARAM)subItem, (LPARAM)&lvColumn)) {
87+
LOG_DEBUGWARNING(L"LVM_GETCOLUMN failed");
88+
return 1;
89+
}
90+
if(!lvColumn.pszText) {
91+
LOG_DEBUGWARNING(L"LVM_GETCOLUMN didn't retrieve any text");
92+
return 1;
93+
}
94+
*text = SysAllocString(lvColumn.pszText);
95+
return 0;
96+
}
97+
98+
error_status_t nvdaInProcUtils_sysListView32_getColumnOrderArray(handle_t bindingHandle, const unsigned long windowHandle, const int columnCount, int* coa) {
99+
if (!SendMessage((HWND)UlongToHandle(windowHandle), LVM_GETCOLUMNORDERARRAY, (WPARAM)columnCount, (LPARAM)coa)) {
100+
LOG_DEBUGWARNING(L"LVM_GETCOLUMNORDERARRAY failed");
101+
return 1;
102+
}
103+
return 0;
104+
}

source/NVDAObjects/IAccessible/sysListView32.py

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import config
2424
from locationHelper import RectLTRB
2525
from logHandler import log
26+
from typing import Optional
2627

2728
#Window messages
2829
LVM_FIRST=0x1000
@@ -228,13 +229,31 @@ def _get_columnCount(self):
228229
return 1
229230
return count
230231

231-
def _get__columnOrderArray(self):
232-
coa=(c_int *self.columnCount)()
232+
def _getColumnOrderArrayRaw(self, columnCount: int):
233+
coa = (ctypes.c_int * columnCount)()
234+
res = watchdog.cancellableExecute(
235+
NVDAHelper.localLib.nvdaInProcUtils_sysListView32_getColumnOrderArray,
236+
self.appModule.helperLocalBindingHandle,
237+
self.windowHandle,
238+
columnCount,
239+
coa
240+
)
241+
if res:
242+
return None
243+
return coa
244+
245+
def _getColumnOrderArrayRawOutProc(self, columnCount: int):
246+
coa = (ctypes.c_int * columnCount)()
233247
processHandle=self.processHandle
234248
internalCoa=winKernel.virtualAllocEx(processHandle,None,sizeof(coa),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
235249
try:
236250
winKernel.writeProcessMemory(processHandle,internalCoa,byref(coa),sizeof(coa),None)
237-
res = watchdog.cancellableSendMessage(self.windowHandle,LVM_GETCOLUMNORDERARRAY, self.columnCount, internalCoa)
251+
res = watchdog.cancellableSendMessage(
252+
self.windowHandle,
253+
LVM_GETCOLUMNORDERARRAY,
254+
columnCount,
255+
internalCoa
256+
)
238257
if res:
239258
winKernel.readProcessMemory(processHandle,internalCoa,byref(coa),sizeof(coa),None)
240259
else:
@@ -243,6 +262,12 @@ def _get__columnOrderArray(self):
243262
winKernel.virtualFreeEx(processHandle,internalCoa,0,winKernel.MEM_RELEASE)
244263
return coa
245264

265+
def _get__columnOrderArray(self):
266+
if not self.appModule.helperLocalBindingHandle:
267+
return self._getColumnOrderArrayRawOutProc(self.columnCount)
268+
return self._getColumnOrderArrayRaw(self.columnCount)
269+
270+
246271
class GroupingItem(Window):
247272

248273
def __init__(self,windowHandle=None,parentNVDAObject=None,groupInfo=None):
@@ -321,7 +346,22 @@ def event_stateChange(self):
321346

322347
class ListItem(RowWithFakeNavigation, RowWithoutCellObjects, ListItemWithoutColumnSupport):
323348

324-
def _getColumnLocationRaw(self,index):
349+
def _getColumnLocationRaw(self, index: int) -> ctypes.wintypes.RECT:
350+
item = self.IAccessibleChildID - 1
351+
subItem = index
352+
rect = ctypes.wintypes.RECT()
353+
if watchdog.cancellableExecute(
354+
NVDAHelper.localLib.nvdaInProcUtils_sysListView32_getColumnLocation,
355+
self.appModule.helperLocalBindingHandle,
356+
self.windowHandle,
357+
item,
358+
subItem,
359+
ctypes.byref(rect)
360+
) != 0:
361+
return None
362+
return rect
363+
364+
def _getColumnLocationRawOutProc(self, index: int) -> ctypes.wintypes.RECT:
325365
processHandle=self.processHandle
326366
# LVM_GETSUBITEMRECT requires a pointer to a RECT structure that will receive the subitem bounding rectangle information.
327367
localRect=RECT(
@@ -353,24 +393,31 @@ def _getColumnLocationRaw(self,index):
353393
if res == 0:
354394
log.debugWarning(f"LVM_GETSUBITEMRECT failed for index {index} in list")
355395
return None
396+
return localRect
397+
398+
def _getColumnLocation(self, column: int) -> Optional[RectLTRB]:
399+
index = self.parent._columnOrderArray[column - 1]
400+
if not self.appModule.helperLocalBindingHandle:
401+
rect = self._getColumnLocationRawOutProc(index)
402+
else:
403+
rect = self._getColumnLocationRaw(index)
404+
if rect is None:
405+
return None
356406
# #8268: this might be a malformed rectangle
357407
# (i.e. with a left coordinate that is greater than the right coordinate).
358408
# This happens in Becky! Internet Mail,
359409
# as well in applications that expose zero width columns.
360-
left = localRect.left
361-
top = localRect.top
362-
right = localRect.right
363-
bottom = localRect.bottom
410+
left = rect.left
411+
top = rect.top
412+
right = rect.right
413+
bottom = rect.bottom
364414
if left > right:
365415
left = right
366416
if top > bottom:
367417
top = bottom
368418
return RectLTRB(left, top, right, bottom).toScreen(self.windowHandle).toLTWH()
369419

370-
def _getColumnLocation(self,column):
371-
return self._getColumnLocationRaw(self.parent._columnOrderArray[column - 1])
372-
373-
def _getColumnContentRaw(self, index):
420+
def _getColumnContentRaw(self, index: int) -> Optional[str]:
374421
item = self.IAccessibleChildID - 1
375422
subItem = index
376423
text = AutoFreeBSTR()
@@ -385,7 +432,7 @@ def _getColumnContentRaw(self, index):
385432
return None
386433
return text.value
387434

388-
def _getColumnContentRawOutProc(self, index):
435+
def _getColumnContentRawOutProc(self, index: int) -> Optional[str]:
389436
buffer=None
390437
processHandle=self.processHandle
391438
internalItem=winKernel.virtualAllocEx(processHandle,None,sizeof(self.LVITEM),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
@@ -405,7 +452,7 @@ def _getColumnContentRawOutProc(self, index):
405452
winKernel.virtualFreeEx(processHandle,internalItem,0,winKernel.MEM_RELEASE)
406453
return buffer.value if buffer else None
407454

408-
def _getColumnContent(self, column):
455+
def _getColumnContent(self, column: int) -> Optional[str]:
409456
index = self.parent._columnOrderArray[column - 1]
410457
if not self.appModule.helperLocalBindingHandle:
411458
return self._getColumnContentRawOutProc(index)
@@ -428,7 +475,7 @@ def _getColumnImageIDRaw(self, index):
428475
def _getColumnImageID(self, column):
429476
return self._getColumnImageIDRaw(self.parent._columnOrderArray[column - 1])
430477

431-
def _getColumnHeaderRaw(self,index):
478+
def _getColumnHeaderRawOutProc(self, index: int) -> Optional[str]:
432479
buffer=None
433480
processHandle=self.processHandle
434481
internalColumn=winKernel.virtualAllocEx(processHandle,None,sizeof(self.LVCOLUMN),winKernel.MEM_COMMIT,winKernel.PAGE_READWRITE)
@@ -448,8 +495,24 @@ def _getColumnHeaderRaw(self,index):
448495
winKernel.virtualFreeEx(processHandle,internalColumn,0,winKernel.MEM_RELEASE)
449496
return buffer.value if buffer else None
450497

451-
def _getColumnHeader(self, column):
452-
return self._getColumnHeaderRaw(self.parent._columnOrderArray[column - 1])
498+
def _getColumnHeaderRaw(self, index: int) -> Optional[str]:
499+
subItem = index
500+
text = AutoFreeBSTR()
501+
if watchdog.cancellableExecute(
502+
NVDAHelper.localLib.nvdaInProcUtils_sysListView32_getColumnHeader,
503+
self.appModule.helperLocalBindingHandle,
504+
self.windowHandle,
505+
subItem,
506+
ctypes.byref(text)
507+
) != 0:
508+
return None
509+
return text.value
510+
511+
def _getColumnHeader(self, column: int) -> Optional[str]:
512+
index = self.parent._columnOrderArray[column - 1]
513+
if not self.appModule.helperLocalBindingHandle:
514+
return self._getColumnHeaderRawOutProc(index)
515+
return self._getColumnHeaderRaw(index)
453516

454517
def _get_name(self):
455518
parent = self.parent

0 commit comments

Comments
 (0)