Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/khaphanspace/gonhanh.org/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Gõ Nhanh provides two intelligent switching features:
  1. Per-App Mode: Remembers ON/OFF state for each application
  2. Input Source Following: Auto-disables when switching to non-Latin input sources

Per-App Mode Switching

How It Works

Gõ Nhanh remembers your Vietnamese mode preference (ON/OFF) separately for each application.
┌─────────────────────────────────────────┐
│ You're coding in VS Code (OFF)          │
│ Switch to Slack to chat (ON)            │
│ Back to VS Code → Automatically OFF ✓   │
└─────────────────────────────────────────┘
No manual toggling needed! Just set it once per app, and Gõ Nhanh remembers.

Example Workflow

1

Code in VS Code

Vietnamese mode: OFF
const user = { name: "John" }; // No accents
2

Switch to Slack

Vietnamese mode: ON (switches automatically)
Chào anh, code xong chưa? // Vietnamese typing works
3

Back to VS Code

Vietnamese mode: OFF (switches back automatically)
function process() { ... } // Still no accents

Implementation Details

The per-app mode is implemented in InputSourceManager.swift and PerAppConfigModels.swift:
struct PerAppConfig: Codable, Equatable {
    var enabledState: Int = 0  // 0=auto, 1=on, -1=off
    var delayPreset: Int = 0
    var injectionOverride: Int = -1
}

Automatic Input Source Following

What It Does

Gõ Nhanh automatically disables when you switch to non-Latin input sources and re-enables when you switch back to English/Latin.

Supported Input Sources

Gõ Nhanh disables when switching to:
  • East Asian: Japanese (あ), Chinese (中), Korean (한)
  • Southeast Asian: Thai (ก), Khmer (ក), Lao (ກ), Myanmar (က)
  • South Asian: Hindi (अ), Bengali (অ), Tamil (அ)
  • Middle Eastern: Arabic (ع), Hebrew (א), Persian (ف)
  • Other: Russian (Р), Greek (Ω), Vietnamese IME (E)

Language Detection

The system checks the input source’s primary language code:
platforms/macos/InputSourceManager.swift
private let nonLatinLanguages: Set<String> = [
    // East Asian
    "ja", "zh", "zh-Hans", "zh-Hant", "ko",
    // Southeast Asian (non-Latin scripts)
    "th", "km", "lo", "my",
    // South Asian
    "hi", "mr", "ne", "sa", "bn", "ta", "te", "kn", "ml",
    // Middle Eastern
    "ar", "he", "fa", "ur",
    // Other non-Latin
    "ru", "uk", "be", "bg", "mk", "sr", "el",
    // Vietnamese IME
    "vi",
]

func isInputSourceAllowed(source: TISInputSource) -> Bool {
    guard let langs = TISGetInputSourceProperty(source, kTISPropertyInputSourceLanguages),
          let lang = (langs as? [String])?.first
    else {
        return true  // No language info → assume Latin
    }
    
    return !nonLatinLanguages.contains(lang)
}
The menu bar icon changes to show the current input source:
Input SourceIconDescription
English (default)VVietnamese mode ready
JapaneseJapanese input active
ChineseChinese input active
KoreanKorean input active
ThaiThai input active
ArabicعArabic input active
The icon updates in real-time when you switch input sources.

Per-App Configuration

Access Settings

  1. Click Gõ Nhanh icon in menu bar
  2. Select Settings → Advanced
  3. Go to “Per-app configuration” section

Available Options

  • Auto (0): Follow global setting
  • On (1): Always enable for this app
  • Off (-1): Always disable for this app
var enabledState: Int = 0  // 0=auto, 1=on, -1=off
Adjust typing delay for apps with slow input handling (e.g., Electron apps):
enum DelayPreset: Int {
    case none = 0       // 200µs backspace, 800µs wait
    case low = 1        // 1000µs backspace, 3000µs wait
    case medium = 2     // 3000µs backspace, 8000µs wait
    case high = 3       // 8000µs backspace, 25000µs wait
    case veryHigh = 4   // 12000µs backspace, 25000µs wait
}
Increase delay if you see “character eating” (dính chữ) in Claude Code, VS Code, Cursor, or Windsurf.
Force a specific text injection method:
enum InjectionOverride: Int {
    case auto = -1              // System decides
    case fast = 0               // Backspace + text
    case slow = 1               // Higher delay for Electron
    case charByChar = 2         // Safari/Google Docs
    case selection = 3          // Select + replace (combo boxes)
    case emptyCharPrefix = 4    // Break browser autocomplete
}
Most users should keep this on Auto.

Use Cases

For Developers

VS Code (OFF)        → Type code without accents
Terminal (OFF)       → Run shell commands
Notion (ON)          → Write documentation in Vietnamese
Slack (ON)           → Chat with team

For Multilingual Users

English keyboard     → Gõ Nhanh ON
Japanese keyboard    → Gõ Nhanh AUTO-DISABLED
Back to English      → Gõ Nhanh AUTO-ENABLED

For Content Creators

Google Docs (ON)     → Write articles
Figma (OFF)          → Design UI
Notion (ON)          → Take notes

Troubleshooting

  1. Check Settings → Advanced → Per-app configuration
  2. Make sure enabledState is set to Auto (not forced ON/OFF)
  3. Try toggling the mode manually once for that app
  1. Ensure you’re using macOS Input Sources (not third-party IMEs)
  2. Check System Settings → Keyboard → Input Sources
  3. Restart Gõ Nhanh
Increase delay preset:
  1. Settings → Advanced → Per-app config
  2. Click + → Select your IDE
  3. Set Delay to “Rất cao” (Very High)

Technical Architecture

Observer Pattern

Gõ Nhanh uses CFNotificationCenter to observe input source changes:
CFNotificationCenterAddObserver(
    CFNotificationCenterGetDistributedCenter(),
    Unmanaged.passUnretained(self).toOpaque(),
    inputSourceCallback,
    kTISNotifySelectedKeyboardInputSourceChanged,
    nil,
    .deliverImmediately
)

State Management

Per-app state is stored in UserDefaults and synchronized with the Rust engine:
┌─────────────────┐
│  macOS Layer    │
│  AppState       │──┐
└─────────────────┘  │
                     │ FFI
┌─────────────────┐  │
│  Rust Engine    │◀─┘
│  enabled: bool  │
└─────────────────┘

Auto-Restore

Automatic English word restoration

Configuration

Customize all settings

Build docs developers (and LLMs) love