Skip to content

fix(hotkey): 收口桌面热键适配边界#38

Merged
appergb merged 4 commits into
Open-Less:mainfrom
H-Chris233:main
Apr 30, 2026
Merged

fix(hotkey): 收口桌面热键适配边界#38
appergb merged 4 commits into
Open-Less:mainfrom
H-Chris233:main

Conversation

@H-Chris233
Copy link
Copy Markdown
Collaborator

@H-Chris233 H-Chris233 commented Apr 29, 2026

摘要

Fixes #36

本 PR 解决桌面热键路径中平台 Hook、UI 文案和 Coordinator 状态混在一起的问题。

本次改动将热键能力收口到统一的后端适配层,保留现有 macOS CGEventTap 实现,并为 Windows 新增显式的低级键盘 Hook 适配器,用于支持右侧修饰键和 modifier-only 按住说话触发。前端不再根据 OS 字符串硬编码热键选项和状态,而是统一根据后端返回的 capability、status 和当前 binding 渲染。

修复 / 新增 / 改进

  • 新增统一热键适配边界:

    • HotkeyAdapter
    • HotkeyCapability
    • HotkeyStatus
    • HotkeyInstallError
  • 保留现有 macOS CGEventTap 热键实现,不改动既有 macOS EventTap 路径。

  • Windows 热键实现不再走泛化的 rdev 分支,改为显式的 WH_KEYBOARD_LL low-level keyboard hook 适配器。

  • Windows modifier-only 触发不再被静默降级为普通 registered shortcut。

  • Coordinator 只消费统一的热键边沿事件,不再接触具体平台 Hook 实现细节。

  • 前端热键展示统一走 lib/hotkey.ts,不再使用类似 os === 'win' ? ... : ... 的 OS 字符串分支。

  • UI 热键选项、当前状态和文案改为基于后端 capability/status/current binding 渲染。

  • Windows 默认热键调整为右 Control 按住说话。

  • 补充平台适配层文档:

    • docs/platform-adapter-architecture.md

兼容

  • 不包含:

    • 不移除现有 macOS CGEventTap 实现。
    • 不新增新的 fallback 热键路径。
    • 不引入新的依赖。
    • 不改变整体构建流程。
  • 对现有用户 / 本地环境 / 构建流程的影响:

    • macOS 继续使用原有 CGEventTap 路径。
    • Windows 热键行为会切换到新的 low-level keyboard hook 适配器。
    • Windows 默认按住说话热键变更为右 Control。
    • 前端展示逻辑改为读取后端能力与状态数据,避免后续平台差异继续散落在 UI 层。
    • 构建流程无额外要求。

测试计划

  • 命令:npm run build

  • 结果:通过

  • 证据路径:本地构建输出

  • 命令:cargo check

  • 结果:通过

  • 证据路径:本地检查输出

  • Windows native hook runtime on real hardware

  • cross-target cargo check

主要改动文件

  • docs/platform-adapter-architecture.md
  • openless-all/app/src-tauri/src/hotkey.rs
  • openless-all/app/src-tauri/src/types.rs
  • openless-all/app/src-tauri/src/coordinator.rs
  • openless-all/app/src-tauri/src/commands.rs
  • openless-all/app/src-tauri/src/lib.rs
  • openless-all/app/src/lib/types.ts
  • openless-all/app/src/lib/ipc.ts
  • openless-all/app/src/lib/hotkey.ts
  • openless-all/app/src/pages/Settings.tsx
  • openless-all/app/src/pages/Overview.tsx
  • openless-all/app/src/pages/History.tsx
  • openless-all/app/src/components/FloatingShell.tsx
  • openless-all/app/src/components/Onboarding.tsx

Summary by Sourcery

Introduce a unified hotkey adapter boundary across platforms and update UI to consume backend-reported hotkey capability and status instead of OS-specific logic.

New Features:

  • Add platform-specific hotkey adapters for macOS EventTap, Windows low-level keyboard hooks, and rdev-based Linux/other implementations behind a common HotkeyAdapter interface.
  • Expose backend hotkey capabilities and adapter metadata to the frontend via new HotkeyCapability and HotkeyStatus fields and a get_hotkey_capability IPC command.
  • Add a shared frontend hotkey utility module to render trigger labels and usage hints consistently across the app.

Bug Fixes:

  • Fix Windows hotkey handling by using a native low-level keyboard hook that preserves modifier-only and side-specific modifier semantics.
  • Ensure hotkey installation errors are surfaced with structured codes and messages instead of silent failures.

Enhancements:

  • Refine coordinator hotkey supervision to track adapter kind, remember last install error, and provide clearer status messaging.
  • Unify frontend permission, settings, onboarding, and shortcut descriptions based on backend-reported hotkey capability instead of hardcoded OS checks.
  • Document the platform adapter architecture and explicit contracts for backend hotkey adapters and UI usage.

Summary by Sourcery

Unify global hotkey handling behind a platform-specific adapter boundary and update both backend and frontend to consume explicit hotkey capabilities and status, including a new native Windows low-level keyboard hook and adjusted defaults.

New Features:

  • Introduce a HotkeyAdapter trait and HotkeyCapability/HotkeyStatus/HotkeyInstallError types to describe platform hotkey support and lifecycle in a structured way.
  • Add a native Windows low-level keyboard hook implementation that preserves modifier-only and side-specific modifier semantics, alongside existing macOS EventTap and rdev-based adapters.
  • Expose hotkey capability and status to the frontend via new IPC commands and a shared HotkeySettings React context, enabling UI components to render trigger options and help text from backend data rather than OS checks.
  • Add a shared frontend hotkey utility module to standardize trigger labels and usage hints across settings, onboarding, overview, history, and shell components.

Bug Fixes:

  • Fix Windows global hotkey behavior by replacing the rdev path with a native low-level keyboard hook so modifier-only triggers like right Control work reliably and are no longer silently downgraded.
  • Ensure hotkey installation failures are surfaced with structured error codes and messages, and tracked in coordinator state instead of failing silently.

Enhancements:

  • Refine the coordinator’s hotkey supervision loop to track the active adapter kind, remember the last install error, and cleanly stop the listener on app exit.
  • Adjust default hotkey bindings so Windows uses right Control with hold-to-talk semantics while other platforms retain right Option toggle behavior.
  • Refactor permissions, settings, onboarding, and shortcut descriptions to be driven by backend-reported hotkey capability and current binding rather than hardcoded OS string branches.
  • Improve mock IPC data to reflect the new hotkey capability and status structures for development builds.
  • Document the platform adapter architecture and contracts between backend adapters, coordinator, and UI.

Documentation:

  • Add platform adapter architecture documentation describing the hotkey adapter boundary, per-OS implementations, and the UI contract for consuming capability and status.

Tests:

  • Update cross-platform build/check paths implicitly by exercising the new hotkey types and IPC commands, while keeping existing build flows unchanged.

Issue Open-Less#36 exposed that the desktop hotkey path was still mixing
platform hooks, UI copy, and coordinator state. This change keeps the
existing macOS EventTap path, introduces an explicit Windows low-level
keyboard adapter for modifier-only triggers, and makes the frontend
render hotkey choices and status from capability/status data instead of
OS string branching.

Constraint: Must preserve the existing macOS CGEventTap implementation
Constraint: Windows modifier-only triggers must not be silently downgraded to registered shortcuts
Rejected: Keep rdev as the only non-macOS path | cannot reliably model right-side modifier-only behavior on Windows
Rejected: Patch UI strings only | would leave root-cause visibility and adapter boundaries coupled
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep platform hook specifics inside the hotkey adapter layer and feed UI from capability/status APIs rather than OS hardcoding
Tested: npm run build; cargo check
Not-tested: Windows native hook runtime on real hardware; cross-target cargo check blocked by missing x86_64-w64-mingw32-gcc in this environment
Related: Open-Less#36
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 29, 2026

Reviewer's Guide

Refactors global hotkey handling behind a new HotkeyAdapter abstraction with per-platform implementations (macOS EventTap, Windows low-level keyboard hook, Linux/other via rdev), exposes HotkeyCapability/HotkeyStatus/HotkeyInstallError to the frontend via IPC, and updates all UI hotkey copy and settings to consume backend-reported capability and current binding instead of OS string checks, including changing Windows defaults to right Control hold-to-talk.

Sequence diagram for get_hotkey_capability IPC flow

sequenceDiagram
  actor User
  participant ReactUI as ReactComponent
  participant Ctx as HotkeySettingsContext
  participant IPC as ipc_getHotkeyCapability
  participant Tauri as TauriCommands
  participant Coord as Coordinator
  participant Monitor as HotkeyMonitor
  participant Types as HotkeyCapability_current

  User->>ReactUI: Open Settings / Onboarding / Overview
  ReactUI->>Ctx: useHotkeySettings()
  Ctx->>Ctx: refresh()
  Ctx->>IPC: getHotkeyCapability()
  IPC->>Tauri: invoke get_hotkey_capability
  Tauri->>Coord: get_hotkey_capability()
  Coord->>Monitor: HotkeyMonitor::capability()
  Monitor->>Types: HotkeyCapability::current()
  Types-->>Monitor: HotkeyCapability
  Monitor-->>Coord: HotkeyCapability
  Coord-->>Tauri: HotkeyCapability
  Tauri-->>IPC: HotkeyCapability
  IPC-->>Ctx: HotkeyCapability
  Ctx-->>ReactUI: { prefs, hotkey, capability }
  ReactUI->>ReactUI: Render triggers, labels,
  ReactUI->>ReactUI: permission hints based on capability
Loading

Class diagram for Rust hotkey adapter and capability types

classDiagram
  class HotkeyTrigger {
    +RightOption
    +LeftOption
    +RightControl
    +LeftControl
    +RightCommand
    +Fn
    +RightAlt
    +display_name() String
  }

  class HotkeyMode {
    <<enum>>
    +Toggle
    +Hold
  }

  class HotkeyAdapterKind {
    <<enum>>
    +MacEventTap
    +WindowsLowLevel
    +Rdev
    +display_name() String
  }

  class HotkeyBinding {
    +HotkeyTrigger trigger
    +HotkeyMode mode
    +default() HotkeyBinding
  }

  class HotkeyCapability {
    +HotkeyAdapterKind adapter
    +Vec~HotkeyTrigger~ available_triggers
    +bool requires_accessibility_permission
    +bool supports_modifier_only_trigger
    +bool supports_side_specific_modifiers
    +bool explicit_fallback_available
    +Option~String~ status_hint
    +current() HotkeyCapability
  }

  class HotkeyInstallError {
    +String code
    +String message
    +fmt(f) fmt::Result
  }

  class HotkeyStatusState {
    <<enum>>
    +Starting
    +Installed
    +Failed
  }

  class HotkeyStatus {
    +HotkeyAdapterKind adapter
    +HotkeyStatusState state
    +Option~String~ message
    +Option~HotkeyInstallError~ last_error
    +default() HotkeyStatus
  }

  class HotkeyEvent {
    <<enum>>
    +Pressed
    +Released
    +Cancelled
  }

  class HotkeyAdapter {
    <<trait>>
    +kind() HotkeyAdapterKind
    +update_binding(binding HotkeyBinding) void
    +shutdown() void
  }

  class Shared {
    +RwLock~HotkeyBinding~ binding
    +AtomicBool trigger_held
  }

  class HotkeyMonitor {
    -Box~dyn HotkeyAdapter~ adapter
    +start(binding HotkeyBinding, tx Sender~HotkeyEvent~) Result~HotkeyMonitor, HotkeyInstallError~
    +update_binding(binding HotkeyBinding) void
    +kind() HotkeyAdapterKind
    +capability() HotkeyCapability
  }

  class MacHotkeyAdapter {
    -Arc~Shared~ shared
    +kind() HotkeyAdapterKind
    +update_binding(binding HotkeyBinding) void
  }

  class WindowsHotkeyAdapter {
    -Arc~Shared~ shared
    -u32 thread_id
    +kind() HotkeyAdapterKind
    +update_binding(binding HotkeyBinding) void
    +shutdown() void
  }

  class RdevHotkeyAdapter {
    -Arc~Shared~ shared
    +kind() HotkeyAdapterKind
    +update_binding(binding HotkeyBinding) void
  }

  class ListenerThread~T~ {
    +Arc~Shared~ shared
    +T startup
  }

  HotkeyBinding --> HotkeyTrigger
  HotkeyBinding --> HotkeyMode

  HotkeyCapability --> HotkeyAdapterKind
  HotkeyCapability --> HotkeyTrigger

  HotkeyStatus --> HotkeyAdapterKind
  HotkeyStatus --> HotkeyStatusState
  HotkeyStatus --> HotkeyInstallError

  HotkeyMonitor o--> HotkeyAdapter
  HotkeyMonitor --> HotkeyCapability

  MacHotkeyAdapter ..|> HotkeyAdapter
  WindowsHotkeyAdapter ..|> HotkeyAdapter
  RdevHotkeyAdapter ..|> HotkeyAdapter

  MacHotkeyAdapter --> Shared
  WindowsHotkeyAdapter --> Shared
  RdevHotkeyAdapter --> Shared

  ListenerThread~T~ --> Shared

  class Coordinator {
    +hotkey_status() HotkeyStatus
    +hotkey_capability() HotkeyCapability
    +stop_hotkey_listener() void
  }

  Coordinator --> HotkeyMonitor
  Coordinator --> HotkeyStatus
  Coordinator --> HotkeyCapability
Loading

Class diagram for frontend hotkey types and HotkeySettingsContext

classDiagram
  class HotkeyTrigger {
    <<type alias>>
    +rightOption
    +leftOption
    +rightControl
    +leftControl
    +rightCommand
    +fn
    +rightAlt
  }

  class HotkeyAdapterKind {
    <<union>>
    +'macEventTap'
    +'windowsLowLevel'
    +'rdev'
  }

  class HotkeyBinding {
    +HotkeyTrigger trigger
    +HotkeyMode mode
  }

  class HotkeyMode {
    <<union>>
    +'toggle'
    +'hold'
  }

  class HotkeyCapability {
    +HotkeyAdapterKind adapter
    +HotkeyTrigger[] availableTriggers
    +boolean requiresAccessibilityPermission
    +boolean supportsModifierOnlyTrigger
    +boolean supportsSideSpecificModifiers
    +boolean explicitFallbackAvailable
    +string statusHint
  }

  class HotkeyInstallError {
    +string code
    +string message
  }

  class HotkeyStatusState {
    <<union>>
    +'starting'
    +'installed'
    +'failed'
  }

  class HotkeyStatus {
    +HotkeyAdapterKind adapter
    +HotkeyStatusState state
    +string message
    +HotkeyInstallError lastError
  }

  class UserPreferences {
    +HotkeyBinding hotkey
    +string defaultMode
    +string[] enabledModes
    +boolean launchAtLogin
    +boolean showCapsule
    +string activeLlmProvider
    +string polishMode
  }

  class HotkeySettingsContextValue {
    +UserPreferences prefs
    +HotkeyBinding hotkey
    +HotkeyCapability capability
    +boolean loading
    +refresh() Promise~void~
    +updatePrefs(next UserPreferences) Promise~void~
  }

  class HotkeySettingsProvider {
    +children ReactNode
  }

  class useHotkeySettings {
    +useHotkeySettings() HotkeySettingsContextValue
  }

  class hotkey_ts {
    +HOTKEY_TRIGGER_LABEL Record~HotkeyTrigger, string~
    +getHotkeyTriggerLabel(trigger HotkeyTrigger) string
    +getHotkeyStartStopLabel(binding HotkeyBinding) string
    +getHotkeyUsageHint(binding HotkeyBinding) string
  }

  class ipc_ts {
    +getSettings() Promise~UserPreferences~
    +setSettings(next UserPreferences) Promise~void~
    +getHotkeyCapability() Promise~HotkeyCapability~
    +getHotkeyStatus() Promise~HotkeyStatus~
  }

  HotkeySettingsContextValue --> UserPreferences
  HotkeySettingsContextValue --> HotkeyBinding
  HotkeySettingsContextValue --> HotkeyCapability

  HotkeySettingsProvider --> HotkeySettingsContextValue
  useHotkeySettings --> HotkeySettingsContextValue

  HotkeyCapability --> HotkeyAdapterKind
  HotkeyCapability --> HotkeyTrigger

  HotkeyStatus --> HotkeyAdapterKind
  HotkeyStatus --> HotkeyStatusState
  HotkeyStatus --> HotkeyInstallError

  UserPreferences --> HotkeyBinding

  HotkeySettingsProvider ..> ipc_ts : uses
  HotkeySettingsProvider ..> HotkeySettingsContextValue : provides

  hotkey_ts --> HotkeyBinding
  hotkey_ts --> HotkeyTrigger

  class SettingsPage {
    +RecordingSection
    +ShortcutsSection
    +PermissionsSection
  }

  class OverviewPage
  class HistoryPage
  class FloatingShell
  class Onboarding

  SettingsPage ..> useHotkeySettings : uses
  OverviewPage ..> useHotkeySettings : uses
  HistoryPage ..> useHotkeySettings : uses
  FloatingShell ..> useHotkeySettings : uses
  Onboarding ..> useHotkeySettings : uses
  SettingsPage ..> hotkey_ts : uses
  OverviewPage ..> hotkey_ts : uses
  HistoryPage ..> hotkey_ts : uses
  FloatingShell ..> hotkey_ts : uses
  Onboarding ..> hotkey_ts : uses
Loading

File-Level Changes

Change Details Files
Introduce unified backend hotkey adapter boundary and richer hotkey data types.
  • Add HotkeyAdapter trait plus per-platform adapter implementations, with HotkeyMonitor delegating to platform::start_adapter and exposing adapter kind and capability.
  • Refactor macOS CGEventTap listener to use shared listener-thread helper, structured startup signaling, and HotkeyInstallError codes instead of boolean status.
  • Implement Windows WH_KEYBOARD_LL low-level keyboard hook adapter that preserves modifier-only and side-specific modifiers, handles Esc cancel, and supports clean shutdown via thread message loop.
  • Keep Linux/other on rdev::listen but wrap it in an adapter and provide startup confirmation and structured listen_failed errors.
  • Extend Rust hotkey types with HotkeyAdapterKind, HotkeyCapability::current(), HotkeyInstallError (including Display impl), HotkeyTrigger::display_name, and richer HotkeyStatus that carries adapter and last_error, plus platform-specific default HotkeyBinding (right Control hold on Windows).
openless-all/app/src-tauri/src/hotkey.rs
openless-all/app/src-tauri/src/types.rs
Have Coordinator own hotkey capability/status and supervise adapter lifecycle, including clean shutdown on app exit.
  • Expose Coordinator::stop_hotkey_listener and wire it to Tauri RunEvent::Exit so native hooks are torn down when the app exits.
  • Add Coordinator::hotkey_capability and use HotkeyMonitor::capability to surface current-platform capability.
  • Update hotkey_supervisor_loop to populate adapter kind, success message, and last error in HotkeyStatus, and to log structured install errors while retrying with backoff.
openless-all/app/src-tauri/src/coordinator.rs
openless-all/app/src-tauri/src/lib.rs
Expose hotkey capability/status over IPC and align mocks with the new Windows defaults and adapter metadata.
  • Add get_hotkey_capability Tauri command that returns Coordinator::hotkey_capability.
  • Extend TypeScript types with HotkeyAdapterKind, HotkeyCapability, HotkeyInstallError, and expanded HotkeyStatus including adapter and lastError.
  • Add getHotkeyCapability IPC helper and in-memory mock capability/status, switching mockSettings to rightControl/hold and reflecting Windows low-level adapter in mock data.
openless-all/app/src-tauri/src/commands.rs
openless-all/app/src/lib/ipc.ts
openless-all/app/src/lib/types.ts
Centralize hotkey labeling/usage text on the frontend and feed all hotkey-related UI from backend capability and current binding via context.
  • Introduce lib/hotkey.ts with shared HOTKEY_TRIGGER_LABEL plus helpers to render trigger labels, start/stop labels, and usage hints given a HotkeyBinding.
  • Add HotkeySettingsContext/Provider that loads UserPreferences and HotkeyCapability, exposes hotkey binding and capability, and centralizes settings updates.
  • Wrap the app in HotkeySettingsProvider so all consumers can access hotkey and capability state.
openless-all/app/src/lib/hotkey.ts
openless-all/app/src/state/HotkeySettingsContext.tsx
openless-all/app/src/App.tsx
Update Settings page to drive hotkey controls, copy, and permissions from capability/status/context rather than OS-specific branches.
  • Refactor RecordingSection to read prefs, capability, and updatePrefs from useHotkeySettings, use capability.availableTriggers for the trigger dropdown, and show requiresAccessibilityPermission-based description plus optional statusHint.
  • Change ShortcutsSection to use useHotkeySettings hotkey/capability and render dynamic start/stop label and OS-appropriate availability text (e.g., mac-only keyboard shortcuts when accessibility-based adapter).
  • Update PermissionsSection to use capability for copy and visibility (e.g., only show Accessibility row if capability.requiresAccessibilityPermission) and display the current adapter display name next to the hotkey status pill.
  • Adjust ProvidersSection to use useHotkeySettings for preferences updates instead of managing prefs locally.
openless-all/app/src/pages/Settings.tsx
Align Overview, History, FloatingShell, and Onboarding flows to use shared hotkey helpers and capability instead of hardcoded OS checks.
  • Update Overview to pull hotkey from useHotkeySettings and use getHotkeyTriggerLabel for inline hotkey hints and empty-state guidance.
  • Change History to show getHotkeyTriggerLabel(hotkey.trigger) in the empty-state copy instead of a fixed OS-based label.
  • Adjust FloatingShell to use useHotkeySettings and getHotkeyTriggerLabel(hotkey.trigger) in the floating shortcut hint.
  • Refine Onboarding to use useHotkeySettings capability and shared trigger label helper to render permission step titles, descriptions, hints, and button states depending on whether accessibility permission is required on the current platform.
openless-all/app/src/pages/Overview.tsx
openless-all/app/src/pages/History.tsx
openless-all/app/src/components/FloatingShell.tsx
openless-all/app/src/components/Onboarding.tsx
Document the new platform adapter architecture and UI contract.
  • Add docs/platform-adapter-architecture.md describing HotkeyAdapter, HotkeyCapability, HotkeyStatus/HotkeyInstallError, per-platform adapters (macOS EventTap, Windows low-level hook, rdev), and frontend integration expectations (IPC endpoints and no direct OS checks in UI).
docs/platform-adapter-architecture.md

Assessment against linked issues

Issue Objective Addressed Explanation
#36 Introduce a unified Rust hotkey abstraction by defining a HotkeyAdapter trait and corresponding HotkeyCapability/HotkeyStatus/HotkeyInstallError types, and have Coordinator consume only edge events and status via this boundary.
#36 Preserve the existing macOS CGEventTap implementation by wrapping it in a MacHotkeyAdapter, and add a new Windows native low-level keyboard hook (WH_KEYBOARD_LL) adapter that correctly supports modifier-only and side-specific triggers without silently replacing them with registered shortcuts, while keeping Linux/other on best-effort rdev.
#36 Update the frontend/UI so that hotkey settings, permissions, and shortcut descriptions are rendered based on backend-reported adapter capability/status and current binding (via IPC), rather than hardcoded OS-specific logic or strings.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • On the Windows adapter, the mapping in trigger_to_vk_code (e.g. LeftOptionVK_RMENU, FnVK_RCONTROL) is a bit surprising—consider either aligning these more closely with their physical keys or adding a brief comment explaining the rationale so future changes don’t accidentally break the intended semantics.
  • Several frontend sections independently call getSettings/getHotkeyCapability and render separate "加载中…" states (RecordingSection, ShortcutsSection, PermissionsSection, Overview, History, FloatingShell); consider centralizing hotkey capability and binding in a shared context or hook to avoid duplicated IPC calls and slightly smoother initial rendering.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- On the Windows adapter, the mapping in `trigger_to_vk_code` (e.g. `LeftOption``VK_RMENU`, `Fn``VK_RCONTROL`) is a bit surprising—consider either aligning these more closely with their physical keys or adding a brief comment explaining the rationale so future changes don’t accidentally break the intended semantics.
- Several frontend sections independently call `getSettings`/`getHotkeyCapability` and render separate "加载中…" states (RecordingSection, ShortcutsSection, PermissionsSection, Overview, History, FloatingShell); consider centralizing hotkey capability and binding in a shared context or hook to avoid duplicated IPC calls and slightly smoother initial rendering.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Windows cross-target cargo check exposed two target-specific mismatches in the
new low-level keyboard hook path: the hook struct import needed to match the
windows crate module layout used here, and the injected-event flag access needed
the wrapper-field form expected by that type. I also split the default hotkey
binding cfg blocks so the Windows default stays explicit without leaving a
cross-target unreachable branch behind.

Constraint: Must preserve the new native Windows low-level hook path added for issue 36
Rejected: Skip Windows-target verification | would leave the affected platform path unproven
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep Windows hook imports and flag access aligned with this repo's windows crate APIs
Tested: cargo check; cargo check --target x86_64-pc-windows-gnu
Not-tested: Windows real hardware runtime behavior
The Windows adapter now documents why a few cross-platform trigger aliases map
to the same modifier virtual key, so follow-up edits do not accidentally undo
issue-36 semantics. On the frontend, hotkey settings and capability now load
through one shared provider instead of repeated per-view IPC fetches, which cuts
redundant loading branches across onboarding, shell, overview, history, and the
hotkey-related settings sections.

Constraint: Keep the issue-36 behavior intact while making the review follow-ups minimal
Rejected: Rework the full settings data flow | broader than the review comments required
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep shared hotkey state limited to binding and capability unless another cross-view settings dependency is proven
Tested: npm run build; cargo check; cargo check --target x86_64-pc-windows-gnu
Not-tested: Real Windows runtime hotkey behavior and interactive UI smoke test
@H-Chris233
Copy link
Copy Markdown
Collaborator Author

@sourcery-ai review

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The three platform-specific start_adapter implementations (macOS, windows, rdev) share a lot of boilerplate (allocating Shared, spawning a thread, status channel + timeout); consider extracting a small helper to centralize this pattern so adapter-specific code only needs to define the listen loop.
  • The Windows low-level hook thread runs a GetMessageW loop without any explicit shutdown signal; it may be worth adding a termination mechanism (e.g., posting a quit message from the coordinator) so the hook can be cleanly torn down on app shutdown or adapter reinitialization.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The three platform-specific `start_adapter` implementations (`macOS`, `windows`, `rdev`) share a lot of boilerplate (allocating `Shared`, spawning a thread, status channel + timeout); consider extracting a small helper to centralize this pattern so adapter-specific code only needs to define the listen loop.
- The Windows low-level hook thread runs a `GetMessageW` loop without any explicit shutdown signal; it may be worth adding a termination mechanism (e.g., posting a quit message from the coordinator) so the hook can be cleanly torn down on app shutdown or adapter reinitialization.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

The three platform adapters were all repeating the same startup scaffolding for
shared state, thread launch, and readiness reporting, so that boilerplate now
lives in one helper and each adapter keeps only its platform-specific listen
loop. The Windows low-level hook also now carries an explicit shutdown path by
posting WM_QUIT to the hook thread when the monitor is dropped during app exit,
which keeps hook teardown aligned with coordinator lifecycle changes.

Constraint: Keep issue-36 hotkey behavior unchanged while tightening adapter lifecycle handling
Rejected: Leave Windows hook teardown implicit | would keep GetMessageW loop lifetime coupled to process exit only
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep adapter startup centralized only for shared scaffolding; platform event semantics should stay in their own modules
Tested: cargo fmt --all; cargo check; cargo check --target x86_64-pc-windows-gnu
Not-tested: Real Windows runtime shutdown and hook reinitialization behavior
@H-Chris233
Copy link
Copy Markdown
Collaborator Author

@sourcery-ai review

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@appergb appergb merged commit 82a24fa into Open-Less:main Apr 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[architecture] 收敛 desktop core 与 native adapter 边界

2 participants