吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 31230|回复: 978
收起左侧

[原创工具] FlowMouse - 心流鼠标手势 v1.1【开源Chrome插件】

    [复制链接]
Hmily 发表于 2025-12-16 12:33

FlowMouse:心流鼠标

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

✨ 核心特性

  • 完全本地,隐私至上:所有操作均在本地完成,零网络请求、零数据收集、零信息上传,彻底守护您的浏览隐私。
  • 自定义手势,随心所欲:除了16种默认手势外,支持自定义扩展更多手势操作。
  • 超级拖拽,效率翻倍
    • 拖拽文字 → 默认使用 Google 搜索,支持前台/后台打开自定义搜索引擎或复制文字。
    • 拖拽链接 → 新标签页打开,支持前台/后台打开或复制链接。
    • 拖拽图片 → 新标签页查看,支持前台/后台查看、保存图片、复制图片地址和自定义搜索。
  • 直观设置,随心定制:提供清晰的可视化设置页,支持自定义手势轨迹颜色、宽度及操作提示。
  • 多语言支持:完整适配简体中文与英文界面。

完整图.png

⚠️ 注意事项

  • 安装或启用扩展后,已打开的页面需要刷新才能使用手势功能。
  • 浏览器内置页面(如新标签页、设置页、扩展管理页、Chrome Web Store等)因浏览器安全限制,无法使用鼠标手势
  • 如果页面包含多个 iframe 窗口,手势功能和鼠标轨迹可能会受影响(暂无法解决)。

🚀 安装方法

方式一:通过 Chrome 应用商店安装(推荐)【如果你喜欢它,请在应用商店给我们一个五星鼓励,这是我们更新的动力。】

https://chrome.google.com/webstore/detail/fnldhkfidchnjiokpoemdhoejmaojkgp

方式二:手动加载解压的扩展程序

  1. 下载并解压本扩展的安装包。
  2. 在 Chrome 地址栏输入 chrome://extensions/ 并访问。
  3. 开启页面右上角的 “开发者模式”
  4. 点击左上角的 “加载已解压的扩展程序”
  5. 选择解压后的 FlowMouse 文件夹即可完成安装。
    FlowMouse v1.1.zip (67.58 KB, 下载次数: 1416)
    链接: https://pan.baidu.com/s/175cd1dOrAcQEAbRRFlOfhA?pwd=52pj

🔧 基础使用方法

  1. 鼠标手势:按住鼠标右键滑动,根据轨迹松开即可触发对应功能。
  2. 超级拖拽:按住鼠标左键拖拽文字、链接或图片,根据拖拽方向(默认支持向右)触发搜索或打开操作。

📖 默认手势指南

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

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

📝 更新日志

v1.1 (2025-12-24)

修复与优化:

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

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

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

新功能:

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

🔒 隐私承诺

FlowMouse 郑重承诺:

  • 本扩展为开源项目,代码已托管于 GitHub,欢迎审阅与贡献。
  • 不收集任何您的浏览历史、书签或操作习惯。
  • 不上传任何本地数据至任何服务器。
  • 不嵌入任何第三方分析或广告代码。
    所有个人配置均仅保存在您的浏览器本地存储中,永不离开您的设备。

💡 缘起

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

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

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

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

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

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


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


👨‍💻 作者信息

免费评分

参与人数 335吾爱币 +342 热心值 +311 收起 理由
绝世大嘴 + 1 + 1 我很赞同!
大游 + 1 + 1 谢谢@Thanks!
bnuxieliang + 1 + 1 我很赞同!
A11111111 + 1 + 1 我很赞同!
52PJ-csteel + 1 + 1 谢谢@Thanks!
Hezee + 1 谢谢@Thanks!
zp999 + 1 + 1 谢谢@Thanks!
qwq2233 + 1 谢谢@Thanks!
odinchu + 1 + 1 鼓励转贴优秀软件安全工具和文档!
wangfeias0 + 1 + 1 谢谢@Thanks!
zgklxj + 1 + 1 我很赞同!
zs668899 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xq03 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hmb860428 + 1 谢谢@Thanks!
llttyy00 + 1 + 1 谢谢@Thanks!
ltfs917 + 1 + 1 我很赞同!
lifelike + 1 + 1 谢谢@Thanks!
cshadow + 1 + 1 谢谢@Thanks!
cbbooxx + 1 + 1 强的可怕
luckyphp + 1 + 1 谢谢@Thanks!
bugzeroman + 1 + 1 谢谢@Thanks!
很鬼很聪明 + 1 + 1 谢谢@Thanks!
Blueyes + 1 + 1 谢谢@Thanks!
mrhu2014 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Pluto2 + 1 + 1 谢谢@Thanks!
神奇的人鱼 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
lcylcylcy + 1 + 1 谢谢@Thanks!
燕十四 + 1 + 1 谢谢@Thanks!
bosen881 + 1 + 1 谢谢@Thanks!
java2003 + 1 + 1 热心回复!
拼尽此生欢 + 1 + 1 谢谢@Thanks!
diuer + 1 + 1 谢谢@Thanks!
Cz99999 + 1 + 1 我很赞同!
yumuyang + 1 + 1 谢谢@Thanks!
eehu + 1 + 1 谢谢@Thanks!
a85401234 + 1 + 1 谢谢@Thanks!
Jesse7701 + 1 + 1 用心讨论,共获提升!
wojianliu + 1 谢谢@Thanks!
dawnfancy + 1 + 1 谢谢@Thanks!
fsjoy52 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
puppet7264 + 1 + 1 我很赞同!
zhelishitudou + 1 + 1 谢谢@Thanks!
teasun + 1 + 1 谢谢@Thanks!
YC256743 + 1 谢谢@Thanks!
Adam0802 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
DKDKDK + 1 + 1 谢谢@Thanks!
tbody + 2 + 1 意外之喜啊
IcelandPatrick + 1 + 1 谢谢@Thanks!
libaibuaidufu + 1 + 1 谢谢@Thanks!
UROKey + 1 + 1 我很赞同!
ChenSSS + 1 + 1 我很赞同!
a709447628 + 1 + 1 热心回复!
dxch + 1 + 1 谢谢@Thanks!
lgc81034 + 1 谢谢@Thanks!
oldbabyjsx + 1 谢谢@Thanks!
yuren008 + 1 + 1 我很赞同!
zqqqq + 1 + 1 谢谢@Thanks!
zhangwei6929 + 1 + 1 谢谢@Thanks!
neiko + 1 + 1 谢谢@Thanks!
haui_2006 + 1 + 1 我很赞同!
zyj1023003926 + 1 + 1 我很赞同!
5D2wpY + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
jasonren + 1 谢谢@Thanks!
EdgeHis + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
XanLiu + 1 + 1 我很赞同!
nightyice + 1 + 1 我很赞同!
hongye0 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
yt1986315 + 1 + 1 我很赞同!
lx12 + 2 + 1 热心回复!
jaffa + 1 + 1 用心讨论,共获提升!
kmyxyjyld + 1 + 1 谢谢@Thanks!
bzgx + 1 + 1 谢谢@Thanks!
笙若 + 1 + 1 谢谢@Thanks!
erchuxin + 1 + 1 热心回复!
CheungZzzz + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
laotzudao0 + 2 + 1 我很赞同!
cnngtc + 2 + 1 厉害了啊 试用下
IKUNking + 1 + 1 没想到还有更新
zmiii + 1 谢谢@Thanks!
pwelyn + 1 + 1 谢谢@Thanks!
muicoder + 1 + 1 我很赞同!
xuhao8588 + 1 + 1 我很赞同!
眼中的神 + 1 + 1 谢谢@Thanks!
ee135 + 1 + 1 谢谢@Thanks!
mouster + 1 + 1 鼓励转贴优秀软件安全工具和文档!
nikolazero + 1 + 1 谢谢@Thanks!
chr1sj0ne + 1 + 1 我很赞同!
OEMBSD + 1 + 1 谢谢@Thanks!
hc6125322 + 1 + 1 我很赞同!
mama + 1 + 1 谢谢@Thanks!
爱免费吧 + 1 + 1 我很赞同!
文zjw + 1 + 1 谢谢@Thanks!
viconly + 1 + 1 谢谢@Thanks!
冷天枫 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ruixiang + 1 + 1 谢谢@Thanks!
FireFrog + 1 我很赞同!
torchhhh + 1 + 1 我很赞同!
okbyte + 1 + 1 我很赞同!
1MajorTom1 + 1 热心回复!
zxc8820 + 1 拖拽链接是在新标签页打开,不是在后台新标签页打开,希望可以更新

查看全部评分

本帖被以下淘专辑推荐:

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

 楼主| Hmily 发表于 2025-12-26 11:47
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大提醒!
beyond0729 + 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 发表于 2025-12-22 16:39
CheungZzzz 发表于 2025-12-21 12:21
求一个拖拽打开新标签后,可以设置在前台还是后台

下个版本支持高级设置自定义。
zzage 发表于 2025-12-16 12:36
抢座,广告位出租

点评

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

免费评分

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

查看全部评分

 楼主| Hmily 发表于 2025-12-19 14:32
FlowMouse - 心流鼠标手势 v1.0 已正式上架 Chrome 应用商店!
https://chrome.google.com/webstore/detail/fnldhkfidchnjiokpoemdhoejmaojkgp

欢迎体验!如果你喜欢它,请给我们一个五星鼓励;如有任何建议,也欢迎留言反馈。
大家之前反馈的问题与功能建议,我们已在即将发布的 v1.1 中进行了修复与完善,新版本很快就会与大家见面。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
viconly + 1 + 1 好像不能直接打开

查看全部评分

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

本版积分规则

返回列表

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

GMT+8, 2026-2-1 20:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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