quickwin 1.0.0
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/README.en.md +197 -0
- package/README.md +196 -0
- package/examples/PdfCanvas.js +67 -0
- package/examples/PdfCanvas.tsx +83 -0
- package/examples/pdf_preview2.js +431 -0
- package/examples/pdf_preview2.ts +375 -0
- package/examples/pdf_viewer.js +17623 -0
- package/examples/pdf_viewer.tsx +279 -0
- package/examples/test_gallery.js +17452 -0
- package/examples/test_gallery.tsx +285 -0
- package/examples/test_react_lazy.js +17336 -0
- package/examples/test_react_lazy.tsx +63 -0
- package/examples/test_react_listbox.js +17339 -0
- package/examples/test_react_listbox.tsx +71 -0
- package/examples/test_root_window.js +17313 -0
- package/examples/test_root_window.tsx +41 -0
- package/examples/test_tab.js +17339 -0
- package/examples/test_tab.tsx +75 -0
- package/examples/tray_demo.js +79 -0
- package/examples/tray_demo.tsx +81 -0
- package/lib/assert.js +8 -0
- package/lib/assert.ts +7 -0
- package/lib/cache-utils.js +43 -0
- package/lib/cache-utils.ts +40 -0
- package/lib/dumpRects.js +25 -0
- package/lib/dumpRects.ts +25 -0
- package/lib/fetch.js +490 -0
- package/lib/fetch.ts +502 -0
- package/lib/http-common.js +342 -0
- package/lib/http-common.ts +399 -0
- package/lib/http-server.js +416 -0
- package/lib/http-server.ts +424 -0
- package/lib/polyfill.js +156 -0
- package/lib/polyfill.ts +171 -0
- package/lib/react-qw/components/Button.js +8 -0
- package/lib/react-qw/components/CheckBox.js +31 -0
- package/lib/react-qw/components/ComboBox.js +42 -0
- package/lib/react-qw/components/DateTimePicker.js +96 -0
- package/lib/react-qw/components/Input.js +50 -0
- package/lib/react-qw/components/Link.js +43 -0
- package/lib/react-qw/components/ListBox.js +48 -0
- package/lib/react-qw/components/ListView.js +328 -0
- package/lib/react-qw/components/PathPicker.js +136 -0
- package/lib/react-qw/components/ProgressBar.js +22 -0
- package/lib/react-qw/components/RadioButton.js +31 -0
- package/lib/react-qw/components/ScrollView.js +139 -0
- package/lib/react-qw/components/Slider.js +45 -0
- package/lib/react-qw/components/Tab.js +61 -0
- package/lib/react-qw/components/Tooltip.js +55 -0
- package/lib/react-qw/components/TreeView.js +130 -0
- package/lib/react-qw/components/index.js +16 -0
- package/lib/react-qw/components/index.ts +17 -0
- package/lib/react-qw/index.js +73 -0
- package/lib/react-qw/index.ts +90 -0
- package/lib/react-qw/jsx.d.ts +34 -0
- package/lib/react-qw/layout.js +82 -0
- package/lib/react-qw/layout.ts +111 -0
- package/lib/react-qw/props.js +27 -0
- package/lib/react-qw/props.ts +36 -0
- package/lib/react-qw/reconciler.js +333 -0
- package/lib/react-qw/reconciler.ts +373 -0
- package/lib/stream.js +2 -0
- package/lib/stream.ts +22 -0
- package/lib/text-codec.js +197 -0
- package/lib/text-codec.ts +171 -0
- package/lib/text-measure.js +52 -0
- package/lib/text-measure.ts +54 -0
- package/lib/url.js +278 -0
- package/lib/url.ts +201 -0
- package/lib/vendor/web-streams/ponyfill.d.mts +829 -0
- package/lib/vendor/web-streams/ponyfill.mjs +8 -0
- package/lib/websocket.js +541 -0
- package/lib/websocket.ts +555 -0
- package/package.json +44 -0
- package/quickwin.d.ts +594 -0
- package/quickwin_const.d.ts +900 -0
- package/qwin-nowasm.exe +0 -0
- package/qwin.exe +0 -0
- package/test/add.wasm +0 -0
- package/test/complex.wasm +0 -0
- package/test/complex_imports.wasm +0 -0
- package/test/debug/http_server_e2e.js +31 -0
- package/test/debug/minwasm.js +52 -0
- package/test/debug/mupdf_debug.js +104 -0
- package/test/debug/wasm.js +122 -0
- package/test/debug/wasm_export_debug.js +64 -0
- package/test/debug/wasm_names.js +46 -0
- package/test/global_imports.wasm +0 -0
- package/test/import_func.wasm +0 -0
- package/test/imports.wasm +0 -0
- package/test/run.js +91 -0
- package/test/run.ts +96 -0
- package/test/sjlj.wasm +0 -0
- package/test/test_basic.js +7 -0
- package/test/test_basic.ts +9 -0
- package/test/test_basic_fetch.js +34 -0
- package/test/test_basic_fetch.ts +33 -0
- package/test/test_brotli.js +48 -0
- package/test/test_brotli.ts +52 -0
- package/test/test_fetch_cache.js +169 -0
- package/test/test_fetch_cache.ts +187 -0
- package/test/test_ffi.js +157 -0
- package/test/test_ffi.ts +174 -0
- package/test/test_frame_encoding.js +128 -0
- package/test/test_frame_encoding.ts +132 -0
- package/test/test_helper.js +84 -0
- package/test/test_helper.ts +80 -0
- package/test/test_http_import.js +78 -0
- package/test/test_http_import.ts +74 -0
- package/test/test_http_server.js +142 -0
- package/test/test_http_server.ts +136 -0
- package/test/test_import_dir.js +4 -0
- package/test/test_import_dir.ts +5 -0
- package/test/test_ipv6.js +134 -0
- package/test/test_ipv6.ts +129 -0
- package/test/test_jsx.js +1314 -0
- package/test/test_meta_url.js +3 -0
- package/test/test_meta_url.ts +4 -0
- package/test/test_mupdf_render.js +69 -0
- package/test/test_mupdf_render.ts +74 -0
- package/test/test_mupdf_twice.js +77 -0
- package/test/test_mupdf_twice.ts +81 -0
- package/test/test_mupdf_wasm.js +33 -0
- package/test/test_mupdf_wasm.ts +30 -0
- package/test/test_net_event.js +57 -0
- package/test/test_net_event.ts +55 -0
- package/test/test_net_fetch.js +259 -0
- package/test/test_net_fetch.ts +238 -0
- package/test/test_net_websocket.js +180 -0
- package/test/test_net_websocket.ts +164 -0
- package/test/test_polyfill.js +144 -0
- package/test/test_polyfill.ts +159 -0
- package/test/test_react_complex.js +17440 -0
- package/test/test_react_counter.js +17331 -0
- package/test/test_react_flex.js +17643 -0
- package/test/test_react_hidden.js +17336 -0
- package/test/test_react_listview_link.js +17371 -0
- package/test/test_react_render.js +17326 -0
- package/test/test_url.js +173 -0
- package/test/test_url.ts +183 -0
- package/test/test_wasm_basic.js +85 -0
- package/test/test_wasm_basic.ts +73 -0
- package/test/test_wasm_import_global.js +41 -0
- package/test/test_wasm_import_global.ts +45 -0
- package/test/test_wasm_sjlj.js +145 -0
- package/test/test_wasm_sjlj.ts +125 -0
- package/test/test_wasm_types.js +97 -0
- package/test/test_wasm_types.ts +124 -0
- package/test/test_worker.js +21 -0
- package/test/test_worker.ts +24 -0
- package/test/test_worker_fetch.js +26 -0
- package/test/test_worker_fetch.ts +27 -0
- package/test/test_worker_net.js +51 -0
- package/test/test_worker_net.ts +54 -0
- package/test/test_worker_wasm_concurrent.js +44 -0
- package/test/test_worker_wasm_concurrent.ts +45 -0
- package/test/types.wasm +0 -0
- package/test/worker_fetch.js +13 -0
- package/test/worker_fetch.ts +13 -0
- package/test/worker_helper.js +1 -0
- package/test/worker_helper.ts +1 -0
- package/test/worker_http.js +18 -0
- package/test/worker_http.ts +20 -0
- package/test/worker_import_lib.js +12 -0
- package/test/worker_import_lib.ts +13 -0
- package/test/worker_module.js +16 -0
- package/test/worker_module.ts +17 -0
- package/test/worker_wasm_concurrent.js +22 -0
- package/test/worker_wasm_concurrent.ts +22 -0
- package/tsconfig.json +27 -0
- package/vendor/mupdf-wasm/mupdf-wasm.d.ts +571 -0
- package/vendor/mupdf-wasm/mupdf-wasm.js +2749 -0
- package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
- package/vendor/mupdf-wasm/mupdf.d.ts +939 -0
- package/vendor/mupdf-wasm/mupdf.js +3317 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import '../lib/polyfill.js'
|
|
2
|
+
import * as gui from 'gui'
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { render, Button, Tab } from '../lib/react-qw/index.js'
|
|
5
|
+
|
|
6
|
+
gui.RegisterClass('TabDemo', (hwnd, msg, wParam, lParam) => {
|
|
7
|
+
if (!hwnd) return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
8
|
+
if (msg === gui.WmMsg.DESTROY) {
|
|
9
|
+
gui.PostQuitMessage(0)
|
|
10
|
+
return 0
|
|
11
|
+
}
|
|
12
|
+
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
function App() {
|
|
16
|
+
const [tabIndex, setTabIndex] = useState(0)
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<w type="STATIC"
|
|
20
|
+
ws={gui.WindowStyle.VISIBLE}
|
|
21
|
+
style={{ flexDirection: 'column', width: 600, height: 400, padding: 10 }}
|
|
22
|
+
>
|
|
23
|
+
<Tab
|
|
24
|
+
tabs={[
|
|
25
|
+
{
|
|
26
|
+
title: 'Counter',
|
|
27
|
+
content: (
|
|
28
|
+
<w type="STATIC"
|
|
29
|
+
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
30
|
+
style={{ flexDirection: 'column', gap: 10, padding: 10, width: 580, height: 300 }}>
|
|
31
|
+
<Button onClick={() => setTabIndex(1)}>Go to Tab 2</Button>
|
|
32
|
+
</w>
|
|
33
|
+
),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: 'Buttons',
|
|
37
|
+
content: (
|
|
38
|
+
<w type="STATIC"
|
|
39
|
+
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
40
|
+
style={{ flexDirection: 'row', gap: 10, padding: 10, width: 580, height: 300, alignItems: 'stretch' }}>
|
|
41
|
+
<Button onClick={() => setTabIndex(2)}>Go to Tab 3</Button>
|
|
42
|
+
<Button onClick={() => setTabIndex(0)} style={{ width: 120 }}>Back</Button>
|
|
43
|
+
</w>
|
|
44
|
+
),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: 'Final',
|
|
48
|
+
content: (
|
|
49
|
+
<w type="STATIC"
|
|
50
|
+
ws={gui.WindowStyle.VISIBLE | gui.WindowStyle.CLIPCHILDREN}
|
|
51
|
+
style={{ flexDirection: 'column', gap: 10, padding: 10, width: 580, height: 300 }}>
|
|
52
|
+
<Button onClick={() => setTabIndex(0)}>Back to Tab 1</Button>
|
|
53
|
+
<Button onClick={() => setTabIndex(1)}>Back to Tab 2</Button>
|
|
54
|
+
</w>
|
|
55
|
+
),
|
|
56
|
+
},
|
|
57
|
+
]}
|
|
58
|
+
style={{ flexGrow: 1 }}
|
|
59
|
+
selectedIndex={tabIndex}
|
|
60
|
+
onChange={(i) => setTabIndex(i)}
|
|
61
|
+
/>
|
|
62
|
+
</w>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const hwnd = gui.CreateWindow(
|
|
67
|
+
'TabDemo', 'Tab Demo',
|
|
68
|
+
gui.WindowStyle.OVERLAPPEDWINDOW,
|
|
69
|
+
100, 100, 640, 480, null, null
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if (hwnd) {
|
|
73
|
+
gui.ShowWindow(hwnd)
|
|
74
|
+
render(<App />, hwnd)
|
|
75
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as gui from 'gui';
|
|
2
|
+
import * as std from 'std';
|
|
3
|
+
const WM_TRAY = 0x8001;
|
|
4
|
+
gui.RegisterClass('TrayApp', (hwnd, msg, wParam, lParam) => {
|
|
5
|
+
if (msg === WM_TRAY) {
|
|
6
|
+
const evt = lParam;
|
|
7
|
+
if (evt === 0x0201) { // WM_LBUTTONDOWN
|
|
8
|
+
gui.ShowWindow(hwnd, 5); // SW_SHOW
|
|
9
|
+
gui.SetForegroundWindow(hwnd);
|
|
10
|
+
}
|
|
11
|
+
else if (evt === 0x0204 || evt === 0x007B) { // WM_RBUTTONDOWN or WM_CONTEXTMENU
|
|
12
|
+
gui.SetForegroundWindow(hwnd);
|
|
13
|
+
const pos = gui.GetCursorPos();
|
|
14
|
+
const x = pos ? pos[0] : 0;
|
|
15
|
+
const y = pos ? pos[1] : 0;
|
|
16
|
+
const hMenu = gui.CreatePopupMenu();
|
|
17
|
+
if (hMenu) {
|
|
18
|
+
gui.AppendMenu(hMenu, 0, 1, '显示窗口');
|
|
19
|
+
gui.AppendMenu(hMenu, 0x0800, 0, '');
|
|
20
|
+
gui.AppendMenu(hMenu, 0, 2, '退出');
|
|
21
|
+
const cmd = gui.TrackPopupMenu(hMenu, x, y, undefined, hwnd);
|
|
22
|
+
gui.DestroyMenu(hMenu);
|
|
23
|
+
if (cmd === 1) {
|
|
24
|
+
gui.ShowWindow(hwnd, 5); // SW_SHOW
|
|
25
|
+
}
|
|
26
|
+
else if (cmd === 2) {
|
|
27
|
+
gui.ShellNotifyIcon(2 /* gui.NotifyIconCmd.DELETE */, { hwnd, uID: 1 });
|
|
28
|
+
gui.PostQuitMessage(0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
if (msg === 16 /* gui.WmMsg.CLOSE */) {
|
|
35
|
+
gui.ShowWindow(hwnd, 0); // SW_HIDE
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
return gui.DefWindowProc(hwnd, msg, wParam, lParam);
|
|
39
|
+
});
|
|
40
|
+
// 创建窗口
|
|
41
|
+
const W = 500, H = 400;
|
|
42
|
+
const scr = gui.GetScreenSize();
|
|
43
|
+
const x = (scr[0] - W) >> 1;
|
|
44
|
+
const y = (scr[1] - H) >> 1;
|
|
45
|
+
const hwnd = gui.CreateWindow('TrayApp', '系统托盘示例', 13565952 /* gui.WindowStyle.OVERLAPPEDWINDOW */, x, y, W, H, null, null);
|
|
46
|
+
if (!hwnd)
|
|
47
|
+
std.exit(0);
|
|
48
|
+
gui.ShowWindow(hwnd);
|
|
49
|
+
// 添加说明文字
|
|
50
|
+
const ES_MULTILINE = 0x0004;
|
|
51
|
+
const ES_READONLY = 0x0800;
|
|
52
|
+
const style = 1073741824 /* gui.WindowStyle.CHILD */ | 268435456 /* gui.WindowStyle.VISIBLE */ | ES_MULTILINE | ES_READONLY;
|
|
53
|
+
const text = gui.CreateWindow('EDIT', 'QuickWin 系统托盘示例\r\n'
|
|
54
|
+
+ '\r\n'
|
|
55
|
+
+ '右键点击托盘图标打开上下文菜单。\r\n'
|
|
56
|
+
+ '关闭此窗口将隐藏到托盘。\r\n'
|
|
57
|
+
+ '从菜单中选择"显示窗口"恢复窗口,"退出"结束程序。', style, 15, 15, W - 30, H - 70, hwnd, null);
|
|
58
|
+
if (text) {
|
|
59
|
+
const font = gui.CreateSystemDpiFont();
|
|
60
|
+
if (font)
|
|
61
|
+
gui.SendMessage(text, 48 /* gui.WmMsg.SETFONT */, font, 1);
|
|
62
|
+
}
|
|
63
|
+
let hIcon = gui.LoadAppIcon();
|
|
64
|
+
if (!hIcon)
|
|
65
|
+
hIcon = gui.LoadImage(null, 32512 /* gui.IDI.APPLICATION */, 1 /* gui.ImageType.ICON */, 0, 0, 32768 /* gui.LoadImageFlag.SHARED */);
|
|
66
|
+
if (hIcon) {
|
|
67
|
+
const ok = gui.ShellNotifyIcon(0 /* gui.NotifyIconCmd.ADD */, {
|
|
68
|
+
hwnd: hwnd, uID: 1,
|
|
69
|
+
flags: 1 /* gui.NotifyIconFlag.MESSAGE */ | 2 /* gui.NotifyIconFlag.ICON */,
|
|
70
|
+
callbackMessage: WM_TRAY,
|
|
71
|
+
hIcon,
|
|
72
|
+
});
|
|
73
|
+
std.out.printf('tray icon %s\n', ok ? 'added' : 'FAILED');
|
|
74
|
+
std.out.flush();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
std.out.printf('failed to load icon\n');
|
|
78
|
+
std.out.flush();
|
|
79
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as gui from 'gui'
|
|
2
|
+
import * as std from 'std'
|
|
3
|
+
|
|
4
|
+
const WM_TRAY = 0x8001
|
|
5
|
+
|
|
6
|
+
gui.RegisterClass('TrayApp', (hwnd, msg, wParam, lParam) => {
|
|
7
|
+
if (msg === WM_TRAY) {
|
|
8
|
+
const evt = lParam
|
|
9
|
+
if (evt === 0x0201) { // WM_LBUTTONDOWN
|
|
10
|
+
gui.ShowWindow(hwnd, 5) // SW_SHOW
|
|
11
|
+
gui.SetForegroundWindow(hwnd)
|
|
12
|
+
} else if (evt === 0x0204 || evt === 0x007B) { // WM_RBUTTONDOWN or WM_CONTEXTMENU
|
|
13
|
+
gui.SetForegroundWindow(hwnd)
|
|
14
|
+
const pos = gui.GetCursorPos()
|
|
15
|
+
const x = pos ? pos[0] : 0
|
|
16
|
+
const y = pos ? pos[1] : 0
|
|
17
|
+
const hMenu = gui.CreatePopupMenu()
|
|
18
|
+
if (hMenu) {
|
|
19
|
+
gui.AppendMenu(hMenu, 0, 1, '显示窗口')
|
|
20
|
+
gui.AppendMenu(hMenu, 0x0800, 0, '')
|
|
21
|
+
gui.AppendMenu(hMenu, 0, 2, '退出')
|
|
22
|
+
const cmd = gui.TrackPopupMenu(hMenu, x, y, undefined, hwnd)
|
|
23
|
+
gui.DestroyMenu(hMenu)
|
|
24
|
+
if (cmd === 1) {
|
|
25
|
+
gui.ShowWindow(hwnd, 5) // SW_SHOW
|
|
26
|
+
} else if (cmd === 2) {
|
|
27
|
+
gui.ShellNotifyIcon(gui.NotifyIconCmd.DELETE, { hwnd, uID: 1 })
|
|
28
|
+
gui.PostQuitMessage(0)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return 0
|
|
33
|
+
}
|
|
34
|
+
if (msg === gui.WmMsg.CLOSE) {
|
|
35
|
+
gui.ShowWindow(hwnd, 0) // SW_HIDE
|
|
36
|
+
return 0
|
|
37
|
+
}
|
|
38
|
+
return gui.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// 创建窗口
|
|
42
|
+
const W = 500, H = 400
|
|
43
|
+
const scr = gui.GetScreenSize()
|
|
44
|
+
const x = (scr[0] - W) >> 1
|
|
45
|
+
const y = (scr[1] - H) >> 1
|
|
46
|
+
const hwnd = gui.CreateWindow('TrayApp', '系统托盘示例', gui.WindowStyle.OVERLAPPEDWINDOW, x, y, W, H, null, null)
|
|
47
|
+
if (!hwnd) std.exit(0)
|
|
48
|
+
gui.ShowWindow(hwnd)
|
|
49
|
+
|
|
50
|
+
// 添加说明文字
|
|
51
|
+
const ES_MULTILINE = 0x0004
|
|
52
|
+
const ES_READONLY = 0x0800
|
|
53
|
+
const style = gui.WindowStyle.CHILD | gui.WindowStyle.VISIBLE | ES_MULTILINE | ES_READONLY
|
|
54
|
+
const text = gui.CreateWindow('EDIT',
|
|
55
|
+
'QuickWin 系统托盘示例\r\n'
|
|
56
|
+
+ '\r\n'
|
|
57
|
+
+ '右键点击托盘图标打开上下文菜单。\r\n'
|
|
58
|
+
+ '关闭此窗口将隐藏到托盘。\r\n'
|
|
59
|
+
+ '从菜单中选择"显示窗口"恢复窗口,"退出"结束程序。',
|
|
60
|
+
style, 15, 15, W - 30, H - 70, hwnd, null)
|
|
61
|
+
if (text) {
|
|
62
|
+
const font = gui.CreateSystemDpiFont()
|
|
63
|
+
if (font)
|
|
64
|
+
gui.SendMessage(text, gui.WmMsg.SETFONT, font, 1)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let hIcon = gui.LoadAppIcon()
|
|
68
|
+
if (!hIcon) hIcon = gui.LoadImage(null, gui.IDI.APPLICATION, gui.ImageType.ICON, 0, 0, gui.LoadImageFlag.SHARED)
|
|
69
|
+
if (hIcon) {
|
|
70
|
+
const ok = gui.ShellNotifyIcon(gui.NotifyIconCmd.ADD, {
|
|
71
|
+
hwnd: hwnd, uID: 1,
|
|
72
|
+
flags: gui.NotifyIconFlag.MESSAGE | gui.NotifyIconFlag.ICON,
|
|
73
|
+
callbackMessage: WM_TRAY,
|
|
74
|
+
hIcon,
|
|
75
|
+
})
|
|
76
|
+
std.out.printf('tray icon %s\n', ok ? 'added' : 'FAILED')
|
|
77
|
+
std.out.flush()
|
|
78
|
+
} else {
|
|
79
|
+
std.out.printf('failed to load icon\n')
|
|
80
|
+
std.out.flush()
|
|
81
|
+
}
|
package/lib/assert.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function assertNonNullable(v, msg) {
|
|
2
|
+
if (v === null || v === undefined)
|
|
3
|
+
throw new Error(msg ?? `Assert failed: unexpected ${v}`);
|
|
4
|
+
}
|
|
5
|
+
export function assertArrayBuffer(v) {
|
|
6
|
+
if (!(v instanceof ArrayBuffer))
|
|
7
|
+
throw new Error('Assert failed: expected ArrayBuffer');
|
|
8
|
+
}
|
package/lib/assert.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function assertNonNullable<T>(v: T, msg?: string): asserts v is NonNullable<T> {
|
|
2
|
+
if (v === null || v === undefined) throw new Error(msg ?? `Assert failed: unexpected ${v}`)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function assertArrayBuffer(v: ArrayBufferLike): asserts v is ArrayBuffer {
|
|
6
|
+
if (!(v instanceof ArrayBuffer)) throw new Error('Assert failed: expected ArrayBuffer')
|
|
7
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// ── INI-format cache helpers ──
|
|
2
|
+
export function parseIni(text) {
|
|
3
|
+
const headers = {};
|
|
4
|
+
const meta = {};
|
|
5
|
+
let section = '';
|
|
6
|
+
for (const line of text.split('\n')) {
|
|
7
|
+
const trimmed = line.trim();
|
|
8
|
+
if (trimmed === '[headers]') {
|
|
9
|
+
section = 'headers';
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
if (trimmed === '[meta]') {
|
|
13
|
+
section = 'meta';
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (!section || !trimmed)
|
|
17
|
+
continue;
|
|
18
|
+
const colon = trimmed.indexOf(':');
|
|
19
|
+
if (colon < 0)
|
|
20
|
+
continue;
|
|
21
|
+
const key = trimmed.slice(0, colon).trim();
|
|
22
|
+
const val = trimmed.slice(colon + 1).trim();
|
|
23
|
+
if (section === 'headers')
|
|
24
|
+
headers[key] = val;
|
|
25
|
+
else if (section === 'meta')
|
|
26
|
+
meta[key] = val;
|
|
27
|
+
}
|
|
28
|
+
return { headers, meta };
|
|
29
|
+
}
|
|
30
|
+
export function toIni(headers, meta) {
|
|
31
|
+
let s = '';
|
|
32
|
+
if (Object.keys(headers).length > 0) {
|
|
33
|
+
s += '[headers]\n';
|
|
34
|
+
for (const k in headers) {
|
|
35
|
+
s += k + ': ' + headers[k] + '\n';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
s += '[meta]\n';
|
|
39
|
+
for (const k in meta) {
|
|
40
|
+
s += k + ': ' + meta[k] + '\n';
|
|
41
|
+
}
|
|
42
|
+
return s;
|
|
43
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// ── INI-format cache helpers ──
|
|
2
|
+
|
|
3
|
+
export interface IniCache {
|
|
4
|
+
headers: Record<string, string>
|
|
5
|
+
meta: Record<string, string>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function parseIni(text: string): IniCache {
|
|
9
|
+
const headers: Record<string, string> = {}
|
|
10
|
+
const meta: Record<string, string> = {}
|
|
11
|
+
let section = ''
|
|
12
|
+
for (const line of text.split('\n')) {
|
|
13
|
+
const trimmed = line.trim()
|
|
14
|
+
if (trimmed === '[headers]') { section = 'headers'; continue }
|
|
15
|
+
if (trimmed === '[meta]') { section = 'meta'; continue }
|
|
16
|
+
if (!section || !trimmed) continue
|
|
17
|
+
const colon = trimmed.indexOf(':')
|
|
18
|
+
if (colon < 0) continue
|
|
19
|
+
const key = trimmed.slice(0, colon).trim()
|
|
20
|
+
const val = trimmed.slice(colon + 1).trim()
|
|
21
|
+
if (section === 'headers') headers[key] = val
|
|
22
|
+
else if (section === 'meta') meta[key] = val
|
|
23
|
+
}
|
|
24
|
+
return { headers, meta }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function toIni(headers: Record<string, string>, meta: Record<string, string>): string {
|
|
28
|
+
let s = ''
|
|
29
|
+
if (Object.keys(headers).length > 0) {
|
|
30
|
+
s += '[headers]\n'
|
|
31
|
+
for (const k in headers) {
|
|
32
|
+
s += k + ': ' + headers[k] + '\n'
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
s += '[meta]\n'
|
|
36
|
+
for (const k in meta) {
|
|
37
|
+
s += k + ': ' + meta[k] + '\n'
|
|
38
|
+
}
|
|
39
|
+
return s
|
|
40
|
+
}
|
package/lib/dumpRects.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
import * as gui from 'gui';
|
|
3
|
+
export function startDumpRects(rootHwnd, intervalMs = 3000) {
|
|
4
|
+
function dumpChild(parent, indent) {
|
|
5
|
+
var ch = gui.GetWindow(parent, 5 /* gui.GetWindowCmd.CHILD */);
|
|
6
|
+
var n = 0;
|
|
7
|
+
while (ch) {
|
|
8
|
+
n++;
|
|
9
|
+
var wr = gui.GetWindowRect(ch);
|
|
10
|
+
var cr = gui.GetClientRect(ch);
|
|
11
|
+
var txt = String(gui.GetWindowText(ch) || '').slice(0, 16);
|
|
12
|
+
console.log(indent + '[' + n + '] hwnd=' + String(ch) + ' txt="' + txt + '" wr=' + JSON.stringify(wr) + ' cr=' + JSON.stringify(cr));
|
|
13
|
+
dumpChild(ch, indent + ' ');
|
|
14
|
+
ch = gui.GetWindow(ch, 2 /* gui.GetWindowCmd.NEXT */);
|
|
15
|
+
}
|
|
16
|
+
if (n === 0)
|
|
17
|
+
console.log(indent + '(no children)');
|
|
18
|
+
}
|
|
19
|
+
function tick() {
|
|
20
|
+
console.log('--- dump rects ---');
|
|
21
|
+
dumpChild(rootHwnd, '');
|
|
22
|
+
os.setTimeout(tick, intervalMs);
|
|
23
|
+
}
|
|
24
|
+
tick();
|
|
25
|
+
}
|
package/lib/dumpRects.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as os from 'os'
|
|
2
|
+
import * as gui from 'gui'
|
|
3
|
+
|
|
4
|
+
export function startDumpRects(rootHwnd: gui.HWND, intervalMs: number = 3000): void {
|
|
5
|
+
function dumpChild(parent: gui.HWND, indent: string): void {
|
|
6
|
+
var ch = gui.GetWindow(parent, gui.GetWindowCmd.CHILD)
|
|
7
|
+
var n = 0
|
|
8
|
+
while (ch) {
|
|
9
|
+
n++
|
|
10
|
+
var wr = gui.GetWindowRect(ch)
|
|
11
|
+
var cr = gui.GetClientRect(ch)
|
|
12
|
+
var txt = String(gui.GetWindowText(ch) || '').slice(0, 16)
|
|
13
|
+
console.log(indent + '[' + n + '] hwnd=' + String(ch) + ' txt="' + txt + '" wr=' + JSON.stringify(wr) + ' cr=' + JSON.stringify(cr))
|
|
14
|
+
dumpChild(ch, indent + ' ')
|
|
15
|
+
ch = gui.GetWindow(ch, gui.GetWindowCmd.NEXT)
|
|
16
|
+
}
|
|
17
|
+
if (n === 0) console.log(indent + '(no children)')
|
|
18
|
+
}
|
|
19
|
+
function tick(): void {
|
|
20
|
+
console.log('--- dump rects ---')
|
|
21
|
+
dumpChild(rootHwnd, '')
|
|
22
|
+
os.setTimeout(tick, intervalMs)
|
|
23
|
+
}
|
|
24
|
+
tick()
|
|
25
|
+
}
|