dsh-mini 0.0.0-stage → 0.1.1
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.md +230 -2
- package/app/HudWindow.cs +1278 -0
- package/app/RegionCapture.cs +552 -0
- package/app/SelectionWatcher.cs +850 -0
- package/app/Service.cs +412 -0
- package/app/app.manifest +22 -0
- package/app/bin/DSH/345/260/217/347/252/227.exe +0 -0
- package/app/bin/Microsoft.Web.WebView2.Core.dll +0 -0
- package/app/bin/Microsoft.Web.WebView2.WinForms.dll +0 -0
- package/app/bin/WebView2Loader.dll +0 -0
- package/app/build-app.ps1 +112 -0
- package/app/dev.ps1 +63 -0
- package/app/hud-page.g.cs +164 -0
- package/app/hud-page.js +157 -0
- package/app/probe/clear-composer.js +8 -0
- package/app/probe/dom-probe.js +40 -0
- package/app/probe/drag.ps1 +35 -0
- package/app/probe/dump-composer.js +5 -0
- package/app/probe/frame-probe.js +21 -0
- package/app/probe/selection-sample.txt +4 -0
- package/app/probe/top-probe.js +39 -0
- package/app/vendor/Microsoft.Web.WebView2.Core.dll +0 -0
- package/app/vendor/Microsoft.Web.WebView2.WinForms.dll +0 -0
- package/app/vendor/WebView2Loader.dll +0 -0
- package/cordis.patch.yml +16 -0
- package/lib/client.js +660 -0
- package/lib/index.js +521 -0
- package/package.json +69 -4
- package/scripts/hud-shot.ps1 +168 -0
- package/scripts/native-status.ps1 +63 -0
- package/scripts/win-hud.ps1 +264 -0
- package//345/274/200/345/217/221/346/226/271/346/241/210-WebView2/345/216/237/347/224/237/345/260/217/347/252/227.md +216 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
namespace DshHud
|
|
2
|
+
{
|
|
3
|
+
internal static class HudPage
|
|
4
|
+
{
|
|
5
|
+
internal const string Script = @"/* DSH HUD page script — injected by DSH小窗.exe after every navigation.
|
|
6
|
+
* Compacts the app for a small always-on-top window and bridges it to the native shell. */
|
|
7
|
+
(function () {
|
|
8
|
+
'use strict';
|
|
9
|
+
if (window.__dshHudReady) return;
|
|
10
|
+
window.__dshHudReady = true;
|
|
11
|
+
|
|
12
|
+
var doc = document;
|
|
13
|
+
var root = doc.documentElement;
|
|
14
|
+
root.setAttribute('data-dsh-hud', '1');
|
|
15
|
+
|
|
16
|
+
/* ---------- compact styling ----------
|
|
17
|
+
* The app switches to its own narrow (""mobile"") layout at this width: drawer
|
|
18
|
+
* sidebar + slim header. We only need to trim the chrome. The overall 0.9 scale
|
|
19
|
+
* is applied by the shell as a WebView2 zoom factor, NOT as a CSS `zoom` here:
|
|
20
|
+
* CSS zoom shrinks the used height but not the viewport, which left a blank band
|
|
21
|
+
* along the bottom (and a sliver on the right). */
|
|
22
|
+
var CSS = [
|
|
23
|
+
':root[data-dsh-hud] .dsh-mobile-app-header{height:42px!important;min-height:42px!important;padding:0 4px!important}',
|
|
24
|
+
':root[data-dsh-hud] .dsh-mobile-app-header *{font-size:13px}',
|
|
25
|
+
':root[data-dsh-hud] button[title=""CDP 浏览器实时视图""]{display:none!important}',
|
|
26
|
+
':root[data-dsh-hud] [class*=""_composerSeat""]{padding-top:0!important;padding-bottom:6px!important}',
|
|
27
|
+
':root[data-dsh-hud] [class*=""_headline""]{min-height:0!important}',
|
|
28
|
+
':root[data-dsh-hud] [class*=""_scrollBody""]{scrollbar-width:thin}',
|
|
29
|
+
':root[data-dsh-hud] ::-webkit-scrollbar{width:6px;height:6px}',
|
|
30
|
+
':root[data-dsh-hud] ::-webkit-scrollbar-thumb{background:rgba(128,128,128,.35);border-radius:3px}',
|
|
31
|
+
':root[data-dsh-hud] ::-webkit-scrollbar-track{background:transparent}'
|
|
32
|
+
].join('\n');
|
|
33
|
+
|
|
34
|
+
var style = doc.getElementById('dsh-hud-style');
|
|
35
|
+
if (!style) {
|
|
36
|
+
style = doc.createElement('style');
|
|
37
|
+
style.id = 'dsh-hud-style';
|
|
38
|
+
(doc.head || root).appendChild(style);
|
|
39
|
+
}
|
|
40
|
+
style.textContent = CSS;
|
|
41
|
+
|
|
42
|
+
/* ---------- probe (debug aid; results land in hud.log) ---------- */
|
|
43
|
+
function probe() {
|
|
44
|
+
function describe(el) {
|
|
45
|
+
var r = el.getBoundingClientRect();
|
|
46
|
+
return {
|
|
47
|
+
tag: el.tagName.toLowerCase(),
|
|
48
|
+
cls: (el.getAttribute('class') || '').slice(0, 70),
|
|
49
|
+
w: Math.round(r.width), h: Math.round(r.height),
|
|
50
|
+
x: Math.round(r.x), y: Math.round(r.y)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
var out = { vw: innerWidth, vh: innerHeight, dpr: devicePixelRatio, els: [] };
|
|
54
|
+
var els = doc.querySelectorAll('#root > div > *, .dsh-mobile-app-header');
|
|
55
|
+
for (var i = 0; i < els.length && i < 24; i++) out.els.push(describe(els[i]));
|
|
56
|
+
var seat = doc.querySelector('[class*=""_composerSeat""]');
|
|
57
|
+
if (seat) out.composer = describe(seat);
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* ---------- sidebar: drive the app's own drawer button ---------- */
|
|
62
|
+
function sidebar() {
|
|
63
|
+
var labels = ['打开侧边栏', '关闭侧边栏', '收起侧边栏', '打开侧边栏'];
|
|
64
|
+
for (var i = 0; i < labels.length; i++) {
|
|
65
|
+
var b = doc.querySelector('button[aria-label=""' + labels[i] + '""]');
|
|
66
|
+
if (b) { b.click(); return true; }
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* ---------- screenshot -> composer ---------- */
|
|
72
|
+
function editor() {
|
|
73
|
+
var all = doc.querySelectorAll('[data-lexical-editor=""true""]');
|
|
74
|
+
for (var i = 0; i < all.length; i++) {
|
|
75
|
+
var r = all[i].getBoundingClientRect();
|
|
76
|
+
if (r.width > 0 && r.height > 0) return all[i];
|
|
77
|
+
}
|
|
78
|
+
return all[0] || null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function insertImage(dataUrl) {
|
|
82
|
+
var ed = editor();
|
|
83
|
+
if (!ed) return false;
|
|
84
|
+
try {
|
|
85
|
+
var bin = atob(dataUrl.slice(dataUrl.indexOf(',') + 1));
|
|
86
|
+
var bytes = new Uint8Array(bin.length);
|
|
87
|
+
for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
88
|
+
var file = new File([bytes], 'screenshot-' + Date.now() + '.png', { type: 'image/png' });
|
|
89
|
+
var dt = new DataTransfer();
|
|
90
|
+
dt.items.add(file);
|
|
91
|
+
ed.focus();
|
|
92
|
+
var ev;
|
|
93
|
+
try {
|
|
94
|
+
ev = new ClipboardEvent('paste', {
|
|
95
|
+
dataTransfer: dt, clipboardData: dt, bubbles: true, cancelable: true, composed: true
|
|
96
|
+
});
|
|
97
|
+
} catch (e) {
|
|
98
|
+
ev = new ClipboardEvent('paste', { bubbles: true, cancelable: true, composed: true });
|
|
99
|
+
Object.defineProperty(ev, 'clipboardData', { value: dt });
|
|
100
|
+
}
|
|
101
|
+
ed.dispatchEvent(ev);
|
|
102
|
+
return true;
|
|
103
|
+
} catch (e) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ---------- quoted text -> composer ---------- */
|
|
109
|
+
function insertText(text) {
|
|
110
|
+
var ed = editor();
|
|
111
|
+
if (!ed) return false;
|
|
112
|
+
try {
|
|
113
|
+
ed.focus();
|
|
114
|
+
var dt = new DataTransfer();
|
|
115
|
+
dt.setData('text/plain', text);
|
|
116
|
+
var ev;
|
|
117
|
+
try {
|
|
118
|
+
ev = new ClipboardEvent('paste', {
|
|
119
|
+
dataTransfer: dt, clipboardData: dt, bubbles: true, cancelable: true, composed: true
|
|
120
|
+
});
|
|
121
|
+
} catch (e) {
|
|
122
|
+
ev = new ClipboardEvent('paste', { bubbles: true, cancelable: true, composed: true });
|
|
123
|
+
Object.defineProperty(ev, 'clipboardData', { value: dt });
|
|
124
|
+
}
|
|
125
|
+
ed.dispatchEvent(ev);
|
|
126
|
+
return true;
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* A quote from elsewhere on the desktop: every line becomes a markdown quote. */
|
|
133
|
+
function quote(text) {
|
|
134
|
+
var t = String(text == null ? '' : text).replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\s+$/, '');
|
|
135
|
+
if (!t) return false;
|
|
136
|
+
var lines = t.split('\n');
|
|
137
|
+
for (var i = 0; i < lines.length; i++) lines[i] = '> ' + lines[i];
|
|
138
|
+
return insertText(lines.join('\n') + '\n\n');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* ---------- native bridge ---------- */
|
|
142
|
+
function post(obj) {
|
|
143
|
+
try { window.chrome.webview.postMessage(obj); } catch (e) { }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (window.chrome && window.chrome.webview) {
|
|
147
|
+
window.chrome.webview.addEventListener('message', function (ev) {
|
|
148
|
+
var msg = ev.data;
|
|
149
|
+
if (typeof msg === 'string') { try { msg = JSON.parse(msg); } catch (e) { return; } }
|
|
150
|
+
if (!msg || !msg.type) return;
|
|
151
|
+
if (msg.type === 'cmd') {
|
|
152
|
+
if (msg.cmd === 'toggle-sidebar') sidebar();
|
|
153
|
+
else if (msg.cmd === 'screenshot') post({ type: 'shot' });
|
|
154
|
+
} else if (msg.type === 'shot-result') {
|
|
155
|
+
insertImage(msg.dataUrl);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
window.__dshHud = { probe: probe, sidebar: sidebar, insertImage: insertImage, insertText: insertText, quote: quote, post: post, compact: function () { style.textContent = CSS; } };
|
|
161
|
+
})();
|
|
162
|
+
";
|
|
163
|
+
}
|
|
164
|
+
}
|
package/app/hud-page.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/* DSH HUD page script — injected by DSH小窗.exe after every navigation.
|
|
2
|
+
* Compacts the app for a small always-on-top window and bridges it to the native shell. */
|
|
3
|
+
(function () {
|
|
4
|
+
'use strict';
|
|
5
|
+
if (window.__dshHudReady) return;
|
|
6
|
+
window.__dshHudReady = true;
|
|
7
|
+
|
|
8
|
+
var doc = document;
|
|
9
|
+
var root = doc.documentElement;
|
|
10
|
+
root.setAttribute('data-dsh-hud', '1');
|
|
11
|
+
|
|
12
|
+
/* ---------- compact styling ----------
|
|
13
|
+
* The app switches to its own narrow ("mobile") layout at this width: drawer
|
|
14
|
+
* sidebar + slim header. We only need to trim the chrome. The overall 0.9 scale
|
|
15
|
+
* is applied by the shell as a WebView2 zoom factor, NOT as a CSS `zoom` here:
|
|
16
|
+
* CSS zoom shrinks the used height but not the viewport, which left a blank band
|
|
17
|
+
* along the bottom (and a sliver on the right). */
|
|
18
|
+
var CSS = [
|
|
19
|
+
':root[data-dsh-hud] .dsh-mobile-app-header{height:42px!important;min-height:42px!important;padding:0 4px!important}',
|
|
20
|
+
':root[data-dsh-hud] .dsh-mobile-app-header *{font-size:13px}',
|
|
21
|
+
':root[data-dsh-hud] button[title="CDP 浏览器实时视图"]{display:none!important}',
|
|
22
|
+
':root[data-dsh-hud] [class*="_composerSeat"]{padding-top:0!important;padding-bottom:6px!important}',
|
|
23
|
+
':root[data-dsh-hud] [class*="_headline"]{min-height:0!important}',
|
|
24
|
+
':root[data-dsh-hud] [class*="_scrollBody"]{scrollbar-width:thin}',
|
|
25
|
+
':root[data-dsh-hud] ::-webkit-scrollbar{width:6px;height:6px}',
|
|
26
|
+
':root[data-dsh-hud] ::-webkit-scrollbar-thumb{background:rgba(128,128,128,.35);border-radius:3px}',
|
|
27
|
+
':root[data-dsh-hud] ::-webkit-scrollbar-track{background:transparent}'
|
|
28
|
+
].join('\n');
|
|
29
|
+
|
|
30
|
+
var style = doc.getElementById('dsh-hud-style');
|
|
31
|
+
if (!style) {
|
|
32
|
+
style = doc.createElement('style');
|
|
33
|
+
style.id = 'dsh-hud-style';
|
|
34
|
+
(doc.head || root).appendChild(style);
|
|
35
|
+
}
|
|
36
|
+
style.textContent = CSS;
|
|
37
|
+
|
|
38
|
+
/* ---------- probe (debug aid; results land in hud.log) ---------- */
|
|
39
|
+
function probe() {
|
|
40
|
+
function describe(el) {
|
|
41
|
+
var r = el.getBoundingClientRect();
|
|
42
|
+
return {
|
|
43
|
+
tag: el.tagName.toLowerCase(),
|
|
44
|
+
cls: (el.getAttribute('class') || '').slice(0, 70),
|
|
45
|
+
w: Math.round(r.width), h: Math.round(r.height),
|
|
46
|
+
x: Math.round(r.x), y: Math.round(r.y)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
var out = { vw: innerWidth, vh: innerHeight, dpr: devicePixelRatio, els: [] };
|
|
50
|
+
var els = doc.querySelectorAll('#root > div > *, .dsh-mobile-app-header');
|
|
51
|
+
for (var i = 0; i < els.length && i < 24; i++) out.els.push(describe(els[i]));
|
|
52
|
+
var seat = doc.querySelector('[class*="_composerSeat"]');
|
|
53
|
+
if (seat) out.composer = describe(seat);
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* ---------- sidebar: drive the app's own drawer button ---------- */
|
|
58
|
+
function sidebar() {
|
|
59
|
+
var labels = ['打开侧边栏', '关闭侧边栏', '收起侧边栏', '打开侧边栏'];
|
|
60
|
+
for (var i = 0; i < labels.length; i++) {
|
|
61
|
+
var b = doc.querySelector('button[aria-label="' + labels[i] + '"]');
|
|
62
|
+
if (b) { b.click(); return true; }
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ---------- screenshot -> composer ---------- */
|
|
68
|
+
function editor() {
|
|
69
|
+
var all = doc.querySelectorAll('[data-lexical-editor="true"]');
|
|
70
|
+
for (var i = 0; i < all.length; i++) {
|
|
71
|
+
var r = all[i].getBoundingClientRect();
|
|
72
|
+
if (r.width > 0 && r.height > 0) return all[i];
|
|
73
|
+
}
|
|
74
|
+
return all[0] || null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function insertImage(dataUrl) {
|
|
78
|
+
var ed = editor();
|
|
79
|
+
if (!ed) return false;
|
|
80
|
+
try {
|
|
81
|
+
var bin = atob(dataUrl.slice(dataUrl.indexOf(',') + 1));
|
|
82
|
+
var bytes = new Uint8Array(bin.length);
|
|
83
|
+
for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
84
|
+
var file = new File([bytes], 'screenshot-' + Date.now() + '.png', { type: 'image/png' });
|
|
85
|
+
var dt = new DataTransfer();
|
|
86
|
+
dt.items.add(file);
|
|
87
|
+
ed.focus();
|
|
88
|
+
var ev;
|
|
89
|
+
try {
|
|
90
|
+
ev = new ClipboardEvent('paste', {
|
|
91
|
+
dataTransfer: dt, clipboardData: dt, bubbles: true, cancelable: true, composed: true
|
|
92
|
+
});
|
|
93
|
+
} catch (e) {
|
|
94
|
+
ev = new ClipboardEvent('paste', { bubbles: true, cancelable: true, composed: true });
|
|
95
|
+
Object.defineProperty(ev, 'clipboardData', { value: dt });
|
|
96
|
+
}
|
|
97
|
+
ed.dispatchEvent(ev);
|
|
98
|
+
return true;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* ---------- quoted text -> composer ---------- */
|
|
105
|
+
function insertText(text) {
|
|
106
|
+
var ed = editor();
|
|
107
|
+
if (!ed) return false;
|
|
108
|
+
try {
|
|
109
|
+
ed.focus();
|
|
110
|
+
var dt = new DataTransfer();
|
|
111
|
+
dt.setData('text/plain', text);
|
|
112
|
+
var ev;
|
|
113
|
+
try {
|
|
114
|
+
ev = new ClipboardEvent('paste', {
|
|
115
|
+
dataTransfer: dt, clipboardData: dt, bubbles: true, cancelable: true, composed: true
|
|
116
|
+
});
|
|
117
|
+
} catch (e) {
|
|
118
|
+
ev = new ClipboardEvent('paste', { bubbles: true, cancelable: true, composed: true });
|
|
119
|
+
Object.defineProperty(ev, 'clipboardData', { value: dt });
|
|
120
|
+
}
|
|
121
|
+
ed.dispatchEvent(ev);
|
|
122
|
+
return true;
|
|
123
|
+
} catch (e) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* A quote from elsewhere on the desktop: every line becomes a markdown quote. */
|
|
129
|
+
function quote(text) {
|
|
130
|
+
var t = String(text == null ? '' : text).replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\s+$/, '');
|
|
131
|
+
if (!t) return false;
|
|
132
|
+
var lines = t.split('\n');
|
|
133
|
+
for (var i = 0; i < lines.length; i++) lines[i] = '> ' + lines[i];
|
|
134
|
+
return insertText(lines.join('\n') + '\n\n');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* ---------- native bridge ---------- */
|
|
138
|
+
function post(obj) {
|
|
139
|
+
try { window.chrome.webview.postMessage(obj); } catch (e) { }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (window.chrome && window.chrome.webview) {
|
|
143
|
+
window.chrome.webview.addEventListener('message', function (ev) {
|
|
144
|
+
var msg = ev.data;
|
|
145
|
+
if (typeof msg === 'string') { try { msg = JSON.parse(msg); } catch (e) { return; } }
|
|
146
|
+
if (!msg || !msg.type) return;
|
|
147
|
+
if (msg.type === 'cmd') {
|
|
148
|
+
if (msg.cmd === 'toggle-sidebar') sidebar();
|
|
149
|
+
else if (msg.cmd === 'screenshot') post({ type: 'shot' });
|
|
150
|
+
} else if (msg.type === 'shot-result') {
|
|
151
|
+
insertImage(msg.dataUrl);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
window.__dshHud = { probe: probe, sidebar: sidebar, insertImage: insertImage, insertText: insertText, quote: quote, post: post, compact: function () { style.textContent = CSS; } };
|
|
157
|
+
})();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
function desc(el) {
|
|
3
|
+
var r = el.getBoundingClientRect();
|
|
4
|
+
var cs = getComputedStyle(el);
|
|
5
|
+
return {
|
|
6
|
+
t: el.tagName.toLowerCase(),
|
|
7
|
+
c: (el.getAttribute && el.getAttribute('class') || '').slice(0, 90),
|
|
8
|
+
i: el.id || '',
|
|
9
|
+
r: el.getAttribute('role') || '',
|
|
10
|
+
d: el.getAttribute('data-testid') || el.getAttribute('data-slot') || el.getAttribute('data-name') || '',
|
|
11
|
+
w: Math.round(r.width), h: Math.round(r.height),
|
|
12
|
+
x: Math.round(r.x), y: Math.round(r.y),
|
|
13
|
+
pos: cs.position, disp: cs.display
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
var out = { vw: innerWidth, vh: innerHeight, dpr: devicePixelRatio, n: 0, els: [], text: [] };
|
|
17
|
+
var all = document.querySelectorAll('body *');
|
|
18
|
+
out.n = all.length;
|
|
19
|
+
for (var i = 0; i < all.length; i++) {
|
|
20
|
+
var el = all[i];
|
|
21
|
+
var r = el.getBoundingClientRect();
|
|
22
|
+
if (r.width < 40 || r.height < 24) continue;
|
|
23
|
+
out.els.push(desc(el));
|
|
24
|
+
if (out.els.length >= 90) break;
|
|
25
|
+
}
|
|
26
|
+
// interactive bits: buttons / inputs / textareas
|
|
27
|
+
var ints = document.querySelectorAll('button,[role="button"],input,textarea,[contenteditable="true"]');
|
|
28
|
+
for (var j = 0; j < ints.length && j < 40; j++) {
|
|
29
|
+
var e2 = ints[j];
|
|
30
|
+
var r2 = e2.getBoundingClientRect();
|
|
31
|
+
out.text.push({
|
|
32
|
+
t: e2.tagName.toLowerCase(),
|
|
33
|
+
aria: e2.getAttribute('aria-label') || '',
|
|
34
|
+
title: e2.getAttribute('title') || '',
|
|
35
|
+
ph: e2.getAttribute('placeholder') || (e2.getAttribute('data-placeholder') || ''),
|
|
36
|
+
w: Math.round(r2.width), h: Math.round(r2.height)
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
})()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[int]$X1 = 0, [int]$Y1 = 0, [int]$X2 = 0, [int]$Y2 = 0, [int]$Left = -1, [int]$Top = -1,
|
|
3
|
+
[int]$Width = 0, [int]$Height = 0
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
$ErrorActionPreference = 'Stop'
|
|
7
|
+
|
|
8
|
+
Add-Type -Namespace Drag -Name U -MemberDefinition @'
|
|
9
|
+
[DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
|
|
10
|
+
[DllImport("user32.dll")] public static extern void mouse_event(uint f, uint dx, uint dy, uint d, System.UIntPtr e);
|
|
11
|
+
[DllImport("user32.dll")] public static extern bool SetWindowPos(System.IntPtr h, System.IntPtr a, int x, int y, int cx, int cy, uint f);
|
|
12
|
+
public const uint DOWN = 0x0002;
|
|
13
|
+
public const uint UP = 0x0004;
|
|
14
|
+
'@
|
|
15
|
+
|
|
16
|
+
if ($Left -ge 0 -and $Width -gt 0) {
|
|
17
|
+
[void][Drag.U]::SetWindowPos([IntPtr]$env:DRAG_HWND, [IntPtr]::Zero, $Left, $Top, $Width, $Height, 0x0014)
|
|
18
|
+
Start-Sleep -Milliseconds 600
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
[void][Drag.U]::SetCursorPos($X1, $Y1)
|
|
22
|
+
Start-Sleep -Milliseconds 200
|
|
23
|
+
[Drag.U]::mouse_event([Drag.U]::DOWN, 0, 0, 0, [System.UIntPtr]::Zero)
|
|
24
|
+
Start-Sleep -Milliseconds 160
|
|
25
|
+
$steps = 12
|
|
26
|
+
for ($i = 1; $i -le $steps; $i++) {
|
|
27
|
+
$x = [int]($X1 + ($X2 - $X1) * $i / $steps)
|
|
28
|
+
$y = [int]($Y1 + ($Y2 - $Y1) * $i / $steps)
|
|
29
|
+
[void][Drag.U]::SetCursorPos($x, $y)
|
|
30
|
+
Start-Sleep -Milliseconds 25
|
|
31
|
+
}
|
|
32
|
+
Start-Sleep -Milliseconds 120
|
|
33
|
+
[Drag.U]::mouse_event([Drag.U]::UP, 0, 0, 0, [System.UIntPtr]::Zero)
|
|
34
|
+
Start-Sleep -Milliseconds 500
|
|
35
|
+
'cursor=' + [System.Windows.Forms.Cursor]::Position
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var out = [];
|
|
3
|
+
var els = document.querySelectorAll('[class*="mP3x-q_"]');
|
|
4
|
+
for (var i = 0; i < els.length; i++) {
|
|
5
|
+
var el = els[i];
|
|
6
|
+
var r = el.getBoundingClientRect();
|
|
7
|
+
out.push({
|
|
8
|
+
c: el.getAttribute('class'),
|
|
9
|
+
t: el.tagName.toLowerCase(),
|
|
10
|
+
w: Math.round(r.width), h: Math.round(r.height),
|
|
11
|
+
x: Math.round(r.x), y: Math.round(r.y)
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
var body = [];
|
|
15
|
+
var kids = document.body.children;
|
|
16
|
+
for (var j = 0; j < kids.length; j++) {
|
|
17
|
+
var k = kids[j], rk = k.getBoundingClientRect();
|
|
18
|
+
body.push({ t: k.tagName.toLowerCase(), c: (k.getAttribute('class') || '').slice(0, 60), w: Math.round(rk.width), h: Math.round(rk.height) });
|
|
19
|
+
}
|
|
20
|
+
return { frame: out, bodyKids: body };
|
|
21
|
+
})()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var out = { vw: innerWidth, vh: innerHeight, top: [], tabs: [], composer: {} };
|
|
3
|
+
|
|
4
|
+
function d(el) {
|
|
5
|
+
var r = el.getBoundingClientRect();
|
|
6
|
+
return {
|
|
7
|
+
t: el.tagName.toLowerCase(),
|
|
8
|
+
c: (el.getAttribute('class') || '').slice(0, 80),
|
|
9
|
+
a: el.getAttribute('aria-label') || '',
|
|
10
|
+
w: Math.round(r.width), h: Math.round(r.height),
|
|
11
|
+
x: Math.round(r.x), y: Math.round(r.y)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var all = document.querySelectorAll('#root *');
|
|
16
|
+
for (var i = 0; i < all.length; i++) {
|
|
17
|
+
var el = all[i];
|
|
18
|
+
var r = el.getBoundingClientRect();
|
|
19
|
+
if (r.height >= 10 && r.width >= 100 && r.y < 60 && r.y > -40) {
|
|
20
|
+
out.top.push(d(el));
|
|
21
|
+
if (out.top.length >= 22) break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// composer geometry: the seat that holds the input
|
|
26
|
+
var tb = document.querySelector('[data-lexical-editor="true"]');
|
|
27
|
+
if (tb) {
|
|
28
|
+
var seat = tb.parentElement;
|
|
29
|
+
for (var up = 0; up < 6 && seat; up++) {
|
|
30
|
+
var rr = seat.getBoundingClientRect();
|
|
31
|
+
if (rr.height > 100) {
|
|
32
|
+
out.composer = { c: seat.getAttribute('class') || '', w: Math.round(rr.width), h: Math.round(rr.height), y: Math.round(rr.y) };
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
seat = seat.parentElement;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
})()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# dsh-mini bundle patch
|
|
2
|
+
#
|
|
3
|
+
# 一行 insert 挂载宿主半身(HTTP 路由 + 开窗)。
|
|
4
|
+
# 浏览器半身由 package.json 的 dsh.client 声明,绑定在 name 为裸包名的这一行上。
|
|
5
|
+
# name 必须与 package.json 的包名完全一致。
|
|
6
|
+
- insert:
|
|
7
|
+
- id: dsh-mini
|
|
8
|
+
name: 'dsh-mini'
|
|
9
|
+
config:
|
|
10
|
+
# 小窗页面标题前缀:PowerShell 靠它定位/置顶/隐藏这扇窗
|
|
11
|
+
titlePrefix: 'DSH 小窗'
|
|
12
|
+
# 小窗初始尺寸(逻辑像素)
|
|
13
|
+
width: 460
|
|
14
|
+
height: 560
|
|
15
|
+
# 留空则自动探测 Edge / Chrome
|
|
16
|
+
browserPath: ''
|