OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
HotKeySupport.c
Go to the documentation of this file.
1
8
11
14
15#include <Library/BaseLib.h>
16#include <Library/MemoryAllocationLib.h>
18#include <Library/OcTimerLib.h>
22#include <Library/OcMiscLib.h>
24#include <Library/OcTypingLib.h>
25#include <Library/UefiBootServicesTableLib.h>
26#include <Library/UefiRuntimeServicesTableLib.h>
27
34
35STATIC
36BOOLEAN
37EFIAPI
39 IN OUT OC_PICKER_CONTEXT *PickerContext,
40 IN EFI_HANDLE BootEntryProtocolHandle,
41 IN OC_BOOT_ENTRY_PROTOCOL *BootEntryProtocol,
42 IN VOID *Context
43 )
44{
45 BEP_APPLY_HOTKEYS_CONTEXT *ApplyHotkeysContext;
46 CHAR8 *BootId;
47
48 ASSERT (Context != NULL);
49 ApplyHotkeysContext = Context;
50
51 if (BootEntryProtocol->CheckHotKeys) {
52 BootId = BootEntryProtocol->CheckHotKeys (
53 PickerContext,
54 ApplyHotkeysContext->NumKeys,
55 ApplyHotkeysContext->Modifiers,
56 ApplyHotkeysContext->Keys
57 );
58 if (BootId != NULL) {
59 PickerContext->PickerCommand = OcPickerProtocolHotKey;
60 PickerContext->HotKeyProtocolHandle = BootEntryProtocolHandle;
61 PickerContext->HotKeyEntryId = BootId;
62
63 ApplyHotkeysContext->Result = EFI_SUCCESS;
64
65 return FALSE;
66 }
67 }
68
69 return TRUE;
70}
71
72STATIC
73EFI_STATUS
75 IN OUT OC_PICKER_CONTEXT *PickerContext,
76 IN UINTN NumKeys,
77 IN APPLE_MODIFIER_MAP Modifiers,
78 IN APPLE_KEY_CODE *Keys
79 )
80{
81 EFI_HANDLE *EntryProtocolHandles;
82 UINTN EntryProtocolHandleCount;
83 BEP_APPLY_HOTKEYS_CONTEXT ApplyHotkeysContext;
84
85 ApplyHotkeysContext.NumKeys = NumKeys;
86 ApplyHotkeysContext.Modifiers = Modifiers;
87 ApplyHotkeysContext.Keys = Keys;
88 ApplyHotkeysContext.Result = EFI_NOT_FOUND;
89
90 OcLocateBootEntryProtocolHandles (&EntryProtocolHandles, &EntryProtocolHandleCount);
91
93 PickerContext,
94 EntryProtocolHandles,
95 EntryProtocolHandleCount,
97 &ApplyHotkeysContext
98 );
99
100 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
101
102 return ApplyHotkeysContext.Result;
103}
104
105//
106// Get hotkeys pressed at load
107//
108VOID
110 IN OUT OC_PICKER_CONTEXT *Context
111 )
112{
113 EFI_STATUS Status;
115
116 UINTN NumKeys;
117 APPLE_MODIFIER_MAP Modifiers;
119
120 BOOLEAN HasCommand;
121 BOOLEAN HasEscape;
122 BOOLEAN HasZero;
123 BOOLEAN HasOption;
124 BOOLEAN HasKeyR;
125 BOOLEAN HasKeyX;
126
127 //
128 // Waiting for boot chime to finish around here, even as a separate option, is
129 // problematic because the chime does not play if muted or below minimum audible gain.
130 //
131 if (Context->TakeoffDelay > 0) {
132 gBS->Stall (Context->TakeoffDelay);
133 }
134
135 KeyMap = OcGetProtocol (&gAppleKeyMapAggregatorProtocolGuid, DEBUG_ERROR, "OcLoadPickerHotKeys", "AppleKeyMapAggregator");
136
137 NumKeys = ARRAY_SIZE (Keys);
138 Status = KeyMap->GetKeyStrokes (
139 KeyMap,
140 &Modifiers,
141 &NumKeys,
142 Keys
143 );
144
145 if (EFI_ERROR (Status)) {
146 DEBUG ((DEBUG_ERROR, "OCHK: GetKeyStrokes - %r\n", Status));
147 return;
148 }
149
150 //
151 // I do not like this code a little, as it is prone to race conditions during key presses.
152 // For the good false positives are not too critical here, and in reality users are not that fast.
153 //
154 // Reference key list:
155 // https://support.apple.com/HT201255
156 // https://support.apple.com/HT204904
157 //
158 // We are slightly more permissive than AppleBds, as we permit combining keys.
159 //
160
161 Status = ApplyBootEntryProtocolHotKeys (Context, NumKeys, Modifiers, Keys);
162 if (!EFI_ERROR (Status)) {
163 //
164 // If boot entry protocol hotkeys detected return without detecting builtin hotkeys, otherwise
165 // for example CMD+OPT+P+R for reset NVRAM gets overridden by CMD+R for recovery.
166 //
167 return;
168 }
169
170 HasCommand = (Modifiers & (APPLE_MODIFIER_LEFT_COMMAND | APPLE_MODIFIER_RIGHT_COMMAND)) != 0;
171 HasOption = (Modifiers & (APPLE_MODIFIER_LEFT_OPTION | APPLE_MODIFIER_RIGHT_OPTION)) != 0;
172 HasEscape = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyEscape);
173 HasZero = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyZero);
174 HasKeyR = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyR);
175 HasKeyX = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyX);
176
177 if (HasCommand && HasKeyR) {
178 DEBUG ((DEBUG_INFO, "OCHK: CMD+R causes recovery to boot\n"));
179 Context->PickerCommand = OcPickerBootAppleRecovery;
180 } else if (HasKeyX) {
181 DEBUG ((DEBUG_INFO, "OCHK: X causes macOS to boot\n"));
182 Context->PickerCommand = OcPickerBootApple;
183 } else if (HasOption) {
184 DEBUG ((DEBUG_INFO, "OCHK: OPT causes picker to show\n"));
185 Context->PickerCommand = OcPickerShowPicker;
186 } else if (HasEscape || HasZero) {
187 DEBUG ((DEBUG_INFO, "OCHK: ESC/0 causes picker to show as OC extension\n"));
188 Context->PickerCommand = OcPickerShowPicker;
189 } else {
190 //
191 // In addition to these overrides we always have ShowPicker = YES in config.
192 // The following keys are not implemented:
193 // C - CD/DVD boot, legacy that is gone now.
194 // D - Diagnostics, could implement dumping stuff here in some future,
195 // but we will need to store the data before handling the key.
196 // Should also be DEBUG only for security reasons.
197 // N - Network boot, simply not supported (and bad for security).
198 // T - Target disk mode, simply not supported (and bad for security).
199 //
200 }
201}
202
203STATIC
204VOID
205EFIAPI
207 IN OUT OC_PICKER_CONTEXT *Context
208 )
209{
210 OcFlushTypingBuffer (Context->HotKeyContext->TypingContext);
211}
212
213STATIC
214VOID
215EFIAPI
217 IN OUT OC_PICKER_CONTEXT *Context,
218 IN OC_PICKER_KEY_MAP KeyFilter,
219 OUT OC_PICKER_KEY_INFO *PickerKeyInfo
220 )
221{
222 EFI_STATUS Status;
223
224 UINTN NumKeys;
225 APPLE_KEY_CODE *Keys;
226 APPLE_KEY_CODE Key;
227 APPLE_MODIFIER_MAP Modifiers;
228 CHAR16 UnicodeChar;
229 UINTN NumKeysUp;
230 UINTN NumKeysDoNotRepeat;
232 APPLE_MODIFIER_MAP ModifiersDoNotRepeat;
233
234 UINTN AkmaNumKeys;
235 APPLE_MODIFIER_MAP AkmaModifiers;
237
238 APPLE_MODIFIER_MAP ValidBootModifiers;
239 BOOLEAN TriggerBoot;
240 BOOLEAN HasCommand;
241 BOOLEAN HasKeyC;
242 BOOLEAN HasKeyK;
243 BOOLEAN HasKeyS;
244 BOOLEAN HasKeyV;
245 BOOLEAN HasKeyMinus;
246 BOOLEAN WantsZeroSlide;
247 UINT32 CsrActiveConfig;
248 UINTN CsrActiveConfigSize;
249
250 ASSERT (Context->HotKeyContext->KeyMap != NULL);
251 ASSERT (Context->HotKeyContext->TypingContext != NULL);
252 ASSERT (Context->HotKeyContext->DoNotRepeatContext != NULL);
253 ASSERT (PickerKeyInfo != NULL);
254
255 PickerKeyInfo->OcKeyCode = OC_INPUT_NO_ACTION;
256 PickerKeyInfo->OcModifiers = OC_MODIFIERS_NONE;
257 PickerKeyInfo->UnicodeChar = CHAR_NULL;
258
259 //
260 // AKMA hotkeys
261 //
262 AkmaNumKeys = ARRAY_SIZE (AkmaKeys);
263 Status = Context->HotKeyContext->KeyMap->GetKeyStrokes (
264 Context->HotKeyContext->KeyMap,
265 &AkmaModifiers,
266 &AkmaNumKeys,
267 AkmaKeys
268 );
269
270 if (EFI_ERROR (Status)) {
271 DEBUG ((DEBUG_WARN, "OCHK: AKMA GetKeyStrokes - %r\n", Status));
272 return;
273 }
274
275 //
276 // Apple Event typing
277 //
278 Keys = &Key;
279 OcGetNextKeystroke (Context->HotKeyContext->TypingContext, &Modifiers, Keys, &UnicodeChar);
280 if (*Keys == 0) {
281 NumKeys = 0;
282 } else {
283 NumKeys = 1;
284 }
285
286 //
287 // Non-repeating keys
288 //
289 NumKeysUp = 0;
290 NumKeysDoNotRepeat = ARRAY_SIZE (KeysDoNotRepeat);
291 Status = OcGetUpDownKeys (
292 Context->HotKeyContext->DoNotRepeatContext,
293 &ModifiersDoNotRepeat,
294 &NumKeysUp,
295 NULL,
296 &NumKeysDoNotRepeat,
297 KeysDoNotRepeat,
298 0ULL // time not needed for non-repeat keys
299 );
300
301 if (EFI_ERROR (Status)) {
302 DEBUG ((DEBUG_WARN, "OCHK: GetUpDownKeys for DoNotRepeatContext - %r\n", Status));
303 return;
304 }
305
306 DEBUG_CODE_BEGIN ();
307 if (Context->KbDebug != NULL) {
308 Context->KbDebug->Show (NumKeys, AkmaNumKeys, Modifiers);
309 }
310
311 DEBUG_CODE_END ();
312
313 //
314 // Set OcModifiers early, so they are correct even if - say - a hotkey or non-repeating key returns first.
315 //
316 ValidBootModifiers = APPLE_MODIFIERS_NONE;
317
318 if (Context->AllowSetDefault) {
319 ValidBootModifiers |= APPLE_MODIFIERS_CONTROL;
320 }
321
322 //
323 // Note: As historically SHIFT handling here is considered a 'hotkey':
324 // it's original reason for being here is to fix difficulties in
325 // detecting this and other hotkey modifiers during no-picker boot.
326 //
327 if (((KeyFilter & OC_PICKER_KEYS_HOTKEYS) != 0) && Context->PollAppleHotKeys) {
328 ValidBootModifiers |= APPLE_MODIFIERS_SHIFT;
329 }
330
331 //
332 // Default update is desired for Ctrl+Index and Ctrl+Enter.
333 // Strictly apply only on CTRL or CTRL+SHIFT (when SHIFT allowed),
334 // but no other modifiers.
335 // Needs to be set/unset even if filtered for typing (otherwise can
336 // get locked on if user tabs to typing context).
337 //
338 if ( ((Modifiers & ~ValidBootModifiers) == 0)
339 && ((Modifiers & APPLE_MODIFIERS_CONTROL) != 0))
340 {
341 PickerKeyInfo->OcModifiers |= OC_MODIFIERS_SET_DEFAULT;
342 }
343
344 //
345 // Alternative 'set default' key, if modifiers not working;
346 // useful both for 'set default' and for tuning KeyForgetThreshold.
347 //
348 if ( Context->AllowSetDefault
349 && OcKeyMapHasKey (AkmaKeys, AkmaNumKeys, AppleHidUsbKbUsageKeyEquals))
350 {
351 PickerKeyInfo->OcModifiers |= OC_MODIFIERS_SET_DEFAULT;
352 }
353
354 //
355 // Loosely apply regardless of other modifiers.
356 //
357 if ( ((KeyFilter & OC_PICKER_KEYS_TAB_CONTROL) != 0)
358 && ((Modifiers & APPLE_MODIFIERS_SHIFT) != 0))
359 {
360 PickerKeyInfo->OcModifiers |= OC_MODIFIERS_REVERSE_SWITCH_FOCUS;
361 }
362
363 //
364 // Handle key combinations.
365 //
366 if (((KeyFilter & OC_PICKER_KEYS_HOTKEYS) != 0) && Context->PollAppleHotKeys) {
367 HasCommand = (AkmaModifiers & APPLE_MODIFIERS_COMMAND) != 0;
368 HasKeyC = OcKeyMapHasKey (AkmaKeys, AkmaNumKeys, AppleHidUsbKbUsageKeyC);
369 HasKeyK = OcKeyMapHasKey (AkmaKeys, AkmaNumKeys, AppleHidUsbKbUsageKeyK);
370 HasKeyS = OcKeyMapHasKey (AkmaKeys, AkmaNumKeys, AppleHidUsbKbUsageKeyS);
371 HasKeyV = OcKeyMapHasKey (AkmaKeys, AkmaNumKeys, AppleHidUsbKbUsageKeyV);
372 //
373 // Checking for PAD minus is our extension to support more keyboards.
374 //
375 HasKeyMinus = OcKeyMapHasKey (AkmaKeys, AkmaNumKeys, AppleHidUsbKbUsageKeyMinus)
376 || OcKeyMapHasKey (AkmaKeys, AkmaNumKeys, AppleHidUsbKbUsageKeyPadMinus);
377
378 //
379 // CMD+V is always valid and enables Verbose Mode.
380 //
381 // Note: Verbose boot may be entered in three different ways:
382 // - Loaded image options passed from bootloader (as will happen due to below
383 // code, when CMD+V is pressed during OpenCore picker menu).
384 // - `-v` option in NVRAM `boot-args` variable.
385 // - boot.efi itself detecting that CMD+V is held down when it starts.
386 //
387 if (HasCommand && HasKeyV) {
388 if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-v", L_STR_LEN ("-v"), NULL) == NULL) {
389 DEBUG ((DEBUG_INFO, "OCHK: CMD+V means -v\n"));
390 OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-v", L_STR_LEN ("-v"));
391 }
392
393 PickerKeyInfo->OcKeyCode = OC_INPUT_INTERNAL;
394 }
395
396 //
397 // CMD+C+MINUS is always valid and disables compatibility check.
398 //
399 if (HasCommand && HasKeyC && HasKeyMinus) {
400 if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check"), NULL) == NULL) {
401 DEBUG ((DEBUG_INFO, "OCHK: CMD+C+MINUS means -no_compat_check\n"));
402 OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check"));
403 }
404
405 PickerKeyInfo->OcKeyCode = OC_INPUT_INTERNAL;
406 }
407
408 //
409 // CMD+K is always valid for new macOS and means force boot to release kernel.
410 //
411 if (HasCommand && HasKeyK) {
412 if (AsciiStrStr (Context->AppleBootArgs, "kcsuffix=release") == NULL) {
413 DEBUG ((DEBUG_INFO, "OCHK: CMD+K means kcsuffix=release\n"));
414 OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "kcsuffix=release", L_STR_LEN ("kcsuffix=release"));
415 }
416
417 PickerKeyInfo->OcKeyCode = OC_INPUT_INTERNAL;
418 }
419
420 //
421 // boot.efi also checks for CMD+X, but I have no idea what it is for.
422 //
423
424 //
425 // boot.efi requires unrestricted NVRAM just for CMD+S+MINUS, and CMD+S
426 // does not work at all on T2 macs. For CMD+S we simulate T2 behaviour with
427 // DisableSingleUser Booter quirk if necessary.
428 // Ref: https://support.apple.com/HT201573
429 //
430 if (HasCommand && HasKeyS) {
431 WantsZeroSlide = HasKeyMinus;
432
433 if (WantsZeroSlide) {
434 CsrActiveConfig = 0;
435 CsrActiveConfigSize = sizeof (CsrActiveConfig);
436 Status = gRT->GetVariable (
437 L"csr-active-config",
439 NULL,
440 &CsrActiveConfigSize,
441 &CsrActiveConfig
442 );
443 //
444 // FIXME: CMD+S+Minus behaves as CMD+S when "slide=0" is not supported
445 // by the SIP configuration. This might be an oversight, but is
446 // consistent with the boot.efi implementation.
447 //
448 WantsZeroSlide = !EFI_ERROR (Status) && (CsrActiveConfig & CSR_ALLOW_UNRESTRICTED_NVRAM) != 0;
449 }
450
451 if (WantsZeroSlide) {
452 if (AsciiStrStr (Context->AppleBootArgs, "slide=0") == NULL) {
453 DEBUG ((DEBUG_INFO, "OCHK: CMD+S+MINUS means slide=0\n"));
454 OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "slide=0", L_STR_LEN ("slide=0"));
455 }
456 } else if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-s", L_STR_LEN ("-s"), NULL) == NULL) {
457 DEBUG ((DEBUG_INFO, "OCHK: CMD+S means -s\n"));
458 OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-s", L_STR_LEN ("-s"));
459 }
460
461 PickerKeyInfo->OcKeyCode = OC_INPUT_INTERNAL;
462 }
463 }
464
465 //
466 // Handle typing chars.
467 //
468 if ((KeyFilter & OC_PICKER_KEYS_TYPING) != 0) {
469 PickerKeyInfo->UnicodeChar = UnicodeChar;
470 }
471
472 //
473 // Handle VoiceOver - non-repeating.
474 //
475 if ( ((KeyFilter & OC_PICKER_KEYS_VOICE_OVER) != 0)
476 && ((Modifiers & APPLE_MODIFIERS_COMMAND) != 0)
477 && OcKeyMapHasKey (KeysDoNotRepeat, NumKeysDoNotRepeat, AppleHidUsbKbUsageKeyF5))
478 {
479 PickerKeyInfo->OcKeyCode = OC_INPUT_VOICE_OVER;
480 return;
481 }
482
483 if ((KeyFilter & OC_PICKER_KEYS_TYPING) == 0) {
484 //
485 // Handle reload menu - non-repeating.
486 //
487 if ( OcKeyMapHasKey (KeysDoNotRepeat, NumKeysDoNotRepeat, AppleHidUsbKbUsageKeyEscape)
488 || OcKeyMapHasKey (KeysDoNotRepeat, NumKeysDoNotRepeat, AppleHidUsbKbUsageKeyZero)
489 )
490 {
491 PickerKeyInfo->OcKeyCode = OC_INPUT_ABORTED;
492 return;
493 }
494
495 //
496 // Handle show or toggle auxiliary - non-repeating.
497 //
498 if (OcKeyMapHasKey (KeysDoNotRepeat, NumKeysDoNotRepeat, AppleHidUsbKbUsageKeySpaceBar)) {
499 PickerKeyInfo->OcKeyCode = OC_INPUT_MORE;
500 return;
501 }
502 }
503
504 if (NumKeys == 1) {
505 if ( ((KeyFilter & OC_PICKER_KEYS_TAB_CONTROL) != 0)
506 && (Keys[0] == AppleHidUsbKbUsageKeyTab))
507 {
508 PickerKeyInfo->OcKeyCode = OC_INPUT_SWITCH_FOCUS;
509 return;
510 }
511
512 if ((KeyFilter & OC_PICKER_KEYS_TYPING) != 0) {
513 //
514 // Typing index key strokes.
515 //
516 if (Keys[0] == AppleHidUsbKbUsageKeyLeftArrow) {
517 PickerKeyInfo->OcKeyCode = OC_INPUT_TYPING_LEFT;
518 return;
519 }
520
521 if (Keys[0] == AppleHidUsbKbUsageKeyRightArrow) {
522 PickerKeyInfo->OcKeyCode = OC_INPUT_TYPING_RIGHT;
523 return;
524 }
525
526 if (Keys[0] == AppleHidUsbKbUsageKeyEscape) {
527 PickerKeyInfo->OcKeyCode = OC_INPUT_TYPING_CLEAR_ALL;
528 return;
529 }
530
531 if (Keys[0] == AppleHidUsbKbUsageKeyBackSpace) {
532 PickerKeyInfo->OcKeyCode = OC_INPUT_TYPING_BACKSPACE;
533 return;
534 }
535
536 if ( (Keys[0] == AppleHidUsbKbUsageKeyEnter)
537 || (Keys[0] == AppleHidUsbKbUsageKeyReturn)
538 || (Keys[0] == AppleHidUsbKbUsageKeyPadEnter))
539 {
540 PickerKeyInfo->OcKeyCode = OC_INPUT_TYPING_CONFIRM;
541 return;
542 }
543 } else {
544 //
545 // Non-typing index key strokes.
546 //
547
548 //
549 // Only select OS if valid modifiers are in place.
550 //
551 if ((Modifiers & ~ValidBootModifiers) == 0) {
552 TriggerBoot = FALSE;
553
554 if ( (Keys[0] == AppleHidUsbKbUsageKeyEnter)
555 || (Keys[0] == AppleHidUsbKbUsageKeyReturn)
556 || (Keys[0] == AppleHidUsbKbUsageKeyPadEnter))
557 {
558 PickerKeyInfo->OcKeyCode = OC_INPUT_CONTINUE;
559 TriggerBoot = TRUE;
560 }
561
563 if ((Keys[0] >= AppleHidUsbKbUsageKeyOne) && (Keys[0] <= AppleHidUsbKbUsageKeyNine)) {
564 PickerKeyInfo->OcKeyCode = (INTN)(Keys[0] - AppleHidUsbKbUsageKeyOne);
565 TriggerBoot = TRUE;
566 }
567
568 STATIC_ASSERT (AppleHidUsbKbUsageKeyA + 25 == AppleHidUsbKbUsageKeyZ, "Unexpected encoding");
569 if ((Keys[0] > AppleHidUsbKbUsageKeyA) && (Keys[0] <= AppleHidUsbKbUsageKeyZ)) {
570 PickerKeyInfo->OcKeyCode = (INTN)(Keys[0] - AppleHidUsbKbUsageKeyA + 9);
571 TriggerBoot = TRUE;
572 }
573
574 if (TriggerBoot) {
575 //
576 // In order to allow shift+tab, shift only applies at time of hitting
577 // enter or index, but if held then it enables Safe Mode.
578 //
579 if ((Modifiers & APPLE_MODIFIERS_SHIFT) != 0) {
580 if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-x", L_STR_LEN ("-x"), NULL) == NULL) {
581 DEBUG ((DEBUG_INFO, "OCHK: Shift means -x\n"));
582 OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-x", L_STR_LEN ("-x"));
583 }
584 }
585
586 return;
587 }
588 }
589
590 //
591 // Apply navigation keys regardless of modifiers.
592 //
593 if (Keys[0] == AppleHidUsbKbUsageKeyUpArrow) {
594 PickerKeyInfo->OcKeyCode = OC_INPUT_UP;
595 return;
596 }
597
598 if (Keys[0] == AppleHidUsbKbUsageKeyDownArrow) {
599 PickerKeyInfo->OcKeyCode = OC_INPUT_DOWN;
600 return;
601 }
602
603 if (Keys[0] == AppleHidUsbKbUsageKeyLeftArrow) {
604 PickerKeyInfo->OcKeyCode = OC_INPUT_LEFT;
605 return;
606 }
607
608 if (Keys[0] == AppleHidUsbKbUsageKeyRightArrow) {
609 PickerKeyInfo->OcKeyCode = OC_INPUT_RIGHT;
610 return;
611 }
612
613 if ( (Keys[0] == AppleHidUsbKbUsageKeyPgUp)
614 || (Keys[0] == AppleHidUsbKbUsageKeyHome))
615 {
616 PickerKeyInfo->OcKeyCode = OC_INPUT_TOP;
617 return;
618 }
619
620 if ( (Keys[0] == AppleHidUsbKbUsageKeyPgDn)
621 || (Keys[0] == AppleHidUsbKbUsageKeyEnd))
622 {
623 PickerKeyInfo->OcKeyCode = OC_INPUT_BOTTOM;
624 return;
625 }
626
627 //
628 // Fn. keys should only apply if no modifiers held.
629 //
630 if (Modifiers == APPLE_MODIFIERS_NONE) {
631 STATIC_ASSERT (AppleHidUsbKbUsageKeyF1 + 11 == AppleHidUsbKbUsageKeyF12, "Unexpected encoding");
632 if ((Keys[0] >= AppleHidUsbKbUsageKeyF1) && (Keys[0] <= AppleHidUsbKbUsageKeyF12)) {
633 PickerKeyInfo->OcKeyCode = OC_INPUT_FUNCTIONAL (Keys[0] - AppleHidUsbKbUsageKeyF1 + 1);
634 return;
635 }
636
637 STATIC_ASSERT (AppleHidUsbKbUsageKeyF13 + 11 == AppleHidUsbKbUsageKeyF24, "Unexpected encoding");
638 if ((Keys[0] >= AppleHidUsbKbUsageKeyF13) && (Keys[0] <= AppleHidUsbKbUsageKeyF24)) {
639 PickerKeyInfo->OcKeyCode = OC_INPUT_FUNCTIONAL (Keys[0] - AppleHidUsbKbUsageKeyF13 + 13);
640 return;
641 }
642 }
643 }
644 }
645
646 //
647 // Return NO_ACTION here, since all non-null actions now feedback
648 // immediately to either picker, to allow UI response.
649 //
650 PickerKeyInfo->OcKeyCode = OC_INPUT_NO_ACTION;
651}
652
653STATIC
654UINT64
655EFIAPI
657 IN UINT64 Timeout
658 )
659{
660 if (Timeout == 0) {
661 return 0ULL;
662 }
663
664 return GetTimeInNanoSecond (GetPerformanceCounter ()) + Timeout * 1000000ULL;
665}
666
667STATIC
668BOOLEAN
669EFIAPI
671 IN OUT OC_PICKER_CONTEXT *Context,
672 IN UINT64 EndTime,
673 IN OC_PICKER_KEY_MAP KeyFilter,
674 IN OUT OC_PICKER_KEY_INFO *PickerKeyInfo
675 )
676{
677 OC_MODIFIER_MAP OldOcModifiers;
678 UINT64 CurrTime;
679 UINT64 LoopDelayStart;
680
681 LoopDelayStart = 0;
682 OldOcModifiers = PickerKeyInfo->OcModifiers;
683
684 //
685 // These hotkeys are normally parsed by boot.efi, and they work just fine
686 // when ShowPicker is disabled. On some BSPs, however, they may fail badly
687 // when ShowPicker is enabled, and for this reason we support these hotkeys
688 // within picker itself.
689 //
690
691 while (TRUE) {
692 GetPickerKeyInfo (Context, KeyFilter, PickerKeyInfo);
693
694 //
695 // All non-null actions (even internal) are now returned to picker for possible UI response.
696 //
697 if ((PickerKeyInfo->OcKeyCode != OC_INPUT_NO_ACTION) ||
698 (PickerKeyInfo->OcModifiers != OldOcModifiers) ||
699 (PickerKeyInfo->UnicodeChar != CHAR_NULL))
700 {
701 break;
702 }
703
704 if (EndTime != 0) {
706 if ((CurrTime != 0) && (CurrTime >= EndTime)) {
707 PickerKeyInfo->OcKeyCode = OC_INPUT_TIMEOUT;
708 break;
709 }
710 }
711
712 DEBUG_CODE_BEGIN ();
713 LoopDelayStart = AsmReadTsc ();
714 DEBUG_CODE_END ();
715
717
718 DEBUG_CODE_BEGIN ();
719 if (Context->KbDebug != NULL) {
720 Context->KbDebug->InstrumentLoopDelay (LoopDelayStart, AsmReadTsc ());
721 }
722
723 DEBUG_CODE_END ();
724 }
725
726 return PickerKeyInfo->OcModifiers != OldOcModifiers;
727}
728
729//
730// Initialise picker keyboard handling.
731//
732EFI_STATUS
734 IN OUT OC_PICKER_CONTEXT *Context
735 )
736{
737 EFI_STATUS Status;
738
739 DEBUG ((DEBUG_INFO, "OCHK: InitHotKeys\n"));
740
741 ASSERT_EQUALS (Context->HotKeyContext, NULL);
742
743 //
744 // No kb debug unless initialiased on settings flag by a given picker itself.
745 //
746 Context->KbDebug = NULL;
747
748 Context->HotKeyContext = AllocatePool (sizeof (*(Context->HotKeyContext)));
749 if (Context->HotKeyContext == NULL) {
750 return EFI_OUT_OF_RESOURCES;
751 }
752
753 //
754 // Fn. ptrs.
755 //
756 Context->HotKeyContext->GetKeyInfo = GetPickerKeyInfo;
757 Context->HotKeyContext->GetKeyWaitEndTime = WaitForPickerKeyInfoGetEndTime;
758 Context->HotKeyContext->WaitForKeyInfo = WaitForPickerKeyInfo;
759 Context->HotKeyContext->FlushTypingBuffer = PickerFlushTypingBuffer;
760
761 Context->HotKeyContext->KeyMap = OcGetProtocol (&gAppleKeyMapAggregatorProtocolGuid, DEBUG_ERROR, "OcInitHotKeys", "AppleKeyMapAggregator");
762 if (Context->HotKeyContext->KeyMap == NULL) {
763 FreePool (Context->HotKeyContext);
764 Context->HotKeyContext = NULL;
765 return EFI_NOT_FOUND;
766 }
767
768 //
769 // Non-repeating keys, e.g. ESC and SPACE.
770 //
771 Status = OcInitKeyRepeatContext (
772 &Context->HotKeyContext->DoNotRepeatContext,
773 Context->HotKeyContext->KeyMap,
775 0,
776 0,
777 TRUE
778 );
779
780 if (EFI_ERROR (Status)) {
781 DEBUG ((DEBUG_ERROR, "OCHK: Init non-repeating context - %r\n", Status));
782 FreePool (Context->HotKeyContext);
783 Context->HotKeyContext = NULL;
784 return Status;
785 }
786
787 //
788 // Typing handler, for most keys.
789 //
790 Status = OcRegisterTypingHandler (&Context->HotKeyContext->TypingContext);
791
792 if (EFI_ERROR (Status)) {
793 DEBUG ((DEBUG_ERROR, "OCHK: Register typing handler - %r\n", Status));
794 OcFreeKeyRepeatContext (&Context->HotKeyContext->DoNotRepeatContext);
795 FreePool (Context->HotKeyContext);
796 Context->HotKeyContext = NULL;
797 return Status;
798 }
799
800 //
801 // Note: Raw AKMA is also still used for HotKeys, since we really do need
802 // three different types of keys response for fluent UI behaviour.
803 //
804
805 return EFI_SUCCESS;
806}
807
808//
809// Free picker keyboard handling resources.
810//
811VOID
813 IN OC_PICKER_CONTEXT *Context
814 )
815{
816 if (Context == NULL) {
817 return;
818 }
819
820 DEBUG ((DEBUG_INFO, "OCHK: FreeHotKeys\n"));
821
822 ASSERT (Context->HotKeyContext != NULL);
823
824 OcUnregisterTypingHandler (&Context->HotKeyContext->TypingContext);
825 OcFreeKeyRepeatContext (&Context->HotKeyContext->DoNotRepeatContext);
826
827 FreePool (Context->HotKeyContext);
828 Context->HotKeyContext = NULL;
829}
#define CSR_ALLOW_UNRESTRICTED_NVRAM
#define APPLE_MODIFIER_RIGHT_OPTION
Definition AppleHid.h:81
#define APPLE_MODIFIERS_NONE
Definition AppleHid.h:98
#define APPLE_MODIFIERS_COMMAND
Definition AppleHid.h:95
@ AppleHidUsbKbUsageKeyPadMinus
Definition AppleHid.h:189
@ AppleHidUsbKbUsageKeyEnter
Definition AppleHid.h:143
@ AppleHidUsbKbUsageKeySpaceBar
Definition AppleHid.h:147
@ AppleHidUsbKbUsageKeyPgUp
Definition AppleHid.h:178
@ AppleHidUsbKbUsageKeyEquals
Definition AppleHid.h:149
@ AppleHidUsbKbUsageKeyS
Definition AppleHid.h:125
@ AppleHidUsbKbUsageKeyRightArrow
Definition AppleHid.h:182
@ AppleHidUsbKbUsageKeyF1
Definition AppleHid.h:161
@ AppleHidUsbKbUsageKeyEnd
Definition AppleHid.h:180
@ AppleHidUsbKbUsageKeyTab
Definition AppleHid.h:146
@ AppleHidUsbKbUsageKeyDownArrow
Definition AppleHid.h:184
@ AppleHidUsbKbUsageKeyUpArrow
Definition AppleHid.h:185
@ AppleHidUsbKbUsageKeyHome
Definition AppleHid.h:177
@ AppleHidUsbKbUsageKeyA
Definition AppleHid.h:107
@ AppleHidUsbKbUsageKeyPgDn
Definition AppleHid.h:181
@ AppleHidUsbKbUsageKeyEscape
Definition AppleHid.h:144
@ AppleHidUsbKbUsageKeyC
Definition AppleHid.h:109
@ AppleHidUsbKbUsageKeyBackSpace
Definition AppleHid.h:145
@ AppleHidUsbKbUsageKeyReturn
Definition AppleHid.h:261
@ AppleHidUsbKbUsageKeyMinus
Definition AppleHid.h:148
@ AppleHidUsbKbUsageKeyF13
Definition AppleHid.h:207
@ AppleHidUsbKbUsageKeyV
Definition AppleHid.h:128
@ AppleHidUsbKbUsageKeyF5
Definition AppleHid.h:165
@ AppleHidUsbKbUsageKeyZ
Definition AppleHid.h:132
@ AppleHidUsbKbUsageKeyR
Definition AppleHid.h:124
@ AppleHidUsbKbUsageKeyOne
Definition AppleHid.h:133
@ AppleHidUsbKbUsageKeyF12
Definition AppleHid.h:172
@ AppleHidUsbKbUsageKeyF24
Definition AppleHid.h:218
@ AppleHidUsbKbUsageKeyX
Definition AppleHid.h:130
@ AppleHidUsbKbUsageKeyZero
Definition AppleHid.h:142
@ AppleHidUsbKbUsageKeyPadEnter
Definition AppleHid.h:191
@ AppleHidUsbKbUsageKeyNine
Definition AppleHid.h:141
@ AppleHidUsbKbUsageKeyK
Definition AppleHid.h:117
@ AppleHidUsbKbUsageKeyLeftArrow
Definition AppleHid.h:183
APPLE_HID_USAGE APPLE_KEY_CODE
Definition AppleHid.h:317
#define APPLE_MODIFIERS_CONTROL
Definition AppleHid.h:86
UINT16 APPLE_MODIFIER_MAP
Definition AppleHid.h:102
#define APPLE_MODIFIERS_SHIFT
Definition AppleHid.h:89
#define APPLE_MODIFIER_LEFT_COMMAND
Definition AppleHid.h:78
#define APPLE_MODIFIER_RIGHT_COMMAND
Definition AppleHid.h:82
#define APPLE_MODIFIER_LEFT_OPTION
Definition AppleHid.h:77
EFI_GUID gAppleKeyMapAggregatorProtocolGuid
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
EFI_GUID gAppleBootVariableGuid
VOID OcFreeHotKeys(IN OC_PICKER_CONTEXT *Context)
STATIC BOOLEAN EFIAPI CheckHotKeysForProtocolInstance(IN OUT OC_PICKER_CONTEXT *PickerContext, IN EFI_HANDLE BootEntryProtocolHandle, IN OC_BOOT_ENTRY_PROTOCOL *BootEntryProtocol, IN VOID *Context)
EFI_STATUS OcInitHotKeys(IN OUT OC_PICKER_CONTEXT *Context)
STATIC EFI_STATUS ApplyBootEntryProtocolHotKeys(IN OUT OC_PICKER_CONTEXT *PickerContext, IN UINTN NumKeys, IN APPLE_MODIFIER_MAP Modifiers, IN APPLE_KEY_CODE *Keys)
STATIC VOID EFIAPI GetPickerKeyInfo(IN OUT OC_PICKER_CONTEXT *Context, IN OC_PICKER_KEY_MAP KeyFilter, OUT OC_PICKER_KEY_INFO *PickerKeyInfo)
STATIC UINT64 EFIAPI WaitForPickerKeyInfoGetEndTime(IN UINT64 Timeout)
STATIC BOOLEAN EFIAPI WaitForPickerKeyInfo(IN OUT OC_PICKER_CONTEXT *Context, IN UINT64 EndTime, IN OC_PICKER_KEY_MAP KeyFilter, IN OUT OC_PICKER_KEY_INFO *PickerKeyInfo)
VOID OcLoadPickerHotKeys(IN OUT OC_PICKER_CONTEXT *Context)
STATIC VOID EFIAPI PickerFlushTypingBuffer(IN OUT OC_PICKER_CONTEXT *Context)
#define OC_HELD_KEYS_DEFAULT_SIZE
EFI_STATUS OcInitKeyRepeatContext(OUT OC_KEY_REPEAT_CONTEXT **Context, IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap, IN UINTN MaxKeysHeld, IN UINT64 InitialDelay, IN UINT64 SubsequentDelay, IN BOOLEAN PreventInitialRepeat)
EFI_STATUS EFIAPI OcGetUpDownKeys(IN OUT OC_KEY_REPEAT_CONTEXT *RepeatContext, OUT APPLE_MODIFIER_MAP *Modifiers, IN OUT UINTN *NumKeysUp, OUT APPLE_KEY_CODE *KeysUp OPTIONAL, IN OUT UINTN *NumKeysDown, OUT APPLE_KEY_CODE *KeysDown OPTIONAL, IN UINT64 CurrentTime)
VOID OcFreeKeyRepeatContext(OC_KEY_REPEAT_CONTEXT **Context)
#define OC_KEY_MAP_DEFAULT_SIZE
BOOLEAN OcKeyMapHasKey(IN CONST APPLE_KEY_CODE *Keys, IN UINTN NumKeys, IN CONST APPLE_KEY_CODE KeyCode)
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
VOID OcConsumeBootEntryProtocol(IN OUT OC_PICKER_CONTEXT *PickerContext, IN EFI_HANDLE *EntryProtocolHandles, IN UINTN EntryProtocolHandleCount, IN OC_CONSUME_ENTRY_PROTOCOL_ACTION Action, IN VOID *Context)
#define OC_INPUT_TYPING_BACKSPACE
Clear last typed character while typing (press backspace)
#define OC_MODIFIERS_NONE
@ OcPickerShowPicker
@ OcPickerBootAppleRecovery
@ OcPickerProtocolHotKey
@ OcPickerBootApple
#define OC_INPUT_TYPING_CONFIRM
Confirm input while typing (press enter)
#define OC_INPUT_DOWN
Move down.
#define OC_INPUT_NO_ACTION
Some other key.
#define OC_INPUT_TIMEOUT
Timeout.
#define OC_MODIFIERS_SET_DEFAULT
VOID OcLocateBootEntryProtocolHandles(IN OUT EFI_HANDLE **EntryProtocolHandles, IN OUT UINTN *EntryProtocolHandleCount)
#define OC_PICKER_KEYS_VOICE_OVER
#define OC_INPUT_TYPING_LEFT
Move left while typing (UI does not have to support)
#define OC_INPUT_LEFT
Move left.
#define OC_MODIFIERS_REVERSE_SWITCH_FOCUS
#define OC_INPUT_INTERNAL
Accepted internal hotkey (e.g. Apple)
VOID OcFreeBootEntryProtocolHandles(EFI_HANDLE **EntryProtocolHandles)
UINTN OC_PICKER_KEY_MAP
#define OC_INPUT_TYPING_RIGHT
Move right while typing (UI does not have to support)
#define OC_PICKER_KEYS_TAB_CONTROL
#define OC_INPUT_CONTINUE
Continue (press enter)
#define OC_PICKER_KEYS_HOTKEYS
#define OC_INPUT_ABORTED
Esc or 0.
CONST CHAR8 * OcGetArgumentFromCmd(IN CONST CHAR8 *CommandLine, IN CONST CHAR8 *Argument, IN CONST UINTN ArgumentLength, OUT UINTN *ValueLength OPTIONAL)
#define OC_INPUT_BOTTOM
Move to bottom.
#define OC_PICKER_KEYS_TYPING
#define OC_INPUT_MORE
Show more entries (press space)
#define OC_INPUT_SWITCH_FOCUS
Switch UI focus (tab and shift+tab)
#define OC_INPUT_FUNCTIONAL(x)
Function hotkeys.
#define OC_INPUT_RIGHT
Move right.
BOOLEAN OcAppendArgumentToCmd(IN OUT OC_PICKER_CONTEXT *Context OPTIONAL, IN OUT CHAR8 *CommandLine, IN CONST CHAR8 *Argument, IN CONST UINTN ArgumentLength)
#define OC_INPUT_UP
Move up.
#define OC_INPUT_TOP
Move to top.
#define OC_INPUT_VOICE_OVER
Toggle VoiceOver (press CMD+F5)
#define OC_INPUT_TYPING_CLEAR_ALL
Clear current input while typing (press esc)
UINT16 OC_MODIFIER_MAP
EFI_BOOT_SERVICES * gBS
#define ASSERT_EQUALS(Expression, ExpectedValue)
Definition OcMiscLib.h:259
VOID * OcGetProtocol(IN EFI_GUID *Protocol, IN UINTN ErrorLevel, IN CONST CHAR8 *CallerName OPTIONAL, IN CONST CHAR8 *ProtocolName OPTIONAL)
#define L_STR_LEN(String)
Definition OcStringLib.h:26
#define OC_MINIMAL_CPU_DELAY
Definition OcTimerLib.h:15
CHAR16 UnicodeChar
Definition OcTypingLib.h:38
EFI_STATUS OcUnregisterTypingHandler(IN OC_TYPING_CONTEXT **Context)
EFI_STATUS OcRegisterTypingHandler(OUT OC_TYPING_CONTEXT **Context)
Definition OcTypingLib.c:91
VOID OcGetNextKeystroke(IN OC_TYPING_CONTEXT *Context, OUT APPLE_MODIFIER_MAP *Modifiers, OUT APPLE_KEY_CODE *AppleKeyCode, OUT CHAR16 *UnicodeChar)
VOID OcFlushTypingBuffer(IN OC_TYPING_CONTEXT *Context)
EFI_RUNTIME_SERVICES * gRT
UINT64 EFIAPI AsmReadTsc(VOID)
Definition UserMisc.c:232
UINT64 EFIAPI GetTimeInNanoSecond(IN UINT64 Ticks)
UINT64 EFIAPI GetPerformanceCounter(VOID)
UINTN EFIAPI MicroSecondDelay(IN UINTN MicroSeconds)
#define ASSERT(x)
Definition coder.h:55
APPLE_MODIFIER_MAP Modifiers