# Keybinding 模块说明

## 模块功能
负责系统快捷键的管理和处理，包括：
- 系统预设快捷键（如启动器、终端等）
- 媒体键控制（音量、亮度等）
- 自定义快捷键
- 窗口管理器快捷键

## 主要文件
- `manager.go`：核心逻辑，处理快捷键事件
- `config.go`：模块配置管理
- `daemon.go`：守护进程入口
- `shortcuts/`：快捷键具体实现

## shortcuts子包
`shortcuts`子包是快捷键模块的核心实现，提供以下功能：

### 核心数据结构
- `Keystroke`：表示单个按键组合（键码+修饰键状态）
- `Shortcut`：表示完整的快捷键（包含ID、类型、Keystroke列表等）
- `Action`：表示快捷键触发的操作（系统操作、媒体控制等）

### 主要组件
1. **ShortcutManager**（`shortcut_manager.go`）
   - 管理所有注册的快捷键
   - 处理快捷键的添加、删除和修改
   - 实现快捷键冲突检测和解决
   - 提供快捷键匹配功能

2. **事件处理器**（`xrecord_event_handler.go`）
   - 在X11环境下捕获键盘事件
   - 将原始事件转换为Keystroke
   - 调用ShortcutManager进行匹配

3. **快捷键类型实现**
   - `system_shortcut.go`：系统预设快捷键
   - `media_shortcut.go`：媒体控制快捷键
   - `custom_shortcut.go`：自定义快捷键
   - `kwin_shortcut.go`：窗口管理器快捷键

### 关键功能
- **快捷键解析**：将字符串（如"Ctrl+Alt+T"）解析为Keystroke
- **冲突检测**：检测并解决快捷键冲突
- **多环境支持**：同时支持X11和Wayland环境
- **布局感知**：自动适应不同键盘布局

## 快捷键处理流程
```mermaid
graph TD
    A[快捷键事件] --> B[handleKeyEvent]
    B --> C{快捷键类型}
    C -->|系统快捷键| D[执行系统操作]
    C -->|媒体键| E[控制音量/亮度等]
    C -->|自定义快捷键| F[执行自定义命令]
    C -->|窗口快捷键| G[窗口管理操作]
```

## 快捷键设置方式

### 1. 系统预设快捷键
通过 GSettings 配置：
- Schema: `com.deepin.dde.keybinding.system`
- 注册方式：`shortcutManager.AddSystem()`
- 示例快捷键：
  - 启动器：Super_L/Super_R
  - 终端：Ctrl+Alt+T
  - 锁屏：Super+L

### 2. 媒体键控制
通过 GSettings 配置：
- Schema: `com.deepin.dde.keybinding.mediakey`
- 注册方式：`shortcutManager.AddMedia()`
- 支持功能：
  - 音量控制（XF86AudioMute, XF86AudioRaiseVolume等）
  - 亮度控制（XF86MonBrightnessUp/Down）
  - 媒体播放控制（播放/暂停/上一首/下一首）

### 3. 自定义快捷键
通过配置文件管理：
- 路径：`~/.config/deepin/dde-daemon/keybinding/custom.ini`
- 注册方式：`shortcutManager.AddCustom()`
- 格式示例：
  ```ini
  [CustomShortcut1]
  Name=打开浏览器
  Command=google-chrome
  Accelerator=Ctrl+Alt+B
  ```

### 4. 窗口管理器快捷键
通过 GSettings 配置：
- Schema: `com.deepin.wrap.gnome.desktop.wm.keybindings`
- 注册方式：`shortcutManager.AddWM()`
- 支持功能：
  - 窗口切换（Alt+Tab）
  - 窗口最大化/最小化
  - 工作区切换

## 特殊功能键处理
- CapsLock/NumLock 状态显示（专用状态管理）
- 键盘布局切换（状态机实现）
- 飞行模式控制（通过DBus接口）
- 触摸板开关（通过DBus接口）

## 功能实现机制
### 快捷键注册流程
1. 在 `manager.init()` 中初始化快捷键管理器
2. 通过 `AddSystem()`, `AddMedia()`, `AddCustom()`, `AddWM()` 注册各类快捷键
3. 系统快捷键从 GSettings 加载
4. 自定义快捷键从 `custom.ini` 文件加载

### 事件处理流程
1. 快捷键事件触发 `handleKeyEvent()`
2. 根据快捷键类型查找对应的处理函数
3. 执行处理函数中的操作：
   ```go
   if handler := m.handlers[int(action.Type)]; handler != nil {
       handler(ev)
   }
   ```
4. 特殊键（如CapsLock）有专门的状态管理机

### EventLoop 核心事件循环
`EventLoop` 函数是快捷键管理器的核心事件循环，负责持续监听外部事件。

```go
func (sm *ShortcutManager) EventLoop() {
    eventChan := make(chan x.GenericEvent, 500)
    sm.conn.AddEventChan(eventChan)
    for ev := range eventChan {
        switch ev.GetEventCode() {
        case x.KeyPressEventCode:
            // 处理按键按下事件
            sm.handleKeyEvent(true, event.Detail, event.State)
        case x.KeyReleaseEventCode:
            // 处理按键释放事件
            sm.handleKeyEvent(false, event.Detail, event.State)
        case x.MappingNotifyEventCode:
            // 处理键盘映射变化事件
        }
    }
}
```

**功能说明**：
- 这里是持续监听外部事件的地方
- 通过事件通道(eventChan)接收X窗口系统的各种事件
- 根据事件类型分发处理：
  - 按键按下事件：调用`handleKeyEvent`处理
  - 按键释放事件：调用`handleKeyEvent`处理
  - 键盘映射变化事件：刷新键盘映射

### 组合键判断机制
组合键在代码中通过`Keystroke`结构体表示：
```go
type Keystroke struct {
    Keysym  x.Keysym
    State   uint16
    Mods    uint16
}
```

#### 组合键解析
1. 使用`ParseKeystroke()`函数将字符串（如"Ctrl+Alt+T"）解析为Keystroke
2. 解析过程：
   - 按"+"分割字符串得到各个键名
   - 将键名转换为对应的键码（keysym）
   - 计算修饰键状态（mods）

#### 组合键匹配
1. 当按键事件发生时，获取当前按下的键码和修饰键状态
2. 与注册的快捷键Keystroke进行比较：
   ```go
   if currentKeystroke.Equals(registeredKeystroke) {
       // 触发快捷键操作
   }
   ```
3. 匹配规则：
   - 键码必须完全一致
   - 修饰键状态必须完全一致
   - 忽略大小写锁定等无关修饰键

#### 特殊键处理
- 修饰键（Ctrl/Alt/Shift等）通过位掩码识别
- 系统键（Super/Hyper）有特殊处理
- 支持多语言键盘布局

### 组合键处理流程图
```mermaid
graph TD
    A[用户按下组合键] --> B[系统捕获按键事件]
    B --> C[解析为Keystroke结构体]
    C --> D{是否匹配注册快捷键}
    D -->|是| E[触发对应处理函数]
    D -->|否| F[忽略事件]
    E --> G[执行具体操作]
    G --> H[打开应用/调节音量等]
    
    style A fill:#9f9,stroke:#333,stroke-width:2px
    style B fill:#f9f,stroke:#333,stroke-width:2px
    style C fill:#ff9,stroke:#333,stroke-width:2px
    style D fill:#f99,stroke:#333,stroke-width:2px
    style E fill:#9ff,stroke:#333,stroke-width:2px
    style G fill:#9f9,stroke:#333,stroke-width:2px
    style H fill:#99f,stroke:#333,stroke-width:2px
```

### 处理函数调用流程
当快捷键匹配成功后，会调用对应的处理函数执行具体操作：

```mermaid
graph TD
    I[触发处理函数] --> J{处理函数类型}
    J -->|系统操作| K[执行系统命令<br>如关机/锁屏等]
    J -->|媒体控制| L[调用DBus接口<br>控制音量/亮度等]
    J -->|自定义命令| M[执行用户定义的<br>命令或脚本]
    J -->|窗口管理| N[调用窗口管理器<br>接口]
    
    K --> O[通过DBus调用<br>系统服务]
    L --> P[通过DBus调用<br>音频/显示服务]
    M --> Q[启动新进程<br>执行命令]
    N --> R[调用KWin接口<br>操作窗口]
    
    style I fill:#9f9,stroke:#333,stroke-width:2px
    style J fill:#f99,stroke:#333,stroke-width:2px
    style K fill:#9ff,stroke:#333,stroke-width:2px
    style L fill:#9ff,stroke:#333,stroke-width:2px
    style M fill:#9ff,stroke:#333,stroke-width:2px
    style N fill:#9ff,stroke:#333,stroke-width:2px
    style O fill:#99f,stroke:#333,stroke-width:2px
    style P fill:#99f,stroke:#333,stroke-width:2px
    style Q fill:#99f,stroke:#333,stroke-width:2px
    style R fill:#99f,stroke:#333,stroke-width:2px
```

#### 处理函数注册机制
处理函数在模块初始化时注册：
```go
// 初始化处理函数数组
m.handlers = make([]shortcuts.KeyEventFunc, shortcuts.ActionTypeCount)

// 注册系统操作处理函数
m.handlers[shortcuts.ActionTypeSystem] = m.handleSystemAction

// 注册媒体控制处理函数
m.handlers[shortcuts.ActionTypeAudioCtrl] = m.handleAudioAction

// 注册自定义命令处理函数
m.handlers[shortcuts.ActionTypeExecCmd] = m.handleExecCommand

// 注册窗口管理处理函数
m.handlers[shortcuts.ActionTypeWM] = m.handleWMAction
```

#### 处理函数执行示例
```go
func (m *Manager) handleKeyEvent(ev *shortcuts.KeyEvent) {
    action := ev.Shortcut.GetAction()
    // 根据action类型调用对应的处理函数
    if handler := m.handlers[int(action.Type)]; handler != nil {
        handler(ev) // 执行处理函数
    }
}

// 系统操作处理函数示例
func (m *Manager) handleSystemAction(ev *shortcuts.KeyEvent) {
    cmd := action.Arg.(shortcuts.ActionCmd)
    switch cmd {
    case shortcuts.SystemShutdown:
        m.systemShutdown() // 执行关机操作
    case shortcuts.SystemLockScreen:
        m.lockScreen() // 执行锁屏操作
    }
}
```

### 快捷键触发机制
#### X11环境
1. 通过X11连接建立键盘事件监听
2. 使用XGrabKey捕获全局快捷键
3. 事件通过 `handleKeyEvent()` 处理
4. 示例代码：
   ```go
   m.shortcutManager = shortcuts.NewShortcutManager(m.conn, m.keySymbols, m.handleKeyEvent)
   ```

#### Wayland环境
1. 通过KWin的全局快捷键服务（org.kde.kglobalaccel）监听
2. 注册DBus信号监听：
   ```go
   sessionBus.Object("org.kde.kglobalaccel", "/component/kwin").AddMatchSignal("org.kde.kglobalaccel.Component", "globalShortcutPressed")
   ```
3. 事件通过 `handleKeyEventByWayland()` 处理
4. 示例代码：
   ```go
   m.sessionSigLoop.AddHandler(&dbusutil.SignalRule{
       Name: "org.kde.kglobalaccel.Component.globalShortcutPressed",
   }, func(sig *dbus.Signal) {
       // 处理Wayland快捷键事件
   })
   ```

#### 特殊场景处理
- **锁屏界面**：通过 `lockFront.ConnectChangKey` 处理
  ```go
  m.lockFront.ConnectChangKey(func(changKey string) {
      m.handleKeyEventFromLockFront(changKey)
  })
  ```
- **关机界面**：通过 `shutdownFront.ConnectChangKey` 处理
  ```go
  m.shutdownFront.ConnectChangKey(func(changKey string) {
      m.handleKeyEventFromShutdownFront(changKey)
  })
  ```

## 模块初始化流程
1. 加载配置文件
2. 初始化快捷键管理器
3. 注册各种快捷键处理器
4. 开始事件监听循环

> 注：部分快捷键实现位于 `shortcuts/` 目录下
## special_keycode.go - 特殊按键处理模块

`special_keycode.go`文件负责处理硬件特殊按键事件，如电源键、Fn组合键、触摸板开关等。该模块将物理按键事件映射到系统功能，是键盘快捷键系统的重要组成部分。

### 主要功能

1. **特殊按键定义**：
   - 定义了各种特殊按键的键码常量（如KEY_POWER, KEY_TOUCHPAD_TOGGLE等）
   - 这些常量基于Linux内核的input-event-codes.h

2. **按键映射处理**：
   - 使用SpecialKeycodeMapKey结构体作为映射键，包含：
     - 按键码
     - 按下/释放状态
     - 修饰键状态（Ctrl/Shift/Alt/Super）
   - 初始化specialKeycodeBindingList映射表，将按键组合绑定到处理函数

3. **特殊按键处理函数**：
   - 电源键(KEY_POWER)：根据电源设置执行关机/休眠/锁屏等操作
   - 触摸板按键(KEY_TOUCHPAD_*): 切换触摸板状态
   - Fn组合键(KEY_FN_ESC)：处理Fn锁定功能
   - 麦克风静音键(KEY_MICMUTE)：切换麦克风状态
   - 控制中心键(KEY_SETUP)：打开控制中心
   - 锁屏键(KEY_SCREENLOCK)：锁定屏幕
   - 多任务键(KEY_CYCLEWINDOWS)：显示工作区视图
   - 性能模式键(KEY_MODE)：切换系统性能模式
   - 键盘背光键(KEY_KBDILLUMTOGGLE)：切换键盘背光模式
   - 飞行模式键(KEY_RFKILL)：切换飞行模式
   - 截图键(KEY_SYSRQ)：触发截图功能
   - 设备管理器键(KEY_UNKNOWN)：打开设备管理器

4. **按键处理流程**：
   1. 系统接收到按键事件
   2. 根据按键码和修饰键状态创建SpecialKeycodeMapKey
   3. 在specialKeycodeBindingList中查找对应的处理函数
   4. 执行处理函数，完成相应系统功能

### 设计特点

1. **模块化设计**：
   - 每个特殊按键有独立的处理函数
   - 新增按键只需添加映射关系和处理函数

2. **状态感知**：
   - 处理函数会检查系统当前状态（如是否已锁定）
   - 避免在不适当时刻触发功能

3. **用户反馈**：
   - 通过OSD(On-Screen Display)提供视觉反馈
   - 显示触摸板状态、麦克风状态等提示

4. **硬件适配**：
   - 支持不同硬件的特殊按键
   - 处理键盘背光等硬件特定功能

### 使用示例

```go
// 添加触摸板开关键映射
key := createSpecialKeycodeIndex(KEY_TOUCHPAD_TOGGLE, true, MODIFY_NONE)
m.specialKeycodeBindingList[key] = m.handleTouchpadToggle

// 触摸板切换处理函数
func (m *Manager) handleTouchpadToggle() {
    showOSD("TouchpadToggle") // 显示触摸板切换提示
}
```

### 相关文件

- `shortcuts/`: 常规快捷键处理
- `keybinding.go`: 主键盘绑定模块
- `audio.go`: 音频控制相关功能
- `power.go`: 电源管理功能

该模块是系统底层输入事件到高层功能调用的重要桥梁，确保特殊按键能正确触发系统功能。