Bundle
dsh-mobile-keys
DSH Web 移动端热键模式:自动检测移动端并切换发送/换行键位(发送 Ctrl+Enter / 换行 Enter),设置面板提供开关
- Source
- liujuntao123
- License
- MIT
- Updated
- Updated 9 hours ago
Readme
# DSH Mobile Keys
**中文** | [English](./README_en.md)
DeepSeek Harness(DSH)**移动端热键模式**插件(浏览器端 bundle 插件)。自动检测移动端设备并切换发送/换行键位,解决「手机软键盘打不出 `Shift+Enter`,导致输入框无法换行」的问题。配置保存在浏览器 `localStorage`,无需后端。
## ⌨️ 键位
| 模式 | 发送 | 换行 | 说明 |
| --- | --- | --- | --- |
| 桌面(默认) | `Enter` | `Shift+Enter` | 与 DSH 原生一致,插件完全放行 |
| 移动端模式 | `Ctrl+Enter` | `Enter` | 发送走 DSH 原生加速手势;换行由插件拦截裸 `Enter` 并合成 `Shift+Enter`,走 DSH 原生换行通路 |
## ✨ 功能特性
- 🔍 **自动检测**:默认 `auto` 模式,按 UA / 触控点数 / 指针类型 / 屏宽综合判定设备并自动切换键位;旋转屏幕、切换外接屏即时跟随。桌面触屏笔记本、触控一体机不会误判。
- 🎛️ **设置面板开关**:DSH 设置 → 通用 → 「**移动端热键模式**」开关,实时显示检测状态与当前键位;手动开/关后可一键「恢复自动检测」。
- 💬 **`/mobilekeys` 命令**:消息输入框输入即可查看状态并切换 自动 / 开启 / 关闭。
- 🛠️ **控制台 API**:`window.__dshMobileKeys.getStatus() / setMode() / getBindings()`。
- 🛡️ **不影响原生行为**:IME 合成中、弹出层(菜单/对话框/命令面板)打开时、提问卡输入框、编辑器以外的按键全部放行;非移动端模式下插件零介入。
- 💾 **零后端**:偏好存 `localStorage`(键 `dsh.mobilekeys.v1`)。键位属「每设备」偏好,各设备独立记忆。
## 🤖 AI install(让 AI 帮你安装)
把下面这句提示词发给你的 AI(DeepSeek / Claude 等),它会自动完成安装:
> 请帮我安装 `dsh-mobile-keys` 插件到 DeepSeek Harness 的 web profile:在任意目录执行
> `dsh plugin --profile web add git+https://github.com/liujuntao123/dsh-mobile-keys.git`,
> 然后重启 `dsh web` 并强刷浏览器(Ctrl+F5),最后在浏览器控制台执行
> `window.__dshMobileKeys.getStatus()` 确认返回 `{ mode, detected, effective, bindings }`,
> 并在设置面板 → 通用里确认出现「移动端热键模式」开关。
完整的给 AI 的安装指令(含手动方式、排查、验证)见 **[AI_INSTALL.md](./AI_INSTALL.md)**。
## 📦 安装方法
### 方式一:从 GitHub 安装(推荐)
```bash
dsh plugin --profile web add git+https://github.com/liujuntao123/dsh-mobile-keys.git
```
DSH 会自动:pnpm 安装(git 依赖)→ 检测到 `dsh.bundle` 声明 → 把 `dsh-mobile-keys` 写进 `package.json` 的 `dsh.profile.bundles`。
> 依赖 `pnpm`。若没装:`npm install -g pnpm`。
### 方式二:手动安装
```bash
cd ~/.dsh/profiles/web # Windows PowerShell: cd $env:USERPROFILE\.dsh\profiles\web
pnpm add git+https://github.com/liujuntao123/dsh-mobile-keys.git
```
然后**必须**把 `"dsh-mobile-keys"` 加进该目录 `package.json` 的 `dsh.profile.bundles` 数组:
```jsonc
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-mobile-keys" // ← 必须加,否则不生效
]
}
}
```
> ⚠️ `pnpm add` 不会自动改 `bundles` 列表;DSH 按该列表加载插件,漏加则不生效。
### 方式三:本地克隆 + link(开发用)
```bash
git clone https://github.com/liujuntao123/dsh-mobile-keys.git
```
在 web profile 的 `package.json` 中挂 link 依赖:
```jsonc
"dependencies": {
"dsh-mobile-keys": "link:/绝对路径/dsh-mobile-keys"
}
```
同样需要把 `"dsh-mobile-keys"` 加进 `bundles`。
### 安装后:重启 + 强刷(三种方式都要)
```bash
bash scripts/restart-dsh-web.sh # 克隆了本仓库时可用;否则按你的方式重启 dsh web
```
然后在浏览器 **Ctrl+F5** 强刷。
## ⚙️ 使用说明
### 模式说明
| store.mode | 含义 |
| --- | --- |
| `auto`(默认) | 自动检测设备,随设备切换键位 |
| `on` | 始终移动端键位(`Ctrl+Enter` 发送 / `Enter` 换行) |
| `off` | 始终桌面键位(`Enter` 发送 / `Shift+Enter` 换行) |
### 设置面板
DSH 侧栏 → 齿轮(设置)→ 通用 → 「移动端热键模式」,两行描述:
```
当前按键:发送 Ctrl+Enter / 换行 Enter
检测到当前设备为移动端 · 建议在移动端时开启,可避免无法换行问题
```
- 开关本体:显示并控制**当前生效**的模式;拨动即写入手动值(`on` / `off`)。
- 行 1:随模式实时显示当前生效的键位。
- 行 2:设备检测结论与建议;手动开/关后此行末尾出现「恢复自动检测」,点击清掉手动值回到 `auto`。
### 命令与控制台
- 输入框输入 `/mobilekeys` → 选择 自动检测 / 开启 / 关闭。
- 浏览器控制台:
```js
window.__dshMobileKeys.getStatus() // { mode, detected, effective, bindings }
window.__dshMobileKeys.setMode('on') // 'auto' | 'on' | 'off'
window.__dshMobileKeys.getBindings() // { send, newline }
```
### 验证清单
1. 设置 → 通用出现「移动端热键模式」行,开关与检测状态正常。
2. `/mobilekeys` 能弹出菜单。
3. 手动开启后:`Enter` 插入换行、`Ctrl+Enter` 发送;关闭后恢复 `Enter` 发送。
4. 命令菜单/斜杠面板打开时 `Enter` 仍是「选中」,不被换行劫持。
## 🔍 实现原理
DSH 的消息输入框是 **Lexical** 编辑器,`Enter` 语义由注册在 CRITICAL 优先级的 `KEY_ENTER_COMMAND` handler 决定:
- `event.shiftKey === true` → handler 返回 `false`,落到 `@lexical/plain-text` 默认行为 → **插入换行**;
- 否则 → **提交发送**(`ctrlKey/metaKey` 视为 accelerated 发送)。
因此本插件:
- **发送侧零改动**:移动端模式的 `Ctrl+Enter` 就是 DSH 原生加速手势;
- **换行侧最小介入**:仅在移动端模式生效时,于 `document` **捕获段**拦截消息编辑器内的裸 `Enter`(`preventDefault + stopImmediatePropagation`),再在 Lexical 根元素(`[data-lexical-editor="true"]`)上合成一次带 `shiftKey: true` 的 `keydown`,完整复用 DSH 原生换行路径(选区、撤销栈、受控更新全部正确)。
判定与防误伤:
- 只处理 `key === 'Enter'`;`Shift/Ctrl/Cmd/Alt+Enter`、IME 合成中(`isComposing` / `keyCode 229`)、弹出层打开(`[role="menu"|"listbox"|"dialog"|…]` 可见)一律放行;
- 目标不在 `[data-lexical-editor="true"]` 内(按钮、提问卡输入框等)一律放行;
- 合成事件带 `__dshMobileKeysSynthetic` 标记,防重入。
移动端检测(`auto` 模式):
```
移动端 ⇐ UA 命中 Android/iPhone/iPad/iPod/Mobile/Silk
⇐ iPadOS 13+ 桌面 UA(Macintosh + maxTouchPoints > 1)
⇐ (pointer: coarse) 且 有触控 且 (max-width: 820px)
```
## 🧪 开发与测试
```bash
npm test # 零依赖 Node 测试:把真实 lib/client.js 装进 VM 端到端验证
node --check lib/client.js
```
目录结构:
```
lib/index.js 宿主侧最小 Cordis 插件(挂载/卸载壳)
lib/client.js 浏览器端全部逻辑(ModuleLoader bundle,无构建步骤)
tests/ 零依赖 Node 测试(node --test)
scripts/ restart-dsh-web.sh:按原命令行重启 dsh web 的辅助脚本
cordis.patch.yml bundle patch:把本插件插入 profile 组合
```
修改 `lib/client.js` 后无需构建;重启 `dsh web` + 强刷浏览器即可生效。
## ❓ FAQ
**Q:与 `dsh-hotkeys` 什么关系?**
A:本插件参考了 [ctenni/dsh-hotkeys](https://github.com/ctenni/dsh-hotkeys) 的 bundle 插件形态与工程约定,聚焦「移动端键位自动切换」这一件事:无需录制,设备即开关。两者可共存。
**Q:手机上没有 Ctrl 键,`Ctrl+Enter` 怎么按?**
A:平板带物理键盘、手机外接键盘直接可用;纯软键盘用户可在设置里关掉移动端模式,或期待后续版本加入「移动端发送键」自定义。
**Q:提问卡(ask_user_question)的输入框会变吗?**
A:不会。它的 `Enter` 语义是「提交/继续」,与 composer 无关,本插件不介入。
**Q:设置面板里没看到开关?**
A:确认 `dsh-mobile-keys` 已在 `dsh.profile.bundles` 里、`dsh web` 已重启、浏览器已强刷;控制台执行 `window.__dshMobileKeys` 应返回对象。
## 📄 License
[MIT](./LICENSE)
Install
dsh plugin --profile web add github:liujuntao123/dsh-mobile-keys#3c05097aa87244ec66c05828c095d7e2ece105c8
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-mobile-keys from the hub