> **本文回答**：快捷键 —— `setShortcuts` / `getShortcuts` / `getDefaultShortcuts` / `setModeToggleShortcut`（已对照 `vjmapext.d.ts` 与运行时核实）。

## 一、方向：动作 → 键位（不是「键位 → 命令」）

`ShortcutMap` 的**键是内置动作名，值是按键串**：

```ts
interface ShortcutMap {
  modeToggle?: string | null;   // edit ↔ browse 切换
  selectAll?: string | null;
  undo?: string | null;
  redo?: string | null;
  delete?: string | null;
  nudgeUp?: string | null;      // 微移（像素）
  nudgeDown?: string | null;
  nudgeLeft?: string | null;
  nudgeRight?: string | null;
  rotateLeft?: string | null;   // 选中实体旋转
  rotateRight?: string | null;
  scaleUp?: string | null;      // 选中实体缩放
  scaleDown?: string | null;
  copy?: string | null;
  cut?: string | null;
  paste?: string | null;
  cancel?: string | null;       // 取消输入/清选集
  confirm?: string | null;      // 确认/结束当前输入
  repeatCommand?: string | null; // 重复上一条命令
}
```

`vjmapext.getDefaultShortcuts()` 的默认值（顶层函数；`MapCadLayer` 实例上无此方法）：

```js
{
  modeToggle: 'ctrl+shift+e',
  selectAll: 'ctrl+a',
  undo: 'ctrl+z',  redo: 'ctrl+y',
  delete: 'delete',
  nudgeUp: 'ctrl+arrowup',  nudgeDown: 'ctrl+arrowdown',
  nudgeLeft: 'ctrl+arrowleft', nudgeRight: 'ctrl+arrowright',
  rotateLeft: 'ctrl+[',  rotateRight: 'ctrl+]',
  scaleUp: 'ctrl+.',     scaleDown: 'ctrl+,',
  copy: 'ctrl+c',  cut: 'ctrl+x',  paste: 'ctrl+v',
  cancel: 'escape', confirm: 'enter',
  repeatCommand: null,     // 默认未绑；可用 confirm(enter) 之外自配
}
```

> ⚠️ **没有「字母键启动命令」体系**（`'l'→'LINE'`、`'co'→'COPY'` 这类 AutoCAD 别名在本库不存在——`handleKeyDown` 只匹配上表动作）。要给命令加速键，自己监听容器 `keydown` 再 `executeCommand('LINE')`。

## 二、读取 / 覆盖

```js
const all = mapcadLayer.getShortcuts();          // ShortcutMap（动作→键位）
mapcadLayer.setShortcuts({ undo: 'ctrl+z', redo: 'ctrl+shift+z' });
mapcadLayer.setShortcuts({ nudgeUp: null });     // 传 null = 禁用该动作键位
mapcadLayer.setModeToggleShortcut('ctrl+e');     // 等效 setShortcuts({modeToggle:'ctrl+e'})
```

`setShortcuts` 是**按动作合并**（Partial），不是整表替换。

## 三、键位串格式

```
ctrl+ / shift+ / alt+  +  主键
```

- 修饰键无序敏感（内部拆 `+` 后按 ctrl/shift/alt 归一）；主键取最后一段，`e.key.toLowerCase()` 比对。
- 主键例：`z`、`a`、`delete`、`escape`、`enter`、`arrowup`、`[`、`]`、`,`、`.`。⚠️ **空格无法绑定**：比对的是 `e.key.toLowerCase()`，空格键的 `e.key` 是 `' '`，写 `'space'` 永不匹配（`' '` 也会被 trim 成空串）；空格只在 `confirm` 里被硬编码兜底（`e.key === ' '`）。
- **不支持** meta、`f1`~`f12` 外的功能键可试但看浏览器；多字符序列键（`co`）不支持。

## 四、键盘触发流程

```
keydown（地图容器聚焦时）→ InputManager.handleKeyDown
  → 逐个 matchShortcut(事件, shortcuts.动作)
    → 命中即 preventDefault + 执行对应内置动作
```

要生效 canvas 必须先聚焦：

```js
mapcadLayer.getMapContainer()?.focus();
```

## 五、禁用某个快捷键

```js
mapcadLayer.setShortcuts({ undo: null });   // 动作→null 即禁用
```

## 六、全局 vs canvas 作用域

快捷键只在**地图容器**监听。要在整页生效自己加全局监听：

```js
window.addEventListener('keydown', e => {
  if (e.ctrlKey && e.key === 's') { e.preventDefault(); /* save */ }
});
```

## 七、和浏览器默认冲突

| 浏览器吞 | 处理 |
|---|---|
| `Ctrl+S` | `e.preventDefault()` 拦截 |
| `Ctrl+W` / `Ctrl+T` | 无法拦截，别占 |
| `F5` / `F11` / `Ctrl+N` | 浏览器保留，别占 |

## 八、常见坑

1. **canvas 没聚焦** → 按键无效；addControl 后手动 `focus()`。
2. **输入框里触发** → 全局 input 聚焦时按键仍会进容器监听（若在容器内）；给业务 input 加 `e.stopPropagation()`。
3. **Ctrl+Z 不 undo**：焦点问题，或 `undoManager` 无可撤销项。
4. **想给 `repeatCommand` 绑键**：默认 `null`，如 `setShortcuts({ repeatCommand: 'enter' })`——但注意 `enter` 已是 `confirm`；选一个就行。
5. **误以为支持命令别名**：`'co'` 这类多键序列没有；字母热键启动命令要自己写 keydown。

## 相关

- 命令注册 → [custom-command](custom-command.md)
- 执行命令 → [execute-command](execute-command.md)
- 撤销 → [undo-redo](undo-redo.md)
- 模式切换 → [mode](mode.md)
