Nt32Pkg/NtGopInput: ReadKeyStrokeEx always return key state
[mirror_edk2.git] / Nt32Pkg / WinNtGopDxe / WinNtGopInput.c
1 /** @file
2
3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 WinNtGopInput.c
15
16 Abstract:
17
18 This file produces the Simple Text In for an Gop window.
19
20 This stuff is linked at the hip to the Window, since the window
21 processing is done in a thread kicked off in WinNtGopImplementation.c
22
23 Since the window information is processed in an other thread we need
24 a keyboard Queue to pass data about. The Simple Text In code just
25 takes data off the Queue. The WinProc message loop takes keyboard input
26 and places it in the Queue.
27
28
29 **/
30
31
32 #include "WinNtGop.h"
33
34
35 /**
36 TODO: Add function description
37
38 @param Private TODO: add argument description
39
40 @retval EFI_SUCCESS TODO: Add description for return value
41
42 **/
43 EFI_STATUS
44 GopPrivateCreateQ (
45 IN GOP_PRIVATE_DATA *Private,
46 IN GOP_QUEUE_FIXED *Queue
47 )
48 {
49 Private->WinNtThunk->InitializeCriticalSection (&Queue->Cs);
50 Queue->Front = 0;
51 Queue->Rear = 0;
52 return EFI_SUCCESS;
53 }
54
55
56 /**
57 TODO: Add function description
58
59 @param Private TODO: add argument description
60
61 @retval EFI_SUCCESS TODO: Add description for return value
62
63 **/
64 EFI_STATUS
65 GopPrivateDestroyQ (
66 IN GOP_PRIVATE_DATA *Private,
67 IN GOP_QUEUE_FIXED *Queue
68 )
69 {
70 Queue->Front = 0;
71 Queue->Rear = 0;
72 Private->WinNtThunk->DeleteCriticalSection (&Queue->Cs);
73 return EFI_SUCCESS;
74 }
75
76
77 /**
78 TODO: Add function description
79
80 @param Private TODO: add argument description
81 @param Key TODO: add argument description
82
83 @retval EFI_NOT_READY TODO: Add description for return value
84 @retval EFI_SUCCESS TODO: Add description for return value
85
86 **/
87 EFI_STATUS
88 GopPrivateAddQ (
89 IN GOP_PRIVATE_DATA *Private,
90 IN GOP_QUEUE_FIXED *Queue,
91 IN EFI_KEY_DATA *KeyData
92 )
93 {
94 Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);
95
96 if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {
97 Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
98 return EFI_NOT_READY;
99 }
100
101 CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
102 Queue->Rear = (Queue->Rear + 1) % MAX_Q;
103
104 Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
105 return EFI_SUCCESS;
106 }
107
108
109 /**
110 TODO: Add function description
111
112 @param Private TODO: add argument description
113 @param Key TODO: add argument description
114
115 @retval EFI_NOT_READY TODO: Add description for return value
116 @retval EFI_SUCCESS TODO: Add description for return value
117
118 **/
119 EFI_STATUS
120 GopPrivateDeleteQ (
121 IN GOP_PRIVATE_DATA *Private,
122 IN GOP_QUEUE_FIXED *Queue,
123 OUT EFI_KEY_DATA *Key
124 )
125 {
126 Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);
127
128 if (Queue->Front == Queue->Rear) {
129 Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
130 return EFI_NOT_READY;
131 }
132
133 CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));
134 Queue->Front = (Queue->Front + 1) % MAX_Q;
135
136 if (Key->Key.ScanCode == SCAN_NULL && Key->Key.UnicodeChar == CHAR_NULL) {
137 if (!Private->IsPartialKeySupport) {
138 //
139 // If partial keystrok is not enabled, don't return the partial keystroke.
140 //
141 Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
142 ZeroMem (Key, sizeof (EFI_KEY_DATA));
143 return EFI_NOT_READY;
144 }
145 }
146 Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);
147 return EFI_SUCCESS;
148 }
149
150
151 /**
152 TODO: Add function description
153
154 @param Private TODO: add argument description
155
156 @retval EFI_NOT_READY TODO: Add description for return value
157 @retval EFI_SUCCESS TODO: Add description for return value
158
159 **/
160 EFI_STATUS
161 GopPrivateCheckQ (
162 IN GOP_QUEUE_FIXED *Queue
163 )
164 {
165 if (Queue->Front == Queue->Rear) {
166 return EFI_NOT_READY;
167 }
168
169 return EFI_SUCCESS;
170 }
171
172 BOOLEAN
173 GopPrivateIsKeyRegistered (
174 IN EFI_KEY_DATA *RegsiteredData,
175 IN EFI_KEY_DATA *InputData
176 )
177 /*++
178
179 Routine Description:
180
181 Arguments:
182
183 RegsiteredData - A pointer to a buffer that is filled in with the keystroke
184 state data for the key that was registered.
185 InputData - A pointer to a buffer that is filled in with the keystroke
186 state data for the key that was pressed.
187
188 Returns:
189 TRUE - Key be pressed matches a registered key.
190 FLASE - Match failed.
191
192 --*/
193 {
194 ASSERT (RegsiteredData != NULL && InputData != NULL);
195
196 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
197 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
198 return FALSE;
199 }
200
201 //
202 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
203 //
204 if (RegsiteredData->KeyState.KeyShiftState != 0 &&
205 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
206 return FALSE;
207 }
208 if (RegsiteredData->KeyState.KeyToggleState != 0 &&
209 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
210 return FALSE;
211 }
212
213 return TRUE;
214
215 }
216
217
218 VOID
219 GopPrivateInvokeRegisteredFunction (
220 IN GOP_PRIVATE_DATA *Private,
221 IN EFI_KEY_DATA *KeyData
222 )
223 /*++
224
225 Routine Description:
226
227 This function updates the status light of NumLock, ScrollLock and CapsLock.
228
229 Arguments:
230
231 Private - The private structure of WinNt Gop device.
232 KeyData - A pointer to a buffer that is filled in with the keystroke
233 state data for the key that was pressed.
234
235 Returns:
236
237 EFI_SUCCESS - The status light is updated successfully.
238
239 --*/
240 {
241 LIST_ENTRY *Link;
242 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;
243
244 for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
245 CurrentNotify = CR (
246 Link,
247 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,
248 NotifyEntry,
249 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE
250 );
251 if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
252 CurrentNotify->KeyNotificationFn (KeyData);
253 }
254 }
255 }
256
257 VOID
258 WinNtGopSimpleTextInTimerHandler (
259 IN EFI_EVENT Event,
260 IN VOID *Context
261 )
262 {
263 GOP_PRIVATE_DATA *Private;
264 EFI_KEY_DATA KeyData;
265
266 Private = (GOP_PRIVATE_DATA *)Context;
267 while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS) {
268 GopPrivateInvokeRegisteredFunction (Private, &KeyData);
269 }
270 }
271
272 /**
273 Initialize the key state.
274
275 @param Private The GOP_PRIVATE_DATA instance.
276 @param KeyState A pointer to receive the key state information.
277 **/
278 VOID
279 InitializeKeyState (
280 IN GOP_PRIVATE_DATA *Private,
281 IN EFI_KEY_STATE *KeyState
282 )
283 {
284 KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID;
285 KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;
286
287 //
288 // Record Key shift state and toggle state
289 //
290 if (Private->LeftCtrl) {
291 KeyState->KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
292 }
293 if (Private->RightCtrl) {
294 KeyState->KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
295 }
296 if (Private->LeftAlt) {
297 KeyState->KeyShiftState |= EFI_LEFT_ALT_PRESSED;
298 }
299 if (Private->RightAlt) {
300 KeyState->KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
301 }
302 if (Private->LeftShift) {
303 KeyState->KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
304 }
305 if (Private->RightShift) {
306 KeyState->KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
307 }
308 if (Private->LeftLogo) {
309 KeyState->KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
310 }
311 if (Private->RightLogo) {
312 KeyState->KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
313 }
314 if (Private->Menu) {
315 KeyState->KeyShiftState |= EFI_MENU_KEY_PRESSED;
316 }
317 if (Private->SysReq) {
318 KeyState->KeyShiftState |= EFI_SYS_REQ_PRESSED;
319 }
320 if (Private->CapsLock) {
321 KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
322 }
323 if (Private->NumLock) {
324 KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
325 }
326 if (Private->ScrollLock) {
327 KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
328 }
329 if (Private->IsPartialKeySupport) {
330 KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;
331 }
332 }
333
334 /**
335 TODO: Add function description
336
337 @param Private TODO: add argument description
338 @param Key TODO: add argument description
339
340 @retval EFI_NOT_READY TODO: Add description for return value
341 @retval EFI_SUCCESS TODO: Add description for return value
342
343 **/
344 EFI_STATUS
345 GopPrivateAddKey (
346 IN GOP_PRIVATE_DATA *Private,
347 IN EFI_INPUT_KEY Key
348 )
349 {
350 EFI_KEY_DATA KeyData;
351
352 KeyData.Key = Key;
353 InitializeKeyState (Private, &KeyData.KeyState);
354
355 //
356 // Convert Ctrl+[1-26] to Ctrl+[A-Z]
357 //
358 if ((Private->LeftCtrl || Private->RightCtrl) &&
359 (KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)
360 ) {
361 if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {
362 KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);
363 } else {
364 KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);
365 }
366 }
367
368 //
369 // Unmask the Shift bit for printable char
370 //
371 if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||
372 ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))
373 ) {
374 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
375 }
376
377 GopPrivateAddQ (Private, &Private->QueueForNotify, &KeyData);
378
379 GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);
380
381 return EFI_SUCCESS;
382 }
383
384 EFI_STATUS
385 GopPrivateUpdateStatusLight (
386 IN GOP_PRIVATE_DATA *Private
387 )
388 /*++
389
390 Routine Description:
391
392 This function updates the status light of NumLock, ScrollLock and CapsLock.
393
394 Arguments:
395
396 Private - The private structure of WinNt console In/Out.
397
398 Returns:
399
400 EFI_SUCCESS - The status light is updated successfully.
401
402 --*/
403 {
404 //
405 // BUGBUG:Only SendInput/keybd_event function can toggle
406 // NumLock, CapsLock and ScrollLock keys.
407 // Neither of these functions is included in EFI_WIN_NT_THUNK_PROTOCOL.
408 // Thus, return immediately without operation.
409 //
410 return EFI_SUCCESS;
411
412 }
413
414
415 EFI_STATUS
416 GopPrivateResetWorker (
417 IN GOP_PRIVATE_DATA *Private
418 )
419 /*++
420
421 Routine Description:
422
423 This function is a worker function for SimpleTextIn/SimpleTextInEx.Reset().
424
425 Arguments:
426
427 Private - WinNT GOP private structure
428
429 Returns:
430
431 EFI_SUCCESS - Reset successfully
432
433 --*/
434 {
435 EFI_KEY_DATA KeyData;
436 EFI_TPL OldTpl;
437
438 //
439 // Enter critical section
440 //
441 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
442
443 //
444 // A reset is draining the Queue
445 //
446 while (GopPrivateDeleteQ (Private, &Private->QueueForRead, &KeyData) == EFI_SUCCESS)
447 ;
448 while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS)
449 ;
450
451 Private->LeftShift = FALSE;
452 Private->RightShift = FALSE;
453 Private->LeftAlt = FALSE;
454 Private->RightAlt = FALSE;
455 Private->LeftCtrl = FALSE;
456 Private->RightCtrl = FALSE;
457 Private->LeftLogo = FALSE;
458 Private->RightLogo = FALSE;
459 Private->Menu = FALSE;
460 Private->SysReq = FALSE;
461
462 Private->CapsLock = FALSE;
463 Private->NumLock = FALSE;
464 Private->ScrollLock = FALSE;
465 Private->IsPartialKeySupport = FALSE;
466
467 Private->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
468 Private->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
469
470 //
471 // Leave critical section and return
472 //
473 gBS->RestoreTPL (OldTpl);
474
475 return EFI_SUCCESS;
476 }
477
478 EFI_STATUS
479 GopPrivateReadKeyStrokeWorker (
480 IN GOP_PRIVATE_DATA *Private,
481 OUT EFI_KEY_DATA *KeyData
482 )
483 /*++
484
485 Routine Description:
486 Reads the next keystroke from the input device. The WaitForKey Event can
487 be used to test for existance of a keystroke via WaitForEvent () call.
488
489 Arguments:
490 Private - The private structure of WinNt Gop device.
491 KeyData - A pointer to a buffer that is filled in with the keystroke
492 state data for the key that was pressed.
493
494 Returns:
495 EFI_SUCCESS - The keystroke information was returned.
496 EFI_NOT_READY - There was no keystroke data availiable.
497 EFI_DEVICE_ERROR - The keystroke information was not returned due to
498 hardware errors.
499 EFI_INVALID_PARAMETER - KeyData is NULL.
500
501 --*/
502 {
503 EFI_STATUS Status;
504 EFI_TPL OldTpl;
505
506 if (KeyData == NULL) {
507 return EFI_INVALID_PARAMETER;
508 }
509
510 //
511 // Enter critical section
512 //
513 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
514
515 //
516 // Call hot key callback before telling caller there is a key available
517 //
518 WinNtGopSimpleTextInTimerHandler (NULL, Private);
519
520 ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
521 InitializeKeyState (Private, &KeyData->KeyState);
522
523 Status = GopPrivateCheckQ (&Private->QueueForRead);
524 if (!EFI_ERROR (Status)) {
525 //
526 // If a Key press exists try and read it.
527 //
528 Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);
529 if (!EFI_ERROR (Status)) {
530 //
531 // If partial keystroke is not enabled, check whether it is value key. If not return
532 // EFI_NOT_READY.
533 //
534 if (!Private->IsPartialKeySupport) {
535 if (KeyData->Key.ScanCode == SCAN_NULL && KeyData->Key.UnicodeChar == CHAR_NULL) {
536 Status = EFI_NOT_READY;
537 }
538 }
539 }
540 }
541
542 //
543 // Leave critical section and return
544 //
545 gBS->RestoreTPL (OldTpl);
546
547 return Status;
548
549 }
550
551
552 //
553 // Simple Text In implementation.
554 //
555
556
557 /**
558 TODO: Add function description
559
560 @param This TODO: add argument description
561 @param ExtendedVerification TODO: add argument description
562
563 @retval EFI_SUCCESS TODO: Add description for return value
564
565 **/
566 EFI_STATUS
567 EFIAPI
568 WinNtGopSimpleTextInReset (
569 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
570 IN BOOLEAN ExtendedVerification
571 )
572 {
573 GOP_PRIVATE_DATA *Private;
574
575 Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);
576
577 return GopPrivateResetWorker (Private);
578 }
579
580
581 /**
582 TODO: Add function description
583
584 @param This TODO: add argument description
585 @param Key TODO: add argument description
586
587 @return TODO: add return values
588
589 **/
590 EFI_STATUS
591 EFIAPI
592 WinNtGopSimpleTextInReadKeyStroke (
593 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
594 OUT EFI_INPUT_KEY *Key
595 )
596 {
597 GOP_PRIVATE_DATA *Private;
598 EFI_STATUS Status;
599 EFI_KEY_DATA KeyData;
600
601 Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);
602 //
603 // Considering if the partial keystroke is enabled, there maybe a partial
604 // keystroke in the queue, so here skip the partial keystroke and get the
605 // next key from the queue
606 //
607 while (1) {
608 Status = GopPrivateReadKeyStrokeWorker (Private, &KeyData);
609 if (EFI_ERROR (Status)) {
610 return Status;
611 }
612 if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
613 continue;
614 }
615 //
616 // Convert Ctrl+[A-Z] to Ctrl+[1-26]
617 //
618 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
619 if ((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) {
620 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
621 } else if ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z')) {
622 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
623 }
624 }
625 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
626 return EFI_SUCCESS;
627 }
628 }
629
630
631 /**
632 TODO: Add function description
633
634 @param Event TODO: add argument description
635 @param Context TODO: add argument description
636
637 @return TODO: add return values
638
639 **/
640 VOID
641 EFIAPI
642 WinNtGopSimpleTextInWaitForKey (
643 IN EFI_EVENT Event,
644 IN VOID *Context
645 )
646 {
647 GOP_PRIVATE_DATA *Private;
648 EFI_STATUS Status;
649 EFI_TPL OldTpl;
650 EFI_KEY_DATA KeyData;
651
652 Private = (GOP_PRIVATE_DATA *) Context;
653
654 //
655 // Enter critical section
656 //
657 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
658
659 //
660 // Call hot key callback before telling caller there is a key available
661 //
662 WinNtGopSimpleTextInTimerHandler (NULL, Private);
663
664 //
665 // WaitforKey doesn't suppor the partial key.
666 // Considering if the partial keystroke is enabled, there maybe a partial
667 // keystroke in the queue, so here skip the partial keystroke and get the
668 // next key from the queue
669 //
670 while (1) {
671 Status = GopPrivateCheckQ (&Private->QueueForRead);
672 if (!EFI_ERROR (Status)) {
673 //
674 // If a there is a key in the queue and it is not partial keystroke, signal event.
675 //
676 if (Private->QueueForRead.Q[Private->QueueForRead.Front].Key.ScanCode == SCAN_NULL &&
677 Private->QueueForRead.Q[Private->QueueForRead.Front].Key.UnicodeChar == CHAR_NULL) {
678 GopPrivateDeleteQ (Private,&Private->QueueForRead,&KeyData);
679 continue;
680 }
681 gBS->SignalEvent (Event);
682 } else {
683 //
684 // We need to sleep or NT will schedule this thread with such high
685 // priority that WinProc thread will never run and we will not see
686 // keyboard input. This Sleep makes the syste run 10x faster, so don't
687 // remove it.
688 //
689 Private->WinNtThunk->Sleep (1);
690 }
691 break;
692 }
693
694 //
695 // Leave critical section and return
696 //
697 gBS->RestoreTPL (OldTpl);
698 }
699
700 //
701 // Simple Text Input Ex protocol functions
702 //
703
704 EFI_STATUS
705 EFIAPI
706 WinNtGopSimpleTextInExResetEx (
707 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
708 IN BOOLEAN ExtendedVerification
709 )
710 /*++
711
712 Routine Description:
713 Reset the input device and optionaly run diagnostics
714
715 Arguments:
716 This - Protocol instance pointer.
717 ExtendedVerification - Driver may perform diagnostics on reset.
718
719 Returns:
720 EFI_SUCCESS - The device was reset.
721
722 --*/
723 {
724 GOP_PRIVATE_DATA *Private;
725
726 Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
727
728 return GopPrivateResetWorker (Private);
729 }
730
731 EFI_STATUS
732 EFIAPI
733 WinNtGopSimpleTextInExReadKeyStrokeEx (
734 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
735 OUT EFI_KEY_DATA *KeyData
736 )
737 /*++
738
739 Routine Description:
740 Reads the next keystroke from the input device. The WaitForKey Event can
741 be used to test for existance of a keystroke via WaitForEvent () call.
742
743 Arguments:
744 This - Protocol instance pointer.
745 KeyData - A pointer to a buffer that is filled in with the keystroke
746 state data for the key that was pressed.
747
748 Returns:
749 EFI_SUCCESS - The keystroke information was returned.
750 EFI_NOT_READY - There was no keystroke data availiable.
751 EFI_DEVICE_ERROR - The keystroke information was not returned due to
752 hardware errors.
753 EFI_INVALID_PARAMETER - KeyData is NULL.
754
755 --*/
756 {
757 GOP_PRIVATE_DATA *Private;
758
759 if (KeyData == NULL) {
760 return EFI_INVALID_PARAMETER;
761 }
762
763 Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
764
765 return GopPrivateReadKeyStrokeWorker (Private, KeyData);
766
767 }
768
769 EFI_STATUS
770 EFIAPI
771 WinNtGopSimpleTextInExSetState (
772 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
773 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
774 )
775 /*++
776
777 Routine Description:
778 Set certain state for the input device.
779
780 Arguments:
781 This - Protocol instance pointer.
782 KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
783 state for the input device.
784
785 Returns:
786 EFI_SUCCESS - The device state was set successfully.
787 EFI_DEVICE_ERROR - The device is not functioning correctly and could
788 not have the setting adjusted.
789 EFI_UNSUPPORTED - The device does not have the ability to set its state.
790 EFI_INVALID_PARAMETER - KeyToggleState is NULL.
791
792 --*/
793 {
794 EFI_STATUS Status;
795 GOP_PRIVATE_DATA *Private;
796
797 if (KeyToggleState == NULL) {
798 return EFI_INVALID_PARAMETER;
799 }
800
801 Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
802
803 if (((Private->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
804 ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
805 return EFI_UNSUPPORTED;
806 }
807
808 Private->ScrollLock = FALSE;
809 Private->NumLock = FALSE;
810 Private->CapsLock = FALSE;
811 Private->IsPartialKeySupport = FALSE;
812
813 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
814 Private->ScrollLock = TRUE;
815 }
816 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
817 Private->NumLock = TRUE;
818 }
819 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
820 Private->CapsLock = TRUE;
821 }
822 if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
823 Private->IsPartialKeySupport = TRUE;
824 }
825
826 Status = GopPrivateUpdateStatusLight (Private);
827 if (EFI_ERROR (Status)) {
828 return EFI_DEVICE_ERROR;
829 }
830
831 Private->KeyState.KeyToggleState = *KeyToggleState;
832 return EFI_SUCCESS;
833
834 }
835
836 EFI_STATUS
837 EFIAPI
838 WinNtGopSimpleTextInExRegisterKeyNotify (
839 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
840 IN EFI_KEY_DATA *KeyData,
841 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
842 OUT VOID **NotifyHandle
843 )
844 /*++
845
846 Routine Description:
847 Register a notification function for a particular keystroke for the input device.
848
849 Arguments:
850 This - Protocol instance pointer.
851 KeyData - A pointer to a buffer that is filled in with the keystroke
852 information data for the key that was pressed.
853 KeyNotificationFunction - Points to the function to be called when the key
854 sequence is typed specified by KeyData.
855 NotifyHandle - Points to the unique handle assigned to the registered notification.
856
857 Returns:
858 EFI_SUCCESS - The notification function was registered successfully.
859 EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
860 EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
861
862 --*/
863 {
864 GOP_PRIVATE_DATA *Private;
865 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;
866 LIST_ENTRY *Link;
867 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *NewNotify;
868
869 if (KeyData == NULL || KeyNotificationFunction == NULL || NotifyHandle == NULL) {
870 return EFI_INVALID_PARAMETER;
871 }
872
873 Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
874
875 //
876 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
877 //
878 for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
879 CurrentNotify = CR (
880 Link,
881 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,
882 NotifyEntry,
883 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE
884 );
885 if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
886 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
887 *NotifyHandle = CurrentNotify;
888 return EFI_SUCCESS;
889 }
890 }
891 }
892
893 //
894 // Allocate resource to save the notification function
895 //
896 NewNotify = (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *) AllocateZeroPool (sizeof (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY));
897 if (NewNotify == NULL) {
898 return EFI_OUT_OF_RESOURCES;
899 }
900
901 NewNotify->Signature = WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE;
902 NewNotify->KeyNotificationFn = KeyNotificationFunction;
903 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
904 InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);
905
906 *NotifyHandle = NewNotify;
907
908 return EFI_SUCCESS;
909
910 }
911
912 EFI_STATUS
913 EFIAPI
914 WinNtGopSimpleTextInExUnregisterKeyNotify (
915 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
916 IN VOID *NotificationHandle
917 )
918 /*++
919
920 Routine Description:
921 Remove a registered notification function from a particular keystroke.
922
923 Arguments:
924 This - Protocol instance pointer.
925 NotificationHandle - The handle of the notification function being unregistered.
926
927 Returns:
928 EFI_SUCCESS - The notification function was unregistered successfully.
929 EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
930
931 --*/
932 {
933 GOP_PRIVATE_DATA *Private;
934 LIST_ENTRY *Link;
935 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;
936
937 if (NotificationHandle == NULL) {
938 return EFI_INVALID_PARAMETER;
939 }
940
941 Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);
942
943 for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {
944 CurrentNotify = CR (
945 Link,
946 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,
947 NotifyEntry,
948 WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE
949 );
950 if (CurrentNotify == NotificationHandle) {
951 //
952 // Remove the notification function from NotifyList and free resources
953 //
954 RemoveEntryList (&CurrentNotify->NotifyEntry);
955
956 gBS->FreePool (CurrentNotify);
957 return EFI_SUCCESS;
958 }
959 }
960
961 //
962 // Can not find the specified Notification Handle
963 //
964 return EFI_INVALID_PARAMETER;
965 }
966
967
968 /**
969 TODO: Add function description
970
971 @param Private TODO: add argument description
972
973 @return TODO: add return values
974
975 **/
976 EFI_STATUS
977 WinNtGopInitializeSimpleTextInForWindow (
978 IN GOP_PRIVATE_DATA *Private
979 )
980 {
981 EFI_STATUS Status;
982
983 GopPrivateCreateQ (Private, &Private->QueueForRead);
984 GopPrivateCreateQ (Private, &Private->QueueForNotify);
985
986 //
987 // Initialize Simple Text In protoocol
988 //
989 Private->SimpleTextIn.Reset = WinNtGopSimpleTextInReset;
990 Private->SimpleTextIn.ReadKeyStroke = WinNtGopSimpleTextInReadKeyStroke;
991
992 Status = gBS->CreateEvent (
993 EVT_NOTIFY_WAIT,
994 TPL_NOTIFY,
995 WinNtGopSimpleTextInWaitForKey,
996 Private,
997 &Private->SimpleTextIn.WaitForKey
998 );
999
1000
1001 Private->SimpleTextInEx.Reset = WinNtGopSimpleTextInExResetEx;
1002 Private->SimpleTextInEx.ReadKeyStrokeEx = WinNtGopSimpleTextInExReadKeyStrokeEx;
1003 Private->SimpleTextInEx.SetState = WinNtGopSimpleTextInExSetState;
1004 Private->SimpleTextInEx.RegisterKeyNotify = WinNtGopSimpleTextInExRegisterKeyNotify;
1005 Private->SimpleTextInEx.UnregisterKeyNotify = WinNtGopSimpleTextInExUnregisterKeyNotify;
1006
1007 Private->SimpleTextInEx.Reset (&Private->SimpleTextInEx, FALSE);
1008
1009 InitializeListHead (&Private->NotifyList);
1010
1011 Status = gBS->CreateEvent (
1012 EVT_NOTIFY_WAIT,
1013 TPL_NOTIFY,
1014 WinNtGopSimpleTextInWaitForKey,
1015 Private,
1016 &Private->SimpleTextInEx.WaitForKeyEx
1017 );
1018 ASSERT_EFI_ERROR (Status);
1019
1020 //
1021 // Create the Timer to trigger hot key notifications
1022 //
1023 Status = gBS->CreateEvent (
1024 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1025 TPL_NOTIFY,
1026 WinNtGopSimpleTextInTimerHandler,
1027 Private,
1028 &Private->TimerEvent
1029 );
1030 ASSERT_EFI_ERROR (Status);
1031
1032 Status = gBS->SetTimer (
1033 Private->TimerEvent,
1034 TimerPeriodic,
1035 KEYBOARD_TIMER_INTERVAL
1036 );
1037 ASSERT_EFI_ERROR (Status);
1038
1039 return Status;
1040 }
1041
1042
1043
1044 /**
1045 TODO: Add function description
1046
1047 @param Private TODO: add argument description
1048
1049 @retval EFI_SUCCESS TODO: Add description for return value
1050
1051 **/
1052 EFI_STATUS
1053 WinNtGopDestroySimpleTextInForWindow (
1054 IN GOP_PRIVATE_DATA *Private
1055 )
1056 {
1057 gBS->CloseEvent (Private->TimerEvent);
1058
1059 GopPrivateDestroyQ (Private, &Private->QueueForRead);
1060 GopPrivateDestroyQ (Private, &Private->QueueForNotify);
1061
1062 return EFI_SUCCESS;
1063 }