@@ -2,6 +2,8 @@ import { onBeforeUnmount, onMounted } from "vue"
22import { HoppActionWithOptionalArgs , invokeAction } from "./actions"
33import { isAppleDevice } from "./platformutils"
44import { isDOMElement , isTypableElement } from "./utils/dom"
5+ import { getKernelMode } from "@hoppscotch/kernel"
6+ import { listen } from "@tauri-apps/api/event"
57
68/**
79 * This variable keeps track whether keybindings are being accepted
@@ -10,6 +12,11 @@ import { isDOMElement, isTypableElement } from "./utils/dom"
1012 */
1113let keybindingsEnabled = true
1214
15+ /**
16+ * Unlisten function for Tauri event
17+ */
18+ let unlistenTauriEvent : ( ( ) => void ) | null = null
19+
1320/**
1421 * Alt is also regarded as macOS OPTION (⌥) key
1522 * Ctrl is also regarded as macOS COMMAND (⌘) key (NOTE: this differs from HTML Keyboard spec where COMMAND is Meta key!)
@@ -30,7 +37,7 @@ type Key =
3037 | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t"
3138 | "u" | "v" | "w" | "x" | "y" | "z" | "0" | "1" | "2" | "3"
3239 | "4" | "5" | "6" | "7" | "8" | "9" | "up" | "down" | "left"
33- | "right" | "/" | "?" | "." | "enter"
40+ | "right" | "/" | "?" | "." | "enter" | "tab"
3441/* eslint-enable */
3542
3643type ModifierBasedShortcutKey = `${ModifierKeys } -${Key } `
@@ -39,7 +46,8 @@ type SingleCharacterShortcutKey = `${Key}`
3946
4047type ShortcutKey = ModifierBasedShortcutKey | SingleCharacterShortcutKey
4148
42- export const bindings : {
49+ // Base bindings available on all platforms
50+ const baseBindings : {
4351 [ _ in ShortcutKey ] ?: HoppActionWithOptionalArgs
4452} = {
4553 "ctrl-enter" : "request.send-cancel" ,
@@ -71,18 +79,68 @@ export const bindings: {
7179 "ctrl-shift-l" : "editor.format" ,
7280}
7381
82+ // Desktop-only bindings
83+ const desktopBindings : {
84+ [ _ in ShortcutKey ] ?: HoppActionWithOptionalArgs
85+ } = {
86+ "ctrl-w" : "tab.close-current" ,
87+ "ctrl-t" : "tab.open-new" ,
88+ "ctrl-alt-left" : "tab.prev" ,
89+ "ctrl-alt-right" : "tab.next" ,
90+ "ctrl-alt-0" : "tab.switch-to-last" ,
91+ "ctrl-alt-9" : "tab.switch-to-first" ,
92+ }
93+
94+ /**
95+ * Get bindings based on the current kernel mode
96+ */
97+ function getActiveBindings ( ) : typeof baseBindings {
98+ const kernelMode = getKernelMode ( )
99+
100+ if ( kernelMode === "desktop" ) {
101+ return {
102+ ...baseBindings ,
103+ ...desktopBindings ,
104+ }
105+ }
106+
107+ return baseBindings
108+ }
109+
110+ export const bindings = getActiveBindings ( )
111+
74112/**
75113 * A composable that hooks to the caller component's
76114 * lifecycle and hooks to the keyboard events to fire
77115 * the appropriate actions based on keybindings
78116 */
79117export function hookKeybindingsListener ( ) {
80- onMounted ( ( ) => {
118+ onMounted ( async ( ) => {
81119 document . addEventListener ( "keydown" , handleKeyDown )
120+
121+ // Listen for Tauri events (desktop only)
122+ if ( getKernelMode ( ) === "desktop" ) {
123+ try {
124+ unlistenTauriEvent = await listen (
125+ "hoppscotch_desktop_shortcut" ,
126+ ( ev ) => {
127+ console . info ( "Tauri shortcut ev" , ev )
128+ handleTauriShortcut ( ev . payload as string )
129+ }
130+ )
131+ } catch ( error ) {
132+ console . error ( "Failed to setup Tauri event listener:" , error )
133+ }
134+ }
82135 } )
83136
84137 onBeforeUnmount ( ( ) => {
85138 document . removeEventListener ( "keydown" , handleKeyDown )
139+
140+ if ( unlistenTauriEvent ) {
141+ unlistenTauriEvent ( )
142+ unlistenTauriEvent = null
143+ }
86144 } )
87145}
88146
@@ -93,13 +151,27 @@ function handleKeyDown(ev: KeyboardEvent) {
93151 const binding = generateKeybindingString ( ev )
94152 if ( ! binding ) return
95153
96- const boundAction = bindings [ binding ]
154+ const activeBindings = getActiveBindings ( )
155+ const boundAction = activeBindings [ binding ]
97156 if ( ! boundAction ) return
98157
99158 ev . preventDefault ( )
100159 invokeAction ( boundAction , undefined , "keypress" )
101160}
102161
162+ function handleTauriShortcut ( shortcut : string ) {
163+ console . info ( "Tauri shortcut:" , shortcut )
164+
165+ // Do not check keybinds if the mode is disabled
166+ if ( ! keybindingsEnabled ) return
167+
168+ const activeBindings = getActiveBindings ( )
169+ const boundAction = activeBindings [ shortcut as ShortcutKey ]
170+ if ( ! boundAction ) return
171+
172+ invokeAction ( boundAction , undefined , "keypress" )
173+ }
174+
103175function generateKeybindingString ( ev : KeyboardEvent ) : ShortcutKey | null {
104176 const target = ev . target
105177
@@ -140,6 +212,9 @@ function getPressedKey(ev: KeyboardEvent): Key | null {
140212 return key . slice ( 5 ) as Key
141213 }
142214
215+ // Check for Tab key
216+ if ( key === "tab" ) return "tab"
217+
143218 // Check letter keys
144219 const isLetter = key . length === 1 && key >= "a" && key <= "z"
145220 if ( isLetter ) return key as Key
0 commit comments