Docs/Keyboard API
Universal Developer

Keyboard API

Keyboard API

Overview

When a plugin's UI View is attached to CoreBox, the system provides automatic keyboard event handling and forwarding, allowing plugins to respond to user keyboard interactions.

Introduction

Keyboard events are ideal for quick actions and navigation. Choose Feature SDK, Bridge Hooks, or raw Channel based on your needs.

ESC Key Auto-Exit

Pressing ESC in the UI View will automatically exit UI mode (deactivate providers), without requiring manual handling by the plugin.

Behavior

  • User presses ESC in the plugin UI View
  • System automatically calls exitUIMode() to exit UI mode
  • Plugin UI View is unmounted, CoreBox returns to search state
  • This is consistent with ESC behavior in the main CoreBox interface

Technical Implementation The system captures ESC key by listening to WebContents' before-input-event:

EXAMPLE.TYPESCRIPT
// Handled automatically by main process (plugins don't need to care)
uiView.webContents.on('before-input-event', (event, input) => {
  if (input.key === 'Escape' && input.type === 'keyDown') {
    coreBoxManager.exitUIMode()
    event.preventDefault()
  }
})

Keyboard Event Forwarding

When focus is on the CoreBox main input, specific keys are forwarded to the plugin UI View.

Forwarded Keys

KeyDescription
EnterConfirm/Submit action
ArrowUpNavigate up
ArrowDownNavigate down
Meta/Ctrl + *Shortcut combinations (except Cmd+V)

Note: ArrowLeft and ArrowRight are NOT forwarded as they are used for text editing in the input field. If you need left/right navigation, use Meta/Ctrl + ArrowLeft/ArrowRight.

Listening to Keyboard Events

Method 1: Using Feature SDK

EXAMPLE.TYPESCRIPT
import { useFeature } from '@talex-touch/utils/plugin/sdk'

const feature = useFeature()

const unsubscribe = feature.onKeyEvent((event) => {
  if (event.key === 'Enter') {
    // Handle enter key
    submitSelection()
  } else if (event.key === 'ArrowDown') {
    // Navigate down
    selectNext()
  } else if (event.key === 'ArrowUp') {
    // Navigate up
    selectPrev()
  } else if (event.metaKey && event.key === 'k') {
    // Handle Cmd+K
    openSearch()
  }
})

// Cleanup on unmount
onUnmounted(() => {
  unsubscribe()
})

Method 2: Using Bridge Hook

EXAMPLE.TYPESCRIPT
import { onCoreBoxKeyEvent } from '@talex-touch/utils/plugin/sdk/hooks/bridge'

onCoreBoxKeyEvent((event) => {
  console.log('Key pressed:', event.key)
  
  if (event.key === 'Enter' && !event.repeat) {
    handleSubmit()
  }
})

Method 3: Direct Channel Listening

EXAMPLE.TYPESCRIPT
// In plugin renderer
// Note: window.$channel exposes regChannel(), send(), and sendSync()
// The handler receives an object with a `data` property containing the key event
const unsubscribe = window.$channel.regChannel('core-box:key-event', (event) => {
  const { key, metaKey, ctrlKey } = event.data
  // Handle key
})

// Cleanup on unmount
onUnmounted(() => {
  unsubscribe()
})

Tip: For a simpler API with on() method, use the SDK wrapper (Method 1 or 2) which provides a more ergonomic interface.

Event Data Structure

EXAMPLE.TYPESCRIPT
interface ForwardedKeyEvent {
  key: string       // Key name, e.g., 'Enter', 'ArrowDown'
  code: string      // Key code, e.g., 'Enter', 'ArrowDown'
  metaKey: boolean  // Whether Cmd/Win key is pressed
  ctrlKey: boolean  // Whether Ctrl key is pressed
  altKey: boolean   // Whether Alt key is pressed
  shiftKey: boolean // Whether Shift key is pressed
  repeat: boolean   // Whether this is a repeat event (key held down)
}

IPC Channels

Channel NameDirectionDescription
core-box:key-eventMain → PluginKeyboard event forwarding
core-box:forward-key-eventRenderer → MainRequest key forwarding
core-box:get-ui-view-stateRenderer → MainQuery UI View state
core-box:ui-mode-exitedMain → RendererUI mode exited notification

Technical Notes

  • The main process handles ESC via before-input-event for consistent behavior.
  • Key events are forwarded through CoreBox and wrapped by SDK/hooks.

Best Practices

1. Avoid Duplicate Handling ESC key is already handled by the system. Plugins should not listen for ESC to exit UI mode.

2. Check repeat Flag For single-trigger actions (like submit), check the repeat flag:

EXAMPLE.TYPESCRIPT
feature.onKeyEvent((event) => {
  if (event.key === 'Enter' && !event.repeat) {
    // Only trigger on first press
    submitForm()
  }
})

3. Modifier Key Handling When handling modifier keys, be aware of platform differences:

EXAMPLE.TYPESCRIPT
feature.onKeyEvent((event) => {
  // macOS uses metaKey (Cmd), Windows/Linux uses ctrlKey
  const modifier = event.metaKey || event.ctrlKey
  
  if (modifier && event.key === 's') {
    // Cmd+S or Ctrl+S to save
    saveDocument()
  }
})

4. Cleanup Listeners Unsubscribe when component unmounts to avoid memory leaks:

EXAMPLE.TYPESCRIPT
const unsubscribe = feature.onKeyEvent(handler)

onUnmounted(() => {
  unsubscribe()
})

Debugging

With DevTools open, you can see keyboard event logs in the console:

EXAMPLE.JSON
[CoreBox] Forwarding key event to UI view: Enter
[CoreBox] ESC pressed in UI view, exiting UI mode
Was this helpful?