]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Nt32Pkg/WinNtGopDxe/WinNtGopInput.c
Nt32Pkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / Nt32Pkg / WinNtGopDxe / WinNtGopInput.c
index a604dad4e5d3c92a068442abf6ef2fa2499c8682..2e11ac11440bc8944cddd65ad87306badb0fa650 100644 (file)
@@ -1,13 +1,7 @@
 /** @file\r
 \r
-Copyright (c) 2006, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 Module Name:\r
 \r
@@ -28,30 +22,6 @@ Abstract:
 \r
 **/\r
 \r
-//\r
-// The package level header files this module uses\r
-//\r
-#include <Uefi.h>\r
-#include <WinNtDxe.h>\r
-//\r
-// The protocols, PPI and GUID defintions for this module\r
-//\r
-#include <Guid/EventGroup.h>\r
-#include <Protocol/WinNtIo.h>\r
-#include <Protocol/ComponentName.h>\r
-#include <Protocol/SimpleTextIn.h>\r
-#include <Protocol/DriverBinding.h>\r
-#include <Protocol/GraphicsOutput.h>\r
-//\r
-// The Library classes this module consumes\r
-//\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/UefiDriverEntryPoint.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
 \r
 #include "WinNtGop.h"\r
 \r
@@ -66,14 +36,13 @@ Abstract:
 **/\r
 EFI_STATUS\r
 GopPrivateCreateQ (\r
-  IN  GOP_PRIVATE_DATA    *Private\r
+  IN  GOP_PRIVATE_DATA    *Private,\r
+  IN  GOP_QUEUE_FIXED     *Queue\r
   )\r
 {\r
-  Private->WinNtThunk->InitializeCriticalSection (&Private->QCriticalSection);\r
-\r
-  Private->Queue.Front  = 0;\r
-  Private->Queue.Rear   = MAX_Q - 1;\r
-  Private->Queue.Count  = 0;\r
+  Private->WinNtThunk->InitializeCriticalSection (&Queue->Cs);\r
+  Queue->Front = 0;\r
+  Queue->Rear  = 0;\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -88,11 +57,13 @@ GopPrivateCreateQ (
 **/\r
 EFI_STATUS\r
 GopPrivateDestroyQ (\r
-  IN  GOP_PRIVATE_DATA    *Private\r
+  IN  GOP_PRIVATE_DATA    *Private,\r
+  IN  GOP_QUEUE_FIXED     *Queue\r
   )\r
 {\r
-  Private->Queue.Count = 0;\r
-  Private->WinNtThunk->DeleteCriticalSection (&Private->QCriticalSection);\r
+  Queue->Front = 0;\r
+  Queue->Rear  = 0;\r
+  Private->WinNtThunk->DeleteCriticalSection (&Queue->Cs);\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -109,22 +80,22 @@ GopPrivateDestroyQ (
 **/\r
 EFI_STATUS\r
 GopPrivateAddQ (\r
-  IN  GOP_PRIVATE_DATA    *Private,\r
-  IN  EFI_INPUT_KEY       Key\r
+  IN GOP_PRIVATE_DATA     *Private,\r
+  IN GOP_QUEUE_FIXED      *Queue,\r
+  IN EFI_KEY_DATA         *KeyData\r
   )\r
 {\r
-  Private->WinNtThunk->EnterCriticalSection (&Private->QCriticalSection);\r
+  Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);\r
 \r
-  if (Private->Queue.Count == MAX_Q) {\r
-    Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+  if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {\r
+    Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
     return EFI_NOT_READY;\r
   }\r
 \r
-  Private->Queue.Rear                   = (Private->Queue.Rear + 1) % MAX_Q;\r
-  Private->Queue.Q[Private->Queue.Rear] = Key;\r
-  Private->Queue.Count++;\r
+  CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));\r
+  Queue->Rear           = (Queue->Rear + 1) % MAX_Q;\r
 \r
-  Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+  Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -142,21 +113,31 @@ GopPrivateAddQ (
 EFI_STATUS\r
 GopPrivateDeleteQ (\r
   IN  GOP_PRIVATE_DATA    *Private,\r
-  OUT EFI_INPUT_KEY       *Key\r
+  IN  GOP_QUEUE_FIXED     *Queue,\r
+  OUT EFI_KEY_DATA        *Key\r
   )\r
 {\r
-  Private->WinNtThunk->EnterCriticalSection (&Private->QCriticalSection);\r
+  Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);\r
 \r
-  if (Private->Queue.Count == 0) {\r
-    Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+  if (Queue->Front == Queue->Rear) {\r
+    Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
     return EFI_NOT_READY;\r
   }\r
 \r
-  *Key                  = Private->Queue.Q[Private->Queue.Front];\r
-  Private->Queue.Front  = (Private->Queue.Front + 1) % MAX_Q;\r
-  Private->Queue.Count--;\r
-\r
-  Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+  CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));\r
+  Queue->Front  = (Queue->Front + 1) % MAX_Q;\r
+\r
+  if (Key->Key.ScanCode == SCAN_NULL && Key->Key.UnicodeChar == CHAR_NULL) {\r
+    if (!Private->IsPartialKeySupport) {\r
+      //\r
+      // If partial keystrok is not enabled, don't return the partial keystroke.\r
+      //\r
+      Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
+      ZeroMem (Key, sizeof (EFI_KEY_DATA));\r
+      return EFI_NOT_READY;\r
+    }\r
+  }\r
+  Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -172,42 +153,281 @@ GopPrivateDeleteQ (
 **/\r
 EFI_STATUS\r
 GopPrivateCheckQ (\r
-  IN  GOP_PRIVATE_DATA    *Private\r
+  IN  GOP_QUEUE_FIXED     *Queue\r
   )\r
 {\r
-  if (Private->Queue.Count == 0) {\r
+  if (Queue->Front == Queue->Rear) {\r
     return EFI_NOT_READY;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
-//\r
-// Simple Text In implementation.\r
-//\r
+BOOLEAN\r
+GopPrivateIsKeyRegistered (\r
+  IN EFI_KEY_DATA  *RegsiteredData,\r
+  IN EFI_KEY_DATA  *InputData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+  RegsiteredData    - A pointer to a buffer that is filled in with the keystroke\r
+                      state data for the key that was registered.\r
+  InputData         - A pointer to a buffer that is filled in with the keystroke\r
+                      state data for the key that was pressed.\r
+\r
+Returns:\r
+  TRUE              - Key be pressed matches a registered key.\r
+  FLASE             - Match failed.\r
+\r
+--*/\r
+{\r
+  ASSERT (RegsiteredData != NULL && InputData != NULL);\r
+\r
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||\r
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
+  //\r
+  if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
+      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
+    return FALSE;\r
+  }\r
+  if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
+      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+\r
+}\r
+\r
+\r
+VOID\r
+GopPrivateInvokeRegisteredFunction (\r
+  IN GOP_PRIVATE_DATA                     *Private,\r
+  IN EFI_KEY_DATA                         *KeyData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function updates the status light of NumLock, ScrollLock and CapsLock.\r
+\r
+Arguments:\r
 \r
+  Private       - The private structure of WinNt Gop device.\r
+  KeyData       - A pointer to a buffer that is filled in with the keystroke\r
+                  state data for the key that was pressed.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS   - The status light is updated successfully.\r
+\r
+--*/\r
+{\r
+  LIST_ENTRY                          *Link;\r
+  WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY  *CurrentNotify;\r
+\r
+  for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link,\r
+                      WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,\r
+                      NotifyEntry,\r
+                      WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
+      CurrentNotify->KeyNotificationFn (KeyData);\r
+    }\r
+  }\r
+}\r
+\r
+VOID\r
+WinNtGopSimpleTextInTimerHandler (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  GOP_PRIVATE_DATA  *Private;\r
+  EFI_KEY_DATA      KeyData;\r
+\r
+  Private = (GOP_PRIVATE_DATA *)Context;\r
+  while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS) {\r
+    GopPrivateInvokeRegisteredFunction (Private, &KeyData);\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize the key state.\r
+\r
+  @param  Private               The GOP_PRIVATE_DATA instance.\r
+  @param  KeyState              A pointer to receive the key state information.\r
+**/\r
+VOID\r
+InitializeKeyState (\r
+  IN  GOP_PRIVATE_DATA    *Private,\r
+  IN  EFI_KEY_STATE       *KeyState\r
+  )\r
+{\r
+  KeyState->KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
+  KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
+\r
+  //\r
+  // Record Key shift state and toggle state\r
+  //\r
+  if (Private->LeftCtrl) {\r
+    KeyState->KeyShiftState  |= EFI_LEFT_CONTROL_PRESSED;\r
+  }\r
+  if (Private->RightCtrl) {\r
+    KeyState->KeyShiftState  |= EFI_RIGHT_CONTROL_PRESSED;\r
+  }\r
+  if (Private->LeftAlt) {\r
+    KeyState->KeyShiftState  |= EFI_LEFT_ALT_PRESSED;\r
+  }\r
+  if (Private->RightAlt) {\r
+    KeyState->KeyShiftState  |= EFI_RIGHT_ALT_PRESSED;\r
+  }\r
+  if (Private->LeftShift) {\r
+    KeyState->KeyShiftState  |= EFI_LEFT_SHIFT_PRESSED;\r
+  }\r
+  if (Private->RightShift) {\r
+    KeyState->KeyShiftState  |= EFI_RIGHT_SHIFT_PRESSED;\r
+  }\r
+  if (Private->LeftLogo) {\r
+    KeyState->KeyShiftState  |= EFI_LEFT_LOGO_PRESSED;\r
+  }\r
+  if (Private->RightLogo) {\r
+    KeyState->KeyShiftState  |= EFI_RIGHT_LOGO_PRESSED;\r
+  }\r
+  if (Private->Menu) {\r
+    KeyState->KeyShiftState  |= EFI_MENU_KEY_PRESSED;\r
+  }\r
+  if (Private->SysReq) {\r
+    KeyState->KeyShiftState  |= EFI_SYS_REQ_PRESSED;\r
+  }\r
+  if (Private->CapsLock) {\r
+    KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
+  }\r
+  if (Private->NumLock) {\r
+    KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;\r
+  }\r
+  if (Private->ScrollLock) {\r
+    KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;\r
+  }\r
+  if (Private->IsPartialKeySupport) {\r
+    KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;\r
+  }\r
+}\r
 \r
 /**\r
   TODO: Add function description\r
 \r
-  @param  This                  TODO: add argument description\r
-  @param  ExtendedVerification  TODO: add argument description\r
+  @param  Private               TODO: add argument description\r
+  @param  Key                   TODO: add argument description\r
 \r
+  @retval EFI_NOT_READY         TODO: Add description for return value\r
   @retval EFI_SUCCESS           TODO: Add description for return value\r
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
-WinNtGopSimpleTextInReset (\r
-  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL          *This,\r
-  IN BOOLEAN                              ExtendedVerification\r
+GopPrivateAddKey (\r
+  IN  GOP_PRIVATE_DATA    *Private,\r
+  IN  EFI_INPUT_KEY       Key\r
   )\r
 {\r
-  GOP_PRIVATE_DATA  *Private;\r
-  EFI_INPUT_KEY     Key;\r
-  EFI_TPL           OldTpl;\r
+  EFI_KEY_DATA            KeyData;\r
 \r
-  Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);\r
+  KeyData.Key = Key;\r
+  InitializeKeyState (Private, &KeyData.KeyState);\r
+\r
+  //\r
+  // Convert Ctrl+[1-26] to Ctrl+[A-Z]\r
+  //\r
+  if ((Private->LeftCtrl || Private->RightCtrl) &&\r
+      (KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)\r
+     ) {\r
+    if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {\r
+      KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);\r
+    } else {\r
+      KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Unmask the Shift bit for printable char\r
+  //\r
+  if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||\r
+      ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))\r
+     ) {\r
+    KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
+  }\r
+\r
+  GopPrivateAddQ (Private, &Private->QueueForNotify, &KeyData);\r
+\r
+  GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GopPrivateUpdateStatusLight (\r
+  IN GOP_PRIVATE_DATA                     *Private\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function updates the status light of NumLock, ScrollLock and CapsLock.\r
+\r
+Arguments:\r
+\r
+  Private       - The private structure of WinNt console In/Out.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS   - The status light is updated successfully.\r
+\r
+--*/\r
+{\r
+  //\r
+  // BUGBUG:Only SendInput/keybd_event function can toggle\r
+  // NumLock, CapsLock and ScrollLock keys.\r
+  // Neither of these functions is included in EFI_WIN_NT_THUNK_PROTOCOL.\r
+  // Thus, return immediately without operation.\r
+  //\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+EFI_STATUS\r
+GopPrivateResetWorker (\r
+  IN GOP_PRIVATE_DATA                     *Private\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function is a worker function for SimpleTextIn/SimpleTextInEx.Reset().\r
+\r
+Arguments:\r
+\r
+  Private     - WinNT GOP private structure\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - Reset successfully\r
+\r
+--*/\r
+{\r
+  EFI_KEY_DATA      KeyData;\r
+  EFI_TPL           OldTpl;\r
 \r
   //\r
   // Enter critical section\r
@@ -217,16 +437,140 @@ WinNtGopSimpleTextInReset (
   //\r
   // A reset is draining the Queue\r
   //\r
-  while (GopPrivateDeleteQ (Private, &Key) == EFI_SUCCESS)\r
+  while (GopPrivateDeleteQ (Private, &Private->QueueForRead, &KeyData) == EFI_SUCCESS)\r
+    ;\r
+  while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS)\r
     ;\r
 \r
+  Private->LeftShift               = FALSE;\r
+  Private->RightShift              = FALSE;\r
+  Private->LeftAlt                 = FALSE;\r
+  Private->RightAlt                = FALSE;\r
+  Private->LeftCtrl                = FALSE;\r
+  Private->RightCtrl               = FALSE;\r
+  Private->LeftLogo                = FALSE;\r
+  Private->RightLogo               = FALSE;\r
+  Private->Menu                    = FALSE;\r
+  Private->SysReq                  = FALSE;\r
+\r
+  Private->CapsLock                = FALSE;\r
+  Private->NumLock                 = FALSE;\r
+  Private->ScrollLock              = FALSE;\r
+  Private->IsPartialKeySupport     = FALSE;\r
+\r
+  Private->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
+  Private->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
+\r
   //\r
   // Leave critical section and return\r
   //\r
   gBS->RestoreTPL (OldTpl);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
+EFI_STATUS\r
+GopPrivateReadKeyStrokeWorker (\r
+  IN GOP_PRIVATE_DATA                   *Private,\r
+  OUT EFI_KEY_DATA                      *KeyData\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Reads the next keystroke from the input device. The WaitForKey Event can\r
+    be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+  Arguments:\r
+    Private    - The private structure of WinNt Gop device.\r
+    KeyData    - A pointer to a buffer that is filled in with the keystroke\r
+                 state data for the key that was pressed.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The keystroke information was returned.\r
+    EFI_NOT_READY         - There was no keystroke data availiable.\r
+    EFI_DEVICE_ERROR      - The keystroke information was not returned due to\r
+                            hardware errors.\r
+    EFI_INVALID_PARAMETER - KeyData is NULL.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_TPL                         OldTpl;\r
+\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Enter critical section\r
+  //\r
+  OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+  //\r
+  // Call hot key callback before telling caller there is a key available\r
+  //\r
+  WinNtGopSimpleTextInTimerHandler (NULL, Private);\r
+\r
+  ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
+  InitializeKeyState (Private, &KeyData->KeyState);\r
+\r
+  Status  = GopPrivateCheckQ (&Private->QueueForRead);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // If a Key press exists try and read it.\r
+    //\r
+    Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // If partial keystroke is not enabled, check whether it is value key. If not return\r
+      // EFI_NOT_READY.\r
+      //\r
+      if (!Private->IsPartialKeySupport) {\r
+        if (KeyData->Key.ScanCode == SCAN_NULL && KeyData->Key.UnicodeChar == CHAR_NULL) {\r
+          Status = EFI_NOT_READY;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Leave critical section and return\r
+  //\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+\r
+//\r
+// Simple Text In implementation.\r
+//\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  This                  TODO: add argument description\r
+  @param  ExtendedVerification  TODO: add argument description\r
+\r
+  @retval EFI_SUCCESS           TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInReset (\r
+  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL          *This,\r
+  IN BOOLEAN                              ExtendedVerification\r
+  )\r
+{\r
+  GOP_PRIVATE_DATA  *Private;\r
+\r
+  Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);\r
+\r
+  return GopPrivateResetWorker (Private);\r
+}\r
+\r
 \r
 /**\r
   TODO: Add function description\r
@@ -237,7 +581,6 @@ WinNtGopSimpleTextInReset (
   @return TODO: add return values\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 WinNtGopSimpleTextInReadKeyStroke (\r
@@ -247,29 +590,35 @@ WinNtGopSimpleTextInReadKeyStroke (
 {\r
   GOP_PRIVATE_DATA  *Private;\r
   EFI_STATUS        Status;\r
-  EFI_TPL           OldTpl;\r
+  EFI_KEY_DATA      KeyData;\r
 \r
   Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);\r
-\r
   //\r
-  // Enter critical section\r
+  // Considering if the partial keystroke is enabled, there maybe a partial\r
+  // keystroke in the queue, so here skip the partial keystroke and get the\r
+  // next key from the queue\r
   //\r
-  OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
-  Status  = GopPrivateCheckQ (Private);\r
-  if (!EFI_ERROR (Status)) {\r
+  while (1) {\r
+    Status = GopPrivateReadKeyStrokeWorker (Private, &KeyData);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
+      continue;\r
+    }\r
     //\r
-    // If a Key press exists try and read it.\r
+    // Convert Ctrl+[A-Z] to Ctrl+[1-26]\r
     //\r
-    Status = GopPrivateDeleteQ (Private, Key);\r
-  }\r
-\r
-  //\r
-  // Leave critical section and return\r
-  //\r
-  gBS->RestoreTPL (OldTpl);\r
-\r
-  return Status;\r
+    if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
+      if ((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) {\r
+        KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
+      } else if ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z')) {\r
+        KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
+      }\r
+    }\r
+    CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+    return EFI_SUCCESS;\r
+  }  \r
 }\r
 \r
 \r
@@ -282,7 +631,6 @@ WinNtGopSimpleTextInReadKeyStroke (
   @return TODO: add return values\r
 \r
 **/\r
-STATIC\r
 VOID\r
 EFIAPI\r
 WinNtGopSimpleTextInWaitForKey (\r
@@ -293,6 +641,7 @@ WinNtGopSimpleTextInWaitForKey (
   GOP_PRIVATE_DATA  *Private;\r
   EFI_STATUS        Status;\r
   EFI_TPL           OldTpl;\r
+  EFI_KEY_DATA      KeyData;\r
 \r
   Private = (GOP_PRIVATE_DATA *) Context;\r
 \r
@@ -301,20 +650,39 @@ WinNtGopSimpleTextInWaitForKey (
   //\r
   OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);\r
 \r
-  Status  = GopPrivateCheckQ (Private);\r
-  if (!EFI_ERROR (Status)) {\r
-    //\r
-    // If a there is a key in the queue signal our event.\r
-    //\r
-    gBS->SignalEvent (Event);\r
-  } else {\r
-    //\r
-    // We need to sleep or NT will schedule this thread with such high\r
-    // priority that WinProc thread will never run and we will not see\r
-    // keyboard input. This Sleep makes the syste run 10x faster, so don't\r
-    // remove it.\r
-    //\r
-    Private->WinNtThunk->Sleep (1);\r
+  //\r
+  // Call hot key callback before telling caller there is a key available\r
+  //\r
+  WinNtGopSimpleTextInTimerHandler (NULL, Private);\r
+  \r
+  //\r
+  // WaitforKey doesn't suppor the partial key.\r
+  // Considering if the partial keystroke is enabled, there maybe a partial\r
+  // keystroke in the queue, so here skip the partial keystroke and get the\r
+  // next key from the queue\r
+  //\r
+  while (1) {\r
+    Status  = GopPrivateCheckQ (&Private->QueueForRead);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // If a there is a key in the queue and it is not partial keystroke,  signal event.\r
+      //\r
+      if (Private->QueueForRead.Q[Private->QueueForRead.Front].Key.ScanCode == SCAN_NULL &&\r
+        Private->QueueForRead.Q[Private->QueueForRead.Front].Key.UnicodeChar == CHAR_NULL) {\r
+        GopPrivateDeleteQ (Private,&Private->QueueForRead,&KeyData);\r
+        continue;\r
+      }\r
+      gBS->SignalEvent (Event);\r
+    } else {\r
+      //\r
+      // We need to sleep or NT will schedule this thread with such high\r
+      // priority that WinProc thread will never run and we will not see\r
+      // keyboard input. This Sleep makes the syste run 10x faster, so don't\r
+      // remove it.\r
+      //\r
+      Private->WinNtThunk->Sleep (1);\r
+    }\r
+    break;\r
   }\r
 \r
   //\r
@@ -323,6 +691,273 @@ WinNtGopSimpleTextInWaitForKey (
   gBS->RestoreTPL (OldTpl);\r
 }\r
 \r
+//\r
+// Simple Text Input Ex protocol functions\r
+//\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExResetEx (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN BOOLEAN                            ExtendedVerification\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Reset the input device and optionaly run diagnostics\r
+\r
+  Arguments:\r
+    This                 - Protocol instance pointer.\r
+    ExtendedVerification - Driver may perform diagnostics on reset.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The device was reset.\r
+\r
+--*/\r
+{\r
+  GOP_PRIVATE_DATA *Private;\r
+\r
+  Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+  return GopPrivateResetWorker (Private);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExReadKeyStrokeEx (\r
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+  OUT EFI_KEY_DATA                      *KeyData\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Reads the next keystroke from the input device. The WaitForKey Event can\r
+    be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+  Arguments:\r
+    This       - Protocol instance pointer.\r
+    KeyData    - A pointer to a buffer that is filled in with the keystroke\r
+                 state data for the key that was pressed.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The keystroke information was returned.\r
+    EFI_NOT_READY         - There was no keystroke data availiable.\r
+    EFI_DEVICE_ERROR      - The keystroke information was not returned due to\r
+                            hardware errors.\r
+    EFI_INVALID_PARAMETER - KeyData is NULL.\r
+\r
+--*/\r
+{\r
+  GOP_PRIVATE_DATA *Private;\r
+\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+  return GopPrivateReadKeyStrokeWorker (Private, KeyData);\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExSetState (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Set certain state for the input device.\r
+\r
+  Arguments:\r
+    This                  - Protocol instance pointer.\r
+    KeyToggleState        - A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
+                            state for the input device.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The device state was set successfully.\r
+    EFI_DEVICE_ERROR      - The device is not functioning correctly and could\r
+                            not have the setting adjusted.\r
+    EFI_UNSUPPORTED       - The device does not have the ability to set its state.\r
+    EFI_INVALID_PARAMETER - KeyToggleState is NULL.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                      Status;\r
+  GOP_PRIVATE_DATA                *Private;\r
+\r
+  if (KeyToggleState == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+  if (((Private->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||\r
+      ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Private->ScrollLock          = FALSE;\r
+  Private->NumLock             = FALSE;\r
+  Private->CapsLock            = FALSE;\r
+  Private->IsPartialKeySupport = FALSE;\r
+\r
+  if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
+    Private->ScrollLock = TRUE;\r
+  }\r
+  if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
+    Private->NumLock = TRUE;\r
+  }\r
+  if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
+    Private->CapsLock = TRUE;\r
+  }\r
+  if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {\r
+    Private->IsPartialKeySupport = TRUE;\r
+  }\r
+\r
+  Status = GopPrivateUpdateStatusLight (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Private->KeyState.KeyToggleState = *KeyToggleState;\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExRegisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_DATA                       *KeyData,\r
+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
+  OUT VOID                              **NotifyHandle\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Register a notification function for a particular keystroke for the input device.\r
+\r
+  Arguments:\r
+    This                    - Protocol instance pointer.\r
+    KeyData                 - A pointer to a buffer that is filled in with the keystroke\r
+                              information data for the key that was pressed.\r
+    KeyNotificationFunction - Points to the function to be called when the key\r
+                              sequence is typed specified by KeyData.\r
+    NotifyHandle            - Points to the unique handle assigned to the registered notification.\r
+\r
+  Returns:\r
+    EFI_SUCCESS             - The notification function was registered successfully.\r
+    EFI_OUT_OF_RESOURCES    - Unable to allocate resources for necesssary data structures.\r
+    EFI_INVALID_PARAMETER   - KeyData or NotifyHandle is NULL.\r
+\r
+--*/\r
+{\r
+  GOP_PRIVATE_DATA                   *Private;\r
+  WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;\r
+  LIST_ENTRY                         *Link;\r
+  WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *NewNotify;\r
+\r
+  if (KeyData == NULL || KeyNotificationFunction == NULL || NotifyHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+  //\r
+  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
+  //\r
+  for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link,\r
+                      WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,\r
+                      NotifyEntry,\r
+                      WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
+        *NotifyHandle = CurrentNotify;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate resource to save the notification function\r
+  //\r
+  NewNotify = (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *) AllocateZeroPool (sizeof (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY));\r
+  if (NewNotify == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewNotify->Signature         = WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE;\r
+  NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
+  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
+  InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);\r
+\r
+  *NotifyHandle = NewNotify;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExUnregisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN VOID                               *NotificationHandle\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Remove a registered notification function from a particular keystroke.\r
+\r
+  Arguments:\r
+    This                    - Protocol instance pointer.\r
+    NotificationHandle      - The handle of the notification function being unregistered.\r
+\r
+  Returns:\r
+    EFI_SUCCESS             - The notification function was unregistered successfully.\r
+    EFI_INVALID_PARAMETER   - The NotificationHandle is invalid.\r
+\r
+--*/\r
+{\r
+  GOP_PRIVATE_DATA                   *Private;\r
+  LIST_ENTRY                         *Link;\r
+  WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;\r
+\r
+  if (NotificationHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+  for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link,\r
+                      WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,\r
+                      NotifyEntry,\r
+                      WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (CurrentNotify == NotificationHandle) {\r
+      //\r
+      // Remove the notification function from NotifyList and free resources\r
+      //\r
+      RemoveEntryList (&CurrentNotify->NotifyEntry);\r
+\r
+      gBS->FreePool (CurrentNotify);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Can not find the specified Notification Handle\r
+  //\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
 \r
 /**\r
   TODO: Add function description\r
@@ -339,7 +974,8 @@ WinNtGopInitializeSimpleTextInForWindow (
 {\r
   EFI_STATUS  Status;\r
 \r
-  GopPrivateCreateQ (Private);\r
+  GopPrivateCreateQ (Private, &Private->QueueForRead);\r
+  GopPrivateCreateQ (Private, &Private->QueueForNotify);\r
 \r
   //\r
   // Initialize Simple Text In protoocol\r
@@ -355,10 +991,50 @@ WinNtGopInitializeSimpleTextInForWindow (
                   &Private->SimpleTextIn.WaitForKey\r
                   );\r
 \r
+\r
+  Private->SimpleTextInEx.Reset               = WinNtGopSimpleTextInExResetEx;\r
+  Private->SimpleTextInEx.ReadKeyStrokeEx     = WinNtGopSimpleTextInExReadKeyStrokeEx;\r
+  Private->SimpleTextInEx.SetState            = WinNtGopSimpleTextInExSetState;\r
+  Private->SimpleTextInEx.RegisterKeyNotify   = WinNtGopSimpleTextInExRegisterKeyNotify;\r
+  Private->SimpleTextInEx.UnregisterKeyNotify = WinNtGopSimpleTextInExUnregisterKeyNotify;\r
+\r
+  Private->SimpleTextInEx.Reset (&Private->SimpleTextInEx, FALSE);\r
+\r
+  InitializeListHead (&Private->NotifyList);\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_NOTIFY,\r
+                  WinNtGopSimpleTextInWaitForKey,\r
+                  Private,\r
+                  &Private->SimpleTextInEx.WaitForKeyEx\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Create the Timer to trigger hot key notifications\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  WinNtGopSimpleTextInTimerHandler,\r
+                  Private,\r
+                  &Private->TimerEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->SetTimer (\r
+                  Private->TimerEvent,\r
+                  TimerPeriodic,\r
+                  KEYBOARD_TIMER_INTERVAL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   return Status;\r
 }\r
 \r
 \r
+\r
 /**\r
   TODO: Add function description\r
 \r
@@ -372,6 +1048,10 @@ WinNtGopDestroySimpleTextInForWindow (
   IN  GOP_PRIVATE_DATA    *Private\r
   )\r
 {\r
-  GopPrivateDestroyQ (Private);\r
+  gBS->CloseEvent (Private->TimerEvent);\r
+\r
+  GopPrivateDestroyQ (Private, &Private->QueueForRead);\r
+  GopPrivateDestroyQ (Private, &Private->QueueForNotify);\r
+\r
   return EFI_SUCCESS;\r
 }\r