Stroke 开源鼠标手势软件

软件名称

Stroke

应用平台

  • Windows

推荐类型

【开发者自荐】

一句简介

Stroke 是一款鼠标手势程序。它允许你通过划动鼠标来执行特定的操作。

应用简介

  • 开源。
  • 支持 C# 语言编写脚本,可使用 .NET Framework 及自己编写 dll。
  • 可对手势进行不断修正,使其变得平滑。

官方网站 && 应用商店地址

1赞

用了下,感觉思路是 好的,但是,现实的路子 走窄了。。。

  • 自定义的东西,全要靠自己编译 DLL ,这个就受众面太小了
    • 以我测试需要自己用 DLL 解决的 包括:新增手势,新增操作对象,新增对象动作等,感觉想要适配自己用,就必须要 编译DLL。。。

除了,不方便外,感觉目前程序可能有点 bug

  • win7 x64 , 对于 explorer 的操作有很多不能实现,比如 新建文件夹 新建窗口 ,已经给了管理员权限,还是不行

感觉如果要自己写DLL,应该至少给个教程示例;或者更简单 把库函数 扩充,弄成 脚本形式 也行。。。感觉目前 门槛太高 耗费的精力和得到的回报 不平衡。。。

注: 目前本人 用的是 MouseInc

几乎所有的 .NET Framework 有的东西你都是可以使用的,Windows 7 打开新窗口和新建文件夹的快捷键不是“Ctrl+n”和“Ctrl+Shift+n”吗?如果是的话那就应该是可以的。需要注意的地方是,手势的起点位置下面的窗口是你需要操作的窗口,这个窗口需要是资源管理器才能响应这两个快捷键。用户可能会有各种各样的需求,所以我只写了一个最常用的 DLL,也就是那个 Base,同时它也是一个示例。

另外,刚想到的是,Windows 7 上资源管理器的路径是否包含“explorer”,如果不能够被这条模式串匹配的话,动作包里面的动作就不会被触发,需要改成合适的模式串。你可以使用“添加路径”按钮查看资源管理器路径的正则表达式。

今天刚好有机会在 Windows 7 上测试了一下,原来是 GetModuleFileNameEx 这个函数不兼容 Windows 7 导致的,这样就不能获取到正确的进程相应的可执行文件路径,因此正则表达式也不能匹配成功模式串(比如“explorer”)。现在换成了 QueryFullProcessImageName,应该能很好的支持 Windows 7 以上的操作系统(XP 被抛弃了)。

2020-09-14 修复了点击右键在某些情况下不能弹出右键菜单的问题。

没截图吗?

门槛太高啦

就是写 C# 代码当脚本呀,C# 还算是比较流行的语言嘛。最常用的脚本已经在默认的配置文件里面了,Base 库里面也有一些最常用的函数可以调。 普通用户基本够用,会 C# 的程序员用得会比较爽,可以体验一下,响应速度能感觉到比 Strokesplus 更快一些,因为脚本是在启动时编译的,启动速度也更快,占用内存也更小喔。

2020-09-23:
修正了编译脚本时的一个小 Bug。
Base.PressKeys(string keys),更改了转义符的方向(例如:/t:Tab 键)。
Base库新增了两个函数:
Base.IsKeyDown(Keys key):某个键是否按下。
Base.IsKeyToggled(Keys key):某键是否开启(例如:CapsLock)。

可自由引用程序集和命名空间,默认配置文件提供的命名空间有:“System”, “System.Collections”, “System.Collections.Concurrent”, “System.Collections.Generic”, “System.Collections.ObjectModel”, “System.Collections.Specialized”, “System.Diagnostics”, “System.Drawing”, “System.Drawing.Imaging”, “System.Drawing.Text”, “System.IO”, “System.IO.Compression”, “System.IO.Pipes”, “System.IO.Ports”, “System.Linq”, “System.Linq.Expressions”, “System.Media”, “System.Net”, “System.Net.Http”, “System.Net.Http.Headers”, “System.Net.Security”, “System.Net.Sockets”, “System.Reflection”, “System.Security”, “System.Security.Authentication”, “System.Security.Cryptography”, “System.Text”, “System.Text.RegularExpressions”, “System.Threading”, “System.Threading.Tasks”, “System.Timers”, “System.Web”, “System.Windows.Forms”, “System.Xml”, “System.Xml.Linq”, “System.Xml.Schema”, “System.Xml.Serialization”。

这里附赠一个百度翻译的脚本:

Base.Activate();
Base.PressKeys("(c)"); 
Thread.Sleep(4);
SynchronizationContext context = SynchronizationContext.Current;
string original = Clipboard.GetText().Replace("-\r\n", "").Replace("\r\n", " ");
(new Thread(new ThreadStart(() =>
{
    string q = original;
    string from = "en";
    string to = "zh";
    string appId = "";
    string salt = (new Random()).Next(100000).ToString();
    string secretKey = "";
    StringBuilder sb = new StringBuilder();
    foreach (byte b in MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(appId + q + salt + secretKey)))
    {
        sb.Append(b.ToString("x2"));
    }
    string sign = sb.ToString();
    string url = "http://api.fanyi.baidu.com/api/trans/vip/translate?";
    url += "q=" + HttpUtility.UrlEncode(q);
    url += "&from=" + from;
    url += "&to=" + to;
    url += "&appid=" + appId;
    url += "&salt=" + salt;
    url += "&sign=" + sign;
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "GET";
    request.ContentType = "text/html;charset=UTF-8";
    request.UserAgent = null;
    request.Timeout = 6000;
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    Stream responseStream = response.GetResponseStream();
    StreamReader streamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
    string result = streamReader.ReadToEnd();
    streamReader.Close();
    responseStream.Close();
    string translation = "";
    foreach (Match item in Regex.Matches(Regex.Match(result, "trans_result\":\\[.*\\]").Value, "{\"src\":\".*?\",\"dst\":\".*?\"}"))
    {
        translation += Regex.Unescape(Regex.Match(item.Value, "\"dst\":\".*?\"").Value.Replace("\"dst\":", "")).Trim('\"');
    }
    if (translation != "")
    {
        context.Post((text) =>
        {
            Form form = new Form();
            form.FormBorderStyle = FormBorderStyle.None;
            form.StartPosition = FormStartPosition.Manual;
            form.Location = Cursor.Position;
            form.ControlBox = false;
            form.ShowIcon = false;
            form.ShowInTaskbar = false;
            form.BackColor = Color.White;
            form.Opacity = 0.96D;
            Label label = new Label();
            label.Text = (string)text;
            label.Font = new Font("宋体", 10.1f);
            label.MaximumSize = new Size(400, 1080);
            label.AutoSize = true;
            label.Location = new Point(4, 4);
            label.TextAlign = ContentAlignment.MiddleLeft;
            form.Controls.Add(label);
            form.MinimumSize = new Size(label.Width + 8, label.Height + 8);
            form.MaximumSize = form.MinimumSize;
            form.Size = form.MinimumSize;
            bool MoveWindow = false;
            int MoveX = Control.MousePosition.X;
            int MoveY = Control.MousePosition.Y;
            label.MouseDown += ((object sender, MouseEventArgs e) =>
            {
                if (e.Button == MouseButtons.Left)
                {
                    MoveX = e.X;
                    MoveY = e.Y;
                    MoveWindow = true;
                }
                if (e.Button == MouseButtons.Right)
                {
                    form.Close();
                }
            });
            label.MouseMove += ((object sender, MouseEventArgs e) =>
            {
                if (MoveWindow == true)
                {
                    form.Location = new Point(Control.MousePosition.X - MoveX, Control.MousePosition.Y - MoveY);
                    return;
                }
            });
            label.MouseUp += ((object sender, MouseEventArgs e) =>
            {
                if (e.Button == MouseButtons.Left && MoveWindow == true)
                {
                    MoveWindow = false;
                }
            });
            label.MouseDoubleClick += ((object sender, MouseEventArgs e) =>
            {
                Clipboard.SetText(label.Text);
            });
            form.Show();
            form.TopMost = true;
        }, translation);
    }
}))).Start();

请前往 https://api.fanyi.baidu.com/api/trans/product/desktop?req=developer ,申请并获取以下两个值。
appId(APP ID)、secretKey(密钥) 。

请问运行之后,在哪里设置?

c#写插件对大多数人而言还是太困难了,毕竟程序员只是少数,用一些简单的脚本语言做扩展可能受众会更广。当然最广泛的受众还是那种一行代码都不会写的,最好你把所有的功能都提供好,只需要在设置里选择就行了。

不过每个人对手势软件的需求都不一样,考虑到每个方面是很困难的,比较现实的方式是提供一个公共的插件共享平台。当然以上讨论只是从如何推广这个软件的角度出发,如果作者本来只是以完成一个相对小众的工具为目标,自然也没必要在这些方面下太多的工夫。

运行时是没有设置的,运行前使用“Stroke.Configure.exe”进行设置。

是的,默认的配置文件中提供了最常用的功能了。如果有更高的需求,主要受众还是程序员。

2020-09-24

新增:在“配置”中鼠标中键点击手势画布可清除手势。
修改:调整了“配置”中手势图形的显示大小。
修复:在“配置”中未选中任何手势时修改手势引发的异常。

另外,忘了说明,插入或删除动作包、动作、手势都是对列表中已有手势点右键进行操作的。

不过,复杂点的功能还是编译成 dll 比较好:

链接: https://pan.baidu.com/s/1Rpcrlc_C1DX2TUykq_fchw 提取码: vuvk

以上是百度翻译的 dll 版本,使用时放在和 Stroke.exe 同一目录下,使用以下脚本可实现以上的功能,同样需要填写你的“APP ID”和“密钥”:

BaiduTranslation.AppId = "";
BaiduTranslation.SecretKey = "";
BaiduTranslation.AwaitClipboardToTranslate();
Base.Activate();
Base.PressKeys("(c)");