From 22315d07bb5b251551f541923be7cfcb08e88639 Mon Sep 17 00:00:00 2001 From: Snider Date: Fri, 13 Mar 2026 14:38:18 +0000 Subject: [PATCH] feat(display): wire keybinding, browser, and file drop through orchestrator 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 --- pkg/display/display.go | 51 ++++++++++++++++++++++++++++++++++++++++++ pkg/display/events.go | 2 ++ 2 files changed, 53 insertions(+) diff --git a/pkg/display/display.go b/pkg/display/display.go index cb0405a..9bedd68 100644 --- a/pkg/display/display.go +++ b/pkg/display/display.go @@ -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 { diff --git a/pkg/display/events.go b/pkg/display/events.go index e0812d1..e71f016 100644 --- a/pkg/display/events.go +++ b/pkg/display/events.go @@ -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.