# dsh-fullscreen-input

[![English](https://img.shields.io/badge/lang-English-9aa0a6)](README.en.md) [![简体中文](https://img.shields.io/badge/lang-%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-4176e6)](README.md)

[![npm](https://img.shields.io/npm/v/dsh-fullscreen-input?color=4176e6)](https://www.npmjs.com/package/dsh-fullscreen-input) [![License](https://img.shields.io/github/license/AL-Yichen/dsh-fullscreen-input?color=4176e6)](./LICENSE) [![DSH](https://img.shields.io/badge/DSH-%3E%3D0.2.0--rc.1%20%3C0.3.0--0-4176e6)](#兼容性) [![PRs](https://img.shields.io/badge/PRs-welcome-brightgreen)](https://github.com/AL-Yichen/dsh-fullscreen-input/pulls)

给 DSH 的输入框加一个**全屏输入面板**：点开它，在整屏空间里写多行文本，写完点按钮发送。`Enter` 只换行、只有 `Ctrl+Enter` 才发送；面板可以移动、可以拖边框改大小，引用与附件都与主输入框共用同一份草稿。

## 为什么需要一个全屏输入框

DSH 自带的输入框只有**窄窄一条**：写长提示词时只能在一个很扁的区域里翻来覆去，引用、附件、正文全挤在一起，想通读一遍自己写了什么几乎做不到。

这个面板把输入区**放大到整屏**：一次能看到的文本量是原来的十几倍；写完之后还能拖标题栏把它挪到别处、拖边框改成想要的宽高，把背后的会话露出来对照着看。**它不是只读预览，而是替换掉那条窄输入框的编辑场所**——草稿是同一份，在面板里改完关掉，主输入框里就是新内容。

## 顺带解决的问题

DSH 原有输入框的 `Shift+Enter` 换行判定依赖一个很短的宽容窗口——输入法组合结束后的 **10 毫秒**内仍算「正在组合」。中文输入法频繁使用 Shift / Enter（切换中英、确认候选词），很容易落进这个窗口，于是 `Shift+Enter` 被误判成发送，多行文本根本写不舒服。

**面板里没有「Enter 发送」这条路径**，所以这个问题在这里不存在。但它是**顺带**解决的：即使没有这个毛病，一个全屏的输入场所本身也是需要的。

## 安装

### 从插件面板（推荐）

打开 DSH 侧栏的 **「插件」** 页面，点 **添加插件**，在输入框里填入包名 `dsh-fullscreen-input`，然后点安装。

> 那个输入框也接受 Git 地址、压缩包或本地绝对路径——所以没有发布到 npm 的插件同样能从这里装。插件管理页只管理声明了 `dsh.bundle` 的包，本插件已声明。

### 命令行

```sh
dsh plugin --profile web add dsh-fullscreen-input
```

装完重启 `dsh web`，刷新页面。

### 从本地目录（开发用）

```sh
git clone <本仓库> dsh-fullscreen-input
dsh plugin --profile web add link:<克隆下来的绝对路径>
```

Windows 例：`link:D:/example/dsh-fullscreen-input`

因为是 `link:` 安装，改完源码跑一次 `node build-client.mjs` 重建，**刷新页面即生效**，不用重装。

## 怎么用

输入框下方工具栏（「+」按钮所在那一行）会多出一个图标，悬停显示「全屏输入」。点开就是面板；默认 `F2` 也能唤起它。

### 键位

| 按键 | 行为 |
|---|---|
| `Enter` | 换行 |
| `Shift+Enter` | 换行（与 `Enter` 等价，Shift 在面板里只表示换行） |
| `Ctrl+Enter` / `Cmd+Enter` | 发送 |
| `Esc` | 关闭面板（设置窗口开着时先关设置窗口，面板保留） |
| `Ctrl+0` | 把面板恢复到默认位置与默认大小（等同双击标题栏）。**面板不可达时的自救入口**：不要求焦点在面板内，只要面板开着就生效 |
| `F2` | 打开 / 关闭面板（可在设置里改绑为其它功能键） |
| 中文输入法组词中的 `Enter` / `Ctrl+Enter` | 换行，**绝不发送** |
| 点击面板之外的区域 | 关闭面板（等同 `Esc`；关掉遮罩后不适用） |

**关闭面板不会丢内容。** 面板与主输入框读写的是**同一份草稿**——不是两份内容互相同步，而是同一个值。所以在面板里敲的字、在主输入框里敲的字，都是同一份。

### 面板里能做什么

| 能力 | 怎么用 |
|---|---|
| **写多行** | 整个面板就是输入区：`Enter` 换行、`Ctrl+Enter` 发送 |
| **调整大小** | 拖拽边框或四个角（8 个方向；光标会变成对应的缩放箭头，没有额外的可见把手）。最小 360×240、最大不超过视口。**尺寸会被记住**，双击标题可连同位置一起复原 |
| **移动面板** | 按住标题那一行拖动（自由拖动，不设边界）；**双击标题回到居中**。位置默认不记住 |
| **看引用** | 草稿里的 `@` 引用显示为带图标的条目，悬停看完整路径 |
| **移除引用** | 引用条目右上角的「×」。它删掉的是**草稿里那段文字**——引用不是附件，所以在文本框里直接选中删除也一样。点「×」后输入框会失焦（焦点被按钮拿走），点回文本框即可继续输入 |
| **看附件** | 图片显示为缩略图，**点击看大图**；文件显示类型图标与文件名 |
| **移除图片附件** | 鼠标移到缩略图上，右上角出现「×」 |
| **添加文件** | 面板左下角「+」，走 DSH 自己的文件选择器 |
| **粘贴** | 在面板里直接 `Ctrl+V`，图片与文件都能贴进来 |
| **拖放** | 把文件直接拖到面板上 |
| **滚动背景** | 鼠标在**面板之外**滚动滚轮，会滚动背后的会话——边看 LLM 输出边写提示词时不用来回开关面板。面板内部的滚轮仍归面板 |
| **唤起快捷键** | 默认 `F2`，按一下开、再按一下关。可在设置里改成任意功能键（F1–F12）；`Esc` 始终关闭 |
| **面板底色** | 想要不透明的面板就开「纯色面板」，想要磨砂质感就开「启用毛玻璃效果」（两者互斥）；两个都关则面板完全透明 |
| **关闭遮罩** | 设置里的「启用遮罩层」可整个关掉遮罩：鼠标从此能直接点击、滚动背后页面。代价是「点击面板外关闭」消失，请用 `Esc` 或唤起快捷键 |
| **使用提示** | 首次打开面板时会弹一次提示。可勾选「不再提示」；设置最下方有「查看提示」可随时唤回 |

### 外观与行为设置

面板头部的**小太阳图标**按钮（八齿造型，看起来更像太阳而不是齿轮）→「全屏输入设置」：

**遮罩层**
- **启用遮罩层**（默认开）
- **遮罩层不透明度**：默认完全透明（0%）
- **遮罩层雾化**：默认不雾化（0%）

**面板底色**
- **启用毛玻璃效果**：默认关闭
- **纯色面板**：默认关闭，与毛玻璃**互斥**——只铺底色、不加模糊；开启时会把「面板不透明度」推到 100%，直接得到一个不透明的纯色面板
- **面板雾化**（默认 40%）、**面板不透明度**（默认 25%）、**面板颜色**：「跟随主题」、6 个固定色，最后那个格子是**系统颜色选择器**——点它选任意颜色
- 底色共三种状态：**两个开关都关 = 面板完全透明**；只开「纯色面板」= 铺色但不模糊；只开「启用毛玻璃效果」= 铺色 + 模糊

**面板行为**
- **记住面板大小**（默认开）、**记住面板位置**（默认关）：两者独立，都关掉时每次打开都回到默认大小与居中
- **唤起快捷键**（默认 `F2`）：点一下按钮，再按一个功能键即可改绑
- **使用提示**：点「查看提示」再次显示首次使用的提示弹窗

设置会持久保存，刷新与重开都保留。

> ⚠️ 一点需要知道的行为：「**遮罩层雾化**」调高会模糊**整个屏幕背景**（含面板背后），因为遮罩层本身是全屏的。这是当前实现的行为，不是故障。

## 兼容性

- **DSH `>=0.2.0-rc.1 <0.3.0-0`**（即 0.2.x 发行线）。面板深度依赖宿主的槽位 props、`inputActions` 与 `insertReference` 的 revision-CAS 语义，这些正是次要版本最可能变动的地方，所以上界是刻意收窄的——旧版声明的 `≥ 0.2.0-rc.1` 会无声地宣称兼容未来的 `0.3.0+`。
- **Node ≥ 20**（仅构建源码时需要）
- 纯浏览器侧插件：host 侧是空实现，**不产生任何网络请求**，不读写会话数据

## 权限

本插件**不需要**任何权限档位、审批放宽或沙箱调整即可工作。它请求的能力面刻意保持在最小：

| 能力 | 用途 |
|---|---|
| `ctx.effect` | 注册样式表与 locale 字典的清理（卸载时完整回滚，无残留） |
| `ctx.inject(['slots','locale','sessions','conversation'])` | 等待并取得这四个服务；全部是读取或驱动宿主自己的输入动作 |
| `slots.inject` + `slots.register` | 往 `conversation.input.left` 槽位贡献一个工具栏按钮 |

**未使用**：`ctx.fs`、`ctx.network`、`ctx.shell`、`ctx.resources`。它不注册任何 Agent 工具，因此不会扩展模型的工具面。

唯一的本机持久化是一个 `localStorage` 键（面板外观偏好）；唯一接触文件的路径是驱动宿主**自己的**隐藏文件输入框，且请求文件对话框必须在你的点击或粘贴手势内完成。完整的攻击面说明与漏洞报告方式见 [SECURITY.md](./SECURITY.md)。

## 改源码

```sh
node build-client.mjs      # 把 src/client.js 包成 lib/client.js
npm run check              # 语法检查（三个文件）
```

| 文件 | 说明 |
|---|---|
| `src/client.js` | 唯一手写实现（浏览器侧，全部 UI 与逻辑） |
| `lib/client.js` | **构建产物，运行时实际加载的就是这个** |
| `lib/index.js` | host 侧，空实现 |
| `build-client.mjs` | 构建脚本，纯文本包裹，无任何依赖 |
| `cordis.patch.yml` | bundle 补丁，挂载 row id `fullscreen-input` |

**改完 `src/` 一定要重建**，否则刷新页面看到的还是旧代码。

## License

MIT
