feat(display): wire keybinding, browser, and file drop through orchestrator
Some checks failed
Security Scan / security (push) Failing after 7s
Test / test (push) Failing after 1m32s

Adds EventKeybindingTriggered and EventWindowFileDrop EventType constants.
HandleIPCEvents bridges keybinding.ActionTriggered and window.ActionFilesDropped
to WS events. handleWSMessage bridges WS commands to IPC for keybinding:add,
keybinding:remove, keybinding:list, browser:open-url, browser:open-file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-03-13 14:38:18 +00:00
parent 23bf0302d3
commit 22315d07bb
2 changed files with 53 additions and 0 deletions

View file

@ -9,8 +9,10 @@ import (
"forge.lthn.ai/core/go-config"
"forge.lthn.ai/core/go/pkg/core"
"forge.lthn.ai/core/gui/pkg/browser"
"forge.lthn.ai/core/gui/pkg/dialog"
"forge.lthn.ai/core/gui/pkg/environment"
"forge.lthn.ai/core/gui/pkg/keybinding"
"forge.lthn.ai/core/gui/pkg/menu"
"forge.lthn.ai/core/gui/pkg/notification"
"forge.lthn.ai/core/gui/pkg/screen"
@ -147,10 +149,59 @@ func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error {
s.events.Emit(Event{Type: EventScreenChange,
Data: map[string]any{"screens": m.Screens}})
}
case keybinding.ActionTriggered:
if s.events != nil {
s.events.Emit(Event{Type: EventKeybindingTriggered,
Data: map[string]any{"accelerator": m.Accelerator}})
}
case window.ActionFilesDropped:
if s.events != nil {
s.events.Emit(Event{Type: EventWindowFileDrop, Window: m.Name,
Data: map[string]any{"paths": m.Paths, "targetId": m.TargetID}})
}
}
return nil
}
// WSMessage represents a command received from a WebSocket client.
type WSMessage struct {
Action string `json:"action"`
Data map[string]any `json:"data,omitempty"`
}
// handleWSMessage bridges WebSocket commands to IPC calls.
func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
var result any
var handled bool
var err error
switch msg.Action {
case "keybinding:add":
accelerator, _ := msg.Data["accelerator"].(string)
description, _ := msg.Data["description"].(string)
result, handled, err = s.Core().PERFORM(keybinding.TaskAdd{
Accelerator: accelerator, Description: description,
})
case "keybinding:remove":
accelerator, _ := msg.Data["accelerator"].(string)
result, handled, err = s.Core().PERFORM(keybinding.TaskRemove{
Accelerator: accelerator,
})
case "keybinding:list":
result, handled, err = s.Core().QUERY(keybinding.QueryList{})
case "browser:open-url":
url, _ := msg.Data["url"].(string)
result, handled, err = s.Core().PERFORM(browser.TaskOpenURL{URL: url})
case "browser:open-file":
path, _ := msg.Data["path"].(string)
result, handled, err = s.Core().PERFORM(browser.TaskOpenFile{Path: path})
default:
return nil, false, nil
}
return result, handled, err
}
// handleTrayAction processes tray menu item clicks.
func (s *Service) handleTrayAction(actionID string) {
switch actionID {

View file

@ -26,6 +26,8 @@ const (
EventNotificationClick EventType = "notification.click"
EventTrayClick EventType = "tray.click"
EventTrayMenuItemClick EventType = "tray.menuitem.click"
EventKeybindingTriggered EventType = "keybinding.triggered"
EventWindowFileDrop EventType = "window.filedrop"
)
// Event represents a display event sent to subscribers.