@@ -34,6 +34,10 @@ interface EncodingOption {
3434 value : number
3535 viewValue : string
3636}
37+ interface KeyObject {
38+ code : number
39+ down : boolean
40+ }
3741
3842@Component ( {
3943 selector : 'amt-kvm' ,
@@ -43,7 +47,7 @@ interface EncodingOption {
4347export class KVMComponent implements OnDestroy {
4448 private readonly renderer = inject ( Renderer2 )
4549 private readonly destroyRef = inject ( DestroyRef )
46-
50+ private KEY_SEQUENCE_DELAY_MS = 10
4751 readonly canvas = viewChild < ElementRef > ( 'canvas' )
4852 readonly device = viewChild . required < string > ( 'device' )
4953
@@ -62,6 +66,7 @@ export class KVMComponent implements OnDestroy {
6266 readonly deviceStatus = output < number > ( )
6367 readonly deviceConnection = input < boolean > ( false )
6468 readonly selectedEncoding = input < number > ( 1 )
69+ readonly selectedHotkey = input < string > ( '' )
6570
6671 // Component state
6772 module : AMTDesktop | null = null
@@ -102,6 +107,15 @@ export class KVMComponent implements OnDestroy {
102107 this . selected . set ( encoding )
103108 this . onEncodingChange ( )
104109 } )
110+
111+ // React to selectedHotkey changes
112+ effect ( ( ) => {
113+ const hotkey = this . selectedHotkey ( )
114+ if ( hotkey && this . deviceConnection ( ) && this . keyboardHelper ) {
115+ console . log ( 'KVMComponent: Hotkey triggered:' , hotkey )
116+ this . sendHotkey ( hotkey )
117+ }
118+ } )
105119 }
106120
107121 toggleFullscreen ( ) : void {
@@ -216,6 +230,149 @@ export class KVMComponent implements OnDestroy {
216230 this . mouseHelper ?. mousemove ( event )
217231 }
218232
233+ sendHotkey ( hotKeyType : string ) : void {
234+ if ( ! this . keyboardHelper ) {
235+ console . warn ( 'KVMComponent: Cannot send hotkey - keyboard helper not available' )
236+ return
237+ }
238+
239+ const keySequence = this . getKeySequence ( hotKeyType )
240+ if ( keySequence ?. keys ) {
241+ console . log ( 'KVMComponent: Sending hotkey sequence for' , hotKeyType )
242+ // Send each key in the sequence with a small delay
243+ keySequence . keys . forEach ( ( key : KeyObject , index : number ) => {
244+ setTimeout ( ( ) => {
245+ // Use the KeyboardHelper's existing handleKeyEvent method
246+ // 0 = Up, 1 = Down (from the UpDown enum)
247+ const upDown = key . down ? 1 : 0
248+
249+ // Create a mock keyboard event with the key code
250+ const mockEvent = {
251+ keyCode : key . code ,
252+ preventDefault : ( ) => { } ,
253+ stopPropagation : ( ) => { }
254+ } as KeyboardEvent
255+
256+ // Use the existing handleKeyEvent method
257+ this . keyboardHelper ! . handleKeyEvent ( upDown , mockEvent )
258+ } , index * this . KEY_SEQUENCE_DELAY_MS ) // delay between keys
259+ } )
260+ }
261+ }
262+
263+ private getKeySequence ( hotKeyType : string ) : { keys : KeyObject [ ] } | null {
264+ // Based on the KeyBoardHelper, these are the key codes for various combinations
265+ switch ( hotKeyType ) {
266+ case 'ctrl-alt-del' :
267+ return {
268+ keys : [
269+ { code : 17 , down : true } , // Ctrl down (JS keyCode)
270+ { code : 18 , down : true } , // Alt down (JS keyCode)
271+ { code : 46 , down : true } , // Delete down (JS keyCode)
272+ { code : 46 , down : false } , // Delete up (JS keyCode)
273+ { code : 18 , down : false } , // Alt up (JS keyCode)
274+ { code : 17 , down : false } // Ctrl up (JS keyCode)
275+ ]
276+ }
277+ case 'alt-tab' :
278+ return {
279+ keys : [
280+ { code : 18 , down : true } , // Alt down (JS keyCode)
281+ { code : 9 , down : true } , // Tab down (JS keyCode)
282+ { code : 9 , down : false } , // Tab up (JS keyCode)
283+ { code : 18 , down : false } // Alt up (JS keyCode)
284+ ]
285+ }
286+ case 'alt-release' :
287+ return {
288+ keys : [
289+ { code : 18 , down : false } // Alt up (JS keyCode)
290+ ]
291+ }
292+ case 'windows' :
293+ return {
294+ keys : [
295+ { code : 0xffe7 , down : true } , // Windows key down
296+ { code : 0xffe7 , down : false } // Windows key up
297+ ]
298+ }
299+ case 'windows-l' :
300+ return {
301+ keys : [
302+ { code : 0xffe7 , down : true } , // Windows down
303+ { code : 108 , down : true } , // L down
304+ { code : 108 , down : false } , // L up
305+ { code : 0xffe7 , down : false } // Windows up
306+ ]
307+ }
308+ case 'windows-r' :
309+ return {
310+ keys : [
311+ { code : 0xffe7 , down : true } , // Windows down
312+ { code : 82 , down : true } , // R down
313+ { code : 82 , down : false } , // R up
314+ { code : 0xffe7 , down : false } // Windows up
315+ ]
316+ }
317+ case 'windows-up' :
318+ return {
319+ keys : [
320+ { code : 0xffe7 , down : true } , // Windows down
321+ { code : 0xff52 , down : true } , // Up arrow down
322+ { code : 0xff52 , down : false } , // Up arrow up
323+ { code : 0xffe7 , down : false } // Windows up
324+ ]
325+ }
326+ case 'windows-down' :
327+ return {
328+ keys : [
329+ { code : 0xffe7 , down : true } , // Windows down
330+ { code : 0xff54 , down : true } , // Down arrow down
331+ { code : 0xff54 , down : false } , // Down arrow up
332+ { code : 0xffe7 , down : false } // Windows up
333+ ]
334+ }
335+ case 'windows-left' :
336+ return {
337+ keys : [
338+ { code : 0xffe7 , down : true } , // Windows down
339+ { code : 0xff51 , down : true } , // Left arrow down
340+ { code : 0xff51 , down : false } , // Left arrow up
341+ { code : 0xffe7 , down : false } // Windows up
342+ ]
343+ }
344+ case 'windows-right' :
345+ return {
346+ keys : [
347+ { code : 0xffe7 , down : true } , // Windows down
348+ { code : 0xff53 , down : true } , // Right arrow down
349+ { code : 0xff53 , down : false } , // Right arrow up
350+ { code : 0xffe7 , down : false } // Windows up
351+ ]
352+ }
353+ case 'alt-f4' :
354+ return {
355+ keys : [
356+ { code : 0xffe9 , down : true } , // Alt down
357+ { code : 0xffc1 , down : true } , // F4 down (F1 = 0xffbe, so F4 = 0xffc1)
358+ { code : 0xffc1 , down : false } , // F4 up
359+ { code : 0xffe9 , down : false } // Alt up
360+ ]
361+ }
362+ case 'ctrl-w' :
363+ return {
364+ keys : [
365+ { code : 0xffe3 , down : true } , // Ctrl down
366+ { code : 87 , down : true } , // W down
367+ { code : 87 , down : false } , // W up
368+ { code : 0xffe3 , down : false } // Ctrl up
369+ ]
370+ }
371+ default :
372+ return null
373+ }
374+ }
375+
219376 ngOnDestroy ( ) : void {
220377 this . mouseMove$ ?. unsubscribe ( )
221378 this . stopKvm ( )
0 commit comments