xw-devtool-cli 1.0.36 → 1.0.37
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/package.json +1 -1
- package/src/commands/colorPick.js +69 -101
package/package.json
CHANGED
|
@@ -145,45 +145,35 @@ export async function colorPickHandler() {
|
|
|
145
145
|
console.log(i18next.t('colorPick.notSupported'));
|
|
146
146
|
return;
|
|
147
147
|
}
|
|
148
|
-
|
|
149
|
-
let sampler = null;
|
|
150
|
-
const readOneLine = (timeoutMs = 800) => new Promise((resolve) => {
|
|
151
|
-
let settled = false;
|
|
152
|
-
const onData = (buf) => {
|
|
153
|
-
if (settled) return;
|
|
154
|
-
settled = true;
|
|
155
|
-
resolve(buf.toString('utf8').trim());
|
|
156
|
-
};
|
|
157
|
-
sampler.stdout.once('data', onData);
|
|
158
|
-
if (timeoutMs > 0) {
|
|
159
|
-
setTimeout(() => {
|
|
160
|
-
if (settled) return;
|
|
161
|
-
settled = true;
|
|
162
|
-
try { sampler.stdout.removeListener('data', onData); } catch {}
|
|
163
|
-
resolve(null);
|
|
164
|
-
}, timeoutMs);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
try {
|
|
168
|
-
const overlayScript = `
|
|
148
|
+
const overlayScript = `
|
|
169
149
|
Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing;
|
|
170
150
|
Add-Type -TypeDefinition @'
|
|
171
151
|
using System;
|
|
172
152
|
using System.Drawing;
|
|
173
|
-
using System.Windows.Forms;
|
|
174
153
|
using System.Runtime.InteropServices;
|
|
154
|
+
using System.Windows.Forms;
|
|
175
155
|
public class OverlayForm : Form {
|
|
176
156
|
const int WS_EX_TRANSPARENT=0x20;
|
|
177
157
|
const int WS_EX_LAYERED=0x80000;
|
|
178
158
|
const int GWL_EXSTYLE=-20;
|
|
179
159
|
[DllImport("user32.dll")] static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
|
180
160
|
[DllImport("user32.dll")] static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
|
161
|
+
[DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr hWnd);
|
|
162
|
+
[DllImport("user32.dll")] static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
|
163
|
+
[DllImport("gdi32.dll")] static extern int GetPixel(IntPtr hdc, int x, int y);
|
|
181
164
|
Timer t;
|
|
165
|
+
DateTime copyUntil = DateTime.MinValue;
|
|
166
|
+
string lastHex = "#000000";
|
|
167
|
+
string lastRgb = "RGB(0,0,0)";
|
|
182
168
|
public OverlayForm(){
|
|
183
169
|
this.FormBorderStyle=FormBorderStyle.None;
|
|
184
170
|
this.TopMost=true;
|
|
185
171
|
this.ShowInTaskbar=false;
|
|
186
|
-
this.
|
|
172
|
+
this.KeyPreview = true;
|
|
173
|
+
Rectangle totalBounds = Rectangle.Empty;
|
|
174
|
+
foreach(Screen s in Screen.AllScreens){ totalBounds = Rectangle.Union(totalBounds, s.Bounds); }
|
|
175
|
+
this.StartPosition = FormStartPosition.Manual;
|
|
176
|
+
this.Bounds = totalBounds;
|
|
187
177
|
this.BackColor=Color.Fuchsia;
|
|
188
178
|
this.TransparencyKey=this.BackColor;
|
|
189
179
|
this.DoubleBuffered=true;
|
|
@@ -192,20 +182,55 @@ public class OverlayForm : Form {
|
|
|
192
182
|
base.OnShown(e);
|
|
193
183
|
int ex=GetWindowLong(this.Handle,GWL_EXSTYLE);
|
|
194
184
|
SetWindowLong(this.Handle,GWL_EXSTYLE,ex|WS_EX_LAYERED|WS_EX_TRANSPARENT);
|
|
185
|
+
this.Focus();
|
|
186
|
+
this.Activate();
|
|
195
187
|
t=new Timer();
|
|
196
188
|
t.Interval=33;
|
|
197
189
|
t.Tick+=(s,ev)=>{ this.Invalidate(); };
|
|
198
190
|
t.Start();
|
|
199
191
|
}
|
|
192
|
+
protected override void OnKeyDown(KeyEventArgs e){
|
|
193
|
+
if(e.KeyCode==Keys.Escape){ Application.Exit(); }
|
|
194
|
+
if(e.KeyCode==Keys.Enter){ Clipboard.SetText(lastHex); copyUntil = DateTime.Now.AddSeconds(2); }
|
|
195
|
+
}
|
|
200
196
|
protected override void OnPaint(PaintEventArgs e){
|
|
201
|
-
var p=Cursor.Position;
|
|
202
197
|
var g=e.Graphics;
|
|
198
|
+
var p=this.PointToClient(Cursor.Position);
|
|
203
199
|
int gap=16;
|
|
204
200
|
using(var pen=new Pen(Color.Red,1)){
|
|
205
201
|
g.DrawLine(pen,0,p.Y,Math.Max(0,p.X-gap),p.Y);
|
|
206
|
-
g.DrawLine(pen,Math.Min(this.Width,p.X+gap),p.Y,this.Width,p.Y);
|
|
202
|
+
g.DrawLine(pen,Math.Min(this.ClientSize.Width,p.X+gap),p.Y,this.ClientSize.Width,p.Y);
|
|
207
203
|
g.DrawLine(pen,p.X,0,p.X,Math.Max(0,p.Y-gap));
|
|
208
|
-
g.DrawLine(pen,p.X,Math.Min(this.Height,p.Y+gap),p.X,this.Height);
|
|
204
|
+
g.DrawLine(pen,p.X,Math.Min(this.ClientSize.Height,p.Y+gap),p.X,this.ClientSize.Height);
|
|
205
|
+
}
|
|
206
|
+
IntPtr hdc = GetDC(IntPtr.Zero);
|
|
207
|
+
int color = GetPixel(hdc, Cursor.Position.X, Cursor.Position.Y);
|
|
208
|
+
ReleaseDC(IntPtr.Zero, hdc);
|
|
209
|
+
if(color!=-1){
|
|
210
|
+
int r = color & 0xFF;
|
|
211
|
+
int gC = (color >> 8) & 0xFF;
|
|
212
|
+
int b = (color >> 16) & 0xFF;
|
|
213
|
+
lastHex = String.Format("#{0:X2}{1:X2}{2:X2}", r, gC, b);
|
|
214
|
+
lastRgb = String.Format("RGB({0},{1},{2})", r, gC, b);
|
|
215
|
+
SizeF szHex = g.MeasureString(lastHex, new Font("Segoe UI", 12, FontStyle.Bold));
|
|
216
|
+
SizeF szRgb = g.MeasureString(lastRgb, new Font("Segoe UI", 10, FontStyle.Regular));
|
|
217
|
+
float pad = 12;
|
|
218
|
+
float boxW = Math.Max(szHex.Width, szRgb.Width) + pad*2 + 40;
|
|
219
|
+
float boxH = szHex.Height + szRgb.Height + pad*3;
|
|
220
|
+
float x = this.ClientSize.Width - boxW - 16;
|
|
221
|
+
float y = this.ClientSize.Height - boxH - 16;
|
|
222
|
+
using(var bg = new SolidBrush(Color.FromArgb(180,0,0,0))){ g.FillRectangle(bg, x, y, boxW, boxH); }
|
|
223
|
+
using(var preview = new SolidBrush(Color.FromArgb(r,gC,b))){ g.FillRectangle(preview, x+pad, y+pad, 36, boxH - pad*2); }
|
|
224
|
+
g.DrawString(lastHex, new Font("Segoe UI", 12, FontStyle.Bold), Brushes.White, x+pad+40, y+pad);
|
|
225
|
+
g.DrawString(lastRgb, new Font("Segoe UI", 10), Brushes.White, x+pad+40, y+pad+szHex.Height+6);
|
|
226
|
+
if(DateTime.Now < copyUntil){
|
|
227
|
+
string copied = "Copied: " + lastHex;
|
|
228
|
+
SizeF szC = g.MeasureString(copied, new Font("Segoe UI", 10));
|
|
229
|
+
float cx = x + pad + 40;
|
|
230
|
+
float cy = y + boxH - szC.Height - pad;
|
|
231
|
+
using(var bg2 = new SolidBrush(Color.FromArgb(160,0,128,0))){ g.FillRectangle(bg2, cx-6, cy-4, szC.Width+12, szC.Height+8); }
|
|
232
|
+
g.DrawString(copied, new Font("Segoe UI", 10), Brushes.White, cx, cy);
|
|
233
|
+
}
|
|
209
234
|
}
|
|
210
235
|
}
|
|
211
236
|
}
|
|
@@ -215,75 +240,17 @@ public static class Entry {
|
|
|
215
240
|
'@ -ReferencedAssemblies System.Windows.Forms,System.Drawing;
|
|
216
241
|
[Entry]::Main()
|
|
217
242
|
`;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
using System;
|
|
222
|
-
using System.Runtime.InteropServices;
|
|
223
|
-
public static class ColorSampler {
|
|
224
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
225
|
-
public struct POINT { public int X; public int Y; }
|
|
226
|
-
[DllImport("user32.dll")] static extern bool GetCursorPos(out POINT lpPoint);
|
|
227
|
-
[DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr hWnd);
|
|
228
|
-
[DllImport("user32.dll")] static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
|
229
|
-
[DllImport("gdi32.dll")] static extern int GetPixel(IntPtr hdc, int x, int y);
|
|
230
|
-
public static string Sample() {
|
|
231
|
-
POINT p;
|
|
232
|
-
if(!GetCursorPos(out p)) return "";
|
|
233
|
-
IntPtr hdc = GetDC(IntPtr.Zero);
|
|
234
|
-
if (hdc == IntPtr.Zero) return "";
|
|
235
|
-
int color = GetPixel(hdc, p.X, p.Y);
|
|
236
|
-
ReleaseDC(IntPtr.Zero, hdc);
|
|
237
|
-
if (color == -1) return "";
|
|
238
|
-
int r = color & 0xFF;
|
|
239
|
-
int g = (color >> 8) & 0xFF;
|
|
240
|
-
int b = (color >> 16) & 0xFF;
|
|
241
|
-
return $"{r},{g},{b},255";
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
'@
|
|
245
|
-
function Sample {
|
|
246
|
-
$s=[ColorSampler]::Sample();
|
|
247
|
-
if([string]::IsNullOrEmpty($s)){ [Console]::Out.WriteLine(""); } else { [Console]::Out.WriteLine($s) }
|
|
248
|
-
}
|
|
249
|
-
while($true){
|
|
250
|
-
$line = [Console]::In.ReadLine();
|
|
251
|
-
if($line -eq $null){ break }
|
|
252
|
-
if($line -eq 'SAMPLE'){ Sample }
|
|
253
|
-
elseif($line -eq 'EXIT'){ break }
|
|
254
|
-
}
|
|
255
|
-
`;
|
|
256
|
-
sampler = spawn('powershell', ['-NoProfile', '-Command', samplerScript], { windowsHide: true, stdio: ['pipe', 'pipe', 'ignore'] });
|
|
257
|
-
try { sampler.stdout.setEncoding('utf8'); } catch {}
|
|
258
|
-
} catch {}
|
|
259
|
-
console.log(i18next.t('colorPick.moveMousePrompt'));
|
|
260
|
-
let last = null;
|
|
261
|
-
const sampleOnce = async () => {
|
|
243
|
+
const overlay = spawn('powershell', ['-NoProfile', '-Command', overlayScript], { windowsHide: true });
|
|
244
|
+
const sampleCmd = `powershell -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing; $p=[System.Windows.Forms.Cursor]::Position; $bmp=New-Object System.Drawing.Bitmap 1,1; $g=[System.Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($p.X,$p.Y,0,0,[System.Drawing.Size]::new(1,1)); $c=$bmp.GetPixel(0,0); Write-Output (\\"$($c.R),$($c.G),$($c.B),255\\"); $g.Dispose(); $bmp.Dispose();"`;
|
|
245
|
+
const sampleNow = () => {
|
|
262
246
|
try {
|
|
263
|
-
|
|
264
|
-
if (sampler && sampler.stdin && !sampler.killed) {
|
|
265
|
-
sampler.stdin.write('SAMPLE\n');
|
|
266
|
-
out = await readOneLine(800);
|
|
267
|
-
}
|
|
268
|
-
if (!out) {
|
|
269
|
-
const cmd = `powershell -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing; $p=[System.Windows.Forms.Cursor]::Position; $bmp=New-Object System.Drawing.Bitmap 1,1; $g=[System.Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($p.X,$p.Y,0,0,[System.Drawing.Size]::new(1,1)); $c=$bmp.GetPixel(0,0); Write-Output (\\"$($c.R),$($c.G),$($c.B),255\\"); $g.Dispose(); $bmp.Dispose();"`;
|
|
270
|
-
out = execSync(cmd, { stdio: ['pipe', 'pipe', 'ignore'] }).toString('utf8').trim();
|
|
271
|
-
}
|
|
247
|
+
const out = execSync(sampleCmd, { stdio: ['pipe', 'pipe', 'ignore'] }).toString('utf8').trim();
|
|
272
248
|
const parts = out.split(',').map(n => parseInt(n, 10));
|
|
273
249
|
const r = parts[0], g = parts[1], b = parts[2];
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
const hex = last.a < 1 ? tc.toHex8String().toUpperCase() : tc.toHexString().toUpperCase();
|
|
277
|
-
const rgb = tc.toRgbString();
|
|
278
|
-
const hsl = tc.toHslString();
|
|
279
|
-
console.log('\n=== ' + i18next.t('colorPick.result') + ' ===');
|
|
280
|
-
console.log(`Hex: ${hex}`);
|
|
281
|
-
console.log(`RGB: ${rgb}`);
|
|
282
|
-
console.log(`HSL: ${hsl}`);
|
|
283
|
-
console.log('==========================\n');
|
|
284
|
-
const label = `${i18next.t('colorPreview.preview')} ${hex} ${rgb} ${hsl}`;
|
|
285
|
-
printColorBar({ r: last.r, g: last.g, b: last.b }, 50, 2, label, last.a);
|
|
250
|
+
const tc = tinycolor({ r, g, b, a: 1 });
|
|
251
|
+
const hex = tc.toHexString().toUpperCase();
|
|
286
252
|
copy(hex);
|
|
253
|
+
console.log(i18next.t('colorPreview.copied', { value: hex }));
|
|
287
254
|
} catch {}
|
|
288
255
|
};
|
|
289
256
|
await new Promise((resolve) => {
|
|
@@ -292,24 +259,25 @@ while($true){
|
|
|
292
259
|
stdin.resume();
|
|
293
260
|
const onData = (data) => {
|
|
294
261
|
const s = data.toString('utf8');
|
|
295
|
-
if (s === '
|
|
296
|
-
sampleOnce();
|
|
297
|
-
} else if (s === '\r' || s === '\n') {
|
|
262
|
+
if (s === '\x1b') {
|
|
298
263
|
stdin.removeListener('data', onData);
|
|
299
264
|
try { stdin.setRawMode(false); } catch {}
|
|
300
265
|
stdin.pause();
|
|
266
|
+
try { overlay.kill(); } catch {}
|
|
301
267
|
resolve();
|
|
268
|
+
} else if (s === '\r' || s === '\n') {
|
|
269
|
+
sampleNow();
|
|
302
270
|
}
|
|
303
271
|
};
|
|
304
272
|
stdin.on('data', onData);
|
|
273
|
+
overlay.on('close', () => {
|
|
274
|
+
stdin.removeListener('data', onData);
|
|
275
|
+
try { stdin.setRawMode(false); } catch {}
|
|
276
|
+
stdin.pause();
|
|
277
|
+
resolve();
|
|
278
|
+
});
|
|
305
279
|
});
|
|
306
|
-
|
|
307
|
-
try { if (overlay) { overlay.kill(); } } catch {}
|
|
308
|
-
if (!last) {
|
|
309
|
-
console.log(i18next.t('colorPick.pickFail'));
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
picked = { r: last.r, g: last.g, b: last.b, a: last.a, region: null };
|
|
280
|
+
return;
|
|
313
281
|
} else {
|
|
314
282
|
const inputPath = await pickInputFile();
|
|
315
283
|
if (inputPath === '__BACK__') {
|