xw-devtool-cli 1.0.28 → 1.0.29
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 +2 -1
- package/README_EN.md +1 -0
- package/package.json +4 -2
- package/src/commands/screenMark.js +169 -0
- package/src/index.js +5 -0
- package/src/locales/en.js +5 -0
- package/src/locales/zh.js +1 -0
package/README.md
CHANGED
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
> 2. 由于涉及跨进程通信,按下空格后可能存在轻微延时,请耐心等待结果。
|
|
22
22
|
> 3. 取色模式下会显示全屏十字辅助线,按 **回车键** 退出模式。
|
|
23
23
|
- **占位图生成**:快速生成指定尺寸、颜色、文字的占位图片 (Placeholder Image)。
|
|
24
|
-
- **全屏十字辅助线**:显示跟随鼠标的全屏红色十字线,用于屏幕对齐和定位。
|
|
24
|
+
- **全屏十字辅助线**:显示跟随鼠标的全屏红色十字线,用于屏幕对齐和定位。
|
|
25
25
|
- **屏幕测距**:点击屏幕上任意两点,测量其像素距离。
|
|
26
|
+
- **屏幕文字标注**:在屏幕上点击并输入文字,进行临时标注。右键撤销,Delete 清空。
|
|
26
27
|
- **Mock 数据生成**:
|
|
27
28
|
- 支持生成:英文段落 (Lorem Ipsum)、中文字符、中国居民身份证号、电子邮箱、URL、订单号、手机号、座机号。
|
|
28
29
|
- 支持批量生成。
|
package/README_EN.md
CHANGED
|
@@ -18,6 +18,7 @@ Key features include: Base64 encoding/decoding, image format conversion, image <
|
|
|
18
18
|
- **Screen Picker**: Pick color directly from the screen at the mouse position; move the cursor and press Enter to sample; supports alpha preview.
|
|
19
19
|
- **Screen Crosshair**: Display a full-screen red crosshair following the mouse for alignment.
|
|
20
20
|
- **Pixel Distance**: Measure pixel distance between two points on the screen.
|
|
21
|
+
- **Screen Mark**: Click on the screen to add text annotations. Right-click to undo, Delete to clear.
|
|
21
22
|
- **Mock Data**:
|
|
22
23
|
- Generate: Lorem Ipsum, Chinese characters, ID cards, Emails, URLs, Order IDs, Phone numbers.
|
|
23
24
|
- Supports batch generation.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xw-devtool-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.29",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "基于node的开发者助手cli",
|
|
6
6
|
"main": "index.js",
|
|
@@ -49,7 +49,9 @@
|
|
|
49
49
|
"md5",
|
|
50
50
|
"color-converter",
|
|
51
51
|
"emoji",
|
|
52
|
-
"markdown"
|
|
52
|
+
"markdown",
|
|
53
|
+
"screen-mark",
|
|
54
|
+
"pixel-distance"
|
|
53
55
|
],
|
|
54
56
|
"author": "npmxw",
|
|
55
57
|
"license": "ISC",
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import i18next from '../i18n.js';
|
|
3
|
+
|
|
4
|
+
export async function screenMarkHandler() {
|
|
5
|
+
if (process.platform !== 'win32') {
|
|
6
|
+
console.log(i18next.t('screenMark.notSupported'));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
console.log(i18next.t('screenMark.startPrompt'));
|
|
11
|
+
|
|
12
|
+
const overlayScript = `
|
|
13
|
+
Add-Type -AssemblyName System.Windows.Forms;
|
|
14
|
+
Add-Type -AssemblyName System.Drawing;
|
|
15
|
+
|
|
16
|
+
Add-Type -TypeDefinition @'
|
|
17
|
+
using System;
|
|
18
|
+
using System.Drawing;
|
|
19
|
+
using System.Windows.Forms;
|
|
20
|
+
using System.Collections.Generic;
|
|
21
|
+
|
|
22
|
+
public class MarkItem {
|
|
23
|
+
public Point Location;
|
|
24
|
+
public string Text;
|
|
25
|
+
public MarkItem(Point loc, string text) {
|
|
26
|
+
Location = loc;
|
|
27
|
+
Text = text;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public class InputBox : Form {
|
|
32
|
+
private TextBox textBox;
|
|
33
|
+
private Button btnOk;
|
|
34
|
+
private Button btnCancel;
|
|
35
|
+
public string InputText { get { return textBox.Text; } }
|
|
36
|
+
|
|
37
|
+
public InputBox(string title, string prompt, Point location) {
|
|
38
|
+
this.Text = title;
|
|
39
|
+
this.Size = new Size(300, 150);
|
|
40
|
+
this.FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
41
|
+
this.StartPosition = FormStartPosition.Manual;
|
|
42
|
+
this.Location = location;
|
|
43
|
+
this.TopMost = true;
|
|
44
|
+
this.MinimizeBox = false;
|
|
45
|
+
this.MaximizeBox = false;
|
|
46
|
+
|
|
47
|
+
Label lbl = new Label();
|
|
48
|
+
lbl.Text = prompt;
|
|
49
|
+
lbl.Location = new Point(10, 10);
|
|
50
|
+
lbl.AutoSize = true;
|
|
51
|
+
this.Controls.Add(lbl);
|
|
52
|
+
|
|
53
|
+
textBox = new TextBox();
|
|
54
|
+
textBox.Location = new Point(10, 35);
|
|
55
|
+
textBox.Size = new Size(260, 20);
|
|
56
|
+
this.Controls.Add(textBox);
|
|
57
|
+
|
|
58
|
+
btnOk = new Button();
|
|
59
|
+
btnOk.Text = "OK";
|
|
60
|
+
btnOk.DialogResult = DialogResult.OK;
|
|
61
|
+
btnOk.Location = new Point(110, 70);
|
|
62
|
+
this.Controls.Add(btnOk);
|
|
63
|
+
|
|
64
|
+
btnCancel = new Button();
|
|
65
|
+
btnCancel.Text = "Cancel";
|
|
66
|
+
btnCancel.DialogResult = DialogResult.Cancel;
|
|
67
|
+
btnCancel.Location = new Point(190, 70);
|
|
68
|
+
this.Controls.Add(btnCancel);
|
|
69
|
+
|
|
70
|
+
this.AcceptButton = btnOk;
|
|
71
|
+
this.CancelButton = btnCancel;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public class MarkForm : Form {
|
|
76
|
+
private List<MarkItem> marks = new List<MarkItem>();
|
|
77
|
+
private Bitmap screenCapture;
|
|
78
|
+
|
|
79
|
+
public MarkForm() {
|
|
80
|
+
this.FormBorderStyle = FormBorderStyle.None;
|
|
81
|
+
this.TopMost = true;
|
|
82
|
+
this.Cursor = Cursors.IBeam;
|
|
83
|
+
this.DoubleBuffered = true;
|
|
84
|
+
|
|
85
|
+
// Calculate total bounds
|
|
86
|
+
Rectangle totalBounds = Rectangle.Empty;
|
|
87
|
+
foreach(Screen s in Screen.AllScreens) {
|
|
88
|
+
totalBounds = Rectangle.Union(totalBounds, s.Bounds);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.StartPosition = FormStartPosition.Manual;
|
|
92
|
+
this.Bounds = totalBounds;
|
|
93
|
+
|
|
94
|
+
// Capture screen
|
|
95
|
+
screenCapture = new Bitmap(totalBounds.Width, totalBounds.Height);
|
|
96
|
+
using (Graphics g = Graphics.FromImage(screenCapture)) {
|
|
97
|
+
g.CopyFromScreen(totalBounds.Location, Point.Empty, totalBounds.Size);
|
|
98
|
+
}
|
|
99
|
+
this.BackgroundImage = screenCapture;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
protected override void OnMouseDown(MouseEventArgs e) {
|
|
103
|
+
if (e.Button == MouseButtons.Right) {
|
|
104
|
+
// Remove last mark
|
|
105
|
+
if (marks.Count > 0) {
|
|
106
|
+
marks.RemoveAt(marks.Count - 1);
|
|
107
|
+
this.Invalidate();
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (e.Button == MouseButtons.Left) {
|
|
113
|
+
// Show input box
|
|
114
|
+
using (InputBox input = new InputBox("Add Text", "Enter text:", Cursor.Position)) {
|
|
115
|
+
if (input.ShowDialog() == DialogResult.OK && !string.IsNullOrWhiteSpace(input.InputText)) {
|
|
116
|
+
marks.Add(new MarkItem(e.Location, input.InputText));
|
|
117
|
+
this.Invalidate();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
protected override void OnPaint(PaintEventArgs e) {
|
|
124
|
+
Graphics g = e.Graphics;
|
|
125
|
+
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
|
126
|
+
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
|
127
|
+
|
|
128
|
+
Font font = new Font("Segoe UI", 12, FontStyle.Bold);
|
|
129
|
+
Brush textBrush = Brushes.White;
|
|
130
|
+
|
|
131
|
+
foreach (var mark in marks) {
|
|
132
|
+
SizeF size = g.MeasureString(mark.Text, font);
|
|
133
|
+
// Draw text without background frame
|
|
134
|
+
g.DrawString(mark.Text, font, textBrush, mark.Location.X, mark.Location.Y - size.Height);
|
|
135
|
+
|
|
136
|
+
// Draw anchor point
|
|
137
|
+
g.FillEllipse(Brushes.Red, mark.Location.X - 3, mark.Location.Y - 3, 6, 6);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected override void OnKeyDown(KeyEventArgs e) {
|
|
142
|
+
if (e.KeyCode == Keys.Escape) {
|
|
143
|
+
Application.Exit();
|
|
144
|
+
}
|
|
145
|
+
if (e.KeyCode == Keys.Delete || e.KeyCode == Keys.C) {
|
|
146
|
+
marks.Clear();
|
|
147
|
+
this.Invalidate();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public static class Entry {
|
|
153
|
+
public static void Main() {
|
|
154
|
+
Application.EnableVisualStyles();
|
|
155
|
+
Application.SetCompatibleTextRenderingDefault(false);
|
|
156
|
+
Application.Run(new MarkForm());
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
'@ -ReferencedAssemblies System.Windows.Forms,System.Drawing
|
|
160
|
+
|
|
161
|
+
[Entry]::Main()
|
|
162
|
+
`;
|
|
163
|
+
|
|
164
|
+
const proc = spawn('powershell', ['-NoProfile', '-Command', overlayScript], { stdio: 'inherit' });
|
|
165
|
+
|
|
166
|
+
proc.on('close', (code) => {
|
|
167
|
+
// console.log('Exited');
|
|
168
|
+
});
|
|
169
|
+
}
|
package/src/index.js
CHANGED
|
@@ -31,6 +31,7 @@ import { dominantColorHandler } from './commands/dominantColor.js';
|
|
|
31
31
|
import { colorPickHandler } from './commands/colorPick.js';
|
|
32
32
|
import { crosshairHandler } from './commands/crosshair.js';
|
|
33
33
|
import { pixelDistanceHandler } from './commands/pixelDistance.js';
|
|
34
|
+
import { screenMarkHandler } from './commands/screenMark.js';
|
|
34
35
|
|
|
35
36
|
process.on('SIGINT', () => {
|
|
36
37
|
console.log(`\n${i18next.t('menu.bye')}`);
|
|
@@ -57,6 +58,7 @@ function getFeatures() {
|
|
|
57
58
|
{ name: i18next.t('menu.features.colorPick'), value: 'colorPick' },
|
|
58
59
|
{ name: i18next.t('menu.features.crosshair'), value: 'crosshair' },
|
|
59
60
|
{ name: i18next.t('menu.features.pixelDistance'), value: 'pixelDistance' },
|
|
61
|
+
{ name: i18next.t('menu.features.screenMark'), value: 'screenMark' },
|
|
60
62
|
{ name: i18next.t('menu.features.placeholderImg'), value: 'placeholderImg' },
|
|
61
63
|
{ name: i18next.t('menu.features.qrcode'), value: 'qrcode' },
|
|
62
64
|
|
|
@@ -204,6 +206,9 @@ async function handleAction(action) {
|
|
|
204
206
|
case 'pixelDistance':
|
|
205
207
|
await pixelDistanceHandler();
|
|
206
208
|
break;
|
|
209
|
+
case 'screenMark':
|
|
210
|
+
await screenMarkHandler();
|
|
211
|
+
break;
|
|
207
212
|
case 'timeFormat':
|
|
208
213
|
await timeFormatHandler();
|
|
209
214
|
break;
|
package/src/locales/en.js
CHANGED
|
@@ -6,6 +6,10 @@ export default {
|
|
|
6
6
|
notSupported: 'Pixel distance tool not supported on this OS.',
|
|
7
7
|
startPrompt: 'Pixel distance tool started. Click 2 points to measure. Right-click to reset. ESC to exit.'
|
|
8
8
|
},
|
|
9
|
+
screenMark: {
|
|
10
|
+
notSupported: 'Screen mark tool not supported on this OS.',
|
|
11
|
+
startPrompt: 'Screen mark tool started. Click to add text. Right-click to undo. ESC to exit.'
|
|
12
|
+
},
|
|
9
13
|
menu: {
|
|
10
14
|
title: 'xw-devtool-cli Menu',
|
|
11
15
|
exit: 'Exit',
|
|
@@ -20,6 +24,7 @@ export default {
|
|
|
20
24
|
colorPick: 'Color Picker',
|
|
21
25
|
crosshair: 'Screen Crosshair',
|
|
22
26
|
pixelDistance: 'Pixel Distance Tool',
|
|
27
|
+
screenMark: 'Screen Mark Tool',
|
|
23
28
|
placeholderImg: 'Placeholder Image Generator',
|
|
24
29
|
qrcode: 'QR Code Generator',
|
|
25
30
|
url: 'URL Encode/Decode',
|