@bobfrankston/winpos 2.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +20 -0
- package/.gitattributes +16 -0
- package/DEVELOPMENT.md +148 -0
- package/README.md +126 -0
- package/ffi-wrapper.d.ts +45 -0
- package/ffi-wrapper.d.ts.map +1 -0
- package/ffi-wrapper.js +172 -0
- package/ffi-wrapper.js.map +1 -0
- package/ffi-wrapper.ts +213 -0
- package/ignores.txt +75 -0
- package/index.d.ts +12 -0
- package/index.d.ts.map +1 -0
- package/index.js +213 -0
- package/index.js.map +1 -0
- package/index.ts +294 -0
- package/package.json +41 -0
- package/screens.d.ts +18 -0
- package/screens.d.ts.map +1 -0
- package/screens.js +83 -0
- package/screens.js.map +1 -0
- package/screens.ts +101 -0
- package/tabs.d.ts +42 -0
- package/tabs.d.ts.map +1 -0
- package/tabs.js +115 -0
- package/tabs.js.map +1 -0
- package/tabs.ts +133 -0
- package/tsconfig.json +28 -0
- package/windows.d.ts +51 -0
- package/windows.d.ts.map +1 -0
- package/windows.js +170 -0
- package/windows.js.map +1 -0
- package/windows.ts +200 -0
package/tabs.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tab enumeration support using Windows UI Automation API
|
|
3
|
+
*
|
|
4
|
+
* NOTE: Tab enumeration is application-specific and not all apps expose tabs
|
|
5
|
+
* through Windows APIs. This module uses UI Automation to attempt to find tabs.
|
|
6
|
+
*
|
|
7
|
+
* Windows Terminal, Chrome, Edge, and other modern apps may expose tabs via
|
|
8
|
+
* UI Automation, but success varies by application.
|
|
9
|
+
*/
|
|
10
|
+
import { isBun } from './ffi-wrapper.js';
|
|
11
|
+
let uiAutomation = null;
|
|
12
|
+
async function initializeUIAutomation() {
|
|
13
|
+
if (isBun) {
|
|
14
|
+
// Bun doesn't have good COM support yet
|
|
15
|
+
console.warn('Tab enumeration not supported in Bun runtime');
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
// UI Automation requires COM interop which is complex with koffi
|
|
20
|
+
// For now, return null - this would require significant additional work
|
|
21
|
+
// with COM initialization, IUIAutomation interface, etc.
|
|
22
|
+
// Potential approach:
|
|
23
|
+
// 1. Load oleaut32.dll and ole32.dll
|
|
24
|
+
// 2. Call CoInitialize/CoInitializeEx
|
|
25
|
+
// 3. Create IUIAutomation instance via CoCreateInstance
|
|
26
|
+
// 4. Use FindFirst/FindAll to locate tab controls
|
|
27
|
+
// 5. Read properties from IUIAutomationElement
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error('Failed to initialize UI Automation:', error.message);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Attempt to enumerate tabs for a window
|
|
37
|
+
*
|
|
38
|
+
* @param hwnd Window handle
|
|
39
|
+
* @returns Array of tab information, or null if not supported/available
|
|
40
|
+
*
|
|
41
|
+
* NOTE: This is a placeholder for future implementation. Tab enumeration
|
|
42
|
+
* requires COM interop with UI Automation API which is complex with FFI.
|
|
43
|
+
*
|
|
44
|
+
* For now, this returns null. A full implementation would require:
|
|
45
|
+
* - COM initialization (CoInitialize)
|
|
46
|
+
* - IUIAutomation interface
|
|
47
|
+
* - Element tree traversal
|
|
48
|
+
* - Property reading from automation elements
|
|
49
|
+
*/
|
|
50
|
+
export async function enumerateTabs(hwnd) {
|
|
51
|
+
if (!uiAutomation) {
|
|
52
|
+
uiAutomation = await initializeUIAutomation();
|
|
53
|
+
}
|
|
54
|
+
if (!uiAutomation) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
// TODO: Implement UI Automation traversal
|
|
58
|
+
// This would involve:
|
|
59
|
+
// 1. Get root element from window handle
|
|
60
|
+
// 2. Search for elements with ControlType_Tab or ControlType_TabItem
|
|
61
|
+
// 3. Read Name property from each tab element
|
|
62
|
+
// 4. Return array of tab info
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check if a window potentially has tabs
|
|
67
|
+
* This is a heuristic based on window class name
|
|
68
|
+
*/
|
|
69
|
+
export function mightHaveTabs(windowTitle) {
|
|
70
|
+
const tabApps = [
|
|
71
|
+
'chrome',
|
|
72
|
+
'edge',
|
|
73
|
+
'firefox',
|
|
74
|
+
'terminal',
|
|
75
|
+
'windows terminal',
|
|
76
|
+
'visual studio code',
|
|
77
|
+
'code',
|
|
78
|
+
'notepad++',
|
|
79
|
+
'sublime',
|
|
80
|
+
'browser'
|
|
81
|
+
];
|
|
82
|
+
const lowerTitle = windowTitle.toLowerCase();
|
|
83
|
+
return tabApps.some(app => lowerTitle.includes(app));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Alternative approach: Enumerate child windows
|
|
87
|
+
* Some applications implement tabs as child windows
|
|
88
|
+
*/
|
|
89
|
+
export function enumerateChildWindows(hwnd) {
|
|
90
|
+
// This would require EnumChildWindows API
|
|
91
|
+
// For now, return empty array
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
// Export a note about limitations
|
|
95
|
+
export const TAB_ENUMERATION_NOTE = `
|
|
96
|
+
Tab Enumeration Limitations:
|
|
97
|
+
|
|
98
|
+
Windows does not provide a standard API for enumerating tabs within applications.
|
|
99
|
+
Tabs are application-specific UI elements. To enumerate tabs, you would need:
|
|
100
|
+
|
|
101
|
+
1. UI Automation API (requires COM interop - complex with FFI)
|
|
102
|
+
2. Application-specific APIs (e.g., Chrome DevTools Protocol)
|
|
103
|
+
3. Accessibility APIs (Windows Automation)
|
|
104
|
+
|
|
105
|
+
Current status: Not implemented due to COM complexity.
|
|
106
|
+
|
|
107
|
+
Alternative approaches:
|
|
108
|
+
- Use application-specific automation (e.g., Puppeteer for Chrome)
|
|
109
|
+
- Use Windows Automation PowerShell cmdlets
|
|
110
|
+
- Use specialized tools like UIAutomationSpy
|
|
111
|
+
|
|
112
|
+
For Windows Terminal specifically, tabs are accessible via Windows.UI.Xaml
|
|
113
|
+
automation, but require UWP/WinRT interop.
|
|
114
|
+
`;
|
|
115
|
+
//# sourceMappingURL=tabs.js.map
|
package/tabs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.js","sourceRoot":"","sources":["tabs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAQzC,IAAI,YAAY,GAAQ,IAAI,CAAC;AAE7B,KAAK,UAAU,sBAAsB;IACjC,IAAI,KAAK,EAAE,CAAC;QACR,wCAAwC;QACxC,OAAO,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,CAAC;QACD,iEAAiE;QACjE,wEAAwE;QACxE,yDAAyD;QAEzD,sBAAsB;QACtB,qCAAqC;QACrC,sCAAsC;QACtC,wDAAwD;QACxD,kDAAkD;QAClD,+CAA+C;QAE/C,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC5C,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,YAAY,GAAG,MAAM,sBAAsB,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,0CAA0C;IAC1C,sBAAsB;IACtB,yCAAyC;IACzC,qEAAqE;IACrE,8CAA8C;IAC9C,8BAA8B;IAE9B,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC7C,MAAM,OAAO,GAAG;QACZ,QAAQ;QACR,MAAM;QACN,SAAS;QACT,UAAU;QACV,kBAAkB;QAClB,oBAAoB;QACpB,MAAM;QACN,WAAW;QACX,SAAS;QACT,SAAS;KACZ,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;IAC7C,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAC9C,0CAA0C;IAC1C,8BAA8B;IAC9B,OAAO,EAAE,CAAC;AACd,CAAC;AAED,kCAAkC;AAClC,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;CAmBnC,CAAC"}
|
package/tabs.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tab enumeration support using Windows UI Automation API
|
|
3
|
+
*
|
|
4
|
+
* NOTE: Tab enumeration is application-specific and not all apps expose tabs
|
|
5
|
+
* through Windows APIs. This module uses UI Automation to attempt to find tabs.
|
|
6
|
+
*
|
|
7
|
+
* Windows Terminal, Chrome, Edge, and other modern apps may expose tabs via
|
|
8
|
+
* UI Automation, but success varies by application.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { isBun } from './ffi-wrapper.js';
|
|
12
|
+
|
|
13
|
+
export interface TabInfo {
|
|
14
|
+
name: string;
|
|
15
|
+
automationId: string;
|
|
16
|
+
index: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let uiAutomation: any = null;
|
|
20
|
+
|
|
21
|
+
async function initializeUIAutomation(): Promise<any> {
|
|
22
|
+
if (isBun) {
|
|
23
|
+
// Bun doesn't have good COM support yet
|
|
24
|
+
console.warn('Tab enumeration not supported in Bun runtime');
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// UI Automation requires COM interop which is complex with koffi
|
|
30
|
+
// For now, return null - this would require significant additional work
|
|
31
|
+
// with COM initialization, IUIAutomation interface, etc.
|
|
32
|
+
|
|
33
|
+
// Potential approach:
|
|
34
|
+
// 1. Load oleaut32.dll and ole32.dll
|
|
35
|
+
// 2. Call CoInitialize/CoInitializeEx
|
|
36
|
+
// 3. Create IUIAutomation instance via CoCreateInstance
|
|
37
|
+
// 4. Use FindFirst/FindAll to locate tab controls
|
|
38
|
+
// 5. Read properties from IUIAutomationElement
|
|
39
|
+
|
|
40
|
+
return null;
|
|
41
|
+
} catch (error: any) {
|
|
42
|
+
console.error('Failed to initialize UI Automation:', error.message);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Attempt to enumerate tabs for a window
|
|
49
|
+
*
|
|
50
|
+
* @param hwnd Window handle
|
|
51
|
+
* @returns Array of tab information, or null if not supported/available
|
|
52
|
+
*
|
|
53
|
+
* NOTE: This is a placeholder for future implementation. Tab enumeration
|
|
54
|
+
* requires COM interop with UI Automation API which is complex with FFI.
|
|
55
|
+
*
|
|
56
|
+
* For now, this returns null. A full implementation would require:
|
|
57
|
+
* - COM initialization (CoInitialize)
|
|
58
|
+
* - IUIAutomation interface
|
|
59
|
+
* - Element tree traversal
|
|
60
|
+
* - Property reading from automation elements
|
|
61
|
+
*/
|
|
62
|
+
export async function enumerateTabs(hwnd: bigint): Promise<TabInfo[] | null> {
|
|
63
|
+
if (!uiAutomation) {
|
|
64
|
+
uiAutomation = await initializeUIAutomation();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!uiAutomation) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// TODO: Implement UI Automation traversal
|
|
72
|
+
// This would involve:
|
|
73
|
+
// 1. Get root element from window handle
|
|
74
|
+
// 2. Search for elements with ControlType_Tab or ControlType_TabItem
|
|
75
|
+
// 3. Read Name property from each tab element
|
|
76
|
+
// 4. Return array of tab info
|
|
77
|
+
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Check if a window potentially has tabs
|
|
83
|
+
* This is a heuristic based on window class name
|
|
84
|
+
*/
|
|
85
|
+
export function mightHaveTabs(windowTitle: string): boolean {
|
|
86
|
+
const tabApps = [
|
|
87
|
+
'chrome',
|
|
88
|
+
'edge',
|
|
89
|
+
'firefox',
|
|
90
|
+
'terminal',
|
|
91
|
+
'windows terminal',
|
|
92
|
+
'visual studio code',
|
|
93
|
+
'code',
|
|
94
|
+
'notepad++',
|
|
95
|
+
'sublime',
|
|
96
|
+
'browser'
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const lowerTitle = windowTitle.toLowerCase();
|
|
100
|
+
return tabApps.some(app => lowerTitle.includes(app));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Alternative approach: Enumerate child windows
|
|
105
|
+
* Some applications implement tabs as child windows
|
|
106
|
+
*/
|
|
107
|
+
export function enumerateChildWindows(hwnd: bigint): bigint[] {
|
|
108
|
+
// This would require EnumChildWindows API
|
|
109
|
+
// For now, return empty array
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Export a note about limitations
|
|
114
|
+
export const TAB_ENUMERATION_NOTE = `
|
|
115
|
+
Tab Enumeration Limitations:
|
|
116
|
+
|
|
117
|
+
Windows does not provide a standard API for enumerating tabs within applications.
|
|
118
|
+
Tabs are application-specific UI elements. To enumerate tabs, you would need:
|
|
119
|
+
|
|
120
|
+
1. UI Automation API (requires COM interop - complex with FFI)
|
|
121
|
+
2. Application-specific APIs (e.g., Chrome DevTools Protocol)
|
|
122
|
+
3. Accessibility APIs (Windows Automation)
|
|
123
|
+
|
|
124
|
+
Current status: Not implemented due to COM complexity.
|
|
125
|
+
|
|
126
|
+
Alternative approaches:
|
|
127
|
+
- Use application-specific automation (e.g., Puppeteer for Chrome)
|
|
128
|
+
- Use Windows Automation PowerShell cmdlets
|
|
129
|
+
- Use specialized tools like UIAutomationSpy
|
|
130
|
+
|
|
131
|
+
For Windows Terminal specifically, tabs are accessible via Windows.UI.Xaml
|
|
132
|
+
automation, but require UWP/WinRT interop.
|
|
133
|
+
`;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"strictNullChecks": false,
|
|
16
|
+
"noImplicitAny": true,
|
|
17
|
+
"noImplicitReturns": false,
|
|
18
|
+
"noImplicitThis": true,
|
|
19
|
+
"newLine": "lf"
|
|
20
|
+
},
|
|
21
|
+
"exclude": [
|
|
22
|
+
"node_modules",
|
|
23
|
+
"cruft",
|
|
24
|
+
".git",
|
|
25
|
+
"tests",
|
|
26
|
+
"prev"
|
|
27
|
+
]
|
|
28
|
+
}
|
package/windows.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window enumeration and filtering
|
|
3
|
+
*/
|
|
4
|
+
import { RECT } from './ffi-wrapper.js';
|
|
5
|
+
export { SW_RESTORE, SW_MINIMIZE, SW_MAXIMIZE, SW_SHOWNORMAL, SW_HIDE, SW_SHOW } from './ffi-wrapper.js';
|
|
6
|
+
export interface WindowInfo {
|
|
7
|
+
hwnd: bigint;
|
|
8
|
+
title: string;
|
|
9
|
+
rect: RECT;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadIgnorePatterns(filePath: string): void;
|
|
12
|
+
export declare function enumerateWindows(includeIgnored?: boolean): WindowInfo[];
|
|
13
|
+
export declare function findWindowsByPattern(pattern: string): WindowInfo[];
|
|
14
|
+
export declare enum WindowState {
|
|
15
|
+
Normal = "normal",
|
|
16
|
+
Minimized = "minimized",
|
|
17
|
+
Maximized = "maximized"
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the current state of a window
|
|
21
|
+
*/
|
|
22
|
+
export declare function getWindowState(hwnd: bigint): WindowState;
|
|
23
|
+
/**
|
|
24
|
+
* Set the state of a window
|
|
25
|
+
*/
|
|
26
|
+
export declare function setWindowState(hwnd: bigint, state: WindowState): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a window is minimized
|
|
29
|
+
*/
|
|
30
|
+
export declare function isMinimized(hwnd: bigint): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Check if a window is maximized
|
|
33
|
+
*/
|
|
34
|
+
export declare function isMaximized(hwnd: bigint): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a window is in normal state
|
|
37
|
+
*/
|
|
38
|
+
export declare function isNormal(hwnd: bigint): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Minimize a window
|
|
41
|
+
*/
|
|
42
|
+
export declare function minimizeWindow(hwnd: bigint): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Maximize a window
|
|
45
|
+
*/
|
|
46
|
+
export declare function maximizeWindow(hwnd: bigint): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Restore a window to normal state
|
|
49
|
+
*/
|
|
50
|
+
export declare function restoreWindow(hwnd: bigint): boolean;
|
|
51
|
+
//# sourceMappingURL=windows.d.ts.map
|
package/windows.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows.d.ts","sourceRoot":"","sources":["windows.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAU,IAAI,EAA8D,MAAM,kBAAkB,CAAC;AAI5G,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEzG,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;CACd;AAKD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,QAgBlD;AAQD,wBAAgB,gBAAgB,CAAC,cAAc,GAAE,OAAe,GAAG,UAAU,EAAE,CA8D9E;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAelE;AAID,oBAAY,WAAW;IACnB,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,SAAS,cAAc;CAC1B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAMxD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAWxE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
package/windows.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window enumeration and filtering
|
|
3
|
+
*/
|
|
4
|
+
import { user32, isBun, SW_RESTORE, SW_MINIMIZE, SW_MAXIMIZE } from './ffi-wrapper.js';
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
export { SW_RESTORE, SW_MINIMIZE, SW_MAXIMIZE, SW_SHOWNORMAL, SW_HIDE, SW_SHOW } from './ffi-wrapper.js';
|
|
7
|
+
let ignores = [];
|
|
8
|
+
let ignoreStarts = [];
|
|
9
|
+
export function loadIgnorePatterns(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
const lines = readFileSync(filePath, 'utf-8').split('\n');
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
const trimmed = line.trim();
|
|
14
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
15
|
+
continue;
|
|
16
|
+
if (trimmed.endsWith('*')) {
|
|
17
|
+
ignoreStarts.push(trimmed.slice(0, -1));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
ignores.push(trimmed);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
// Ignore file doesn't exist - that's OK
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function shouldIgnoreWindow(title) {
|
|
29
|
+
const lowerTitle = title.toLowerCase();
|
|
30
|
+
return ignores.some(ign => lowerTitle === ign.toLowerCase()) ||
|
|
31
|
+
ignoreStarts.some(start => lowerTitle.startsWith(start.toLowerCase()));
|
|
32
|
+
}
|
|
33
|
+
export function enumerateWindows(includeIgnored = false) {
|
|
34
|
+
const windows = [];
|
|
35
|
+
if (isBun) {
|
|
36
|
+
// Bun implementation
|
|
37
|
+
const { ptr } = globalThis.Bun;
|
|
38
|
+
const callback = (hwnd, lParam) => {
|
|
39
|
+
const textBuf = new Uint16Array(256);
|
|
40
|
+
const textPtr = ptr(textBuf);
|
|
41
|
+
const length = user32.GetWindowTextW(hwnd, textPtr, 256);
|
|
42
|
+
if (length > 0) {
|
|
43
|
+
const title = String.fromCharCode(...textBuf.slice(0, length));
|
|
44
|
+
if (includeIgnored || !shouldIgnoreWindow(title)) {
|
|
45
|
+
const rect = { Left: 0, Top: 0, Right: 0, Bottom: 0 };
|
|
46
|
+
const rectBuf = new Int32Array(4);
|
|
47
|
+
const rectPtr = ptr(rectBuf);
|
|
48
|
+
if (user32.GetWindowRect(hwnd, rectPtr)) {
|
|
49
|
+
rect.Left = rectBuf[0];
|
|
50
|
+
rect.Top = rectBuf[1];
|
|
51
|
+
rect.Right = rectBuf[2];
|
|
52
|
+
rect.Bottom = rectBuf[3];
|
|
53
|
+
if (rect.Top !== rect.Bottom && rect.Left !== rect.Right) {
|
|
54
|
+
windows.push({ hwnd, title, rect });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
};
|
|
61
|
+
user32.EnumWindows(callback, 0n);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Node.js with koffi
|
|
65
|
+
const callback = (hwnd, lParam) => {
|
|
66
|
+
const textBuf = Buffer.alloc(512);
|
|
67
|
+
const length = user32.GetWindowTextW(hwnd, textBuf, 256);
|
|
68
|
+
if (length > 0) {
|
|
69
|
+
const title = textBuf.toString('utf16le', 0, length * 2);
|
|
70
|
+
if (includeIgnored || !shouldIgnoreWindow(title)) {
|
|
71
|
+
const rect = { Left: 0, Top: 0, Right: 0, Bottom: 0 };
|
|
72
|
+
if (user32.GetWindowRect(hwnd, rect)) {
|
|
73
|
+
if (rect.Top !== rect.Bottom && rect.Left !== rect.Right) {
|
|
74
|
+
windows.push({ hwnd, title, rect });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
};
|
|
81
|
+
user32.EnumWindows(callback, 0n);
|
|
82
|
+
}
|
|
83
|
+
return windows;
|
|
84
|
+
}
|
|
85
|
+
export function findWindowsByPattern(pattern) {
|
|
86
|
+
const allWindows = enumerateWindows();
|
|
87
|
+
if (pattern.startsWith('/') && pattern.endsWith('/')) {
|
|
88
|
+
// Regex match
|
|
89
|
+
const regex = new RegExp(pattern.slice(1, -1), 'i');
|
|
90
|
+
return allWindows.filter(w => regex.test(w.title));
|
|
91
|
+
}
|
|
92
|
+
else if (pattern.endsWith('*')) {
|
|
93
|
+
// Prefix match
|
|
94
|
+
const prefix = pattern.slice(0, -1).toLowerCase();
|
|
95
|
+
return allWindows.filter(w => w.title.toLowerCase().startsWith(prefix));
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// Exact match
|
|
99
|
+
return allWindows.filter(w => w.title.toLowerCase() === pattern.toLowerCase());
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Window state management API
|
|
103
|
+
export var WindowState;
|
|
104
|
+
(function (WindowState) {
|
|
105
|
+
WindowState["Normal"] = "normal";
|
|
106
|
+
WindowState["Minimized"] = "minimized";
|
|
107
|
+
WindowState["Maximized"] = "maximized";
|
|
108
|
+
})(WindowState || (WindowState = {}));
|
|
109
|
+
/**
|
|
110
|
+
* Get the current state of a window
|
|
111
|
+
*/
|
|
112
|
+
export function getWindowState(hwnd) {
|
|
113
|
+
if (user32.IsIconic(hwnd))
|
|
114
|
+
return WindowState.Minimized;
|
|
115
|
+
if (user32.IsZoomed(hwnd))
|
|
116
|
+
return WindowState.Maximized;
|
|
117
|
+
return WindowState.Normal;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Set the state of a window
|
|
121
|
+
*/
|
|
122
|
+
export function setWindowState(hwnd, state) {
|
|
123
|
+
switch (state) {
|
|
124
|
+
case WindowState.Minimized:
|
|
125
|
+
return user32.ShowWindow(hwnd, SW_MINIMIZE);
|
|
126
|
+
case WindowState.Maximized:
|
|
127
|
+
return user32.ShowWindow(hwnd, SW_MAXIMIZE);
|
|
128
|
+
case WindowState.Normal:
|
|
129
|
+
return user32.ShowWindow(hwnd, SW_RESTORE);
|
|
130
|
+
default:
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check if a window is minimized
|
|
136
|
+
*/
|
|
137
|
+
export function isMinimized(hwnd) {
|
|
138
|
+
return user32.IsIconic(hwnd);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if a window is maximized
|
|
142
|
+
*/
|
|
143
|
+
export function isMaximized(hwnd) {
|
|
144
|
+
return user32.IsZoomed(hwnd);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Check if a window is in normal state
|
|
148
|
+
*/
|
|
149
|
+
export function isNormal(hwnd) {
|
|
150
|
+
return !user32.IsIconic(hwnd) && !user32.IsZoomed(hwnd);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Minimize a window
|
|
154
|
+
*/
|
|
155
|
+
export function minimizeWindow(hwnd) {
|
|
156
|
+
return user32.ShowWindow(hwnd, SW_MINIMIZE);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Maximize a window
|
|
160
|
+
*/
|
|
161
|
+
export function maximizeWindow(hwnd) {
|
|
162
|
+
return user32.ShowWindow(hwnd, SW_MAXIMIZE);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Restore a window to normal state
|
|
166
|
+
*/
|
|
167
|
+
export function restoreWindow(hwnd) {
|
|
168
|
+
return user32.ShowWindow(hwnd, SW_RESTORE);
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=windows.js.map
|
package/windows.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows.js","sourceRoot":"","sources":["windows.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAQ,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAiB,MAAM,kBAAkB,CAAC;AAC5G,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAGlC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAQzG,IAAI,OAAO,GAAa,EAAE,CAAC;AAC3B,IAAI,YAAY,GAAa,EAAE,CAAC;AAEhC,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;gBACnC,SAAS;YACb,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,CAAC;iBAAM,CAAC;gBACJ,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1B,CAAC;QACL,CAAC;IACL,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,wCAAwC;IAC5C,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAa;IACrC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACvC,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;QACxD,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,iBAA0B,KAAK;IAC5D,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,IAAI,KAAK,EAAE,CAAC;QACR,qBAAqB;QACrB,MAAM,EAAE,GAAG,EAAE,GAAI,UAAkB,CAAC,GAAG,CAAC;QAExC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE;YAC9C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;YAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YAEzD,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;gBAE/D,IAAI,cAAc,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC/C,MAAM,IAAI,GAAS,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;oBAC5D,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;oBAClC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;oBAE7B,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;wBACtC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;wBACvB,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;wBACtB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;wBACxB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;wBAEzB,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;4BACvD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;wBACxC,CAAC;oBACL,CAAC;gBACL,CAAC;YACL,CAAC;YACD,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC;QAEF,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC;SAAM,CAAC;QACJ,qBAAqB;QACrB,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE;YAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,OAAc,EAAE,GAAG,CAAC,CAAC;YAEhE,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;gBAEzD,IAAI,cAAc,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC/C,MAAM,IAAI,GAAS,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;oBAE5D,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;wBACnC,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;4BACvD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;wBACxC,CAAC;oBACL,CAAC;gBACL,CAAC;YACL,CAAC;YACD,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC;QAEF,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAChD,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC;IAEtC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,cAAc;QACd,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACpD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACvD,CAAC;SAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,eAAe;QACf,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QAClD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5E,CAAC;SAAM,CAAC;QACJ,cAAc;QACd,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACnF,CAAC;AACL,CAAC;AAED,8BAA8B;AAE9B,MAAM,CAAN,IAAY,WAIX;AAJD,WAAY,WAAW;IACnB,gCAAiB,CAAA;IACjB,sCAAuB,CAAA;IACvB,sCAAuB,CAAA;AAC3B,CAAC,EAJW,WAAW,KAAX,WAAW,QAItB;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QACrB,OAAO,WAAW,CAAC,SAAS,CAAC;IACjC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QACrB,OAAO,WAAW,CAAC,SAAS,CAAC;IACjC,OAAO,WAAW,CAAC,MAAM,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,KAAkB;IAC3D,QAAQ,KAAK,EAAE,CAAC;QACZ,KAAK,WAAW,CAAC,SAAS;YACtB,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAChD,KAAK,WAAW,CAAC,SAAS;YACtB,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAChD,KAAK,WAAW,CAAC,MAAM;YACnB,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC/C;YACI,OAAO,KAAK,CAAC;IACrB,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACpC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACpC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACtC,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AAC/C,CAAC"}
|