플랫폼과 단축키Platform and shortcuts

OS와 실행 환경을 읽는 헬퍼, Mod 키 규칙, 단축키 문자열 문법입니다.The helpers that read the OS and the shell, the Mod key rules and the shortcut string syntax.

OS 감지Detecting the OS

detectOs(input: PlatformInput = {})는 Os를 돌려줍니다. Os는 macos, windows, linux, ios, android, unknown입니다. 힌트는 userAgentData.platform, navigator.platform, user agent 순서로 읽고 처음 이름이 나온 값을 씁니다.detectOs(input: PlatformInput = {}) returns an Os: macos, windows, linux, ios, android or unknown. It reads the hints in order, userAgentData.platform, then navigator.platform, then the user agent, and takes the first that names an OS.

  • 힌트에 mac이 있고 터치 포인트가 1보다 크면 ios입니다. iPadOS가 Mac을 보고하기 때문입니다.A hint that says mac with more than one touch point is ios, because iPadOS reports a Mac.
  • 어느 힌트도 OS를 이름 붙이지 않으면 unknown입니다. 서버 렌더와 빈 입력도 unknown입니다.When no hint names an OS the result is unknown. A server render and empty input are unknown too.
  • PlatformInput의 필드는 userAgent, platform, uaPlatform, maxTouchPoints입니다. 브라우저에서는 navigator에서 이 값을 채워 넘깁니다.PlatformInput holds userAgent, platform, uaPlatform and maxTouchPoints. In a browser, fill them from navigator.

실행 환경Runtime

detectRuntime(win: RuntimeWindow | null = null)는 web 또는 desktop을 돌려줍니다. window.__TAURI_INTERNALS__가 있으면 desktop이고, 없으면 user agent에 electron이 있을 때 desktop입니다. 인자를 주지 않거나 null이면 web입니다.detectRuntime(win: RuntimeWindow | null = null) returns web or desktop. window.__TAURI_INTERNALS__ means desktop; otherwise an electron user agent means desktop. Omitted or null reports web.

  • RuntimeWindow는 __TAURI_INTERNALS__와 navigator.userAgent만 읽습니다. 그 밖의 window 속성은 보지 않습니다.RuntimeWindow reads only __TAURI_INTERNALS__ and navigator.userAgent. Other window properties are not inspected.

Mod 키The Mod key

단축키 문자열의 Mod는 OS마다 다른 실제 키를 가리킵니다.Mod in a shortcut string stands for a different physical key on each OS.

  • macos와 ios는 ⌘(metaKey)입니다. Ctrl이 함께 눌린 조합은 Mod로 보지 않습니다.macos and ios use ⌘ (metaKey). A combination that also holds Ctrl is not Mod.
  • windows, linux, android는 Ctrl(ctrlKey)입니다. ⌘이 함께 눌린 조합은 Mod로 보지 않습니다.windows, linux and android use Ctrl (ctrlKey). A combination that also holds ⌘ is not Mod.
  • unknown은 둘 중 하나가 눌리면 Mod입니다. 서버 렌더와 첫 하이드레이션이 여기에 해당합니다.unknown treats either key as Mod. That covers a server render and the first hydration pass.

isModKey(event, os)는 그 OS의 Mod 키가 눌렸는지만 봅니다. 이벤트에서 key, metaKey, ctrlKey, altKey, shiftKey를 읽으므로 KeyboardEvent를 그대로 넘깁니다.isModKey(event, os) only answers whether that OS's Mod key is down. It reads key, metaKey, ctrlKey, altKey and shiftKey, so a KeyboardEvent passes as-is.

단축키 문자열Shortcut strings

문자열은 +로 이어 붙이고 Mod, Shift, Alt와 마지막 키 하나로 씁니다. 예: Mod+K, Mod+Shift+Enter, Escape.A string joins its parts with + and holds Mod, Shift, Alt and one final key, such as Mod+K, Mod+Shift+Enter or Escape.

  • formatShortcut(keys, os)는 그리는 문자열을 만듭니다. macos와 ios는 ⌘⇧↵처럼 기호를 붙여 쓰고, 나머지는 Ctrl+Shift+Enter처럼 +를 유지합니다. unknown은 Mac 기호로 그립니다.formatShortcut(keys, os) builds the label. macos and ios glue the symbols, ⌘⇧↵, and the rest keep +, as in Ctrl+Shift+Enter. unknown draws the Mac symbols.
  • matchesShortcut(event, keys, os)는 키 이벤트를 문자열과 맞춥니다. Alt와 Shift는 문자열에 있는 그대로 눌리거나 눌리지 않아야 합니다.matchesShortcut(event, keys, os) tests a key event against the string. Alt and Shift must be held or released exactly as the string says.
  • 수정자만 있는 문자열은 어느 키와도 맞지 않습니다. esc와 escape는 같은 키이고, 비교는 대소문자를 가리지 않습니다.A string of modifiers alone matches nothing. esc and escape are the same key, and the comparison ignores case.
  • 이름이 없는 키는 문자열에 쓴 그대로 비교합니다. K는 K입니다.A key with no label in the table is compared as written. K stays K.
shortcut.ts
import { detectOs, detectRuntime, formatShortcut, matchesShortcut, type Os } from "@horon-ai/react";

function readPlatform() {
  const os = detectOs({
    userAgent: navigator.userAgent,
    platform: navigator.platform,
    maxTouchPoints: navigator.maxTouchPoints,
  });
  return { os, shell: detectRuntime(window), label: formatShortcut("Mod+K", os) };
}

function bindPaletteKey(os: Os, open: () => void) {
  const onKeyDown = (event: KeyboardEvent) => {
    if (matchesShortcut(event, "Mod+K", os)) open();
  };
  document.addEventListener("keydown", onKeyDown);
  return () => document.removeEventListener("keydown", onKeyDown);
}

Kbd와 단축키 표시Kbd and key hints

Kbd의 keys prop은 같은 문자열을 받아 그 OS의 라벨로 그립니다. keys="Mod+K"는 macOS에서 ⌘K, Windows에서 Ctrl+K입니다. keys를 주지 않으면 children을 그리므로 칩을 손으로 조합할 수 있습니다.Kbd's keys prop takes the same string and draws that OS's labels: keys="Mod+K" is ⌘K on macOS and Ctrl+K on Windows. Without keys it renders children, so chips can be composed by hand.

  • size는 sm, md, lg이고 높이가 16px, 20px, 24px입니다. 기본은 md입니다.size is sm, md or lg at 16px, 20px and 24px tall. The default is md.
  • 문자열이 실제 키 입력과 맞는지는 호출하는 쪽이 정합니다. keydown 처리에는 matchesShortcut을 쓰거나 useHotkey를 씁니다.Matching the string against real key presses is the caller's job: use matchesShortcut in a keydown handler, or useHotkey.
  • 키 힌트를 보여줄지 정하려면 useDevice의 keyboardHints를 봅니다. OS와 셸, Mod 키는 usePlatform이, keydown 연결은 useHotkey가 맡습니다. 두 훅의 계약은 훅 페이지에 있습니다.To decide whether to show a key hint, read keyboardHints from useDevice. usePlatform reports the OS, the shell and the Mod key, and useHotkey binds a keydown. Their hook pages hold the contracts.
hint.tsx
import { Kbd } from "@horon-ai/react";

<span className="flex items-center gap-1 text-caption">
  Search <Kbd keys="Mod+K" />
  Send <Kbd keys="Mod+Enter" size="sm" />
</span>