# Configuring and Customizing Global Hotkeys in Clash Verge Rev: A Complete Technical Guide

> Configure and customize global hotkeys in Clash Verge Rev for seamless control. Learn to bind actions like switching modes or toggling proxy to system-wide shortcuts in this technical guide.

- Repository: [Clash Verge Rev/clash-verge-rev](https://github.com/clash-verge-rev/clash-verge-rev)
- Tags: how-to-guide
- Published: 2026-02-27

---

**Clash Verge Rev allows users to bind predefined actions—such as opening the dashboard, switching proxy modes, or toggling system proxy—to system-wide keyboard shortcuts that function even when the application window is not focused, implemented through a React frontend and Rust backend architecture.**

Configuring and customizing global hotkeys in Clash Verge Rev enables efficient workflow automation for proxy management. The implementation spans TypeScript type definitions, React UI components, and Rust system-level integration using Tauri's global-shortcut plugin. This guide examines the complete architecture based on the `clash-verge-rev/clash-verge-rev` source code.

## Understanding the Global Hotkey Architecture

The hotkey system operates through three distinct layers that handle configuration persistence, user interaction, and OS-level registration.

**Configuration Layer** stores user preferences in the `IVergeConfig` interface defined in [`src/types/global.d.ts`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/types/global.d.ts) (lines 924-927). This includes the `enable_global_hotkey` boolean flag and the `hotkeys` string array.

**Frontend UI Layer** provides the interactive interface through React components. The `HotkeyViewer` component in [`src/components/setting/mods/hotkey-viewer.tsx`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/components/setting/mods/hotkey-viewer.tsx) (lines 43-55) renders the settings dialog, while `HotkeyInput` in [`src/components/setting/mods/hotkey-input.tsx`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/components/setting/mods/hotkey-input.tsx) (lines 65-88) captures keyboard input.

**Backend Layer** handles OS-level registration in [`src-tauri/src/core/hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src-tauri/src/core/hotkey.rs). The `Hotkey::init` function reads stored configurations and registers shortcuts using `tauri_plugin_global_shortcut`, respecting the global flag to determine whether shortcuts work when the window is unfocused.

## Configuring Hotkeys Through the Settings UI

The primary method for customizing shortcuts uses the React-based settings interface.

When you navigate to Settings → Hotkeys, the `HotkeyViewer` component initializes by fetching the current configuration via the `useVerge` hook. It constructs a `hotkeyMap` by parsing the `hotkeys` array from `verge?.hotkeys`, splitting each `"func,key"` string (lines 60-70 in [`hotkey-viewer.tsx`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/hotkey-viewer.tsx)).

The `HotkeyInput` component captures raw `KeyboardEvent` data and normalizes it using `parseHotkey` from [`src/utils/parse-hotkey.ts`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/utils/parse-hotkey.ts). This converts complex key combinations into standardized strings like `"CTRL+ALT+S"` that the backend can parse.

When you save changes, the `onSave` function concatenates the map back into `["func,key"]` strings (lines 77-90) and calls `patchVerge` with the updated `hotkeys` and `enable_global_hotkey` values. The backend then triggers `Hotkey::update` to re-register the modified shortcuts.

## Manual Configuration via verge.json

For advanced customization or batch configuration, you can edit the configuration file directly.

The settings persist in [`verge.json`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/verge.json) in the application's user data directory. The configuration uses two key fields defined in [`src/types/global.d.ts`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/types/global.d.ts) (lines 924-927):

- `enable_global_hotkey`: Boolean flag controlling whether shortcuts work globally
- `hotkeys`: Array of strings in `"function_name,key_combination"` format

Example configuration:

```json
{
  "enable_global_hotkey": true,
  "hotkeys": [
    "open_or_close_dashboard,CTRL+ALT+D",
    "clash_mode_rule,CTRL+ALT+R",
    "toggle_system_proxy,CTRL+ALT+P",
    "toggle_tun_mode,CTRL+SHIFT+T"
  ]
}

```

Available function names correspond to variants in the `HotkeyFunction` enum defined in [`src-tauri/src/core/hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src-tauri/src/core/hotkey.rs) (lines 13-27), including `open_or_close_dashboard`, `toggle_system_proxy`, `clash_mode_rule`, `clash_mode_global`, `clash_mode_direct`, and `toggle_tun_mode`.

## Extending Hotkey Functions in Rust

To add custom actions beyond the built-in set, you must extend the Rust backend.

First, modify the `HotkeyFunction` enum in [`src-tauri/src/core/hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src-tauri/src/core/hotkey.rs) (lines 13-27) to include your new variant:

```rust
impl fmt::Display for HotkeyFunction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            Self::OpenOrCloseDashboard => "open_or_close_dashboard",
            Self::ToggleSystemProxy => "toggle_system_proxy",
            Self::ToggleTunMode => "toggle_tun_mode",
            Self::ClashModeRule => "clash_mode_rule",
            Self::ClashModeGlobal => "clash_mode_global",
            Self::ClashModeDirect => "clash_mode_direct",
            Self::ToggleWindowVisibility => "toggle_window_visibility",
            Self::MyNewAction => "my_new_action",   // New variant
        };
        write!(f, "{s}")
    }
}

```

Then implement the execution logic in the `execute_function` method:

```rust
match function {
    HotkeyFunction::OpenOrCloseDashboard => {
        AsyncHandler::spawn(async move {
            feat::open_or_close_dashboard().await;
        });
    }
    // ... existing cases ...
    HotkeyFunction::MyNewAction => {
        AsyncHandler::spawn(async move {
            feat::run_my_new_action().await;
            notify_event(NotificationEvent::MyNewActionExecuted).await;
        });
    }
}

```

After recompiling the application, users can bind the new function using `"my_new_action,CTRL+ALT+M"` in the configuration.

## Enabling and Disabling Global Mode

The `enable_global_hotkey` flag determines whether shortcuts work system-wide or only when the application window is focused.

In the React frontend, a switch component in `HotkeyViewer` ([`src/components/setting/mods/hotkey-viewer.tsx`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/components/setting/mods/hotkey-viewer.tsx), lines 18-22) controls this setting:

```tsx
<Switch
  edge="end"
  checked={enableGlobalHotkey}
  onChange={(e) => setEnableGlobalHotkey(e.target.checked)}
/>

```

When disabled, the Rust backend in [`src-tauri/src/core/hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src-tauri/src/core/hotkey.rs) (around lines 57-71) checks this flag before dispatching shortcut events. If the flag is false and the window is not focused, the shortcut trigger is ignored.

On macOS, the backend additionally handles system-wide shortcuts like `Cmd+Q` and `Cmd+W` (lines 69-95 in [`hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/hotkey.rs)) to ensure proper integration with macOS window management.

## Summary

- **Clash Verge Rev** implements global hotkeys through a three-layer stack: TypeScript configuration types, React UI components, and Rust OS-level registration.
- **Configuration** persists in `IVergeConfig` ([`src/types/global.d.ts`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/types/global.d.ts), lines 924-927) and stores data in [`verge.json`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/verge.json) using the format `"function_name,key_combination"`.
- **UI Components** `HotkeyViewer` and `HotkeyInput` (`src/components/setting/mods/`) manage the settings interface, utilizing `useVerge` for state and `parseHotkey` for key normalization.
- **Backend Registration** occurs in [`src-tauri/src/core/hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src-tauri/src/core/hotkey.rs), where `Hotkey::init` registers shortcuts with Tauri's global-shortcut plugin and respects the `enable_global_hotkey` flag.
- **Customization** is possible by extending the `HotkeyFunction` enum in Rust to add new executable actions.

## Frequently Asked Questions

### Where are the global hotkey settings stored in Clash Verge Rev?

The settings are stored in the [`verge.json`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/verge.json) file located in the application's user data directory. This file contains the `enable_global_hotkey` boolean flag and the `hotkeys` array, where each entry follows the format `"function_name,key_combination"` (for example, `"toggle_system_proxy,CTRL+ALT+P"`). The TypeScript interface `IVergeConfig` in [`src/types/global.d.ts`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/types/global.d.ts) (lines 924-927) defines these fields.

### Why do my hotkeys only work when the Clash Verge Rev window is focused?

This behavior occurs when the **Enable Global Hotkey** setting is disabled. In [`src-tauri/src/core/hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src-tauri/src/core/hotkey.rs) (around lines 57-71), the backend checks the `enable_global_hotkey` flag before dispatching shortcut events. When this flag is false, the application ignores global shortcut triggers unless the main window currently has focus. Enable the global mode in Settings → Hotkeys to allow shortcuts to work from any application.

### Can I add custom hotkey actions beyond the built-in functions?

Yes, but extending functionality requires modifying the Rust source code. You must add a new variant to the `HotkeyFunction` enum in [`src-tauri/src/core/hotkey.rs`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src-tauri/src/core/hotkey.rs) (lines 13-27), implement the `Display` trait to map it to a string identifier, and add execution logic in the `execute_function` method. After recompiling the application, users can bind the new function using your defined string identifier in the JSON configuration or UI.

### How does the frontend capture and normalize keyboard input?

The React frontend uses the `HotkeyInput` component located in [`src/components/setting/mods/hotkey-input.tsx`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/components/setting/mods/hotkey-input.tsx) (lines 65-88) to capture raw `KeyboardEvent` data. This component utilizes the `parseHotkey` utility from [`src/utils/parse-hotkey.ts`](https://github.com/clash-verge-rev/clash-verge-rev/blob/main/src/utils/parse-hotkey.ts) to normalize the input into a standardized string format (such as `"CTRL+ALT+S"`). This normalized format ensures consistency between the frontend display, JSON configuration storage, and Rust backend parsing when registering shortcuts with the OS.