@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/windows.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window enumeration and filtering
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { user32, RECT, isBun, SW_RESTORE, SW_MINIMIZE, SW_MAXIMIZE, SW_SHOWNORMAL } from './ffi-wrapper.js';
|
|
6
|
+
import { readFileSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
|
|
9
|
+
export { SW_RESTORE, SW_MINIMIZE, SW_MAXIMIZE, SW_SHOWNORMAL, SW_HIDE, SW_SHOW } from './ffi-wrapper.js';
|
|
10
|
+
|
|
11
|
+
export interface WindowInfo {
|
|
12
|
+
hwnd: bigint;
|
|
13
|
+
title: string;
|
|
14
|
+
rect: RECT;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let ignores: string[] = [];
|
|
18
|
+
let ignoreStarts: string[] = [];
|
|
19
|
+
|
|
20
|
+
export function loadIgnorePatterns(filePath: string) {
|
|
21
|
+
try {
|
|
22
|
+
const lines = readFileSync(filePath, 'utf-8').split('\n');
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
26
|
+
continue;
|
|
27
|
+
if (trimmed.endsWith('*')) {
|
|
28
|
+
ignoreStarts.push(trimmed.slice(0, -1));
|
|
29
|
+
} else {
|
|
30
|
+
ignores.push(trimmed);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} catch (error: any) {
|
|
34
|
+
// Ignore file doesn't exist - that's OK
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function shouldIgnoreWindow(title: string): boolean {
|
|
39
|
+
const lowerTitle = title.toLowerCase();
|
|
40
|
+
return ignores.some(ign => lowerTitle === ign.toLowerCase()) ||
|
|
41
|
+
ignoreStarts.some(start => lowerTitle.startsWith(start.toLowerCase()));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function enumerateWindows(includeIgnored: boolean = false): WindowInfo[] {
|
|
45
|
+
const windows: WindowInfo[] = [];
|
|
46
|
+
|
|
47
|
+
if (isBun) {
|
|
48
|
+
// Bun implementation
|
|
49
|
+
const { ptr } = (globalThis as any).Bun;
|
|
50
|
+
|
|
51
|
+
const callback = (hwnd: bigint, lParam: bigint) => {
|
|
52
|
+
const textBuf = new Uint16Array(256);
|
|
53
|
+
const textPtr = ptr(textBuf);
|
|
54
|
+
const length = user32.GetWindowTextW(hwnd, textPtr, 256);
|
|
55
|
+
|
|
56
|
+
if (length > 0) {
|
|
57
|
+
const title = String.fromCharCode(...textBuf.slice(0, length));
|
|
58
|
+
|
|
59
|
+
if (includeIgnored || !shouldIgnoreWindow(title)) {
|
|
60
|
+
const rect: RECT = { Left: 0, Top: 0, Right: 0, Bottom: 0 };
|
|
61
|
+
const rectBuf = new Int32Array(4);
|
|
62
|
+
const rectPtr = ptr(rectBuf);
|
|
63
|
+
|
|
64
|
+
if (user32.GetWindowRect(hwnd, rectPtr)) {
|
|
65
|
+
rect.Left = rectBuf[0];
|
|
66
|
+
rect.Top = rectBuf[1];
|
|
67
|
+
rect.Right = rectBuf[2];
|
|
68
|
+
rect.Bottom = rectBuf[3];
|
|
69
|
+
|
|
70
|
+
if (rect.Top !== rect.Bottom && rect.Left !== rect.Right) {
|
|
71
|
+
windows.push({ hwnd, title, rect });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
user32.EnumWindows(callback, 0n);
|
|
80
|
+
} else {
|
|
81
|
+
// Node.js with koffi
|
|
82
|
+
const callback = (hwnd: bigint, lParam: bigint) => {
|
|
83
|
+
const textBuf = Buffer.alloc(512);
|
|
84
|
+
const length = user32.GetWindowTextW(hwnd, textBuf as any, 256);
|
|
85
|
+
|
|
86
|
+
if (length > 0) {
|
|
87
|
+
const title = textBuf.toString('utf16le', 0, length * 2);
|
|
88
|
+
|
|
89
|
+
if (includeIgnored || !shouldIgnoreWindow(title)) {
|
|
90
|
+
const rect: RECT = { Left: 0, Top: 0, Right: 0, Bottom: 0 };
|
|
91
|
+
|
|
92
|
+
if (user32.GetWindowRect(hwnd, rect)) {
|
|
93
|
+
if (rect.Top !== rect.Bottom && rect.Left !== rect.Right) {
|
|
94
|
+
windows.push({ hwnd, title, rect });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
user32.EnumWindows(callback, 0n);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return windows;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function findWindowsByPattern(pattern: string): WindowInfo[] {
|
|
109
|
+
const allWindows = enumerateWindows();
|
|
110
|
+
|
|
111
|
+
if (pattern.startsWith('/') && pattern.endsWith('/')) {
|
|
112
|
+
// Regex match
|
|
113
|
+
const regex = new RegExp(pattern.slice(1, -1), 'i');
|
|
114
|
+
return allWindows.filter(w => regex.test(w.title));
|
|
115
|
+
} else if (pattern.endsWith('*')) {
|
|
116
|
+
// Prefix match
|
|
117
|
+
const prefix = pattern.slice(0, -1).toLowerCase();
|
|
118
|
+
return allWindows.filter(w => w.title.toLowerCase().startsWith(prefix));
|
|
119
|
+
} else {
|
|
120
|
+
// Exact match
|
|
121
|
+
return allWindows.filter(w => w.title.toLowerCase() === pattern.toLowerCase());
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Window state management API
|
|
126
|
+
|
|
127
|
+
export enum WindowState {
|
|
128
|
+
Normal = 'normal',
|
|
129
|
+
Minimized = 'minimized',
|
|
130
|
+
Maximized = 'maximized'
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get the current state of a window
|
|
135
|
+
*/
|
|
136
|
+
export function getWindowState(hwnd: bigint): WindowState {
|
|
137
|
+
if (user32.IsIconic(hwnd))
|
|
138
|
+
return WindowState.Minimized;
|
|
139
|
+
if (user32.IsZoomed(hwnd))
|
|
140
|
+
return WindowState.Maximized;
|
|
141
|
+
return WindowState.Normal;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Set the state of a window
|
|
146
|
+
*/
|
|
147
|
+
export function setWindowState(hwnd: bigint, state: WindowState): boolean {
|
|
148
|
+
switch (state) {
|
|
149
|
+
case WindowState.Minimized:
|
|
150
|
+
return user32.ShowWindow(hwnd, SW_MINIMIZE);
|
|
151
|
+
case WindowState.Maximized:
|
|
152
|
+
return user32.ShowWindow(hwnd, SW_MAXIMIZE);
|
|
153
|
+
case WindowState.Normal:
|
|
154
|
+
return user32.ShowWindow(hwnd, SW_RESTORE);
|
|
155
|
+
default:
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Check if a window is minimized
|
|
162
|
+
*/
|
|
163
|
+
export function isMinimized(hwnd: bigint): boolean {
|
|
164
|
+
return user32.IsIconic(hwnd);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Check if a window is maximized
|
|
169
|
+
*/
|
|
170
|
+
export function isMaximized(hwnd: bigint): boolean {
|
|
171
|
+
return user32.IsZoomed(hwnd);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Check if a window is in normal state
|
|
176
|
+
*/
|
|
177
|
+
export function isNormal(hwnd: bigint): boolean {
|
|
178
|
+
return !user32.IsIconic(hwnd) && !user32.IsZoomed(hwnd);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Minimize a window
|
|
183
|
+
*/
|
|
184
|
+
export function minimizeWindow(hwnd: bigint): boolean {
|
|
185
|
+
return user32.ShowWindow(hwnd, SW_MINIMIZE);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Maximize a window
|
|
190
|
+
*/
|
|
191
|
+
export function maximizeWindow(hwnd: bigint): boolean {
|
|
192
|
+
return user32.ShowWindow(hwnd, SW_MAXIMIZE);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Restore a window to normal state
|
|
197
|
+
*/
|
|
198
|
+
export function restoreWindow(hwnd: bigint): boolean {
|
|
199
|
+
return user32.ShowWindow(hwnd, SW_RESTORE);
|
|
200
|
+
}
|