吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 58153|回复: 1509
上一主题 下一主题
收起左侧

[原创工具] FlowMouse - 心流鼠标手势 v2.0.2【开源Chrome、Edge、Firefox插件】

    [复制链接]
跳转到指定楼层
楼主
Hmily 发表于 2025-12-16 12:33 回帖奖励

FlowMouse:心流鼠标

一款追求极致流畅与隐私保护的开源鼠标手势扩展。通过自然的鼠标滑动,助您无缝操控浏览器,真正进入专注高效的“心流”状态。

✨ 核心特性

  • 完全本地,隐私至上:所有操作均在本地完成(除浏览器内置同步外),零网络请求、零数据收集、零信息上传,彻底守护您的浏览隐私。
  • 自定义手势,随心所欲:除了16种默认手势外,支持自定义扩展更多手势操作。
  • 超级拖拽,效率翻倍
    • 拖拽文字 → 支持自定义搜索引擎划词搜索和复制文字等细节设置。
    • 拖拽图片 → 支持新标签页查看、保存图片、复制图片地址、以图搜索或自定义搜索等细节设置。
    • 拖拽链接 → 支持打开链接和复制链接等细节设置。
  • 直观设置,随心定制:提供清晰的可视化设置页,支持自定义手势轨迹颜色、宽度及操作提示。
  • 多语言支持:完整适配简体中文、英文等世界主流语言界面。
  • 新手引导:首次安装后自动跳转至使用教程页面,手把手教您玩转鼠标手势,零门槛轻松入门。

🚀 安装方法

📦 方式一:通过 浏览器 应用商店安装(推荐)

如果你喜欢FlowMouse,请在应用商店给我们一个五星鼓励,这是我们更新的动力。

📦 方式二:离线安装扩展

  1. 下载安装包(测试版只发布于网盘和论坛,测试后再同步到商店和Github)
    百度网盘GitHub Releases 下载最新版本的 .crx.zip 文件。
    Flowmouse-Chrome.v2.0.2.crx.7z (824.66 KB, 下载次数: 2070)
    Flowmouse-Edge.v2.0.2..crx.7z (824.95 KB, 下载次数: 46)
    Flowmouse-Firefox v2.0.2.xpi.7z (837.7 KB, 下载次数: 42)
  2. 打开扩展程序界面
    在 Chrome 浏览器地址栏输入以下地址并回车访问:chrome://extensions/
  3. 开启开发者模式
    在页面右上角找到 “开发者模式” (Developer mode),点击开关将其切换为 开启 状态。
  4. 安装扩展程序
    • 将下载好的 .crx.zip 文件直接拖入该扩展程序页面中。
    • 当浏览器显示“要添加...吗?”的提示框时,点击 “添加扩展程序” 即可。
    • 提示:如果是 ZIP 文件且拖拽无效,请先解压,然后点击页面左上角的“加载已解压的扩展程序”并选择解压后的文件夹。

📖 默认手势指南

所有手势均可在选项页面修改或自定义。

手势 功能 手势 功能
后退 前进
向上滚动 向下滚动
↓→ 关闭当前标签页 ←↑ 恢复关闭的标签页
→↑ 新建标签页 →↓ 刷新当前页面
↑← 切换到左侧标签页 ↑→ 切换到右侧标签页
↓← 停止加载 ←↓ 关闭所有标签页
↑↓ 滚动到底部 ↓↑ 滚动到顶部
←→ 关闭当前标签页 →← 恢复关闭的标签页

📝 更新日志

详见Github:https://github.com/Hmily-LCG/FlowMouse/blob/main/CHANGELOG.zh_CN.md

🔒 隐私承诺

FlowMouse 郑重承诺:

  • 本扩展为开源项目,代码已托管于 GitHub,欢迎审阅与贡献。
  • 不收集任何您的浏览历史、书签或操作习惯。
  • 不上传任何本地数据至第三方服务器(仅限浏览器同步)。
  • 不嵌入任何第三方分析或广告代码。
    您保存的设置通过浏览器内置的同步服务在您已登录的设备间加密同步。该过程完全由浏览器控制,并遵循您浏览器的隐私与同步设置。

💡 缘起

多年以来,我一直是 CrxMouse 的忠实用户,它确实极大地提升了我的操作效率。然而,长期使用中也一直伴随着一个困扰:它频繁弹出请求授予“高级功能”权限——实质上是希望获取用户访问的网址记录。出于对隐私的坚持,我始终没有同意。

直到几个月前,CrxMouse 的一次版本更新导致我在访问吾爱破解论坛时,发现了异常:用户无法登陆、不能评分,甚至回帖后页面也不再自动跳转。经过排查,我很快确认问题根源在于该扩展程序注入的 JavaScript 脚本。论坛里也陆续出现了大量用户反馈,他们遇到了同样的困扰,以为是网站本身出了问题,其实是插件兼容性导致的,并且这个问题影响所有 Discuz! 论坛。

我本期待插件作者能尽快修复。可惜事与愿违,尽管接连发布了两个更新,问题依然存在。在等待一个多月仍无进展后,我意识到可能需要寻找替代方案。然而市场上同类扩展程序寥寥无几,功能也难以完全符合需求。

于是,我决定自己动手。就这样,FlowMouse 诞生了。

在此,我依然想感谢 CrxMouse,它不仅多年来为我带来了效率提升,也正是因为它所暴露的问题,直接促成了这个新扩展程序的开发。同时,也要感谢 Edge 浏览器,除了我常用的几个核心手势外,FlowMouse 中其余的手势功能也参考了 Edge 的常用手势进行了补全。一直很羡慕 Edge 原生手势的流畅性能与出色兼容性,毕竟相比通过 JavaScript 绘制轨迹,原生支持的效果确实要好太多。

FlowMouse 希望能延续手势操作的便捷,同时更注重隐私保护与稳定兼容。这是一个源于实际需求、也回归用户体验的小项目。如果你也遇到类似困扰,或许它能为你提供一个新的选择。


FlowMouse · 让浏览更流畅,让操作更随心。


👨‍💻 作者信息

免费评分

参与人数 470吾爱币 +467 热心值 +431 收起 理由
palec + 1 + 1 谢谢@Thanks!
晴天雨过 + 1 + 1 我很赞同!
xc1226 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
阳tuto + 1 + 1 用心讨论,共获提升!
980 + 1 + 1 谢谢@Thanks!
orzoo + 1 + 1 已经处理,感谢您对吾爱破解论坛的支持!
JaryminRex + 1 + 1 我很赞同!
LiuAi + 1 已经在使用了,很好用
abcbbb007 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
cgfjj + 1 我很赞同!
17yl + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
迷途的羔羊 + 1 鼓励转贴优秀软件安全工具和文档!
chengzhijun93 + 1 + 1 谢谢@Thanks!
izisak + 1 + 1 谢谢@Thanks!
gqdsc + 1 + 1 谢谢@Thanks!
babybing + 1 + 1 热心回复!
theWoon + 1 + 1 谢谢@Thanks!
WenkeC + 1 谢谢@Thanks!
lfc0311 + 1 谢谢@Thanks!
TiXiMi + 1 我很赞同!
hefeng258520 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
seventeen. + 1 谢谢@Thanks!
shuihan + 1 + 1 用心讨论,共获提升!
竹轩 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
muyeyulin + 1 谢谢@Thanks!
Bulaixi + 1 + 1 我很赞同!
L1996 + 1 + 1 热心回复!
sihehe + 1 + 1 我很赞同!
liyongtao + 1 + 1 热心回复!
sshawn + 1 + 1 谢谢@Thanks!
Jiste + 1 + 1 谢谢@Thanks!
笑笑就过去了 + 1 + 1 谢谢@Thanks!
ydc0619 + 1 + 1 谢谢@Thanks!
greatuser + 1 谢谢@Thanks!
happybronze + 1 + 1 我很赞同!
fenglv + 1 + 1 我很赞同!
nullid + 1 这种工具用熟了操作效率高
shuangluo + 1 + 1 我很赞同!
强哥945 + 2 + 1 谢谢@Thanks!
她眉眼如画 + 1 + 1 谢谢@Thanks!
soullesfox + 1 + 1 热心回复!
Cooper + 1 谢谢@Thanks!
supret + 1 + 1 谢谢@Thanks!
一花依世界 + 1 + 1 我很赞同!
huiyong66 + 1 鼓励转贴优秀软件安全工具和文档!
limerence513 + 1 我很赞同!
狂徒再现 + 1 + 1 我很赞同!
Zercher + 1 我很赞同!
qqzfh138 + 1 + 1 我很赞同!
黄教主 + 1 + 1 谢谢@Thanks!
acbbtdxy + 1 谢谢@Thanks!
Hippy + 1 + 1 谢谢@Thanks!
ver127 + 1 + 1 我很赞同!
只因有你 + 1 + 1 我很赞同!
AiMuTiLooy + 1 + 1 谢谢@Thanks!
g2695885 + 1 谢谢@Thanks!
zwzcyeah + 1 + 1 谢谢@Thanks!
yiketiantong + 1 我很赞同!
lmx288 + 1 + 1 热心回复!
starvalue + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xiaozhu0808 + 1 + 1 用心讨论,共获提升!
5Bug + 1 + 1 谢谢@Thanks!
gnut + 1 + 1 谢谢@Thanks!
lxf_07222 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
junlangzhang2 + 1 谢谢@Thanks!
wuyounanhai + 1 + 1 谢谢@Thanks!
xiaomu77 + 1 + 1 用心讨论,共获提升!
ORSSR + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Dream_cc + 1 + 1 谢谢@Thanks!
xiaobai314 + 1 + 1 用心讨论,共获提升!
chiker + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ncvt + 1 + 1 我很赞同!
nicle + 1 + 1 我很赞同!
caoxuexin + 1 + 1 我很赞同!
kyokusanagi2000 + 1 热心回复!
521cat + 1 + 1 必须来点赞,等了这么多年,终于来了
Luckies050505 + 1 + 1 太感谢大佬了
听雨客舟 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
oedoof + 1 + 1 谢谢@Thanks!
seny1163 + 1 + 1 我很赞同!
qingyuan29 + 1 + 1 热心回复!
RinbowP + 1 + 1 我很赞同!
oldpandada + 1 + 1 热心回复!
ronvic + 1 + 1 希望在zen浏览器里添加的功能 1 刷新页面 加入跳过缓存 2 手势增加复制当前 ...
光与影 + 1 谢谢@Thanks!
dwarld + 1 谢谢@Thanks!
tangke25306 + 1 + 1 热心回复!
adslpal + 1 + 1 我很赞同!
fengtian99 + 2 + 1 我很赞同!
bao520 + 1 + 1 谢谢@Thanks!
geyk333 + 1 + 1 谢谢@Thanks!
LLLLEAP + 1 + 1 谢谢@Thanks!
taoshucheng + 1 + 1 谢谢@Thanks!
FLove33 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
chaosjr + 1 + 1 热心回复!
woshileilei + 1 热心回复!
凌筱珥 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
WocBin + 1 + 1 我很赞同!
hjkmo + 1 + 1 我很赞同!
slowdive + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 #
 楼主| Hmily 发表于 2025-12-26 11:47 |楼主

FlowMouse 更新日志

v2.0.2 (2026-04-23)

  • 修复 Firefox 下最近关闭的标签页弹出菜单时间显示错误的问题
  • 修复与 Firefox 151+ 测试版的兼容性
  • 其他细节改进

v2.0.1 (2026-04-22)

  • 添加书签支持指定书签目录
  • 添加书签时避免重复添加同一页面
  • 修复命令链设置中“延迟”命令消失的问题
  • 修复可能影响 macOS 等系统下使用 Control + 左键 等组合键打开上下文菜单的问题
  • 区域框选细节改进,并优化 iframe 下的兼容性

v2.0 (2026-04-21)

新功能:

  • 区域框选:快速框选页面上的链接并进行批量操作
  • 专家模式:自定义 CSS
  • 专家模式:支持自定义 HUD 上显示的手势、拖拽动作的名称
  • 重新设计命令设置窗,简化命令链添加流程
  • 新增手势命令
    • 弹出菜单
    • 切换标签页
    • 显示最近关闭的标签页
    • 显示书签
    • 自定义菜单
    • 放大页面/缩小页面/重置缩放
    • 复制页面标题和网址(可选 Markdown 格式)
    • 暂停手势直到刷新
    • 移动标签页到新窗口
    • 粘贴剪贴板
    • 搜索剪贴板
    • 查看页面源代码
    • 保存为 MHTML
  • 新增拖拽手势
    • 专家模式:发送自定义事件
    • 链接拖拽:复制文字和链接(可选 Markdown 格式)
  • 新增鼠标滚轮手势:按住右键并点击滚轮
  • 发送自定义事件时支持包含手势起始点等信息

手势改进:

  • 绘制手势时支持按下左键取消手势
  • 打开自定义网址支持使用占位符(插入当前页面标题和网址)
  • 改进滚动命令的逻辑,优先滚动鼠标下的元素

拖拽改进:

  • 拖拽图片时,改进触发优先打开链接时的 HUD 显示
  • 非专家模式下默认显示更多功能
  • 修复涉及 ShadowDOM 时,拖拽文本可能遗漏文本的问题
  • 专家模式:支持禁用输入框内的拖拽
  • 修复部分页面拖拽链接无法执行手势操作的问题
  • 在部分依赖拖拽功能的网页中智能禁用拖拽功能,避免干扰

滚轮手势改进:

  • 修复部分情况下,执行滚轮手势后可能弹出右键菜单的问题

界面及更多改进:

  • 改进事件绑定逻辑,提升部分网页的兼容性
  • 修复部分 iframe 下无法使用手势的问题
  • 修复部分网页全屏模式下绘制手势时,操作提示不可见的问题
  • 设置内添加部分功能的说明提示
  • 手势执行完成后移除插入页面的元素,提升兼容性
  • 完善设置界面控件设计细节
  • 支持安装/更新后无需刷新已打开的网页即可直接使用手势
  • 其他细节改进

v1.4.2 (2026-03-31)

  • 放宽 Firefox 的版本要求
  • 优化 HUD 显示逻辑,提升与 KindEditor 等编辑器的兼容性

v1.4 (2026-03-22)

手势改进:

  • 专家模式:支持设置手势触发按键:右键/中键/侧键/触控笔右键
  • 关闭标签页时支持保留固定标签页
  • 简化手势图标显示
  • 刷新标签页命令支持硬性重新加载(跳过缓存)
  • 打开新标签页/打开自定义链接支持指定标签页位置

拖拽改进:

  • 拖拽文本时,改进触发自动识别链接后的 HUD 显示
  • 改进拖拽类型识别逻辑
  • 修复 Firefox 下 ShadowDOM 内拖拽图片可能识别成链接的问题
  • 修复部分网站拖拽功能无法使用的问题

界面及更多改进:

  • 部分事件按需绑定,优化与旧网页的兼容性
  • 修复 RTL 语言下设置界面边栏的 BUG
  • 修复部分页面上手势轨迹显示卡顿的问题
  • 其他细节改进

v1.3 (2026-03-17)

新功能:

  • 适配 Firefox、Edge 浏览器
  • 新增鼠标滚轮手势:按住右键并向上/向下滚动滚轮
  • 新增特殊手势:按住右键并点击左键/按住左键并点击右键
  • 专家模式:新增命令链,一次手势可以执行多个操作
  • 支持在右键菜单中显示禁用/启用手势的选项
  • 新颜色选择器,支持调整手势文字/线条透明度、模糊、关闭阴影等
  • 专家模式:支持调节手势转向容差设置
  • 新增手势
    • 模拟按键
    • 发送自定义事件(感谢 @g9wp )
    • 切换到第一个标签页/切换到最后一个标签页
    • 固定/取消固定当前标签页
    • 关闭窗口
    • 复制当前网址时可同时复制页面标题

手势改进:

  • 支持单独调整每个滚动手势的滚动距离、动画
  • 优化连续滚动动画、支持设置连续滚动加速功能
  • 切换到左侧/右侧/第一个/最后一个标签页支持设置为移动当前标签页
  • 新手势动作选择界面
  • 支持单独调整部分手势命令的设置

拖拽改进:

  • 同方向拖拽支持执行多个操作,如多引擎以图搜图/多引擎搜索等
  • 支持自定义拖拽手势
  • 支持拖拽时在无痕窗口打开页面
  • 支持拖拽复制链接文字

界面及更多改进:

  • 全新 Logo 设计(感谢 @Ps出来的小赵 )
  • 重构大量代码,优化性能,修复 BUG
  • 新设置界面设计
  • 重新设计手势录制流程
  • 改进扩展按钮浮窗设计
  • 设置界面为部分设置添加重置按钮
  • 改进语言选择菜单设计
  • 修复 macOS/Linux 下手势可能影响网页右键菜单的问题
  • 修复 Chrome 下在 Bing 网页点击右键可能使链接失效的问题
  • 改进对 Android 部分第三方浏览器的支持
  • 其他细节改进

v1.2 (2026-02-10)

新功能:

  • 首次安装,显示交互式教程
  • 完善本地化,支持39种语言
  • 手势受限页面新增提示(可在设置中关闭部分提示)
  • 新增手势
    • 当前标签页静音/恢复
    • 全部标签页静音/恢复
    • 关闭标签页(保留窗口)
    • 关闭左侧标签
    • 关闭浏览器
    • 刷新所有标签页
  • 手势识别使用动态阈值算法,减少手势误判
  • 手势轨迹使用平滑算法,提升视觉体验
  • 支持在 FlowMouse 设置页面使用手势及拖拽
  • 支持使用 ESC 打断手势、拖拽

手势改进:

  • 改善使用 iframe 网站的手势体验
  • 高级设置:支持使用系统(高性能)滚动动画、支持关闭动画
  • 高级设置:支持调整手势识别触发距离
  • 修复部分网站滚动手势不生效的问题
  • 支持使用浏览器默认搜索引擎搜索,并添加更多搜索引擎

拖拽改进:

  • 优化超级拖拽,鼠标离开窗口时自动取消拖拽
  • 高级设置:支持拖拽文字或图片识别到链接时,优先打开链接
  • 高级设置:支持当前标签页打开拖拽目标
  • 修复 B 站等网站拖拽无效的问题
  • 修复 URL 相对路径的拖拽
  • 修复 HTTP 协议页面无法使用拖拽复制手势的问题
  • 适配触摸屏、触控笔按住拖拽

界面及更多改进:

  • 设置页新界面设计、调整功能位置
  • 更清晰的手势箭头设计
  • 优化设置同步,支持同步更多设置(本地备份设置建议使用“导出配置”功能)
  • 减少默认权限请求,选择手势保存图片/添加书签手势时按需请求权限
  • 修复部分网站手势提示框排版、字体错误的问题
  • 手势提示框使用 Shadow DOM,避免被网站样式干扰
  • 改善 RTL 语言下的支持
  • 重构大量代码,优化性能,修复 BUG
  • 其他细节改进

v1.1 (2025-12-24)

修复与优化:

  • 系统兼容性修复 Mac 和 Linux 下右键菜单冲突问题,改为双击呼出右键菜单,确保鼠标手势可用

    注意:受 macOS 系统特性影响,拖拽文本时需先选中文字,按住左键短暂停顿后再拖动,否则可能无法触发搜索。

  • 默认体验优化
    • 重新调整默认手势映射以对齐 Edge 浏览器,降低学习成本
    • 新标签页打开位置由“最右侧”改为当前标签右侧
    • 取消“滚到顶/底部”的平滑滚动动画,显著提升响应速度。
  • Bug 修复
    • 修复 localhost 域名无法添加黑名单的问题。
    • 修复向左拖拽误触“创建拆分视图”导致功能失效的问题。
  • 识别优化:优化手势匹配规则,必须完全符合手势轨迹才响应,有效防止误报。
  • 其他:多项细节体验优化。

新功能:

  • 全局开关:新增鼠标手势功能的全局“启用/禁用”开关(超级拖拽不受影响)。
  • 更多手势动作:新增“窗口最大化/还原”、“窗口最小化”、“打开自定义网址”、“复制当前网址”等实用操作。
  • 高级设置(专为高级用户打造):
    • 自定义滚动:支持自定义“上/下滚”手势的滚动距离。
    • 视觉微调:支持开启/关闭手势轨迹的起始原点显示。
    • 自定义手势:支持绘制并添加自定义鼠标手势(默认已支持 ↑↓←→ 四向组合)。
    • 超级拖拽增强
      • 全面支持文字、图片、链接的四向(↑↓←→)拖拽及前/后台打开设置。
      • 文字:新增“复制文字”。
      • 图片:新增“保存图片”、“复制图片地址”、“自定义图片搜索”。
      • 链接:新增“复制链接”。


推荐
夜泉 发表于 2025-12-16 12:59
本帖最后由 夜泉 于 2025-12-16 13:03 编辑

我一直用 mouseinc ,这个工具很强是我开机必备自启之一,除了能用作浏览器,其他窗口都差不多能控制,但是mouseinc作者已经停更了,可惜,,,

[转]发个链接判了4年。。。mouseinc 告别信
https://www.52pojie.cn/thread-1695359-1-1.html
(出处: 吾爱破解论坛)
推荐
 楼主| Hmily 发表于 2025-12-16 12:39 |楼主
@beyond0729 @yakev999 @话落三大碗 @Ta'ta @注册个id @soojing 可以试试了。

如果有其他同学也遇到无法登陆、不能评分,回帖后页面不再自动跳转的问题,并且装了CrxMouse 无法取代可以试试本插件。

免费评分

参与人数 5吾爱币 +7 热心值 +5 收起 理由
gorbydon + 1 + 1 我很赞同!
话落三大碗 + 1 + 1 非常感谢,禁用插件后已经手痒很久了~~
soojing + 3 + 1 多谢H大提醒!
梅球王 + 1 + 1 多谢大佬提醒
Ta'ta + 1 + 1 感谢H大还记得A我一下

查看全部评分

推荐
 楼主| Hmily 发表于 2025-12-18 16:47 |楼主
约定的童话 发表于 2025-12-18 08:39
看了半天没整明白做啥用的,有视频教程没

右键按下去然后画,左键按下去拖图片、链接、文字。
推荐
寂寞知己 发表于 2025-12-16 16:20
油猴版
[Asm] 纯文本查看 复制代码
// ==UserScript==
// [url=home.php?mod=space&uid=170990]@name[/url]         FlowMouse - 心流鼠标
// [url=home.php?mod=space&uid=467642]@namespace[/url]    [url]http://tampermonkey.net/[/url]
// [url=home.php?mod=space&uid=1248337]@version[/url]      1.0
// @description  一款追求极致流畅与隐私保护的鼠标手势脚本。支持手势导航、页面滚动、超级拖拽(文字/链接/图片),完全本地运行。
// [url=home.php?mod=space&uid=686208]@AuThor[/url]       Hmily[LCG] (Ported by AI)
// [url=home.php?mod=space&uid=195849]@match[/url]        *://*/*
// [url=home.php?mod=space&uid=609072]@grant[/url]        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_openInTab
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // =========================================================================
    // 1. 常量与默认配置 (可在此修改)
    // =========================================================================
    const DEFAULT_CONFIG = {
        enableTrail: true,      // 开启轨迹
        enableHUD: true,        // 开启提示文字
        enableTextDrag: true,   // 开启文字拖拽
        enableLinkDrag: true,   // 开启链接拖拽
        enableImageDrag: true,  // 开启图片拖拽
        searchEngine: 'google', // 默认搜索引擎
        newTabUrl: 'https://www.google.com', // 【设置】新建标签页打开的网址 (因浏览器限制,无法打开原生NewTab)
        trailColor: '#4285f4',  // 轨迹颜色
        trailWidth: 4,          // 轨迹粗细
        hudBgColor: '#000000',  // 提示框背景
        hudOpacity: 0.7         // 提示框透明度
    };

    const SEARCH_ENGINES = {
        'google': 'https://www.google.com/search?q=',
        'bing': 'https://www.bing.com/search?q=',
        'baidu': 'https://www.baidu.com/s?wd='
    };

    // 【自定义手势区域】
    const GESTURE_ACTIONS = {
        '←': 'back',             // 后退
        '→': 'forward',          // 前进
        '↑': 'scrollUp',         // 向上滚动
        '↓': 'scrollDown',       // 向下滚动
        '↓→': 'closeTab',        // 关闭当前页
        '→↓': 'refresh',         // 刷新
        '↑←': 'scrollToTop',     // 滚到顶部
        '↑→': 'scrollToBottom',  // 滚到底部
        '→↑': 'newTab',          // 新建标签页
        '←↓': 'minimize',        // 最小化/打开主页
        '→←': 'restore'          // 恢复
    };

    // 动作显示名称
    const ACTION_NAMES = {
        'back': '后退',
        'forward': '前进',
        'scrollUp': '向上滚动',
        'scrollDown': '向下滚动',
        'scrollToTop': '滚动到顶部',
        'scrollToBottom': '滚动到底部',
        'refresh': '刷新',
        'closeTab': '关闭当前页',
        'newTab': '新标签页',
        'search': '搜索'
    };

    // =========================================================================
    // 2. 配置管理
    // =========================================================================
    const Config = {
        get: (key) => GM_getValue(key, DEFAULT_CONFIG[key]),
        set: (key, value) => {
            GM_setValue(key, value);
            updateMenus();
        },
        getAll: () => {
            let cfg = {};
            for (let k in DEFAULT_CONFIG) cfg[k] = Config.get(k);
            return cfg;
        }
    };

    // =========================================================================
    // 3. 视觉效果
    // =========================================================================
    class GestureVisualizer {
        constructor() {
            this.canvas = null;
            this.ctx = null;
            this.trail = [];
            this.hud = null;
        }

        init() {
            if (this.canvas) return;
            this.canvas = document.createElement('canvas');
            this.canvas.style.cssText = `
                position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                pointer-events: none; z-index: 2147483647; opacity: 0;
                transition: opacity 0.1s;
            `;
            document.documentElement.appendChild(this.canvas);
            this.ctx = this.canvas.getContext('2d');

            this.hud = document.createElement('div');
            this.hud.style.cssText = `
                position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
                padding: 12px 24px; border-radius: 8px;
                color: #fff; font-family: sans-serif; font-size: 20px; font-weight: bold;
                pointer-events: none; z-index: 2147483647; opacity: 0;
                transition: opacity 0.2s; text-align: center;
                box-shadow: 0 4px 12px rgba(0,0,0,0.3); backdrop-filter: blur(2px);
            `;
            this.updateStyle();
            document.documentElement.appendChild(this.hud);
            window.addEventListener('resize', () => this.resize());
            this.resize();
        }

        updateStyle() {
            if (!this.hud) return;
            const bg = Config.get('hudBgColor');
            const op = Config.get('hudOpacity');
            let r = parseInt(bg.slice(1, 3), 16), g = parseInt(bg.slice(3, 5), 16), b = parseInt(bg.slice(5, 7), 16);
            this.hud.style.backgroundColor = `rgba(${r}, ${g}, ${b}, ${op})`;
        }

        resize() {
            if (!this.canvas) return;
            const dpr = window.devicePixelRatio || 1;
            this.canvas.width = window.innerWidth * dpr;
            this.canvas.height = window.innerHeight * dpr;
            this.ctx.scale(dpr, dpr);
        }

        show() {
            if (!Config.get('enableTrail')) return;
            this.init();
            this.canvas.style.opacity = '1';
            this.trail = [];
        }

        addPoint(x, y) {
            if (!Config.get('enableTrail')) return;
            this.trail.push({ x, y });
            this.draw();
        }

        draw() {
            if (!this.ctx || this.trail.length < 2) return;
            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.ctx.beginPath();
            this.ctx.strokeStyle = Config.get('trailColor');
            this.ctx.lineWidth = Config.get('trailWidth');
            this.ctx.lineCap = 'round';
            this.ctx.lineJoin = 'round';
            this.ctx.moveTo(this.trail[0].x, this.trail[0].y);
            for (let i = 1; i < this.trail.length; i++) {
                this.ctx.lineTo(this.trail[i].x, this.trail[i].y);
            }
            this.ctx.stroke();
        }

        updateAction(text) {
            if (!Config.get('enableHUD')) return;
            this.init();
            if (text) {
                this.hud.textContent = text;
                this.hud.style.opacity = '1';
            } else {
                this.hud.style.opacity = '0';
            }
        }

        hide() {
            if (this.canvas) {
                this.canvas.style.opacity = '0';
                setTimeout(() => { if (this.ctx) this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); }, 100);
            }
            if (this.hud) this.hud.style.opacity = '0';
            this.trail = [];
        }
    }

    const visualizer = new GestureVisualizer();

    // =========================================================================
    // 4. 核心逻辑
    // =========================================================================
    let state = {
        active: false,
        startX: 0, startY: 0,
        lastX: 0, lastY: 0,
        pattern: [],
        isDrag: false,
        dragType: null,
        dragContent: null,
        preventMenu: false
    };

    const DISTANCE_THRESHOLD = 20;

    function executeAction(actionCode, extraData) {
        switch (actionCode) {
            case 'back': window.history.back(); break;
            case 'forward': window.history.forward(); break;
            case 'scrollUp': window.scrollBy({ top: -window.innerHeight * 0.8, behavior: 'smooth' }); break;
            case 'scrollDown': window.scrollBy({ top: window.innerHeight * 0.8, behavior: 'smooth' }); break;
            case 'scrollToTop': window.scrollTo({ top: 0, behavior: 'smooth' }); break;
            case 'scrollToBottom': window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); break;
            case 'refresh': location.reload(); break;
            case 'closeTab': window.close(); break;
            case 'newTab': GM_openInTab(Config.get('newTabUrl'), { active: true }); break;
            case 'search': {
                let engine = Config.get('searchEngine');
                let url = (SEARCH_ENGINES[engine] || SEARCH_ENGINES.google) + encodeURIComponent(extraData);
                GM_openInTab(url, { active: true, insert: true });
                break;
            }
            case 'openLink':
                GM_openInTab(extraData, { active: false, insert: true });
                break;
            case 'openImage':
                GM_openInTab(extraData, { active: true });
                break;
        }
    }

    function getDirection(dx, dy) {
        if (Math.abs(dx) > Math.abs(dy)) return dx > 0 ? '→' : '←';
        return dy > 0 ? '↓' : '↑';
    }

    function handleMove(currentX, currentY) {
        if (!state.active) return;
        
        visualizer.addPoint(currentX, currentY);

        let dx = currentX - state.lastX;
        let dy = currentY - state.lastY;
        
        if (Math.sqrt(dx*dx + dy*dy) > DISTANCE_THRESHOLD) {
            let dir = getDirection(dx, dy);
            if (state.pattern[state.pattern.length - 1] !== dir) {
                state.pattern.push(dir);
                let patternStr = state.pattern.join('');
                let actionName = '';
                
                if (state.isDrag) {
                    if (patternStr.includes('→')) actionName = '搜索 / 打开';
                } else {
                    let actionCode = GESTURE_ACTIONS[patternStr];
                    actionName = ACTION_NAMES[actionCode] || patternStr;
                }
                visualizer.updateAction(actionName);
            }
            state.lastX = currentX;
            state.lastY = currentY;
        }
    }

    // --- 强制拖拽逻辑 ---
    document.addEventListener('mousedown', (e) => {
        if (e.button !== 0) return;
        let target = e.target;
        
        // 【修复】确保 target 是元素节点
        if (target.nodeType === 3) target = target.parentNode;
        if (!target || !target.closest) return;

        // 如果点击的是可编辑区域,不要强制开启拖拽,否则无法选字
        if (target.isContentEditable || target.closest('[contenteditable="true"]')) return;

        let depth = 0;
        while (target && target !== document.body && depth < 5) {
            if (target.getAttribute && target.getAttribute('draggable') === 'false') {
                if (target.tagName === 'A' || target.tagName === 'IMG' ||
                    (window.getSelection().rangeCount > 0 && window.getSelection().containsNode(target, true))) {
                    target.setAttribute('draggable', 'true');
                    target.setAttribute('data-shoushi-modified', 'true');
                }
            }
            target = target.parentElement;
            depth++;
        }
    }, true);

    const restoreDraggable = () => {
        const modified = document.querySelectorAll('[data-shoushi-modified="true"]');
        modified.forEach(el => {
            el.setAttribute('draggable', 'false');
            el.removeAttribute('data-shoushi-modified');
        });
    };
    document.addEventListener('mouseup', restoreDraggable, true);
    document.addEventListener('dragend', restoreDraggable, true);


    // --- 鼠标手势事件 ---
    document.addEventListener('mousedown', (e) => {
        if (e.button === 2) {
            state.active = false;
            state.isDrag = false;
            state.startX = e.clientX;
            state.startY = e.clientY;
            state.lastX = e.clientX;
            state.lastY = e.clientY;
            state.pattern = [];
            state.preventMenu = false;
        }
    }, true);

    document.addEventListener('mousemove', (e) => {
        if (e.buttons !== 2 && !state.isDrag) return;
        
        if (e.buttons === 2 && !state.active) {
            let dist = Math.sqrt(Math.pow(e.clientX - state.startX, 2) + Math.pow(e.clientY - state.startY, 2));
            if (dist > 10) {
                state.active = true;
                state.preventMenu = true;
                visualizer.show();
                visualizer.addPoint(state.startX, state.startY);
            }
        }
        
        if (state.active) {
            handleMove(e.clientX, e.clientY);
        }
    }, true);

    document.addEventListener('mouseup', (e) => {
        if (e.button === 2 && state.active) {
            let patternStr = state.pattern.join('');
            let action = GESTURE_ACTIONS[patternStr];
            if (action) executeAction(action);
            
            visualizer.hide();
            state.active = false;
            e.preventDefault();
            e.stopPropagation();
        } else if (e.button === 2) {
             state.preventMenu = false;
        }
    }, true);

    document.addEventListener('contextmenu', (e) => {
        if (state.preventMenu) {
            e.preventDefault();
            e.stopPropagation();
            state.preventMenu = false;
        }
    }, true);

    // --- 超级拖拽事件 (核心修复) ---
    document.addEventListener('dragstart', (e) => {
        state.dragType = null;
        state.dragContent = null;
        state.pattern = [];

        // 【修复】处理文本节点,确保 target 是 Element
        let target = e.target;
        if (target.nodeType === 3) target = target.parentNode;
        
        // 安全检查
        if (!target || typeof target.closest !== 'function') return;

        if (Config.get('enableLinkDrag') && target.closest('a')) {
            state.dragType = 'link';
            state.dragContent = target.closest('a').href;
        } else if (Config.get('enableImageDrag') && target.tagName === 'IMG') {
            state.dragType = 'image';
            state.dragContent = target.src;
        } else if (Config.get('enableTextDrag')) {
            let selection = window.getSelection().toString();
            if (selection) {
                state.dragType = 'text';
                state.dragContent = selection;
            }
        }

        if (state.dragType) {
            state.isDrag = true;
            state.startX = e.clientX;
            state.startY = e.clientY;
            state.lastX = e.clientX;
            state.lastY = e.clientY;
            
            e.dataTransfer.effectAllowed = 'copy';
            // 兜底:如果没数据,强行塞一点,防止浏览器判定为空拖拽而禁止
            if (!e.dataTransfer.types.length) {
                e.dataTransfer.setData('text/plain', state.dragContent || 'FlowMouseDrag');
            }
        }
    }, true); // 捕获阶段

    // 【关键修复】使用捕获阶段(true)监听dragover,抢在网页JS之前告诉浏览器"这里可以Drop"
    document.addEventListener('dragover', (e) => {
        if (state.isDrag) {
            e.preventDefault();
            e.stopPropagation(); // 阻止事件冒泡给网页,防止网页的禁止逻辑生效
            e.dataTransfer.dropEffect = 'copy';
            
            if (!state.active) {
                 state.active = true;
                 visualizer.show();
                 visualizer.addPoint(state.startX, state.startY);
            }
            handleMove(e.clientX, e.clientY);
        }
    }, true); // &#9888;&#65039; 注意这里的 true,非常重要

    document.addEventListener('dragend', (e) => {
        if (state.isDrag && state.active) {
            e.preventDefault();
            visualizer.hide();
            
            let patternStr = state.pattern.join('');
            if (patternStr.includes('→') || patternStr.length === 0) { 
                if (state.dragType === 'text') executeAction('search', state.dragContent);
                if (state.dragType === 'link') executeAction('openLink', state.dragContent);
                if (state.dragType === 'image') executeAction('openImage', state.dragContent);
            }
        }
        state.isDrag = false;
        state.active = false;
    }, true);
    
    // 捕获阶段阻止 drop,防止网页原生的搜索或跳转干扰
    document.addEventListener('drop', (e) => {
        if (state.isDrag && state.active) {
             e.preventDefault();
             e.stopPropagation();
        }
    }, true);


    // =========================================================================
    // 5. 菜单系统
    // =========================================================================
    let menuIds = [];
    function updateMenus() {
        menuIds.forEach(id => GM_unregisterMenuCommand(id));
        menuIds = [];

        const add = (name, fn) => menuIds.push(GM_registerMenuCommand(name, fn));

        add((Config.get('enableTrail') ? '&#9989;' : '&#10060;') + ' 启用轨迹', () => {
            Config.set('enableTrail', !Config.get('enableTrail'));
        });

        add((Config.get('enableHUD') ? '&#9989;' : '&#10060;') + ' 启用提示', () => {
            Config.set('enableHUD', !Config.get('enableHUD'));
        });
        
        add('&#128269; 搜索引擎: ' + (Config.get('searchEngine') === 'google' ? 'Google' : Config.get('searchEngine') === 'baidu' ? '百度' : 'Bing'), () => {
            let engines = ['google', 'baidu', 'bing'];
            let current = Config.get('searchEngine');
            let next = engines[(engines.indexOf(current) + 1) % engines.length];
            Config.set('searchEngine', next);
        });

        add((Config.get('enableTextDrag') ? '&#9989;' : '&#10060;') + ' 启用文字拖拽', () => {
            Config.set('enableTextDrag', !Config.get('enableTextDrag'));
        });
        
        add((Config.get('enableLinkDrag') ? '&#9989;' : '&#10060;') + ' 启用链接拖拽', () => {
            Config.set('enableLinkDrag', !Config.get('enableLinkDrag'));
        });
        
        add((Config.get('enableImageDrag') ? '&#9989;' : '&#10060;') + ' 启用图片拖拽', () => {
            Config.set('enableImageDrag', !Config.get('enableImageDrag'));
        });
    }

    updateMenus();

})();

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
_达圣 + 1 + 1 用心讨论,共获提升!

查看全部评分

推荐
longfei9527 发表于 2025-12-16 15:51
用着比CrxMouse舒服,用了CrxMouse好多年了,支持H大
推荐
cageforawalk666 发表于 2025-12-16 14:35
使用方法是:鼠标左键按住文字、图片或链接拖拽到浏览器顶部会触发对应的功能

点评

是向右拖拽就打开了,不需要到顶部,安装完插件需要刷新之前的页面才会加载插件。  发表于 2025-12-20 10:41
推荐
 楼主| Hmily 发表于 2025-12-29 14:02 |楼主
hupo376787 发表于 2025-12-29 11:36
新版需要查看下载内容的权限额,这没必要吧
申请 "downloads" 权限是为了实现“超级拖拽”中的图片保存功能。当用户拖拽网页图片并执行“保存图片”手势时,扩展需要该权限将图片保存到用户的本地设备。此权限仅在用户主动操作时触发,不用于其他用途。


下个版本修改一下,搞成用到这个功能再申请。
推荐
 楼主| Hmily 发表于 2026-4-23 11:59 |楼主
Autorun 发表于 2026-4-22 22:07
不知道为什么用起来有点慢,而用独立的程序比如WGestures就不会,难道因为它是扩展就会这样?

具体哪里慢?
推荐
 楼主| Hmily 发表于 2026-4-20 10:44 |楼主
fushenzhi 发表于 2026-4-19 16:33
edge浏览器不是本来就支持鼠标手势吗?

会有人说Edge本来原生就有鼠标手势,我们的优势是什么?相比较而言单纯简单的手势没有比原生更好的选择了,但是简单之外才是我们插件的优势:
1、支持自定义手势,可以设置四个不同方向进行组合。
2、更为丰富的的手势功能,一直持续不断在增加,新版还支持命令链功能,一个手势可以执行多个功能。
3、强大的“拖拽”功能是最大的优势,这是Edge没有的。
4、即将发布的各种新功能,比如区域选框支持批量操作URL等。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
fushenzhi + 1 + 1 鼓励转贴优秀软件安全工具和文档!

查看全部评分

推荐
 楼主| Hmily 发表于 2026-4-13 10:46 |楼主
zykcnro 发表于 2026-4-13 10:36
感谢大佬的手势插件,真是各种好用!!

提个微小的建议:希望能够自定义”显示操作提示“的提示位置。

你想放到哪里去?
3#
zzage 发表于 2025-12-16 12:36
抢座,广告位出租

点评

请勿灌水,提高帖子质量是每位会员应尽的义务!  发表于 2025-12-20 00:09

免费评分

参与人数 1吾爱币 -1 收起 理由
Hmily -1 请勿灌水,提高帖子质量是每位会员应尽的义务!

查看全部评分

4#
TR小米哥 发表于 2025-12-16 12:40
用手势在页面上画圈圈,就能可以到很多页面项
5#
rickyliu1188 发表于 2025-12-16 12:43
dy感谢分享
6#
pwd 发表于 2025-12-16 12:47
不错,已经使用
7#
各有因缘莫羡人 发表于 2025-12-16 12:49
好东西 之前就烦谷歌没360这种手势
8#
ZHANGZHILING 发表于 2025-12-16 12:50
点赞该插件正在下载中
9#
enjoylun 发表于 2025-12-16 12:53
挺方便的
10#
阿源小哥哥 发表于 2025-12-16 12:57
看大佬这排版是在github开源勒?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-5-3 11:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表