Quicker+C#实现划词翻译

一直想给 Quicker 的沙拉查词动作加个划词小图标,实现真正的划词翻译。

类似的划词翻译:

  • 知云文献翻译:选中文本之后就自动显示翻译

  • 有道词典,欧路词典,金山词霸等:选中文本后在鼠标旁边出现一个小图标,点击图标就可以翻译

目前实现的效果: 体验跟有道差太多了😭用的话勉强能用。。。。

下面就简单记录下实现的思路(→_→)

识别划词

网上有的说使用系统接口,或者调用金山词霸的 dll。看得有点混乱,难下手。

于是决定换一个简单但不完美的思路——监听鼠标的左键事件。 Quicker 恰好提供了按键检测模块,现成的轮子美滋滋( ̄y▽, ̄)╭

划词一共有两种状态,满足下面这两种状态则模拟 Ctrl+C 获取文本,获取文本成功就是划词成功了。

  • 鼠标移动划词
    • 鼠标左键长时间按下
    • 鼠标位置变化
  • 鼠标双击取词
    • 鼠标左键短时间按下两次
    • 鼠标位置不变

按照上面的思路,简单画一个实现流程

太长我也没眼看了😳

到这一步的话大概就是知云文献翻译的效果。

划词图标

划词小图标简单的实现想法:在划词后,弹出一个小窗口,小窗口的位置在鼠标附近。

在 Quicker 动作中写窗口的话首选 C# 了(Quicker 支持运行 C# 代码,并且动作库中也有不少 C#实现的动作),于是决定尝试下 C#,写一个小窗口就溜。

零基础第一步:以前看到 C# 脑里会变成 C 井 🤣,查了下原来叫 C Sharp。(菜鸡说起都是泪)

第二步:B 站白嫖入门教程。一开始看 B 站的C#语言入门详解,没看一点就原地螺旋升天睡着了。不过好歹也知道自己需要的是 C# 的 WinForm 程序。

第三步:C# WinForm 教程。再次来到学习网站 B 站,C# WinForm 图形界面 GUI 编程62 集视频教程 (桌面开发)阿发你好🤣🤣。实际上也没看多少,看了前面几个就差不多弄一个比较理想的窗口了。

第四步:特定问题。一些特定的问题,直接搜索参考(抄袭)别人的解决方案就行。

程序中只涉及两个部分,主窗口和按钮。

  • 主窗口:大小约在 40*40 像素,隐藏顶部标题栏,背景透明,鼠标附近弹出置顶。

  • 按钮:铺满主窗口,设置背景图片。

实现逻辑:

  1. 检测到划词操作成功后,则运行 C# 程序,在鼠标附近弹出且置顶。
  2. 如果鼠标点击划词图标(按钮),那么关闭窗口,并且给 Quicker 返回成功触发值。
  3. 如果鼠标点击了图标外部,使得图标失去了焦点,那么关闭窗口,并且给 Quicker 返回未成功触发值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 引用必要的命名空间
using System.Drawing;
using System.Windows.Forms;

// Quicker将会调用的函数
public static void Exec(Quicker.Public.IStepContext context)
{
var getBitmp = context.GetVarValue("saladictImg"); // 读取动作里的变量值
Image pic = getBitmp as Image;
Saladict.icon = pic;
Saladict form = new Saladict();
form.ShowDialog();
bool trigger = Saladict.triggerSuccess;
context.SetVarValue("CSharpTrigger", trigger); // 向变量里输出值
}

public partial class Saladict : Form
{
public static bool triggerSuccess = false;
public static Image icon;

public Saladict()
{
InitializeComponent();
this.CloseButton.BackgroundImage = icon;
}

private void Saladict_Load(object sender, EventArgs e)
{
var _point = new System.Drawing.Point(Cursor.Position.X, Cursor.Position.Y);
Top = _point.Y;
Left = _point.X;

this.BackColor = Color.Black;
this.TransparencyKey = Color.Black;
}

private void Clicked(object sender, EventArgs e)
{
triggerSuccess = true;
this.Deactivate -= LoseFocus;
// MessageBox.Show(triggerSuccess.ToString());
this.Close();
}

private void LoseFocus(object sender, EventArgs e)
{
triggerSuccess = false;
this.Deactivate -= LoseFocus;
// MessageBox.Show(triggerSuccess.ToString());
this.Close();
}


/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows 窗体设计器生成的代码

/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.CloseButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// CloseButton
//
this.CloseButton.BackColor = System.Drawing.Color.Transparent;
this.CloseButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.CloseButton.FlatAppearance.BorderSize = 0;
this.CloseButton.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Transparent;
this.CloseButton.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent;
this.CloseButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.CloseButton.ForeColor = System.Drawing.Color.Transparent;
this.CloseButton.Location = new System.Drawing.Point(0, 0);
this.CloseButton.Margin = new System.Windows.Forms.Padding(0);
this.CloseButton.MaximumSize = new System.Drawing.Size(40, 40);
this.CloseButton.MinimumSize = new System.Drawing.Size(30, 30);
this.CloseButton.Name = "CloseButton";
this.CloseButton.Size = new System.Drawing.Size(40, 40);
this.CloseButton.TabIndex = 0;
this.CloseButton.UseVisualStyleBackColor = false;
this.CloseButton.Click += new System.EventHandler(this.Clicked);
//
// Saladict
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoSize = true;
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.ClientSize = new System.Drawing.Size(40, 40);
this.Controls.Add(this.CloseButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.MaximumSize = new System.Drawing.Size(40, 40);
this.MinimumSize = new System.Drawing.Size(30, 30);
this.Name = "Saladict";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.TopMost = true;
this.Deactivate += new System.EventHandler(this.LoseFocus);
this.Load += new System.EventHandler(this.Saladict_Load);
this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.Button CloseButton;
}

其实还存在几个令人非常不爽的问题,程序比较简陋。

  1. 弹出的窗口会抢占焦点
  2. 图标显示有锯齿
  3. 没有处理高分屏显示的问题。(主要是贫穷如我没有高分屏😅)

实现过程中一个小插曲——这图标文件怎么存。想了两个方案

  1. 检查电脑特定路径中是否存在图标文件,不存在就后台下载一份。
  2. 把图标转成 base64 编码,以文本形式存在 Quicker 变量中,要用的时候再转回图片,传入 C#。

还是第二个方案比较好一点,免得下载文件了。

总结

需求才是学习的最大动力啊,用着 Quicker 附带着学了其他东西。下面总结下划词的实现。

实现过程:

  1. 首先要判断是否划词成功——通过监控鼠标左键状态实现。
  2. 其次要在划词成功后弹出划词图标——通过 C# WinForm 画一个小窗口。

存在问题:

  1. 纯粹通过鼠标左键来判断划词容易误判;并且模拟 Ctrl+C 获取文本也容易在某些窗口引起误操作(例如终端窗口)。
  2. 划词图标抢占焦点;图标显示有锯齿;高分屏不友好。

划词图标抢占焦点的问题,虽然可通过加载鼠标挂钩获取全局坐标来判断,但是实现成本太高,响应速度也成问题,故暂时不考虑这个方案了。