# How FluentRead Manages Hotkey Conflicts and Custom Hotkey Assignments

> Discover how FluentRead handles hotkey conflicts and custom hotkey assignments. Learn about its conflict validation and reliable runtime detection for a seamless user experience.

- Repository: [ThinkStu/fluentread](https://github.com/bistutu/fluentread)
- Tags: how-to-guide
- Published: 2026-02-26

---

**FluentRead prevents hotkey conflicts by validating user-defined shortcuts against a hard-coded list of common OS shortcuts before saving, while supporting custom hotkey assignments through a parsing and normalization layer that ensures reliable runtime detection.**

FluentRead is an open-source browser extension that provides instant translation capabilities through customizable keyboard shortcuts. Understanding how FluentRead manages hotkey conflicts and custom hotkey assignments reveals a defensive design that prioritizes system stability while offering users flexibility in defining their own translation triggers.

## Architecture and Workflow

FluentRead's hotkey system operates through four coordinated components that handle configuration, validation, and runtime detection.

### Configuration Model

The configuration schema is defined in [`entrypoints/utils/model.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/model.ts), where the `Config` interface declares fields for `hotkey`, `customHotkey`, and `floatingBallHotkey`. Default values are established here, ensuring that every installation starts with safe, non-conflicting presets.

### Hotkey Processing Engine

All parsing, validation, and display logic resides in [`entrypoints/utils/hotkey.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/hotkey.ts). This module exports `parseHotkey`, `validateHotkeyConflicts`, and `generateDisplayName`, forming a complete pipeline from raw user input to validated configuration.

### Runtime Detection

The content script in [`entrypoints/content.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/content.ts) implements the actual keyboard listener. It retrieves the configured hotkey parts via `getConfiguredMouseHotkeyParts()` and maintains a `Set<string>` of currently pressed keys, triggering translation only when the exact combination is pressed and subsequently released.

## Parsing and Validation Logic

FluentRead implements strict validation to prevent both malformed inputs and dangerous conflicts with system operations.

### The parseHotkey Function

The `parseHotkey` function in [`entrypoints/utils/hotkey.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/hotkey.ts) normalizes user input into a structured format. It splits strings like `"Ctrl+Alt+T"` by the "+" delimiter, lowercases each component, and validates that all elements except the last are modifiers defined in `MODIFIER_KEYS` (`ctrl`, `alt`, `shift`, `meta`). The final element must exist in `REGULAR_KEYS`.

The function enforces two critical safety rules:

- Single-letter keys must include at least one modifier to prevent intercepting normal typing.
- The `meta` (Cmd) modifier is explicitly blocked on macOS to avoid capturing system-level shortcuts.

### Conflict Detection with validateHotkeyConflicts

Before saving, `validateHotkeyConflicts` compares the parsed hotkey against a hard-coded `commonConflicts` array containing approximately 30 common OS shortcuts (copy, paste, new tab, close window, etc.). If the modifiers and key match any entry exactly, the function returns `{hasConflict: true, conflictDescription: '与系统快捷键冲突: 复制'}`, preventing the user from saving a destructive configuration.

### Display Name Generation

The `generateDisplayName` function creates platform-specific strings (e.g., `"Control+Option+T"` on macOS versus `"Ctrl+Alt+T"` on Windows) for UI presentation, ensuring users recognize their configured shortcuts regardless of underlying normalization.

## Runtime Hotkey Matching

The content script translates physical key events into the abstract representation used during validation.

### Event Normalization

In [`entrypoints/content.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/content.ts), keyboard events are normalized to match the identifiers used by `parseHotkey`. The script checks `e.ctrlKey`, `e.altKey`, and `e.shiftKey`, pushing corresponding strings (`'control'`, `'alt'`, `'shift'`) into a `Set<string>` named `mouseHotkeysPressed`. The regular key is lowercased and added if it is a single character.

### Configuration Retrieval

The function `getConfiguredMouseHotkeyParts()` reads `config.hotkey` and `config.customHotkey` from the singleton configuration object managed by [`entrypoints/utils/config.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/config.ts). If `config.hotkey` equals `'custom'`, it parses `config.customHotkey`; otherwise, it uses the preset value.

The `checkMouseHotkey()` function compares the current `mouseHotkeysPressed` set against the required parts. It verifies that both sets have identical length and that every required key is present. When matched, `screen.hotkeyPressed` is set to `true`. Upon `keyup`, if the set becomes empty and `screen.hotkeyPressed` was true, `handleTranslation()` executes the translation workflow.

## Implementation Examples

The following examples demonstrate how FluentRead's hotkey system handles parsing, validation, and runtime detection.

**Parsing and validating a user-provided hotkey:**

```typescript
import { parseHotkey, validateHotkeyConflicts } from '@/entrypoints/utils/hotkey';

// Example user input
const userInput = 'Ctrl+Alt+T';

// Step 1 – parse
const parsed = parseHotkey(userInput);
if (!parsed.isValid) {
  console.error('Invalid format:', parsed.errorMessage);
}

// Step 2 – conflict check
const conflict = validateHotkeyConflicts(parsed);
if (conflict.hasConflict) {
  console.warn('Conflict detected:', conflict.conflictDescription);
} else {
  console.log('Hotkey is safe to use:', parsed.displayName);
}

```

**Saving a custom hotkey in the options page:**

```typescript
async function saveHotkey(newHotkey: string) {
  const parsed = parseHotkey(newHotkey);
  const conflict = validateHotkeyConflicts(parsed);

  if (!parsed.isValid) throw new Error(parsed.errorMessage);
  if (conflict.hasConflict) throw new Error(conflict.conflictDescription);

  // store as custom hotkey
  await storage.setItem('local:config', JSON.stringify({
    ...config,
    hotkey: 'custom',
    customHotkey: newHotkey,
  }));
}

```

**Runtime detection in the content script:**

```typescript
// In entrypoints/content.ts
window.addEventListener('keydown', e => {
  // normalise pressed keys (same identifiers as parseHotkey)
  const parts = [];
  if (e.ctrlKey) parts.push('control');
  if (e.altKey) parts.push('alt');
  if (e.shiftKey) parts.push('shift');
  const key = e.key.toLowerCase();
  if (key.length === 1) parts.push(key);   // regular key

  // compare with configured hotkey
  const required = getConfiguredMouseHotkeyParts(); // from config
  const matches = required.length === parts.length &&
                  required.every(k => parts.includes(k));

  if (matches) {
    screen.hotkeyPressed = true;
  }
});

```

## Summary

FluentRead implements a multi-layered defense system for managing hotkey conflicts and custom hotkey assignments:

- **Structured Configuration**: The `Config` model in [`entrypoints/utils/model.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/model.ts) maintains separate fields for preset and custom hotkeys, ensuring type safety and default fallbacks.
- **Rigorous Parsing**: The `parseHotkey` function in [`entrypoints/utils/hotkey.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/hotkey.ts) normalizes input strings, enforces modifier requirements for single-letter keys, and explicitly blocks the `meta` (Cmd) modifier on macOS.
- **Conflict Prevention**: `validateHotkeyConflicts` compares proposed hotkeys against a hard-coded list of approximately 30 common OS shortcuts, preventing users from saving configurations that would interfere with system operations.
- **Runtime Reliability**: The content script in [`entrypoints/content.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/content.ts) uses exact set matching against normalized key events, ensuring translations trigger only when the precise configured combination is pressed and released.

## Frequently Asked Questions

### How does FluentRead prevent conflicts with system shortcuts?

FluentRead prevents conflicts through the `validateHotkeyConflicts` function in [`entrypoints/utils/hotkey.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/hotkey.ts), which checks every custom hotkey against a hard-coded `commonConflicts` array containing approximately 30 common OS shortcuts like copy, paste, and new tab operations. If the parsed modifiers and key match any system shortcut exactly, the function returns a conflict description and prevents the configuration from being saved.

### Can users define completely custom hotkey combinations?

Yes, users can define custom hotkey combinations through the `customHotkey` field in the configuration model defined in [`entrypoints/utils/model.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/model.ts). When `config.hotkey` is set to `'custom'`, the system uses the user-defined string stored in `config.customHotkey`. The `parseHotkey` function in [`entrypoints/utils/hotkey.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/hotkey.ts) validates these custom strings, ensuring they contain supported modifiers and regular keys while blocking potentially problematic combinations like single-letter keys without modifiers.

### Why does FluentRead block the Meta (Cmd) key on macOS?

FluentRead explicitly blocks the `meta` modifier (Cmd key on macOS) in the `parseHotkey` function within [`entrypoints/utils/hotkey.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/utils/hotkey.ts) to avoid capturing system-level shortcuts that are fundamental to macOS operation. This deliberate restriction prevents the extension from interfering with essential macOS commands like Cmd+C (copy), Cmd+V (paste), and Cmd+Tab (application switching), ensuring the browser extension remains unobtrusive and does not degrade the core user experience.

### How does the extension detect hotkeys while browsing?

The extension detects hotkeys through the content script in [`entrypoints/content.ts`](https://github.com/bistutu/fluentread/blob/main/entrypoints/content.ts), which listens for `keydown` and `keyup` events. It normalizes each event into a `Set<string>` of pressed keys using the same identifiers as the `parseHotkey` function (e.g., `'control'`, `'alt'`, `'t'`). The `checkMouseHotkey()` function compares this set against the required parts retrieved from `getConfiguredMouseHotkeyParts()`. When the sets match exactly, `screen.hotkeyPressed` is set to `true`, and upon key release, the translation workflow executes via `handleTranslation()`.