]> git.proxmox.com Git - mirror_edk2.git/commitdiff
EmulatorPkg/Win: Add input/output support
authorRuiyu Ni <ruiyu.ni@intel.com>
Thu, 23 Aug 2018 05:33:54 +0000 (13:33 +0800)
committerRuiyu Ni <ruiyu.ni@intel.com>
Mon, 27 Aug 2018 07:20:54 +0000 (15:20 +0800)
The patch adds GOP and SimpleTextIn[Ex] support.
Now firmware can boot to UI and Shell but timer doesn't work.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Andrew Fish <afish@apple.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
EmulatorPkg/Win/Host/WinGop.h [new file with mode: 0644]
EmulatorPkg/Win/Host/WinGopInput.c [new file with mode: 0644]
EmulatorPkg/Win/Host/WinGopScreen.c [new file with mode: 0644]
EmulatorPkg/Win/Host/WinHost.c
EmulatorPkg/Win/Host/WinHost.h
EmulatorPkg/Win/Host/WinHost.inf

diff --git a/EmulatorPkg/Win/Host/WinGop.h b/EmulatorPkg/Win/Host/WinGop.h
new file mode 100644 (file)
index 0000000..de27238
--- /dev/null
@@ -0,0 +1,205 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+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
+\r
+Module Name:\r
+\r
+  WinGop.h\r
+\r
+Abstract:\r
+\r
+  Private data for the Gop driver that is bound to the WinNt Thunk protocol\r
+\r
+\r
+**/\r
+\r
+#ifndef _WIN_GOP_H_\r
+#define _WIN_GOP_H_\r
+\r
+\r
+#include "WinHost.h"\r
+\r
+#include <Protocol/EmuIoThunk.h>\r
+#include <Protocol/EmuGraphicsWindow.h>\r
+#include <Protocol/SimpleTextIn.h>\r
+#include <Protocol/SimpleTextInEx.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+\r
+//\r
+// WM_SYSKEYDOWN/WM_SYSKEYUP Notification\r
+// lParam\r
+// bit 24: Specifies whether the key is an extended key,\r
+// such as the right-hand ALT and CTRL keys that appear on\r
+// an enhanced 101- or 102-key keyboard.\r
+// The value is 1 if it is an extended key; otherwise, it is 0.\r
+// bit 29:Specifies the context code.\r
+// The value is 1 if the ALT key is down while the key is pressed/released;\r
+// it is 0 if the WM_SYSKEYDOWN message is posted to the active window\r
+// because no window has the keyboard focus.\r
+#define GOP_EXTENDED_KEY         (0x1 << 24)\r
+#define GOP_ALT_KEY_PRESSED      (0x1 << 29)\r
+\r
+#define KEYBOARD_TIMER_INTERVAL         200000  // 0.02s\r
+\r
+#define MAX_Q 256\r
+\r
+typedef struct {\r
+  UINTN             Front;\r
+  UINTN             Rear;\r
+  EFI_KEY_DATA      Q[MAX_Q];\r
+  CRITICAL_SECTION  Cs;\r
+} GOP_QUEUE_FIXED;\r
+\r
+#define WIN_NT_GOP_CLASS_NAME       L"WinNtGopWindow"\r
+\r
+\r
+typedef struct {\r
+  UINT64                        Signature;\r
+  EMU_GRAPHICS_WINDOW_PROTOCOL  GraphicsWindowIo;\r
+\r
+  //\r
+  // GOP Private Data knowing when to start hardware\r
+  //\r
+  BOOLEAN                       HardwareNeedsStarting;\r
+\r
+  CHAR16                        *WindowName;\r
+  CHAR16                        Buffer[160];\r
+\r
+  HANDLE                        ThreadInited; // Semaphore\r
+  HANDLE                        ThreadHandle; // Thread\r
+  DWORD                         ThreadId;\r
+\r
+  HWND                          WindowHandle;\r
+  WNDCLASSEX                    WindowsClass;\r
+\r
+  UINT32                        Width;\r
+  UINT32                        Height;\r
+  //\r
+  // This screen is used to redraw the scree when windows events happen. It's\r
+  // updated in the main thread and displayed in the windows thread.\r
+  //\r
+  BITMAPV4HEADER                *VirtualScreenInfo;\r
+  RGBQUAD                       *VirtualScreen;\r
+\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillLine;\r
+\r
+  //\r
+  // Keyboard Queue used by Simple Text In.\r
+  // QueueForRead:   WinProc thread adds, and main thread removes.\r
+  //\r
+  GOP_QUEUE_FIXED               QueueForRead;\r
+\r
+  EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    MakeRegisterdKeyCallback;\r
+  EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    BreakRegisterdKeyCallback;\r
+  VOID                                                *RegisterdKeyCallbackContext;\r
+\r
+  EFI_KEY_STATE                     KeyState;\r
+  BOOLEAN                           LeftShift;\r
+  BOOLEAN                           RightShift;\r
+  BOOLEAN                           LeftAlt;\r
+  BOOLEAN                           RightAlt;\r
+  BOOLEAN                           LeftCtrl;\r
+  BOOLEAN                           RightCtrl;\r
+  BOOLEAN                           LeftLogo;\r
+  BOOLEAN                           RightLogo;\r
+  BOOLEAN                           Menu;\r
+  BOOLEAN                           SysReq;\r
+  BOOLEAN                           NumLock;\r
+  BOOLEAN                           ScrollLock;\r
+  BOOLEAN                           CapsLock;\r
+  BOOLEAN                           IsPartialKeySupport;\r
+} GRAPHICS_PRIVATE_DATA;\r
+#define GRAPHICS_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('g', 'f', 'x', 'd')\r
+#define GRAPHICS_PRIVATE_DATA_FROM_THIS(a)  \\r
+         CR(a, GRAPHICS_PRIVATE_DATA, GraphicsWindowIo, GRAPHICS_PRIVATE_DATA_SIGNATURE)\r
+\r
+\r
+//\r
+// Gop Hardware abstraction internal worker functions\r
+//\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Private              TODO: add argument description\r
+  @param  Key                  TODO: add argument description\r
+\r
+  @return TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+GopPrivateAddKey (\r
+  IN  GRAPHICS_PRIVATE_DATA    *Private,\r
+  IN  EFI_INPUT_KEY            Key\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndGetKey (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,\r
+  IN  EFI_KEY_DATA                  *KeyData\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndCheckKey (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndKeySetState (\r
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL   *GraphicsIo,\r
+  IN EFI_KEY_TOGGLE_STATE           *KeyToggleState\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndRegisterKeyNotify (\r
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL                        *GraphicsIo,\r
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    MakeCallBack,\r
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    BreakCallBack,\r
+  IN VOID                                                *Context\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndCheckPointer (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndGetPointerState (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,\r
+  IN  EFI_SIMPLE_POINTER_STATE      *State\r
+  );\r
+EFI_STATUS\r
+GopPrivateCreateQ (\r
+  IN  GRAPHICS_PRIVATE_DATA    *Private,\r
+  IN GOP_QUEUE_FIXED           *Queue\r
+  );\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Private               TODO: add argument description\r
+\r
+  @retval EFI_SUCCESS           TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+GopPrivateDestroyQ (\r
+  IN  GRAPHICS_PRIVATE_DATA    *Private,\r
+  IN GOP_QUEUE_FIXED           *Queue\r
+  );\r
+#endif\r
+\r
diff --git a/EmulatorPkg/Win/Host/WinGopInput.c b/EmulatorPkg/Win/Host/WinGopInput.c
new file mode 100644 (file)
index 0000000..6c218ab
--- /dev/null
@@ -0,0 +1,417 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+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
+\r
+Module Name:\r
+\r
+  WinGopInput.c\r
+\r
+Abstract:\r
+\r
+  This file produces the Simple Text In for an Gop window.\r
+\r
+  This stuff is linked at the hip to the Window, since the window\r
+  processing is done in a thread kicked off in WinNtGopImplementation.c\r
+\r
+  Since the window information is processed in an other thread we need\r
+  a keyboard Queue to pass data about. The Simple Text In code just\r
+  takes data off the Queue. The WinProc message loop takes keyboard input\r
+  and places it in the Queue.\r
+\r
+\r
+**/\r
+\r
+\r
+#include "WinGop.h"\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Private               TODO: add argument description\r
+\r
+  @retval EFI_SUCCESS           TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+GopPrivateCreateQ (\r
+  IN  GRAPHICS_PRIVATE_DATA    *Private,\r
+  IN GOP_QUEUE_FIXED           *Queue\r
+  )\r
+{\r
+  InitializeCriticalSection (&Queue->Cs);\r
+  Queue->Front = 0;\r
+  Queue->Rear  = 0;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Private               TODO: add argument description\r
+\r
+  @retval EFI_SUCCESS           TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+GopPrivateDestroyQ (\r
+  IN  GRAPHICS_PRIVATE_DATA    *Private,\r
+  IN GOP_QUEUE_FIXED           *Queue\r
+  )\r
+{\r
+  Queue->Front = 0;\r
+  Queue->Rear  = 0;\r
+  DeleteCriticalSection (&Queue->Cs);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\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
+GopPrivateAddQ (\r
+  IN  GRAPHICS_PRIVATE_DATA    *Private,\r
+  IN GOP_QUEUE_FIXED           *Queue,\r
+  IN EFI_KEY_DATA              *KeyData\r
+  )\r
+{\r
+  EnterCriticalSection (&Queue->Cs);\r
+\r
+  if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {\r
+    LeaveCriticalSection (&Queue->Cs);\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));\r
+  Queue->Rear           = (Queue->Rear + 1) % MAX_Q;\r
+\r
+  LeaveCriticalSection (&Queue->Cs);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\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
+GopPrivateDeleteQ (\r
+  IN  GRAPHICS_PRIVATE_DATA    *Private,\r
+  IN  GOP_QUEUE_FIXED          *Queue,\r
+  OUT EFI_KEY_DATA             *Key\r
+  )\r
+{\r
+  EnterCriticalSection (&Queue->Cs);\r
+\r
+  if (Queue->Front == Queue->Rear) {\r
+    LeaveCriticalSection (&Queue->Cs);\r
+    return EFI_NOT_READY;\r
+  }\r
+\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
+      LeaveCriticalSection (&Queue->Cs);\r
+      ZeroMem (Key, sizeof (EFI_KEY_DATA));\r
+      return EFI_NOT_READY;\r
+    }\r
+  }\r
+  LeaveCriticalSection (&Queue->Cs);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Private               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
+GopPrivateCheckQ (\r
+  IN  GOP_QUEUE_FIXED     *Queue\r
+  )\r
+{\r
+  if (Queue->Front == Queue->Rear) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  return EFI_SUCCESS;\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  GRAPHICS_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  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
+GopPrivateAddKey (\r
+  IN  GRAPHICS_PRIVATE_DATA  *Private,\r
+  IN  EFI_INPUT_KEY          Key\r
+  )\r
+{\r
+  EFI_KEY_DATA            KeyData;\r
+\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->QueueForRead, &KeyData);\r
+  if (Private->MakeRegisterdKeyCallback != NULL) {\r
+    Private->MakeRegisterdKeyCallback (Private->RegisterdKeyCallbackContext, &KeyData);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndCheckKey (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
+  )\r
+{\r
+  GRAPHICS_PRIVATE_DATA           *Private;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
+\r
+  return GopPrivateCheckQ (&Private->QueueForRead);\r
+\r
+}\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndGetKey (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,\r
+  IN  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
+  GRAPHICS_PRIVATE_DATA           *Private;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\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
+  return Status;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndKeySetState (\r
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL   *GraphicsIo,\r
+  IN EFI_KEY_TOGGLE_STATE           *KeyToggleState\r
+  )\r
+{\r
+  GRAPHICS_PRIVATE_DATA           *Private;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
+  Private->KeyState.KeyToggleState = *KeyToggleState;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndRegisterKeyNotify (\r
+  IN EMU_GRAPHICS_WINDOW_PROTOCOL                        *GraphicsIo,\r
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    MakeCallBack,\r
+  IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    BreakCallBack,\r
+  IN VOID                                                *Context\r
+  )\r
+{\r
+  GRAPHICS_PRIVATE_DATA           *Private;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
+\r
+  Private->MakeRegisterdKeyCallback    = MakeCallBack;\r
+  Private->BreakRegisterdKeyCallback   = BreakCallBack;\r
+  Private->RegisterdKeyCallbackContext = Context;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndCheckPointer (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
+  )\r
+{\r
+  GRAPHICS_PRIVATE_DATA           *Private;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
+\r
+  return EFI_NOT_READY;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndGetPointerState (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,\r
+  IN  EFI_SIMPLE_POINTER_STATE      *State\r
+  )\r
+{\r
+  GRAPHICS_PRIVATE_DATA           *Private;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
+\r
+  return EFI_NOT_READY;\r
+}\r
diff --git a/EmulatorPkg/Win/Host/WinGopScreen.c b/EmulatorPkg/Win/Host/WinGopScreen.c
new file mode 100644 (file)
index 0000000..2ca51d2
--- /dev/null
@@ -0,0 +1,872 @@
+/** @file\r
+\r
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+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
+\r
+Module Name:\r
+\r
+    WinGopScreen.c\r
+\r
+Abstract:\r
+\r
+  This file produces the graphics abstration of GOP. It is called by\r
+  WinNtGopDriver.c file which deals with the UEFI 2.0 driver model.\r
+  This file just does graphics.\r
+\r
+\r
+**/\r
+\r
+#include "WinGop.h"\r
+\r
+DWORD                     mTlsIndex         = TLS_OUT_OF_INDEXES;\r
+DWORD                     mTlsIndexUseCount = 0;  // lets us know when we can free mTlsIndex.\r
+\r
+BOOLEAN\r
+WinNtGopConvertParamToEfiKeyShiftState (\r
+  IN  GRAPHICS_PRIVATE_DATA  *Private,\r
+  IN  WPARAM                 *wParam,\r
+  IN  LPARAM                 *lParam,\r
+  IN  BOOLEAN                Flag\r
+  )\r
+{\r
+  switch (*wParam) {\r
+  //\r
+  // BUGBUG: Only GetAsyncKeyState() and GetKeyState() can distinguish\r
+  // left and right Ctrl, and Shift key.\r
+  // Neither of the two is defined in EFI_WIN_NT_THUNK_PROTOCOL.\r
+  // Therefor, we can not set the correct Shift state here.\r
+  //\r
+  case VK_SHIFT:\r
+    if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {\r
+        Private->RightShift = Flag;\r
+      } else {\r
+        Private->LeftShift = Flag;\r
+      }\r
+    return TRUE;\r
+\r
+  case VK_LSHIFT:\r
+    Private->LeftShift = Flag;\r
+    return TRUE;\r
+\r
+  case VK_RSHIFT:\r
+    Private->RightShift = Flag;\r
+    return TRUE;\r
+\r
+  case VK_CONTROL:\r
+    if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {\r
+        Private->RightCtrl= Flag;\r
+      } else {\r
+        Private->LeftCtrl = Flag;\r
+      }\r
+    return TRUE;\r
+\r
+  case VK_LCONTROL:\r
+    Private->LeftCtrl = Flag;\r
+    return TRUE;\r
+\r
+  case VK_RCONTROL:\r
+    Private->RightCtrl = Flag;\r
+    return TRUE;\r
+\r
+  case VK_LWIN:\r
+    Private->LeftLogo   = Flag;\r
+    return TRUE;\r
+\r
+  case VK_RWIN:\r
+    Private->RightLogo  = Flag;\r
+    return TRUE;\r
+\r
+  case VK_APPS:\r
+    Private->Menu       = Flag;\r
+    return TRUE;\r
+  //\r
+  // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message,\r
+  // so SySReq shift state is not supported here.\r
+  //\r
+  case VK_PRINT:\r
+    Private->SysReq     = Flag;\r
+    return TRUE;\r
+  //\r
+  // For Alt Keystroke.\r
+  //\r
+  case VK_MENU:\r
+    if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {\r
+        Private->RightAlt = Flag;\r
+      } else {\r
+        Private->LeftAlt = Flag;\r
+      }\r
+    return TRUE;\r
+\r
+  default:\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+BOOLEAN\r
+WinNtGopConvertParamToEfiKey (\r
+  IN  GRAPHICS_PRIVATE_DATA  *Private,\r
+  IN  WPARAM                 *wParam,\r
+  IN  LPARAM                 *lParam,\r
+  IN  EFI_INPUT_KEY          *Key\r
+  )\r
+{\r
+  BOOLEAN Flag;\r
+  Flag = FALSE;\r
+  switch (*wParam) {\r
+  case VK_HOME:       Key->ScanCode = SCAN_HOME;      Flag = TRUE; break;\r
+  case VK_END:        Key->ScanCode = SCAN_END;       Flag = TRUE; break;\r
+  case VK_LEFT:       Key->ScanCode = SCAN_LEFT;      Flag = TRUE; break;\r
+  case VK_RIGHT:      Key->ScanCode = SCAN_RIGHT;     Flag = TRUE; break;\r
+  case VK_UP:         Key->ScanCode = SCAN_UP;        Flag = TRUE; break;\r
+  case VK_DOWN:       Key->ScanCode = SCAN_DOWN;      Flag = TRUE; break;\r
+  case VK_DELETE:     Key->ScanCode = SCAN_DELETE;    Flag = TRUE; break;\r
+  case VK_INSERT:     Key->ScanCode = SCAN_INSERT;    Flag = TRUE; break;\r
+  case VK_PRIOR:      Key->ScanCode = SCAN_PAGE_UP;   Flag = TRUE; break;\r
+  case VK_NEXT:       Key->ScanCode = SCAN_PAGE_DOWN; Flag = TRUE; break;\r
+  case VK_ESCAPE:     Key->ScanCode = SCAN_ESC;       Flag = TRUE; break;\r
+\r
+  case VK_F1:         Key->ScanCode = SCAN_F1;    Flag = TRUE;     break;\r
+  case VK_F2:         Key->ScanCode = SCAN_F2;    Flag = TRUE;     break;\r
+  case VK_F3:         Key->ScanCode = SCAN_F3;    Flag = TRUE;     break;\r
+  case VK_F4:         Key->ScanCode = SCAN_F4;    Flag = TRUE;     break;\r
+  case VK_F5:         Key->ScanCode = SCAN_F5;    Flag = TRUE;     break;\r
+  case VK_F6:         Key->ScanCode = SCAN_F6;    Flag = TRUE;     break;\r
+  case VK_F7:         Key->ScanCode = SCAN_F7;    Flag = TRUE;     break;\r
+  case VK_F8:         Key->ScanCode = SCAN_F8;    Flag = TRUE;     break;\r
+  case VK_F9:         Key->ScanCode = SCAN_F9;    Flag = TRUE;     break;\r
+  case VK_F11:        Key->ScanCode = SCAN_F11;   Flag = TRUE;     break;\r
+  case VK_F12:        Key->ScanCode = SCAN_F12;   Flag = TRUE;     break;\r
+\r
+  case VK_F13:        Key->ScanCode = SCAN_F13;   Flag = TRUE;     break;\r
+  case VK_F14:        Key->ScanCode = SCAN_F14;   Flag = TRUE;     break;\r
+  case VK_F15:        Key->ScanCode = SCAN_F15;   Flag = TRUE;     break;\r
+  case VK_F16:        Key->ScanCode = SCAN_F16;   Flag = TRUE;     break;\r
+  case VK_F17:        Key->ScanCode = SCAN_F17;   Flag = TRUE;     break;\r
+  case VK_F18:        Key->ScanCode = SCAN_F18;   Flag = TRUE;     break;\r
+  case VK_F19:        Key->ScanCode = SCAN_F19;   Flag = TRUE;     break;\r
+  case VK_F20:        Key->ScanCode = SCAN_F20;   Flag = TRUE;     break;\r
+  case VK_F21:        Key->ScanCode = SCAN_F21;   Flag = TRUE;     break;\r
+  case VK_F22:        Key->ScanCode = SCAN_F22;   Flag = TRUE;     break;\r
+  case VK_F23:        Key->ScanCode = SCAN_F23;   Flag = TRUE;     break;\r
+  case VK_F24:        Key->ScanCode = SCAN_F24;   Flag = TRUE;     break;\r
+  case VK_PAUSE:      Key->ScanCode = SCAN_PAUSE; Flag = TRUE;     break;\r
+\r
+  //\r
+  // Set toggle state\r
+  //\r
+  case VK_NUMLOCK:\r
+    Private->NumLock    = (BOOLEAN)(!Private->NumLock);\r
+    Flag = TRUE;\r
+    break;\r
+  case VK_SCROLL:\r
+    Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock);\r
+    Flag = TRUE;\r
+    break;\r
+  case VK_CAPITAL:\r
+    Private->CapsLock   = (BOOLEAN)(!Private->CapsLock);\r
+    Flag = TRUE;\r
+    break;\r
+  }\r
+\r
+  return (WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, lParam, TRUE)) == TRUE ? TRUE : Flag;\r
+}\r
+\r
+\r
+//\r
+// GOP Protocol Member Functions\r
+//\r
+\r
+/**\r
+  Change the resolution and resize of the window\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtWndSize (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,\r
+  IN  UINT32                        Width,\r
+  IN  UINT32                        Height\r
+)\r
+{\r
+  UINT32                            Size;\r
+  GRAPHICS_PRIVATE_DATA             *Private;\r
+  RECT                              Rect;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *NewFillLine;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
+  Private->Width  = Width;\r
+  Private->Height = Height;\r
+\r
+\r
+  //\r
+  // Free the old buffer. We do not save the content of the old buffer since the\r
+  // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.\r
+  // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()\r
+  //\r
+  if (Private->VirtualScreenInfo != NULL) {\r
+    HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);\r
+  }\r
+\r
+  //\r
+  // Allocate DIB frame buffer directly from NT for performance enhancement\r
+  // This buffer is the virtual screen/frame buffer. This buffer is not the\r
+  // same a a frame buffer. The first row of this buffer will be the bottom\r
+  // line of the image. This is an artifact of the way we draw to the screen.\r
+  //\r
+  Size = Private->Width * Private->Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);\r
+  Private->VirtualScreenInfo = HeapAlloc (\r
+    GetProcessHeap (),\r
+    HEAP_ZERO_MEMORY,\r
+    Size\r
+  );\r
+\r
+  //\r
+  // Update the virtual screen info data structure\r
+  //\r
+  Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);\r
+  Private->VirtualScreenInfo->bV4Width = Private->Width;\r
+  Private->VirtualScreenInfo->bV4Height = Private->Height;\r
+  Private->VirtualScreenInfo->bV4Planes = 1;\r
+  Private->VirtualScreenInfo->bV4BitCount = 32;\r
+  //\r
+  // uncompressed\r
+  //\r
+  Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;\r
+\r
+  //\r
+  // The rest of the allocated memory block is the virtual screen buffer\r
+  //\r
+  Private->VirtualScreen = (RGBQUAD *)(Private->VirtualScreenInfo + 1);\r
+\r
+  //\r
+  // Use the AdjuctWindowRect fuction to calculate the real width and height\r
+  // of the new window including the border and caption\r
+  //\r
+  Rect.left = 0;\r
+  Rect.top = 0;\r
+  Rect.right = Private->Width;\r
+  Rect.bottom = Private->Height;\r
+\r
+  AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);\r
+\r
+  Width  = Rect.right - Rect.left;\r
+  Height = Rect.bottom - Rect.top;\r
+\r
+  //\r
+  // Retrieve the original window position information\r
+  //\r
+  GetWindowRect (Private->WindowHandle, &Rect);\r
+\r
+  //\r
+  // Adjust the window size\r
+  //\r
+  MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE);\r
+\r
+  NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Private->Width);\r
+  if (NewFillLine == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (Private->FillLine != NULL) {\r
+    FreePool (Private->FillLine);\r
+  }\r
+\r
+  Private->FillLine = NewFillLine;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Blt pixels from the rectangle (Width X Height) formed by the BltBuffer\r
+  onto the graphics screen starting a location (X, Y). (0, 0) is defined as\r
+  the upper left hand side of the screen. (X, Y) can be outside of the\r
+  current screen geometry and the BltBuffer will be cliped when it is\r
+  displayed. X and Y can be negative or positive. If Width or Height is\r
+  bigger than the current video screen the image will be clipped.\r
+\r
+  @param  This                   Protocol instance pointer.\r
+  @param  X                      X location on graphics screen.\r
+  @param  Y                      Y location on the graphics screen.\r
+  @param  Width                  Width of BltBuffer.\r
+  @param  Height                 Hight of BltBuffer\r
+  @param  BltOperation           Operation to perform on BltBuffer and video memory\r
+  @param  BltBuffer              Buffer containing data to blt into video buffer.\r
+                                 This  buffer has a size of\r
+                                 Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
+  @param  SourceX                If the BltOperation is a EfiCopyBlt this is the\r
+                                 source of the copy. For other BLT operations this\r
+                                 argument is not used.\r
+  @param  SourceX                If the BltOperation is a EfiCopyBlt this is the\r
+                                 source of the copy. For other BLT operations this\r
+                                 argument is not used.\r
+\r
+  @retval EFI_SUCCESS            The palette is updated with PaletteArray.\r
+  @retval EFI_INVALID_PARAMETER  BltOperation is not valid.\r
+  @retval EFI_DEVICE_ERROR       A hardware error occured writting to the video\r
+                                 buffer.\r
+\r
+**/\r
+// TODO:    SourceY - add argument and description to function comment\r
+// TODO:    DestinationX - add argument and description to function comment\r
+// TODO:    DestinationY - add argument and description to function comment\r
+// TODO:    Delta - add argument and description to function comment\r
+EFI_STATUS\r
+WinNtWndBlt (\r
+  IN  EMU_GRAPHICS_WINDOW_PROTOCOL            *GraphicsIo,\r
+  IN  EFI_UGA_PIXEL                           *BltBuffer OPTIONAL,\r
+  IN  EFI_UGA_BLT_OPERATION                   BltOperation,\r
+  IN  EMU_GRAPHICS_WINDOWS__BLT_ARGS          *Args\r
+)\r
+{\r
+  GRAPHICS_PRIVATE_DATA         *Private;\r
+  UINTN                         DstY;\r
+  UINTN                         SrcY;\r
+  RGBQUAD                       *VScreen;\r
+  RGBQUAD                       *VScreenSrc;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
+  UINTN                         Index;\r
+  RECT                          Rect;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel;\r
+  UINT32                        VerticalResolution;\r
+  UINT32                        HorizontalResolution;\r
+\r
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
+\r
+  //\r
+  // We need to fill the Virtual Screen buffer with the blt data.\r
+  // The virtual screen is upside down, as the first row is the bootom row of\r
+  // the image.\r
+  //\r
+  VerticalResolution = Private->VirtualScreenInfo->bV4Height;\r
+  HorizontalResolution = Private->VirtualScreenInfo->bV4Width;\r
+  if (BltOperation == EfiBltVideoToBltBuffer) {\r
+\r
+    for (SrcY = Args->SourceY, DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); SrcY++, DstY++) {\r
+      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Args->Delta) + Args->DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+      VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];\r
+      CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Args->Width);\r
+    }\r
+  } else {\r
+    if (BltOperation == EfiBltVideoFill) {\r
+      FillPixel = BltBuffer;\r
+      for (Index = 0; Index < Args->Width; Index++) {\r
+        Private->FillLine[Index] = *FillPixel;\r
+      }\r
+    }\r
+\r
+    for (Index = 0; Index < Args->Height; Index++) {\r
+      if (Args->DestinationY <= Args->SourceY) {\r
+        SrcY  = Args->SourceY + Index;\r
+        DstY  = Args->DestinationY + Index;\r
+      } else {\r
+        SrcY  = Args->SourceY + Args->Height - Index - 1;\r
+        DstY  = Args->DestinationY + Args->Height - Index - 1;\r
+      }\r
+\r
+      VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + Args->DestinationX];\r
+      switch (BltOperation) {\r
+      case EfiBltBufferToVideo:\r
+        Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Args->Delta) + Args->SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+        CopyMem (VScreen, Blt, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+        break;\r
+\r
+      case EfiBltVideoToVideo:\r
+        VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];\r
+        CopyMem (VScreen, VScreenSrc, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+        break;\r
+\r
+      case EfiBltVideoFill:\r
+        CopyMem (VScreen, Private->FillLine, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (BltOperation != EfiBltVideoToBltBuffer) {\r
+    //\r
+    // Mark the area we just blted as Invalid so WM_PAINT will update.\r
+    //\r
+    Rect.left   = (LONG)Args->DestinationX;\r
+    Rect.top    = (LONG)Args->DestinationY;\r
+    Rect.right  = (LONG)(Args->DestinationX + Args->Width);\r
+    Rect.bottom = (LONG)(Args->DestinationY + Args->Height);\r
+    InvalidateRect (Private->WindowHandle, &Rect, FALSE);\r
+\r
+    //\r
+    // Send the WM_PAINT message to the thread that is drawing the window. We\r
+    // are in the main thread and the window drawing is in a child thread.\r
+    // There is a child thread per window. We have no CriticalSection or Mutex\r
+    // since we write the data and the other thread displays the data. While\r
+    // we may miss some data for a short period of time this is no different than\r
+    // a write combining on writes to a frame buffer.\r
+    //\r
+\r
+    UpdateWindow (Private->WindowHandle);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Win32 Windows event handler.\r
+\r
+  See Win32 Book\r
+\r
+  @return See Win32 Book\r
+\r
+**/\r
+// TODO:    hwnd - add argument and description to function comment\r
+// TODO:    iMsg - add argument and description to function comment\r
+// TODO:    wParam - add argument and description to function comment\r
+// TODO:    lParam - add argument and description to function comment\r
+LRESULT\r
+CALLBACK\r
+WinNtGopThreadWindowProc (\r
+  IN  HWND    hwnd,\r
+  IN  UINT    iMsg,\r
+  IN  WPARAM  wParam,\r
+  IN  LPARAM  lParam\r
+  )\r
+{\r
+  GRAPHICS_PRIVATE_DATA *Private;\r
+  UINTN                 Size;\r
+  HDC                   Handle;\r
+  PAINTSTRUCT           PaintStruct;\r
+  LPARAM                Index;\r
+  EFI_INPUT_KEY         Key;\r
+  BOOLEAN               AltIsPress;\r
+\r
+  //\r
+  // BugBug - if there are two instances of this DLL in memory (such as is\r
+  // the case for ERM), the correct instance of this function may not be called.\r
+  // This also means that the address of the mTlsIndex value will be wrong, and\r
+  // the value may be wrong too.\r
+  //\r
+\r
+\r
+  //\r
+  // Use mTlsIndex global to get a Thread Local Storage version of Private.\r
+  // This works since each Gop protocol has a unique Private data instance and\r
+  // a unique thread.\r
+  //\r
+  AltIsPress = FALSE;\r
+  Private = TlsGetValue (mTlsIndex);\r
+  ASSERT (NULL != Private);\r
+\r
+  switch (iMsg) {\r
+  case WM_CREATE:\r
+    Size = Private->Width * Private->Height * sizeof (RGBQUAD);\r
+\r
+    //\r
+    // Allocate DIB frame buffer directly from NT for performance enhancement\r
+    // This buffer is the virtual screen/frame buffer. This buffer is not the\r
+    // same a a frame buffer. The first fow of this buffer will be the bottom\r
+    // line of the image. This is an artifact of the way we draw to the screen.\r
+    //\r
+    Private->VirtualScreenInfo = HeapAlloc (\r
+                                   GetProcessHeap (),\r
+                                   HEAP_ZERO_MEMORY,\r
+                                   Size\r
+                                   );\r
+\r
+    Private->VirtualScreenInfo->bV4Size           = sizeof (BITMAPV4HEADER);\r
+    Private->VirtualScreenInfo->bV4Width          = Private->Width;\r
+    Private->VirtualScreenInfo->bV4Height         = Private->Height;\r
+    Private->VirtualScreenInfo->bV4Planes         = 1;\r
+    Private->VirtualScreenInfo->bV4BitCount       = 32;\r
+    //\r
+    // uncompressed\r
+    //\r
+    Private->VirtualScreenInfo->bV4V4Compression  = BI_RGB;\r
+    Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);\r
+    return 0;\r
+\r
+  case WM_PAINT:\r
+    //\r
+    // I have not found a way to convert hwnd into a Private context. So for\r
+    // now we use this API to convert hwnd to Private data.\r
+    //\r
+\r
+    Handle = BeginPaint (hwnd, &PaintStruct);\r
+\r
+    SetDIBitsToDevice (\r
+      Handle,                                     // Destination Device Context\r
+      0,                                          // Destination X - 0\r
+      0,                                          // Destination Y - 0\r
+      Private->Width,                             // Width\r
+      Private->Height,                            // Height\r
+      0,                                          // Source X\r
+      0,                                          // Source Y\r
+      0,                                          // DIB Start Scan Line\r
+      Private->Height,                            // Number of scan lines\r
+      Private->VirtualScreen,                     // Address of array of DIB bits\r
+      (BITMAPINFO *) Private->VirtualScreenInfo,  // Address of structure with bitmap info\r
+      DIB_RGB_COLORS                              // RGB or palette indexes\r
+      );\r
+\r
+    EndPaint (hwnd, &PaintStruct);\r
+    return 0;\r
+\r
+  //\r
+  // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case\r
+  // WM_SYSKEYDOWN is posted when F10 is pressed or\r
+  // holds down ALT key and then presses another key.\r
+  //\r
+  case WM_SYSKEYDOWN:\r
+\r
+    Key.ScanCode    = 0;\r
+    Key.UnicodeChar = CHAR_NULL;\r
+    switch (wParam) {\r
+    case VK_F10:\r
+      Key.ScanCode    = SCAN_F10;\r
+      Key.UnicodeChar = CHAR_NULL;\r
+      GopPrivateAddKey (Private, Key);\r
+      return 0;\r
+    }\r
+\r
+    //\r
+    // If ALT or ALT + modifier key is pressed.\r
+    //\r
+    if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {\r
+      if (Key.ScanCode != 0){\r
+        //\r
+        // If ALT is pressed with other ScanCode.\r
+        // Always revers the left Alt for simple.\r
+        //\r
+        Private->LeftAlt = TRUE;\r
+      }\r
+      GopPrivateAddKey (Private, Key);\r
+      //\r
+      // When Alt is released there is no windoes message, so\r
+      // clean it after using it.\r
+      //\r
+      Private->RightAlt = FALSE;\r
+      Private->LeftAlt  = FALSE;\r
+      return 0;\r
+    }\r
+    AltIsPress = TRUE;\r
+\r
+  case WM_CHAR:\r
+    //\r
+    // The ESC key also generate WM_CHAR.\r
+    //\r
+    if (wParam == 0x1B) {\r
+      return 0;\r
+    }\r
+\r
+    if (AltIsPress == TRUE) {\r
+      //\r
+      // If AltIsPress is true that means the Alt key is pressed.\r
+      //\r
+      Private->LeftAlt = TRUE;\r
+    }\r
+    for (Index = 0; Index < (lParam & 0xffff); Index++) {\r
+      if (wParam != 0) {\r
+        Key.UnicodeChar = (CHAR16) wParam;\r
+        Key.ScanCode    = SCAN_NULL;\r
+        GopPrivateAddKey (Private, Key);\r
+      }\r
+    }\r
+    if (AltIsPress == TRUE) {\r
+      //\r
+      // When Alt is released there is no windoes message, so\r
+      // clean it after using it.\r
+      //\r
+      Private->LeftAlt  = FALSE;\r
+      Private->RightAlt = FALSE;\r
+    }\r
+    return 0;\r
+\r
+  case WM_SYSKEYUP:\r
+    //\r
+    // ALT is pressed with another key released\r
+    //\r
+    WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);\r
+    return 0;\r
+\r
+  case WM_KEYDOWN:\r
+    Key.ScanCode    = SCAN_NULL;\r
+    Key.UnicodeChar = CHAR_NULL;\r
+    //\r
+    // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR\r
+    // So if there is no modifier key updated, skip the WM_KEYDOWN even.\r
+    //\r
+    if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {\r
+      //\r
+      // Support the partial keystroke, add all keydown event into the queue.\r
+      //\r
+      GopPrivateAddKey (Private, Key);\r
+    }\r
+    return 0;\r
+\r
+  case WM_KEYUP:\r
+    WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);\r
+    return 0;\r
+\r
+  case WM_CLOSE:\r
+    //\r
+    // This close message is issued by user, core is not aware of this,\r
+    // so don't release the window display resource, just hide the window.\r
+    //\r
+    ShowWindow (Private->WindowHandle, SW_HIDE);\r
+    return 0;\r
+\r
+  case WM_DESTROY:\r
+    DestroyWindow (hwnd);\r
+    PostQuitMessage (0);\r
+\r
+    HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);\r
+\r
+    ExitThread (0);\r
+\r
+  default:\r
+    break;\r
+  };\r
+\r
+  return DefWindowProc (hwnd, iMsg, wParam, lParam);\r
+}\r
+\r
+\r
+/**\r
+  This thread simulates the end of WinMain () aplication. Each Winow nededs\r
+  to process it's events. The messages are dispatched to\r
+  WinNtGopThreadWindowProc ().\r
+  Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()\r
+  are running in a seperate thread. We have to do this to process the events.\r
+\r
+  @param  lpParameter            Handle of window to manage.\r
+\r
+  @return if a WM_QUIT message is returned exit.\r
+\r
+**/\r
+DWORD\r
+WINAPI\r
+WinNtGopThreadWinMain (\r
+  LPVOID    lpParameter\r
+  )\r
+{\r
+  MSG                    Message;\r
+  GRAPHICS_PRIVATE_DATA  *Private;\r
+  RECT                   Rect;\r
+\r
+  Private = (GRAPHICS_PRIVATE_DATA *) lpParameter;\r
+  ASSERT (NULL != Private);\r
+\r
+  //\r
+  // Since each thread has unique private data, save the private data in Thread\r
+  // Local Storage slot. Then the shared global mTlsIndex can be used to get\r
+  // thread specific context.\r
+  //\r
+  TlsSetValue (mTlsIndex, Private);\r
+\r
+  Private->ThreadId                   = GetCurrentThreadId ();\r
+\r
+  Private->WindowsClass.cbSize        = sizeof (WNDCLASSEX);\r
+  Private->WindowsClass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;\r
+  Private->WindowsClass.lpfnWndProc   = WinNtGopThreadWindowProc;\r
+  Private->WindowsClass.cbClsExtra    = 0;\r
+  Private->WindowsClass.cbWndExtra    = 0;\r
+  Private->WindowsClass.hInstance     = NULL;\r
+  Private->WindowsClass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);\r
+  Private->WindowsClass.hCursor       = LoadCursor (NULL, IDC_ARROW);\r
+  Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW;\r
+  Private->WindowsClass.lpszMenuName  = NULL;\r
+  Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME;\r
+  Private->WindowsClass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);\r
+\r
+  //\r
+  // Use 100 x 100 as initial Window size.\r
+  //\r
+  Private->Width  = 100;\r
+  Private->Height = 100;\r
+\r
+\r
+  //\r
+  // This call will fail after the first time, but thats O.K. since we only need\r
+  // WIN_NT_GOP_CLASS_NAME to exist to create the window.\r
+  //\r
+  // Note: Multiple instances of this DLL will use the same instance of this\r
+  // Class, including the callback function, unless the Class is unregistered and\r
+  // successfully registered again.\r
+  //\r
+  RegisterClassEx (&Private->WindowsClass);\r
+\r
+  //\r
+  // Setting Rect values to allow for the AdjustWindowRect to provide\r
+  // us the correct sizes for the client area when doing the CreateWindowEx\r
+  //\r
+  Rect.top    = 0;\r
+  Rect.bottom = Private->Height;\r
+  Rect.left   = 0;\r
+  Rect.right  = Private->Width;\r
+\r
+  AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);\r
+\r
+  Private->WindowHandle = CreateWindowEx (\r
+                            0,\r
+                            WIN_NT_GOP_CLASS_NAME,\r
+                            Private->WindowName,\r
+                            WS_OVERLAPPEDWINDOW,\r
+                            CW_USEDEFAULT,\r
+                            CW_USEDEFAULT,\r
+                            Rect.right - Rect.left,\r
+                            Rect.bottom - Rect.top,\r
+                            NULL,\r
+                            NULL,\r
+                            NULL,\r
+                            (VOID **)&Private\r
+                            );\r
+\r
+  //\r
+  // The reset of this thread is the standard winows program. We need a sperate\r
+  // thread since we must process the message loop to make windows act like\r
+  // windows.\r
+  //\r
+\r
+  ShowWindow (Private->WindowHandle, SW_SHOW);\r
+  UpdateWindow (Private->WindowHandle);\r
+\r
+  //\r
+  // Let the main thread get some work done\r
+  //\r
+  ReleaseSemaphore (Private->ThreadInited, 1, NULL);\r
+\r
+  //\r
+  // This is the message loop that all Windows programs need.\r
+  //\r
+  while (GetMessage (&Message, Private->WindowHandle, 0, 0)) {\r
+    TranslateMessage (&Message);\r
+    DispatchMessage (&Message);\r
+  }\r
+\r
+  return (DWORD)Message.wParam;\r
+}\r
+\r
+\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  Private                TODO: add argument description\r
+  @param  HorizontalResolution   TODO: add argument description\r
+  @param  VerticalResolution     TODO: add argument description\r
+  @param  ColorDepth             TODO: add argument description\r
+  @param  RefreshRate            TODO: add argument description\r
+\r
+  @return TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGraphicsWindowOpen (\r
+  IN  EMU_IO_THUNK_PROTOCOL *This\r
+  )\r
+{\r
+  DWORD                    NewThreadId;\r
+  GRAPHICS_PRIVATE_DATA    *Private;\r
+\r
+  Private = AllocateZeroPool (sizeof (*Private));\r
+\r
+  GopPrivateCreateQ (Private, &Private->QueueForRead);\r
+\r
+  Private->GraphicsWindowIo.Size              = WinNtWndSize;\r
+  Private->GraphicsWindowIo.CheckKey          = WinNtWndCheckKey;\r
+  Private->GraphicsWindowIo.GetKey            = WinNtWndGetKey;\r
+  Private->GraphicsWindowIo.KeySetState       = WinNtWndKeySetState;\r
+  Private->GraphicsWindowIo.RegisterKeyNotify = WinNtWndRegisterKeyNotify;\r
+  Private->GraphicsWindowIo.Blt               = WinNtWndBlt;\r
+  Private->GraphicsWindowIo.CheckPointer      = WinNtWndCheckPointer;\r
+  Private->GraphicsWindowIo.GetPointerState   = WinNtWndGetPointerState;\r
+\r
+  Private->WindowName = This->ConfigString;\r
+  //\r
+  // Initialize a Thread Local Storge variable slot. We use TLS to get the\r
+  // correct Private data instance into the windows thread.\r
+  //\r
+  if (mTlsIndex == TLS_OUT_OF_INDEXES) {\r
+    ASSERT (0 == mTlsIndexUseCount);\r
+    mTlsIndex = TlsAlloc ();\r
+  }\r
+\r
+  //\r
+  // always increase the use count!\r
+  //\r
+  mTlsIndexUseCount++;\r
+\r
+  Private->ThreadInited = CreateSemaphore (NULL, 0, 1, NULL);\r
+  Private->ThreadHandle = CreateThread (\r
+                            NULL,\r
+                            0,\r
+                            WinNtGopThreadWinMain,\r
+                            (VOID *) Private,\r
+                            0,\r
+                            &NewThreadId\r
+                            );\r
+\r
+  //\r
+  // The other thread has entered the windows message loop so we can\r
+  // continue our initialization.\r
+  //\r
+  WaitForSingleObject (Private->ThreadInited, INFINITE);\r
+  CloseHandle (Private->ThreadInited);\r
+\r
+  This->Private = Private;\r
+  This->Interface = &Private->GraphicsWindowIo;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGraphicsWindowClose (\r
+  IN  EMU_IO_THUNK_PROTOCOL   *This\r
+)\r
+{\r
+  GRAPHICS_PRIVATE_DATA       *Private;\r
+\r
+  Private = (GRAPHICS_PRIVATE_DATA *)This->Private;\r
+\r
+  //\r
+  // BugBug: Shutdown GOP Hardware and any child devices.\r
+  //\r
+  SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);\r
+  CloseHandle (Private->ThreadHandle);\r
+\r
+  mTlsIndexUseCount--;\r
+\r
+  //\r
+  // The callback function for another window could still be called,\r
+  // so we need to make sure there are no more users of mTlsIndex.\r
+  //\r
+  if (0 == mTlsIndexUseCount) {\r
+    ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);\r
+\r
+    TlsFree (mTlsIndex);\r
+    mTlsIndex = TLS_OUT_OF_INDEXES;\r
+\r
+    UnregisterClass (\r
+      Private->WindowsClass.lpszClassName,\r
+      Private->WindowsClass.hInstance\r
+    );\r
+  }\r
+\r
+\r
+  GopPrivateDestroyQ (Private, &Private->QueueForRead);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo = {\r
+  &gEmuGraphicsWindowProtocolGuid,\r
+  NULL,\r
+  NULL,\r
+  0,\r
+  WinNtGraphicsWindowOpen,\r
+  WinNtGraphicsWindowClose,\r
+  NULL\r
+};\r
index 22399f18b94c77e6fa5c7d2a00e4f7712a7d8c71..f8d21d26d9ff329e2d06374d36374169a86b395f 100644 (file)
@@ -424,6 +424,11 @@ Returns:
   //\r
   AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);\r
 \r
+  //\r
+  // Emulator Bus Driver Thunks\r
+  //\r
+  AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);\r
+\r
   //\r
   // Allocate space for gSystemMemory Array\r
   //\r
index c73ba17e747df7bf71624f29e535bcc006dbd563..3dc6a7e641379dcba2a90ca6a6f4db5e3e1be657 100644 (file)
@@ -197,4 +197,5 @@ SecInitializeThunk (
   VOID\r
 );\r
 extern EMU_THUNK_PROTOCOL    gEmuThunkProtocol;\r
+extern EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo;\r
 #endif
\ No newline at end of file
index 544e775c49b46e83a719400a58dfffc86bfabad2..b62791bcfaf99c235585e7671510c3016f5f7165 100644 (file)
@@ -30,6 +30,9 @@
 \r
 [Sources]\r
   WinMemoryAllocationLib.c\r
+  WinGopInput.c\r
+  WinGopScreen.c\r
+  WinGop.h\r
   WinThunk.c\r
   WinHost.h\r
   WinHost.c\r
@@ -55,6 +58,9 @@
 [Ppis]\r
   gEmuThunkPpiGuid\r
 \r
+[Protocols]\r
+  gEmuIoThunkProtocolGuid\r
+  gEmuGraphicsWindowProtocolGuid\r
 [Pcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack\r
 \r
@@ -62,6 +68,7 @@
   gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareVolume\r
   gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize\r
   gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress\r
+  gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"\r
   gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage\r
 \r
 [BuildOptions]\r