public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] Features/Intel/UserInterface: Add VirtualKeyboardFeaturePkg
@ 2020-03-26  0:43 Tan, Ming
  2020-04-01  5:40 ` [edk2-devel] " Dong, Eric
  2020-04-01  8:58 ` Ni, Ray
  0 siblings, 2 replies; 3+ messages in thread
From: Tan, Ming @ 2020-03-26  0:43 UTC (permalink / raw)
  To: devel

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2603

It add a VirtualKeyboardDxe driver.
It is used with a touch panel, simulate a keyboard in the screen.

Signed-off-by: Ming Tan <ming.tan@intel.com>
---
 .../Include/PostMemory.fdf                    |   10 +
 .../Include/PreMemory.fdf                     |    8 +
 .../Include/VirtualKeyboardFeature.dsc        |   96 ++
 .../VirtualKeyboardFeaturePkg/Readme.md       |   95 ++
 .../CapitalLetterKeyboard.bmp                 |  Bin 0 -> 330454 bytes
 .../VirtualKeyboardDxe/ComponentName.c        |  159 ++
 .../VirtualKeyboardDxe/ComponentName.h        |   95 ++
 .../VirtualKeyboardDxe/DigitKeyboard.bmp      |  Bin 0 -> 330454 bytes
 .../VirtualKeyboardDxe/FullIcon.bmp           |  Bin 0 -> 5454 bytes
 .../VirtualKeyboardDxe/Keyboard.c             | 1400 +++++++++++++++++
 .../VirtualKeyboardDxe/KeyboardLayout.c       | 1364 ++++++++++++++++
 .../VirtualKeyboardDxe/KeyboardLayout.idf     |   12 +
 .../VirtualKeyboardDxe/SimpleIcon.bmp         |  Bin 0 -> 2814 bytes
 .../VirtualKeyboardDxe/SimpleKeyboard.bmp     |  Bin 0 -> 30054 bytes
 .../VirtualKeyboardDxe/VirtualKeyboard.h      |  777 +++++++++
 .../VirtualKeyboardDriver.c                   |  541 +++++++
 .../VirtualKeyboardDxe/VirtualKeyboardDxe.inf |   77 +
 .../VirtualKeyboardFeaturePkg.dec             |   26 +
 .../VirtualKeyboardFeaturePkg.dsc             |   30 +
 19 files changed, 4690 insertions(+)
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/CapitalLetterKeyboard.bmp
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/DigitKeyboard.bmp
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/FullIcon.bmp
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleIcon.bmp
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleKeyboard.bmp
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
 create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc

diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf
new file mode 100644
index 0000000000..bf4a4d5078
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf
@@ -0,0 +1,10 @@
+## @file
+#  FDF file for post-memory modules that enable Virtual Keyboard.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+  INF UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf
new file mode 100644
index 0000000000..c39a057f94
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf
@@ -0,0 +1,8 @@
+## @file
+#  FDF file for pre-memory modules that enable Virtual Keyboard.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc
new file mode 100644
index 0000000000..c10fb2d567
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc
@@ -0,0 +1,96 @@
+## @file
+# This is a build description file for the Virtual Keyboard feature.
+# This file should be included into another package DSC file to build this feature.
+#
+# The DEC files are used by the utilities that parse DSC and
+# INF files to generate AutoGen.c and AutoGen.h files
+# for the build infrastructure.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+!ifndef $(PEI_ARCH)
+  !error "PEI_ARCH must be specified to build this feature!"
+!endif
+!ifndef $(DXE_ARCH)
+  !error "DXE_ARCH must be specified to build this feature!"
+!endif
+
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this feature.
+#
+################################################################################
+[LibraryClasses]
+  #######################################
+  # Edk2 Packages
+  #######################################
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+  #######################################
+  # Edk2 Packages
+  #######################################
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+#                      tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+#       into firmware volume images. This section is just a list of modules to compile from
+#       source into UEFI-compliant binaries.
+#       It is the FDF file that contains information on combining binary files into firmware
+#       volume images, whose concept is beyond UEFI and is described in PI specification.
+#       Binary modules do not need to be listed in this section, as they should be
+#       specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+#       Logo (Logo.bmp), and etc.
+#       There may also be modules listed in this section that are not required in the FDF file,
+#       When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+#       generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+#
+# Feature DXE Components
+#
+[Components.X64]
+  #####################################
+  # Virtual Keyboard Feature Package
+  #####################################
+  UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
+
+###################################################################################################
+#
+# BuildOptions Section - Define the module specific tool chain flags that should be used as
+#                        the default flags for a module. These flags are appended to any
+#                        standard flags that are defined by the build process. They can be
+#                        applied for any modules or only those modules with the specific
+#                        module style (EDK or EDKII) specified in [Components] section.
+#
+#                        For advanced features, it is recommended to enable [BuildOptions] in
+#                        the applicable INF file so it does not affect the whole board package
+#                        build when this DSC file is active.
+#
+###################################################################################################
+[BuildOptions]
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
new file mode 100644
index 0000000000..17a3a00215
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
@@ -0,0 +1,95 @@
+# Overview
+* **Feature Name:** Virtual Keyboard
+* **PI Phase(s) Supported:** DXE
+* **SMM Required?** No
+
+## Purpose
+This feature provides a DXE virtual keyboard driver, used with a touch panel.
+
+# High-Level Theory of Operation
+This driver will use the following protocol:
+  gEfiAbsolutePointerProtocolGuid
+  gEfiTouchPanelGuid
+  gEfiGraphicsOutputProtocolGuid
+
+It will show a picture like a keyboard in the graphic output, then detect
+position when user touch the touch panel, then calculate the key which the
+user want to type.
+
+## Firmware Volumes
+*_TODO_*
+A bulleted list of the firmware volumes that feature module(s) are placed in.
+
+## Modules
+VirtualKeyboardDxe: The main driver of virtual keyboard
+
+## <Module Name>
+*_TODO_*
+Each module in the feature should have a section that describes the module in a level of detail that is useful
+to better understand the module source code.
+
+## <Library Name>
+*_TODO_*
+Each library in the feature should have a section that describes the library in a level of detail that is useful
+to better understand the library source code.
+
+## Key Functions
+*_TODO_*
+A bulleted list of key functions for interacting with the feature.
+
+Not all features need to be listed. Only functions exposed through external interfaces that are important for feature
+users to be aware of.
+
+## Configuration
+*_TODO_*
+Information that is useful for configuring the feature.
+
+Not all configuration options need to be listed. This section is used to provide more background on configuration
+options than possible elsewhere.
+
+## Data Flows
+*_TODO_*
+Architecturally defined data structures and flows for the feature.
+
+## Control Flows
+*_TODO_*
+Key control flows for the feature.
+
+## Build Flows
+*_TODO_*
+Any special build flows should be described in this section.
+
+This is particularly useful for features that use custom build tools or require non-standard tool configuration. If the
+standard flow in the feature package template is used, this section may be empty.
+
+## Test Point Results
+*_TODO_*
+The test(s) that can verify porting is complete for the feature.
+
+Each feature must describe at least one test point to verify the feature is successful. If the test point is not
+implemented, this should be stated.
+
+## Functional Exit Criteria
+*_TODO_*
+The testable functionality for the feature.
+
+This section should provide an ordered list of criteria that a board integrator can reference to ensure the feature is
+functional on their board.
+
+## Feature Enabling Checklist
+*_TODO_*
+An ordered list of required activities to achieve desired functionality for the feature.
+
+## Performance Impact
+A general expectation for the impact on overall boot performance due to using this feature.
+
+This section is expected to provide guidance on:
+* How to estimate performance impact due to the feature
+* How to measure performance impact of the feature
+* How to manage performance impact of the feature
+
+## Common Optimizations
+*_TODO_*
+Common size or performance tuning options for this feature.
+
+This section is recommended but not required. If not used, the contents should be left empty.
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/CapitalLetterKeyboard.bmp b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/CapitalLetterKeyboard.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..759c3d46a9f0cf6a69fa98563cd04f7a082d3b4d
GIT binary patch
literal 330454
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
Ka0)zo_WuC{9xg=y

literal 0
HcmV?d00001

diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c
new file mode 100644
index 0000000000..6ac28ab90b
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c
@@ -0,0 +1,159 @@
+/** @file
+  Virtual Keyboard driver name.
+
+  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VirtualKeyboard.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName = {
+  VirtualKeyboardComponentNameGetDriverName,
+  VirtualKeyboardComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     VirtualKeyboardComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) VirtualKeyboardComponentNameGetControllerName,
+  "en"
+};
+
+//
+// Table of driver names
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVirtualKeyboardDriverNameTable[] = {
+  {
+    "eng;en",
+    L"UEFI Virtual Keyboard Driver"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+
+//
+// Controller name string table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVirtualKeyboardControllerNameStringTable[] = {
+  {
+    "eng",
+    L"UEFI Virtual Keyboard Driver"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+
+/**
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Language          A pointer to a three-character ISO 639-2 language identifier.
+                                This is the language of the driver name that that the caller
+                                is requesting, and it must match one of the languages specified
+                                in SupportedLanguages.  The number of languages supported by a
+                                driver is up to the driver writer.
+  @param[out] DriverName        A pointer to the Unicode string to return.  This Unicode string
+                                is the name of the driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
+                                and the language specified by Language was returned
+                                in DriverName.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mVirtualKeyboardDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gVirtualKeyboardComponentName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle  The handle of a controller that the driver specified by
+                                This is managing.  This handle specifies the controller
+                                whose name is to be returned.
+  @param[in]  ChildHandle       The handle of the child controller to retrieve the name
+                                of.  This is an optional parameter that may be NULL.  It
+                                will be NULL for device drivers.  It will also be NULL
+                                for a bus drivers that wish to retrieve the name of the
+                                bus controller.  It will not be NULL for a bus driver
+                                that wishes to retrieve the name of a child controller.
+  @param[in]  Language          A pointer to a three character ISO 639-2 language
+                                identifier.  This is the language of the controller name
+                                that the caller is requesting, and it must match one
+                                of the languages specified in SupportedLanguages.  The
+                                number of languages supported by a driver is up to the
+                                driver writer.
+  @param[out] ControllerName    A pointer to the Unicode string to return.  This Unicode
+                                string is the name of the controller specified by
+                                ControllerHandle and ChildHandle in the language specified
+                                by Language, from the point of view of the driver specified
+                                by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
+                                language specified by Language for the driver
+                                specified by This was returned in DriverName.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
+                                the controller specified by ControllerHandle and
+                                ChildHandle.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  EFI_HANDLE                  ControllerHandle,
+  IN  EFI_HANDLE                  ChildHandle, OPTIONAL
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  )
+{
+  //
+  // ChildHandle must be NULL for a Device Driver
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mVirtualKeyboardControllerNameStringTable,
+           ControllerName,
+           (BOOLEAN)(This == &gVirtualKeyboardComponentName)
+           );
+}
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h
new file mode 100644
index 0000000000..327ce9f9cb
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h
@@ -0,0 +1,95 @@
+/** @file
+  Header file for Virtual Keyboard driver name.
+
+  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
+#define _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
+
+#include <Uefi.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+
+/**
+  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Language          A pointer to a three-character ISO 639-2 language identifier.
+                                This is the language of the driver name that that the caller
+                                is requesting, and it must match one of the languages specified
+                                in SupportedLanguages.  The number of languages supported by a
+                                driver is up to the driver writer.
+  @param[out] DriverName        A pointer to the Unicode string to return.  This Unicode string
+                                is the name of the driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
+                                and the language specified by Language was returned
+                                in DriverName.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **DriverName
+  );
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle  The handle of a controller that the driver specified by
+                                This is managing.  This handle specifies the controller
+                                whose name is to be returned.
+  @param[in]  ChildHandle       The handle of the child controller to retrieve the name
+                                of.  This is an optional parameter that may be NULL.  It
+                                will be NULL for device drivers.  It will also be NULL
+                                for a bus drivers that wish to retrieve the name of the
+                                bus controller.  It will not be NULL for a bus driver
+                                that wishes to retrieve the name of a child controller.
+  @param[in]  Language          A pointer to a three character ISO 639-2 language
+                                identifier.  This is the language of the controller name
+                                that the caller is requesting, and it must match one
+                                of the languages specified in SupportedLanguages.  The
+                                number of languages supported by a driver is up to the
+                                driver writer.
+  @param[out] ControllerName    A pointer to the Unicode string to return.  This Unicode
+                                string is the name of the controller specified by
+                                ControllerHandle and ChildHandle in the language specified
+                                by Language, from the point of view of the driver specified
+                                by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
+                                language specified by Language for the driver
+                                specified by This was returned in DriverName.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
+                                the controller specified by ControllerHandle and
+                                ChildHandle.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  EFI_HANDLE                  ControllerHandle,
+  IN  EFI_HANDLE                  ChildHandle, OPTIONAL
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  );
+#endif
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/DigitKeyboard.bmp b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/DigitKeyboard.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b64d62034817e7407120ee2181c935e07bef5a8c
GIT binary patch
literal 330454
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

literal 0
HcmV?d00001

diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/FullIcon.bmp b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/FullIcon.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b940505c8bc74ad6550bc322629d7975c1e1c1fc
GIT binary patch
literal 5454
zcmdUyTS!(}6o56!L@l#1k<1H~<*msK=EYIGfJHUFgo!=$AR-O~g3Ln$_Tv5C7@{FW
zuaziT6L~3b87f|a5!5uTbW}2D5<@ff*ZKTcvp6&*5#z(Z`TxV--&uR@b@o|%t#u-Q
zirH&rZa;AK<^LmpPyW_cZd|Rb+&<nn4?bRUiz^!H>wdS8R##V7QBl$K<d1cWYA;{D
ztZVAFD3jL*2L~Hl`%J6LZf@c|8xF%GjEsyJ{RdKAU2P;=(N9lLXQANWU{&7M)&|ib
zoyp0`=g*%vw)L&AuN^pWKyM*7F)?9hXD7tQ#s+ft?p+nwqR!Q;S6L`LJY4m6b#+0u
zZ{MzDW@ct|bX06Ubm)+BvDx0<UI<el_wL<Ofi3EY%@Gk1s$XojwY3#uZEbDoHhXz_
z>C>^R<KyGTHv*}xtyO_7>J%0hvQTJfsOs<N=zy@jN?yNyjc+ux_O7p)LPA3J?c3++
z>FMO;BsL#Bc+kVc!`<E8$Hxa!UtjO&=*XjOQDfb*vN9GrckZ04t1GKGI5_n5^gz75
zz4!0mk1<@|ym`YJtZUwgb&HFO@87>)T3UMd?j1wg!omWC#w~`ctE&(Mwy2?ed3l+I
z(9eooA!}=E5V1`y85$b0#P}@x{Fk}?ZEkdDXJ>gplgWhtz!<)L`xf%y!v{{T5P2hW
zb93B<z*kmQkfDzTuFPdf69FJ^mLXzvM9KX8JOoujm?BD8PG%vdO{TNY4Xu4^rqvTC
zPVC;jd#|}UJ39vk2J&_W1_pNR+U4Tnf+xqv$D_QmvU10c9Y_%gFI~C>NlHq>@sNRc
zcW<~^OiawqojboXH;fq@8{?$x*|P_=etv!kG&D5G6vWP+JqzLViCT`^qeqV*iHV8G
zh&^&eA4+&A%_;b~o=rNWMV^-|sqoaPQ>eOg=Z+Grg~Y|hDe3L)g%}S$PWa-*i*4Js
zi40~VK%Jvg$RLo+%uFR>vr(<yqVuKr%q>nRhmN<P@@LMRK{@-ZBsn=5a^b=SC4GIQ
z)OBN0;AK(Lu!kbUjv+t@(kW3<QIPEHY$Z)iO`oXMTbtw*WGupFBC|dY9X15tz@HUH
zM@RGcw{PE8g3Cc-V`G(wZxHI0;2Zd}4kh?Mc<?|;SXdZJGBPrhJbd^Na{l~zCB_c^
ztU2ZM>C+sL@6FBM-=9}Th`={|eSMD}J$m@?VL5SB9aK{g>XWpzG?ZVye3?E3{`Bcn
zNJ2uwkt0Vq#Wcdgt5>f$-~j;vsKsp%XlZF7Pca3tix)3K%FD}{&f+AF_V#v2YHBJn
zVvk(Wh7v*tHK#?!XA7+P>zg-nI@L&PYb!N2hngXN$Qy*v=s<WW#8m`{MMOvlbrik_
zflIXS?CeAsLNr5wCQ2ZUjg1V+&N%bq$BzjP{r&wA5{IZo6%hu)p=fSy7PXRb5XKA$
zoHY0B*)!^AlWB#7qOQ(FtkNMJh%w5gq@+M{b8}UOyAX1R5<(?JhoWR^YD&q;lP3|V
zsi{#S-zoUH5={L>3EwH-R`XxEas^eTrKPI;{{8!qpr9ZnQr?h2l^{Sy(4iz&W2}~%
zKQb~>Wu)fU@V-fWMmgVBn|!By$>w9nj_Gn@Gx=A^SK4e$N&n+_%GcZc4g36Gn?JkH
z)JPOL#tkth0ytY#RaK<|1W!moL4gwPLX1VrXZ?A4dRnJQF<|^OCWE8o`0?W^Be7bC
zbT|?CbA8K3+_-V$2JTc+Qj(LC!;lK|w}0EUYu6y0N^a55&(G)JL->fu%gckXmPC@9
zH*Xdf7emNv;v1p^wPFv|JGT&^kmF+wC2USsRu+U4EuL`e)~%wVA_yD{kzt4)l+dAo
p86F<C#GKOBxe+HVs7?Mk@$)bFIfd8L^U5+T;g?l#J@wbDe*hRVpnL!T

literal 0
HcmV?d00001

diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c
new file mode 100644
index 0000000000..a2c9a3bfc4
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c
@@ -0,0 +1,1400 @@
+/** @file
+  Virtural Keyboard Control Engine
+
+  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VirtualKeyboard.h"
+
+/**
+  Notify all keyboards pressed specific key need to hidden Virtual
+  Keyboard.
+
+  @param[in] KeyData          Keyboard pressed specific key data
+
+  @retval EFI_SUCCESS         Success for the function.
+  @retval EFI_NOT_FOUND       Not found Virtual Keyboard protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+VkNotifyKeyCallback (
+  IN EFI_KEY_DATA *KeyData
+  )
+{
+  EFI_STATUS Status;
+  VK_CONTEXT *VkContext;
+  UINTN      MaxColumn;
+  UINTN      MaxRow;
+  UINT32     HorizontalPixel;
+  UINT32     VerticalPixel;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkNotifyKeyCallback Start\n"));
+
+  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, (VOID **) &VkContext);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  gST->ConOut->QueryMode (
+                 gST->ConOut,
+                 gST->ConOut->Mode->Mode,
+                 &MaxColumn,
+                 &MaxRow
+                 );
+  HorizontalPixel = VkContext->GraphicsOutput->Mode->Info->HorizontalResolution;
+  VerticalPixel   = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
+
+  //
+  // CursorRow and CursorColumn are started from 0, so need to add 2 not 1.
+  //
+  if (((UINTN)(gST->ConOut->Mode->CursorColumn * EFI_GLYPH_WIDTH) < VkContext->SimIconBackWidth) &&
+      ((UINTN)((gST->ConOut->Mode->CursorRow + 2) * EFI_GLYPH_HEIGHT) > (VerticalPixel - VkContext->SimIconBackHeight))) {
+    SaveVkIconBackgroundBltBuffer (VkContext, VkDisplayAttributeSimpleBottom);
+  } else if (((UINTN)((gST->ConOut->Mode->CursorColumn + 2) * EFI_GLYPH_WIDTH) > (HorizontalPixel - VkContext->FullIconBackWidth)) &&
+             ((UINTN)((gST->ConOut->Mode->CursorRow + 2) * EFI_GLYPH_HEIGHT) > (VerticalPixel - VkContext->FullIconBackHeight))){
+    SaveVkIconBackgroundBltBuffer (VkContext, VkDisplayAttributeFullBottom);
+  }
+
+  //
+  // Hide icon/keyboard to prevent screen scroll up.
+  //
+  if ((KeyData->Key.UnicodeChar         == CHAR_CARRIAGE_RETURN)    ||
+      (KeyData->Key.ScanCode            == SCAN_ESC)                ||
+      ((gST->ConOut->Mode->CursorColumn >= (INT32) (MaxColumn - 2)) &&
+       (gST->ConOut->Mode->CursorRow    == (INT32) (MaxRow - 1)))) {
+    HideVkBody (VkContext);
+    HideVkIcon (VkContext);
+    VkContext->IconReDrawCheck = 0;
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkNotifyKeyCallback End\n"));
+  return EFI_SUCCESS;
+}
+
+/**
+  Judge whether is a registed key.
+
+  @param[in] RegsiteredData   A pointer to a buffer that is filled in with the keystroke
+                              state data for the key that was registered.
+  @param[in] InputData        A pointer to a buffer that is filled in with the keystroke
+                              state data for the key that was pressed.
+
+  @retval TRUE                Key be pressed matches a registered key.
+  @retval FLASE               Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+  IN EFI_KEY_DATA  *RegsiteredData,
+  IN EFI_KEY_DATA  *InputData
+  )
+{
+  ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
+    return FALSE;
+  }
+
+  //
+  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
+  //
+  if (RegsiteredData->KeyState.KeyShiftState != 0 &&
+      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
+    return FALSE;
+  }
+  if (RegsiteredData->KeyState.KeyToggleState != 0 &&
+      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Pop the key from the keybuffer.
+
+  @param[in, out] VkContext    Address of an VK_CONTEXT structure.
+  @param[out]     KeyData      The EFI stand key infomation when code get the key will put
+                               correct mapping key.
+
+  @retval EFI_SUCCESS          The keystroke information was returned.
+  @retval EFI_NOT_READY        The keystroke data is empty.
+
+**/
+EFI_STATUS
+VkPopTheKey (
+  IN OUT VK_CONTEXT   *VkContext,
+     OUT EFI_KEY_DATA *KeyData OPTIONAL
+  )
+{
+  EFI_STATUS Status;
+  UINT8      IndexSt;
+  UINT8      IndexEd;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Start\n"));
+  //
+  // KeyBuffer
+  // [         0          ]
+  // [         1          ]<-*IndexSt/IndexEd
+  // [         2          ]
+  // [        ...         ]
+  // [MAX_KEY_BUF_SIZE - 1]
+  //
+  Status  = EFI_SUCCESS;
+  IndexSt = VkContext->KeyStartIndex;
+  IndexEd = VkContext->KeyEndIndex;
+
+  if (IndexEd == IndexSt) {
+    DEBUG ((DEBUG_VK_KEYS, "ERROR - Keyboard buffer is empty.\n"));
+    Status = EFI_NOT_READY;
+    goto Error;
+  }
+
+  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey Unicode:    %08x\n", VkContext->Keybuffer[IndexSt].Key.UnicodeChar));
+  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey ScanCode:   %08x\n", VkContext->Keybuffer[IndexSt].Key.ScanCode));
+  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey ShiftState: %08x\n", VkContext->Keybuffer[IndexSt].KeyState.KeyShiftState));
+  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey ToggleState:%08x\n", VkContext->Keybuffer[IndexSt].KeyState.KeyToggleState));
+
+  if (KeyData != NULL) {
+    *KeyData = VkContext->Keybuffer[IndexSt];
+  }
+  VkContext->KeyStartIndex = ++IndexSt % MAX_KEY_BUF_SIZE;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey End\n"));
+  return Status;
+}
+
+/**
+  Push the event mapping key index to the input key buffer.
+
+  @param[in, out] VkContext    Address of an VK_CONTEXT structure.
+  @param[in]      Unicode      The font's unicode number.
+
+  @retval EFI_SUCCESS          The maping key index did put the key buffer.
+
+**/
+EFI_STATUS
+VkPushTheKey (
+  IN OUT VK_CONTEXT *VkContext,
+  IN     UINT16     Unicode
+  )
+{
+  UINT8        IndexSt;
+  UINT8        IndexEd;
+  EFI_KEY_DATA KeyData;
+  EFI_STATUS   Status;
+  LIST_ENTRY   *Link;
+  VK_NOTIFY    *CurrentNotify;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPushTheKey Start\n"));
+  //
+  // KeyBuffer
+  // [         0          ]
+  // [         1          ]<-IndexSt/*IndexEd
+  // [         2          ]
+  // [        ...         ]
+  // [MAX_KEY_BUF_SIZE - 1]
+  //
+  IndexSt = VkContext->KeyStartIndex;
+  IndexEd = VkContext->KeyEndIndex;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // Check Keyboard Buffer if is full that will pop the first key
+  //
+  if (VkContext->IsSupportPartialKey &&
+    ((VkContext->KeyEndIndex + 2) % MAX_KEY_BUF_SIZE) == IndexSt) {
+    VkPopTheKey (VkContext, NULL);
+  }
+
+  if (((VkContext->KeyEndIndex + 1) % MAX_KEY_BUF_SIZE) == IndexSt) {
+    VkPopTheKey (VkContext, NULL);
+  }
+
+  KeyData.Key.ScanCode             = SCAN_NULL;
+  KeyData.Key.UnicodeChar          = CHAR_NULL;
+  KeyData.KeyState.KeyShiftState   = EFI_SHIFT_STATE_VALID;
+  KeyData.KeyState.KeyToggleState  = VkContext->KeyToggleState;
+  KeyData.KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
+  KeyData.KeyState.KeyToggleState |= VkContext->IsCapsLockFlag ? EFI_CAPS_LOCK_ACTIVE : 0;
+
+  switch (Unicode) {
+  case VkKeyShift:
+    VkContext->IsShiftKeyFlag = !VkContext->IsShiftKeyFlag;
+    if (VkContext->PageNumber >= VkPage2 && VkContext->PageNumber <= VkPage3) {
+      VkContext->IsShiftKeyFlag ? VkContext->PageNumber++ : VkContext->PageNumber--;
+    }
+    VkContext->IsRedrawUpdateUI = TRUE;
+    break;
+
+  case VkKeyTwoPage:
+    switch (VkContext->PageNumber) {
+    case VkPage0:
+    case VkPage1:
+      VkContext->IsShiftKeyFlag = FALSE;
+      VkContext->PageNumber     = VkContext->IsShiftKeyFlag ? VkPage3 : VkPage2;
+      break;
+
+    case VkPage2:
+    case VkPage3:
+      VkContext->IsShiftKeyFlag = FALSE;
+      VkContext->PageNumber     = VkContext->IsCapsLockFlag ? VkPage1 : VkPage0;
+      break;
+
+    default:
+      break;
+    }
+    VkContext->IsRedrawUpdateUI = TRUE;
+    break;
+
+  case VkKeyCapslock:
+    VkContext->IsCapsLockFlag = !VkContext->IsCapsLockFlag;
+    if (VkContext->PageNumber >= VkPage0 && VkContext->PageNumber <= VkPage1) {
+      VkContext->IsCapsLockFlag ? VkContext->PageNumber++ : VkContext->PageNumber--;
+    }
+    KeyData.KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
+    KeyData.KeyState.KeyToggleState |= VkContext->IsCapsLockFlag ? EFI_CAPS_LOCK_ACTIVE : 0;
+    VkContext->IsRedrawUpdateUI      = TRUE;
+    break;
+
+  default:
+    if ((Unicode & VkKeyScanMask) != 0) {
+      KeyData.Key.ScanCode    = Unicode & ~VkKeyScanMask;
+    } else {
+      KeyData.Key.UnicodeChar = Unicode;
+    }
+    break;
+  }
+
+  if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
+    if (!VkContext->IsSupportPartialKey) {
+      goto End;
+    }
+  }
+
+  for (Link = GetFirstNode (&VkContext->NotifyList); !IsNull (&VkContext->NotifyList, Link); Link = GetNextNode (&VkContext->NotifyList, Link)) {
+    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
+    //
+    // The key notification function needs to run at TPL_CALLBACK
+    // while current TPL is TPL_NOTIFY. It will be invoked in
+    // VkKeyNotifyProcessHandler() which runs at TPL_CALLBACK.
+    //
+    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+      VkContext->Keybuffer[IndexEd] = KeyData;
+      VkContext->KeyEndIndex        = ++IndexEd % MAX_KEY_BUF_SIZE;
+      gBS->SignalEvent (VkContext->KeyNotifyProcessEvent);
+    }
+  }
+  VkContext->Keybuffer[IndexEd] = KeyData;
+  VkContext->KeyEndIndex        = ++IndexEd % MAX_KEY_BUF_SIZE;
+
+  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkPushTheKey Success, Status: %r\n", Status));
+  goto End;
+
+End:
+  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkPushTheKey End\n"));
+  return Status;
+}
+
+/**
+  Process key notify.
+
+  @param[in] Event                 Indicates the event that invoke this function.
+  @param[in] Context               Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+VkKeyNotifyProcessHandler (
+  IN  EFI_EVENT Event,
+  IN  VOID      *Context
+  )
+{
+  EFI_STATUS   Status;
+  VK_CONTEXT   *VkContext;
+  EFI_KEY_DATA KeyData;
+  LIST_ENTRY   *Link;
+  LIST_ENTRY   *NotifyList;
+  VK_NOTIFY    *CurrentNotify;
+  EFI_TPL      OldTpl;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler Start\n"));
+  VkContext = (VK_CONTEXT *) Context;
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  //
+  // Invoke notification functions.
+  //
+  NotifyList = &VkContext->NotifyList;
+  Status = VkPopTheKey (VkContext, &KeyData);
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
+    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
+    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+      CurrentNotify->KeyNotificationFn (&KeyData);
+    }
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler Failed, Status: %r\n", Status));
+
+End:
+  gBS->RestoreTPL (OldTpl);
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler End\n"));
+}
+
+/**
+  Push the event mapping key index to the input key buffer.
+
+  @param[in]  VkContext        Address of an VK_CONTEXT structure.
+  @param[out] KeyItem          Key Item.
+  @param[out] Index            Index of Key Item.
+  @param[in]  TouchX           X position of finger touch.
+  @param[in]  TouchY           Y position of finger touch.
+
+  @retval TRUE                 Touch on Virtual Keyboard.
+  @retval FALSE                Not touch on Virtual Keyboard.
+
+**/
+BOOLEAN
+IsTouchVk (
+  IN  VK_CONTEXT *VkContext,
+  OUT VK_STRUCT  *KeyItem,
+  OUT UINT32     *Index,
+  IN  UINT32     TouchX,
+  IN  UINT32     TouchY
+  )
+{
+  for (*Index = 0; *Index < VkContext->NumOfKeysInfo; (*Index)++) {
+    if (VkContext->KeyboardBodyPtr[*Index].DisStartX < TouchX &&
+        VkContext->KeyboardBodyPtr[*Index].DisEndX   > TouchX &&
+        VkContext->KeyboardBodyPtr[*Index].DisStartY < TouchY &&
+        VkContext->KeyboardBodyPtr[*Index].DisEndY   > TouchY) {
+      break;
+    }
+  }
+  if (*Index != VkContext->NumOfKeysInfo) {
+    *KeyItem = VkContext->KeyboardBodyPtr[*Index];
+  }
+
+  return *Index != VkContext->NumOfKeysInfo;
+}
+
+VOID
+EFIAPI
+VkReadyToBootCallBack (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  VK_CONTEXT                    *VkContext;
+  VkContext = (VK_CONTEXT *)Context;
+
+  HideVkBody (VkContext);
+  VkContext->TargetKeyboardDisplay  = VkDisplayAttributeNone;
+}
+
+/**
+  Timer event
+
+  This routine is called at TPL_VK_SYNC.
+
+  This routine polls for touch panel input.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context,
+                      which is implementation-dependent. Context corresponds
+                      to NotifyContext in CreateEventEx().
+
+**/
+VOID
+EFIAPI
+VkTimer (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer;
+  EFI_ABSOLUTE_POINTER_STATE    Point;
+  EFI_STATUS                    Status;
+  UINT32                        TouchX;
+  UINT32                        TouchY;
+  VK_CONTEXT                    *VkContext;
+  UINT32                        Index;
+  VK_STRUCT                     KeyItem;
+  UINT32                        Font;
+
+  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Start\n"));
+  VkContext = (VK_CONTEXT *)Context;
+
+  //
+  // Update keyboard UI layout
+  //
+  CheckIconCleared (VkContext);
+  CheckScreenCleared (VkContext);
+  CheckBackgroundChanged (VkContext);
+  if (VkContext->IsRedrawUpdateUI) {
+    HideVkBody (VkContext);
+    DrawKeyboardLayout (VkContext);
+    VkContext->IsRedrawUpdateUI = FALSE;
+  }
+
+  //
+  // Error handle for invalid information
+  //
+  AbsolutePointer = VkContext->AbsolutePointer;
+  Status = gBS->CheckEvent (AbsolutePointer->WaitForInput);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS, "ERROR - VkContext->AbsolutePointer->WaitForInput->CheckEvent failed! Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = AbsolutePointer->GetState (AbsolutePointer, &Point);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS, "ERROR - GetState failed, Status: %r\n", Status));
+    goto Error;
+  }
+
+  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxX <= Point.CurrentX) {
+    DEBUG ((
+      DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS,
+      "ERROR - X value exceeds maximum: X: 0x%016Lx, MaxX: 0x%016Lx\n",
+      Point.CurrentX,
+      VkContext->AbsolutePointer->Mode->AbsoluteMaxX
+      ));
+    Status = EFI_PROTOCOL_ERROR;
+    goto Error;
+  }
+  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxY <= Point.CurrentY) {
+    DEBUG ((
+      DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS,
+      "ERROR - Y value exceeds maximum: Y: 0x%016Lx, MaxY: 0x%016Lx\n",
+      Point.CurrentY,
+      VkContext->AbsolutePointer->Mode->AbsoluteMaxY
+      ));
+    Status = EFI_PROTOCOL_ERROR;
+    goto Error;
+  }
+
+  //
+  // Update the touch active status
+  //
+  VkContext->TouchActive = ((Point.ActiveButtons & EFI_ABSP_TouchActive) != 0) ? TRUE : FALSE;
+  if (!VkContext->TouchActive) {
+    VkContext->KeyPressed = FALSE;
+  }
+  ConvertCoordinate (VkContext, Point, &TouchX, &TouchY);
+
+  if (!VkContext->KeyPressed &&
+      VkContext->TouchActive &&
+      IsTouchVk (VkContext, &KeyItem, &Index, TouchX, TouchY)) {
+    VkGetMappingFont (VkContext, KeyItem, &Font);
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO,                   "VK Touch event is trigger!\n" ));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "TouchActive:            0x%04x  \n", VkContext->TouchActive));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "CurrentKeyboardDisplay: 0x%04x  \n", VkContext->CurrentKeyboardDisplay));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "X:                      0x%016Lx\n", Point.CurrentX));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Y:                      0x%016Lx\n", Point.CurrentY));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Z:                      0x%016Lx\n", Point.CurrentZ));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Buttons:                0x%08x  \n", Point.ActiveButtons));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "MapKey Index:           0x%04x  \n", Index));
+    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Key Unicode:            0x%08x  \n", Font));
+
+    switch (Font) {
+    //
+    // Touch the small keyboard icon, show/hide the keyboard.
+    //
+    case VkKeyTypeMaximum:
+      KeyboardLayoutHandler (VkContext, Index);
+      break;
+
+    //
+    // Touch the key raw.
+    //
+    default:
+      if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeNone) {
+        break;
+      }
+      VkPushTheKey (VkContext, (UINT16) Font);
+    }
+    VkContext->KeyPressed = TRUE;
+  }
+
+  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer End\n"));
+  return;
+}
+
+/**
+  VkTouchWaitForKey - SignalEvent when the keybuffer has keys.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  Pointer to the notification function's context,
+                      which is implementation-dependent.  Context corresponds
+                      to NotifyContext in CreateEventEx().
+
+**/
+VOID
+EFIAPI
+VkTouchWaitForKey (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  VK_CONTEXT *VkContext;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkTouchWaitForKey Start\n"));
+  VkContext = (VK_CONTEXT*) Context;
+
+  if (VkContext->KeyStartIndex != VkContext->KeyEndIndex) {
+    DEBUG ((DEBUG_VK_KEYS, "Signal VkTouchWaitForKey\n"));
+    gBS->SignalEvent (Event);
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkTouchWaitForKey End\n"));
+}
+
+/**
+  Get image file data from BIOS image through specific ImageId.
+
+  @param[in] VkContext      Address of an VK_CONTEXT structure.
+  @param[in] ImageId        Guid to get specific image file used.
+
+  @retval EFI_IMAGE_INPUT   Image data on BIOS image.
+
+**/
+EFI_IMAGE_INPUT*
+VkGetImage (
+  IN VK_CONTEXT   *VkContext,
+  IN EFI_IMAGE_ID ImageId
+  )
+{
+  EFI_STATUS      Status;
+  EFI_IMAGE_INPUT Image;
+  EFI_IMAGE_INPUT *VkImage;
+
+
+  Status = VkContext->HiiImageEx->GetImageEx (
+                                    VkContext->HiiImageEx,
+                                    VkContext->HiiHandle,
+                                    ImageId,
+                                    &Image
+                                    );
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  VkImage = AllocateCopyPool (sizeof (EFI_IMAGE_INPUT), &Image);
+  if (VkImage == NULL) {
+    ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
+    return NULL;
+  }
+
+  return VkImage;
+}
+
+/**
+  Dump partial debug message on VkContext.
+
+  @param[in] VkContext        Address of an VK_CONTEXT structure.
+
+**/
+VOID
+VkDumpContext (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT,
+    "VkContext->Signature: 0x%016x\n",
+    VkContext->Signature
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT,
+    "VkContext->Controller: 0x%016x\n",
+    VkContext->Controller
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
+    "VkContext->GraphicsOutput->Mode->MaxMode: 0x%08x\n",
+    VkContext->GraphicsOutput->Mode->MaxMode
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
+    "VkContext->GraphicsOutput->Mode->Mode: 0x%08x\n",
+    VkContext->GraphicsOutput->Mode->Mode
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
+    "VkContext->GraphicsOutput->Mode->Info->HorizontalResolution: 0x%08x\n",
+    VkContext->GraphicsOutput->Mode->Info->HorizontalResolution
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
+    "VkContext->GraphicsOutput->Mode->Info->VerticalResolution: 0x%08x\n",
+    VkContext->GraphicsOutput->Mode->Info->VerticalResolution
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
+    "VkContext->AbsolutePointer->Mode X: 0x%016Lx - 0x%016Lx\n",
+    VkContext->AbsolutePointer->Mode->AbsoluteMinX,
+    VkContext->AbsolutePointer->Mode->AbsoluteMaxX
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
+    "VkContext->AbsolutePointer->Mode Y: 0x%016Lx - 0x%016Lx\n",
+    VkContext->AbsolutePointer->Mode->AbsoluteMinY,
+    VkContext->AbsolutePointer->Mode->AbsoluteMaxY
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
+    "VkContext->AbsolutePointer->Mode Z: 0x%016Lx - 0x%016Lx\n",
+    VkContext->AbsolutePointer->Mode->AbsoluteMinZ,
+    VkContext->AbsolutePointer->Mode->AbsoluteMaxZ
+    ));
+  DEBUG ((
+    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
+    "VkContext->AbsolutePointer->Mode->Attributes: 0x%08x\n",
+    VkContext->AbsolutePointer->Mode->Attributes
+    ));
+}
+
+/**
+  Start the virtual keyboard driver
+
+  This routine allocates the necessary resources for the driver.
+
+  This routine is called by VirtualKeyboardDriverStart to complete the driver
+  initialization.
+
+  @param[in, out] VkContext        Address of an VK_CONTEXT structure
+  @param[in]      Controller       Handle of device to work with.
+
+  @retval EFI_SUCCESS              Driver API properly initialized
+
+**/
+EFI_STATUS
+VkApiStart (
+  IN OUT VK_CONTEXT *VkContext,
+  IN EFI_HANDLE     Controller
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
+  EFI_KEY_DATA                      KeyData;
+  EFI_HANDLE                        NotifyHandle;
+  EFI_EVENT                         ReadyToBootEvent;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Start\n"));
+
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  VkKeyNotifyProcessHandler,
+                  VkContext,
+                  &VkContext->KeyNotifyProcessEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create VkContext->KeyNotifyProcessEvent, Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_WAIT,
+                  TPL_NOTIFY,
+                  VkTouchWaitForKey,
+                  VkContext,
+                  &(VkContext->SimpleTextIn.WaitForKey)
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create VkContext->SimpleTextIn.WaitForKey, Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_WAIT,
+                  TPL_NOTIFY,
+                  VkTouchWaitForKey,
+                  VkContext,
+                  &(VkContext->SimpleTextInEx.WaitForKeyEx)
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create VkContext->SimpleTextInEx.WaitForKeyEx, Status %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_VK_SYNC,
+                  VkTimer,
+                  (VOID *)VkContext,
+                  &(VkContext->TimerEvent)
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create the timer event, Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->SetTimer (
+                  VkContext->TimerEvent,
+                  TimerPeriodic,
+                  (UINT64) VK_POLL_INTERVAL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to set the timer event, Status: %r\n", Status));
+    goto Error;
+  }
+
+  //
+  // Create event to clear keyboard before boot into OS.
+  //
+  Status = EfiCreateEventReadyToBootEx (
+             TPL_CALLBACK,
+             VkReadyToBootCallBack,
+             (VOID *)VkContext,
+             &ReadyToBootEvent
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create ReadyToBootEvent, Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gEfiHiiImageExProtocolGuid,
+                  NULL,
+                  (VOID **) &VkContext->HiiImageEx
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to open HiiImageEx protocol, Status: %r\n", Status));
+    goto Error;
+  }
+
+  //
+  // Initialize VkContext
+  //
+  VkContext->Signature                          = VK_SIGNATURE;
+  VkContext->Controller                         = Controller;
+  VkContext->SimpleTextIn.Reset                 = VkKeyboardReset;
+  VkContext->SimpleTextIn.ReadKeyStroke         = VkKeyboardReadKeyStroke;
+  VkContext->SimpleTextInEx.Reset               = VkKeyboardResetEx;
+  VkContext->SimpleTextInEx.ReadKeyStrokeEx     = VkKeyboardReadKeyStrokeEx;
+  VkContext->SimpleTextInEx.SetState            = VkKeyboardSetState;
+  VkContext->SimpleTextInEx.RegisterKeyNotify   = VkKeyboardRegisterKeyNotify;
+  VkContext->SimpleTextInEx.UnregisterKeyNotify = VkKeyboardUnregisterKeyNotify;
+  VkContext->IsIconShowed                       = FALSE;
+  VkContext->IsBackgroundChanged                = FALSE;
+  VkContext->PageNumber                         = 0;
+  VkContext->CurrentKeyboardDisplay             = VkDisplayAttributeNone;
+  VkContext->TargetKeyboardDisplay              = VkDisplayAttributeNone;
+  VkContext->VkBodyBackgroundBltBuffer          = NULL;
+  VkContext->VkBodyCompoundBltBuffer            = NULL;
+  VkContext->VkBodyBltSize                      = 0;
+  VkContext->VkBodyBltStartX                    = 0;
+  VkContext->VkBodyBltStartY                    = 0;
+  VkContext->VkBodyBltHeight                    = 0;
+  VkContext->VkBodyBltWidth                     = 0;
+  VkContext->IconBltBuffer                      = NULL;
+  VkContext->IconBltSize                        = 0;
+  VkContext->IconReDrawCheck                    = 0;
+  VkContext->FullIconUpdatedFlag                = FALSE;
+  VkContext->SimIconUpdatedFlag                 = FALSE;
+  VkContext->KeyStartIndex                      = 0;
+  VkContext->KeyEndIndex                        = 0;
+  VkContext->KeyToggleState                     = EFI_TOGGLE_STATE_VALID;
+  VkContext->SmallIcon                          = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_SIMPLEICON));
+  VkContext->FullIcon                           = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_FULLICON));
+  VkContext->SimKeyBody                         = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_SIMPLEKEYBOARD));
+  VkContext->DigKeyBody                         = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_DIGITKEYBOARD));
+  VkContext->CapLeKeyBody                       = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_CAPITALLETTERKEYBOARD));
+
+  InitializeListHead (&VkContext->NotifyList);
+
+  Status = SetCharacterPosition (VkContext, 800, 600);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = DrawKeyboardLayout (VkContext);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = HideVkBody (VkContext);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = HideVkIcon (VkContext);
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG_CODE (
+    VkDumpContext (VkContext);
+  );
+
+  Status = gBS->HandleProtocol (
+                  gST->ConsoleInHandle,
+                  &gEfiSimpleTextInputExProtocolGuid,
+                  (VOID **)&SimpleEx
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to found ConIn Protocol, Status: %r\n", Status));
+    goto Error;
+  }
+
+  KeyData.KeyState.KeyToggleState = 0;
+  KeyData.KeyState.KeyShiftState  = 0;
+  KeyData.Key.ScanCode            = SCAN_ESC;
+  KeyData.Key.UnicodeChar         = CHAR_NULL;
+  NotifyHandle                    = NULL;
+  Status = SimpleEx->RegisterKeyNotify (
+                       SimpleEx,
+                       &KeyData,
+                       VkNotifyKeyCallback,
+                       &NotifyHandle
+                       );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to register 'Esc', Status: %r\n", Status));
+    goto Error;
+  }
+
+  KeyData.KeyState.KeyToggleState = 0;
+  KeyData.KeyState.KeyShiftState  = 0;
+  KeyData.Key.ScanCode            = SCAN_NULL;
+  KeyData.Key.UnicodeChar         = CHAR_CARRIAGE_RETURN;
+  Status = SimpleEx->RegisterKeyNotify (
+                       SimpleEx,
+                       &KeyData,
+                       VkNotifyKeyCallback,
+                       &NotifyHandle
+                       );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to register 'Enter', Status: %r\n", Status));
+    goto Error;
+  }
+
+  for (KeyData.Key.UnicodeChar = L' '; KeyData.Key.UnicodeChar <= L'~'; KeyData.Key.UnicodeChar++) {
+    Status = SimpleEx->RegisterKeyNotify (
+                         SimpleEx,
+                         &KeyData,
+                         VkNotifyKeyCallback,
+                         &NotifyHandle
+                         );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR,
+        "ERROR - Failed to register '%c', Status: %r\n",
+        KeyData.Key.UnicodeChar,
+        Status
+        ));
+      break;
+    }
+  }
+  if (EFI_ERROR(Status)) {
+    goto Error;
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  VkApiStop (VkContext);
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart End\n"));
+  return Status;
+}
+
+/**
+  Stop the virtual keyboard driver
+
+  This routine releases the resources allocated by VKApiStart.
+
+  This routine is called by VirtualKeyboardDriverStop to initiate the driver
+  shutdown.
+
+  @param[in] VkContext        Address of an VK_CONTEXT structure
+
+**/
+VOID
+VkApiStop (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  EFI_STATUS Status;
+  VK_NOTIFY  *NotifyNode;
+  LIST_ENTRY *NotifyList;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop Start\n"));
+
+  Status = gBS->SetTimer (VkContext->TimerEvent, TimerCancel, 0);
+  ASSERT_EFI_ERROR (Status);
+
+  if (VkContext->KeyNotifyProcessEvent != NULL) {
+    Status = gBS->CloseEvent (VkContext->KeyNotifyProcessEvent);
+    ASSERT_EFI_ERROR (Status);
+    VkContext->KeyNotifyProcessEvent = NULL;
+  }
+
+  if (VkContext->TimerEvent != NULL) {
+    Status = gBS->CloseEvent (VkContext->TimerEvent);
+    ASSERT_EFI_ERROR (Status);
+    VkContext->TimerEvent = NULL;
+  }
+
+  if (VkContext->SimpleTextIn.WaitForKey != NULL) {
+    Status = gBS->CloseEvent (VkContext->SimpleTextIn.WaitForKey);
+    ASSERT_EFI_ERROR (Status);
+    VkContext->SimpleTextIn.WaitForKey = NULL;
+  }
+
+  if (VkContext->SimpleTextInEx.WaitForKeyEx != NULL) {
+    Status = gBS->CloseEvent (VkContext->SimpleTextInEx.WaitForKeyEx);
+    ASSERT_EFI_ERROR (Status);
+    VkContext->SimpleTextInEx.WaitForKeyEx = NULL;
+  }
+
+  NotifyList = &VkContext->NotifyList;
+  if (NotifyList != NULL) {
+    while (!IsListEmpty (NotifyList)) {
+      NotifyNode = CR (NotifyList->ForwardLink, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
+      RemoveEntryList (NotifyList->ForwardLink);
+      gBS->FreePool (NotifyNode);
+    }
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop End\n"));
+}
+
+/**
+  Reset the input device and optionally run diagnostics
+
+  @param[in] This                 Protocol instance pointer.
+  @param[in] ExtendedVerification Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS             The device was reset.
+  @retval EFI_DEVICE_ERROR        The device is not functioning properly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardReset (
+  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+  IN BOOLEAN                        ExtendedVerification
+  )
+{
+  EFI_STATUS Status;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReset Start\n"));
+  Status = EFI_SUCCESS;
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReset End\n"));
+  return Status;
+}
+
+/**
+  Resets the input device hardware.
+
+  The Reset() function resets the input device hardware. As part
+  of initialization process, the firmware/device will make a quick
+  but reasonable attempt to verify that the device is functioning.
+  If the ExtendedVerification flag is TRUE the firmware may take
+  an extended amount of time to verify the device is operating on
+  reset. Otherwise the reset operation is to occur as quickly as
+  possible. The hardware verification process is not defined by
+  this specification and is left up to the platform firmware or
+  driver to implement.
+
+  @param[in] This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param[in] ExtendedVerification Indicates that the driver may perform a more exhaustive
+                                  verification operation of the device during reset.
+
+  @retval EFI_SUCCESS             The device was reset.
+  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardResetEx (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN BOOLEAN                           ExtendedVerification
+  )
+{
+  EFI_STATUS Status;
+  VK_CONTEXT *VkContext;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx Start\n"));
+
+  Status = EFI_SUCCESS;
+  if (This == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Error;
+  }
+
+  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
+
+  Status = VkContext->SimpleTextIn.Reset (&VkContext->SimpleTextIn, ExtendedVerification);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_KEYS, "ERROR - Failed to VK reset, Status: %r\n", Status));
+    goto Error;
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx End\n"));
+  return Status;
+}
+
+/**
+  Reads the next keystroke from the input device. The WaitForKey Event can
+  be used to test for existence of a keystroke via WaitForEvent () call.
+
+  @param[in]  This         Protocol instance pointer.
+  @param[out] Key          Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS      The keystroke information was returned.
+  @retval EFI_NOT_READY    There was no keystroke data available.
+  @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+                           hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardReadKeyStroke (
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+  OUT EFI_INPUT_KEY                  *Key
+  )
+{
+  EFI_STATUS    Status;
+  VK_CONTEXT    *VkContext;
+  EFI_KEY_DATA  TmpKeyData;
+  EFI_TPL       OldTpl;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke Start\n"));
+
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+  if (This == NULL || Key == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Error;
+  }
+
+  VkContext = VK_CONTEXT_FROM_PROTOCOL (This);
+
+  Status = VkKeyboardReadKeyStrokeEx (&VkContext->SimpleTextInEx, &TmpKeyData);
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+  *Key = TmpKeyData.Key;
+
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke Failed, Status: %r\n", Status));
+
+End:
+  gBS->RestoreTPL (OldTpl);
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke End\n"));
+  return Status;
+}
+
+/**
+  Reads the next keystroke from the input device.
+
+  @param[in]  This               Protocol instance pointer.
+  @param[out] KeyData            A pointer to a buffer that is filled in with the keystroke
+                                 state data for the key that was pressed.
+
+  @retval EFI_SUCCESS            The keystroke information was returned.
+  @retval EFI_NOT_READY          There was no keystroke data available.
+  @retval EFI_INVALID_PARAMETER  This or KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardReadKeyStrokeEx (
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  OUT EFI_KEY_DATA                      *KeyData
+  )
+{
+  VK_CONTEXT        *VkContext;
+  EFI_STATUS        Status;
+  EFI_TPL           OldTpl;
+  EFI_KEY_DATA      TmpKeyData;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx Start\n"));
+
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+  if (This == NULL || KeyData == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Error;
+  }
+
+  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
+
+  while (TRUE) {
+    Status = VkPopTheKey (VkContext, &TmpKeyData);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_VK_KEYS, "ERROR - Failed to VkPopTheKey check whether keybuffer is empty, Status: %r\n", Status));
+      goto Error;
+    }
+    if (TmpKeyData.Key.ScanCode != SCAN_NULL || TmpKeyData.Key.UnicodeChar != CHAR_NULL) {
+      break;
+    }
+  }
+  *KeyData = TmpKeyData;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx Failed, Status: %r\n", Status));
+
+End:
+  gBS->RestoreTPL (OldTpl);
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx End\n"));
+  return Status;
+}
+
+/**
+  Set certain state for the input device.
+
+  @param[in] This                 Protocol instance pointer.
+  @param[in] KeyToggleState       A pointer to the EFI_KEY_TOGGLE_STATE to set the
+                                  state for the input device.
+
+  @retval EFI_SUCCESS             The device state was set appropriately.
+  @retval EFI_INVALID_PARAMETER   This or KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardSetState (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN EFI_KEY_TOGGLE_STATE              *KeyToggleState
+  )
+{
+  EFI_STATUS Status;
+  VK_CONTEXT *VkContext;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState Start\n"));
+
+  Status = EFI_SUCCESS;
+  if (This == NULL || KeyToggleState == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Error;
+  }
+
+  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
+
+  VkContext->KeyToggleState      = *KeyToggleState;
+  VkContext->IsCapsLockFlag      = (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE;
+  VkContext->IsSupportPartialKey = (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED;
+
+  if (VkContext->PageNumber >= VkPage0 && VkContext->PageNumber <= VkPage1) {
+    VkContext->PageNumber = VkContext->IsCapsLockFlag ? VkPage1 : VkPage0;
+  }
+
+  HideVkBody (VkContext);
+  DrawKeyboardLayout (VkContext);
+
+  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext->KeyToggleState:      %02x\n", VkContext->KeyToggleState));
+  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext->IsCapsLockFlag:      %02x\n", VkContext->IsCapsLockFlag));
+  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext->IsSupportPartialKey: %02x\n", VkContext->IsSupportPartialKey));
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState End\n"));
+  return Status;
+}
+
+/**
+  Register a notification function for a particular keystroke for the input device.
+
+  @param[in]  This                        Protocol instance pointer.
+  @param[in]  KeyData                     A pointer to a buffer that is filled in with the keystroke
+                                          information data for the key that was pressed.
+  @param[in]  KeyNotificationFunction     Points to the function to be called when the key
+                                          sequence is typed specified by KeyData.
+  @param[out] NotifyHandle                Points to the unique handle assigned to the registered notification.
+
+  @retval EFI_SUCCESS                     The notification function was registered successfully.
+  @retval EFI_OUT_OF_RESOURCES            Unable to allocate resources for necessary data structures.
+  @retval EFI_INVALID_PARAMETER           KeyData or NotifyHandle or KeyNotificationFunction is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardRegisterKeyNotify (
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN  EFI_KEY_DATA                      *KeyData,
+  IN  EFI_KEY_NOTIFY_FUNCTION           KeyNotificationFunction,
+  OUT EFI_HANDLE                        *NotifyHandle
+  )
+{
+  EFI_STATUS Status;
+  EFI_TPL    OldTpl;
+  VK_CONTEXT *VkContext;
+  LIST_ENTRY *Link;
+  VK_NOTIFY  *CurrentNotify;
+  VK_NOTIFY  *NewNotify;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify Start\n"));
+
+  //
+  // Enter critical section
+  //
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+  Status = EFI_SUCCESS;
+  if (This == NULL || KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Error;
+  }
+  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
+
+
+  //
+  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+  //
+  for (Link = VkContext->NotifyList.ForwardLink; Link != &VkContext->NotifyList; Link = Link->ForwardLink) {
+    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+        *NotifyHandle = CurrentNotify;
+        Status = EFI_SUCCESS;
+        goto End;
+      }
+    }
+  }
+
+  //
+  // Allocate resource to save the notification function
+  //
+  NewNotify = (VK_NOTIFY *) AllocateZeroPool (sizeof (VK_NOTIFY));
+  if (NewNotify == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  NewNotify->Signature         = VK_NOTIFY_SIGNATURE;
+  NewNotify->KeyNotificationFn = KeyNotificationFunction;
+  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+  InsertTailList (&VkContext->NotifyList, &NewNotify->NotifyEntry);
+
+  *NotifyHandle = NewNotify;
+  Status        = EFI_SUCCESS;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify Failed, Status: %r\n", Status));
+
+End:
+  //
+  // Leave critical section and return
+  //
+  gBS->RestoreTPL (OldTpl);
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify End\n"));
+  return Status;
+}
+
+/**
+  Remove a registered notification function from a particular keystroke.
+
+  @param[in] This                Protocol instance pointer.
+  @param[in] NotificationHandle  The handle of the notification function being unregistered.
+
+  @retval EFI_SUCCESS            The notification function was unregistered successfully.
+  @retval EFI_INVALID_PARAMETER  The NotificationHandle is invalid
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardUnregisterKeyNotify (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN EFI_HANDLE                        NotificationHandle
+  )
+{
+  EFI_STATUS Status;
+  VK_CONTEXT *VkContext;
+  EFI_TPL    OldTpl;
+  LIST_ENTRY *Link;
+  VK_NOTIFY  *CurrentNotify;
+  BOOLEAN    IsFindNotifyHandle;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify Start\n"));
+
+  //
+  // Enter critical section
+  //
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+  Status = EFI_SUCCESS;
+  if (This == NULL || NotificationHandle == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Error;
+  }
+  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
+
+  IsFindNotifyHandle = FALSE;
+  for (Link = VkContext->NotifyList.ForwardLink; Link != &VkContext->NotifyList; Link = Link->ForwardLink) {
+    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
+    if (CurrentNotify == NotificationHandle) {
+      //
+      // Remove the notification function from NotifyList and free resources
+      //
+      RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+      gBS->FreePool (CurrentNotify);
+      IsFindNotifyHandle = TRUE;
+      break;
+    }
+  }
+
+  if (!IsFindNotifyHandle) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Error;
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify Failed, Status: %r\n", Status));
+
+End:
+  //
+  // Leave critical section and return
+  //
+  gBS->RestoreTPL (OldTpl);
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify End\n"));
+  return Status;
+}
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c
new file mode 100644
index 0000000000..dcf78985ee
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c
@@ -0,0 +1,1364 @@
+/** @file
+  Virtural Keyboard Layout Engine
+
+  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VirtualKeyboard.h"
+
+//
+// 1.FullKeyboardBody
+// Follow below design
+//   (1).\KeyboardLayout\CapitalLetterKeyboard.bmp
+//   (2).\KeyboardLayout\DigitKeyboard.bmp
+// Based on keyboard's (startX, startY)
+//
+// Page0Font
+// +---+---+---+---+---+---+---+---+---+---+---+
+// | q | w | e | r | t | y | u | i | o | p |<X|| Line 0
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | | a | s | d | f | g | h | j | k | l | F2| | Line 1
+// +-+---+---+---+---+---+---+---+---+---+---+-+
+// |Caps | z | x | c | v | b | n | m |aU |Enter| Line 2
+// +-----+---+---+---+---+---+---+---+---+---+-+
+// | Esc |12#|       Space       |aL |aD |aR | | Line 3
+// +-----+---+-------------------+---+---+---+-+
+//
+// Page1Font
+// +---+---+---+---+---+---+---+---+---+---+---+
+// | Q | W | E | R | T | Y | U | I | O | P |<X|| Line 0
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | | A | S | D | F | G | H | J | K | L | F2| | Line 1
+// +-+---+---+---+---+---+---+---+---+---+---+-+
+// |Caps | Z | X | C | V | B | N | M |aU |Enter| Line 2
+// +-----+---+---+---+---+---+---+---+---+---+-+
+// | Esc |12#|       Space       |aL |aD |aR | | Line 3
+// +-----+---+-------------------+---+---+---+-+
+//
+// Page2Font
+// +---+---+---+---+---+---+---+---+---+---+---+
+// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |<X|| Line 0
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
+// +-+---+---+---+---+---+---+---+---+---+---+-+
+// |Shift| . | ; | ' | , | . | / |F11|F12|Enter| Line 2
+// +-----+---+---+---+---+---+---+---+---+---+-+
+// | Esc |12#|       Space       | \ | - | = | | Line 3
+// +-----+---+-------------------+---+---+---+-+
+//
+// Page3Font
+// +---+---+---+---+---+---+---+---+---+---+---+
+// | ! | @ | # | $ | % | ^ | & | * | ( | ) |<X|| Line 0
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
+// +-+---+---+---+---+---+---+---+---+---+---+-+
+// |Shift| ~ | : | " | < | > | ? |F11|F12|Enter| Line 2
+// +-----+---+---+---+---+---+---+---+---+---+-+
+// | Esc |12#|       Space       | | | _ | + | | Line 3
+// +-----+---+-------------------+---+---+---+-+
+//
+// 2.Screen Corner
+// Follow below design
+//   (1).\KeyboardLayout\SimpleIcon.bmp # Screen Corner A/B
+//   (2).\KeyboardLayout\FullIcon.bmp   # Screen Corner C/D
+// +-+------------------------------------+-+
+// |A|                                    |C|
+// +-+                                    +-+
+// |                                        |
+// |                                        |
+// |                                        |
+// |                                        |
+// |                                        |
+// |                                        |
+// +-+                                    +-+
+// |B|                                    |D|
+// +-+------------------------------------+-+
+//
+VK_STRUCT mFullKeyboardBody[] = {
+  // StartX  StartY  EndX    EndY     Page0Font            Page1Font            Page2Font            Page3Font
+  // Line 0
+  {  0x0000, 0x0000, 0x0032, 0x0032, {L'q',                L'Q',                L'1',                L'!'            }},
+  {  0x0032, 0x0000, 0x0064, 0x0032, {L'w',                L'W',                L'2',                L'@'            }},
+  {  0x0064, 0x0000, 0x0096, 0x0032, {L'e',                L'E',                L'3',                L'#'            }},
+  {  0x0096, 0x0000, 0x00C8, 0x0032, {L'r',                L'R',                L'4',                L'$'            }},
+  {  0x00C8, 0x0000, 0x00FA, 0x0032, {L't',                L'T',                L'5',                L'%'            }},
+  {  0x00FA, 0x0000, 0x012C, 0x0032, {L'y',                L'Y',                L'6',                L'^'            }},
+  {  0x012C, 0x0000, 0x015E, 0x0032, {L'u',                L'U',                L'7',                L'&'            }},
+  {  0x015E, 0x0000, 0x0190, 0x0032, {L'i',                L'I',                L'8',                L'*'            }},
+  {  0x0190, 0x0000, 0x01C2, 0x0032, {L'o',                L'O',                L'9',                L'('            }},
+  {  0x01C2, 0x0000, 0x01F4, 0x0032, {L'p',                L'P',                L'0',                L')'            }},
+  {  0x01F4, 0x0000, 0x0226, 0x0032, {VkKeyBackspace,      VkKeyBackspace,      VkKeyBackspace,      VkKeyBackspace  }},
+  // Line 1
+  {  0x0000, 0x0032, 0x0019, 0x0064, {VkKeyNull,           VkKeyNull,           VkKeyNull,           VkKeyNull       }},
+  {  0x0019, 0x0032, 0x004B, 0x0064, {L'a',                L'A',                VkKeyF1,             VkKeyF1         }},
+  {  0x004B, 0x0032, 0x007D, 0x0064, {L's',                L'S',                VkKeyF2,             VkKeyF2         }},
+  {  0x007D, 0x0032, 0x00AF, 0x0064, {L'd',                L'D',                VkKeyF3,             VkKeyF3         }},
+  {  0x00AF, 0x0032, 0x00E1, 0x0064, {L'f',                L'F',                VkKeyF4,             VkKeyF4         }},
+  {  0x00E1, 0x0032, 0x0113, 0x0064, {L'g',                L'G',                VkKeyF5,             VkKeyF5         }},
+  {  0x0113, 0x0032, 0x0145, 0x0064, {L'h',                L'H',                VkKeyF6,             VkKeyF6         }},
+  {  0x0145, 0x0032, 0x0177, 0x0064, {L'j',                L'J',                VkKeyF7,             VkKeyF7         }},
+  {  0x0177, 0x0032, 0x01A9, 0x0064, {L'k',                L'K',                VkKeyF8,             VkKeyF8         }},
+  {  0x01A9, 0x0032, 0x01DB, 0x0064, {L'l',                L'L',                VkKeyF9,             VkKeyF9         }},
+  {  0x01DB, 0x0032, 0x020D, 0x0064, {VkKeyF2,             VkKeyF2,             VkKeyF10,            VkKeyF10        }},
+  // Line 2
+  {  0x0000, 0x0064, 0x004B, 0x0096, {VkKeyCapslock,       VkKeyCapslock,       VkKeyShift,          VkKeyShift      }},
+  {  0x004B, 0x0064, 0x007D, 0x0096, {L'z',                L'Z',                L'`',                L'~'            }},
+  {  0x007D, 0x0064, 0x00AF, 0x0096, {L'x',                L'X',                L';',                L':'            }},
+  {  0x00AF, 0x0064, 0x00E1, 0x0096, {L'c',                L'C',                L'\'',               L'"'            }},
+  {  0x00E1, 0x0064, 0x0113, 0x0096, {L'v',                L'V',                L',',                L'<'            }},
+  {  0x0113, 0x0064, 0x0145, 0x0096, {L'b',                L'B',                L'.',                L'>'            }},
+  {  0x0145, 0x0064, 0x0177, 0x0096, {L'n',                L'N',                L'/',                L'?'            }},
+  {  0x0177, 0x0064, 0x01A9, 0x0096, {L'm',                L'M',                VkKeyF11,            VkKeyF11        }},
+  {  0x01A9, 0x0064, 0x01DB, 0x0096, {VkKeyUp,             VkKeyUp,             VkKeyF12,            VkKeyF12        }},
+  {  0x01DB, 0x0064, 0x0226, 0x0096, {VkKeyEnter,          VkKeyEnter,          VkKeyEnter,          VkKeyEnter      }},
+  // Line 3
+  {  0x0000, 0x0096, 0x004B, 0x00C8, {VkKeyEsc,            VkKeyEsc,            VkKeyEsc,            VkKeyEsc        }},
+  {  0x004B, 0x0096, 0x007D, 0x00C8, {VkKeyTwoPage,        VkKeyTwoPage,        VkKeyTwoPage,        VkKeyTwoPage    }},
+  {  0x007D, 0x0096, 0x0177, 0x00C8, {L' ',                L' ',                L' ',                L' '            }},
+  {  0x0177, 0x0096, 0x01A9, 0x00C8, {VkKeyLeft,           VkKeyLeft,           L'\\',               L'|'            }},
+  {  0x01A9, 0x0096, 0x01DB, 0x00C8, {VkKeyDown,           VkKeyDown,           L'-',                L'_'            }},
+  {  0x01DB, 0x0096, 0x020D, 0x00C8, {VkKeyRight,          VkKeyRight,          L'=',                L'+'            }},
+  // Screen Corner A
+  {  0x0000, 0x0000, 0x001E, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
+  // Screen Corner B
+  {  0x0000, 0x023A, 0x001E, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
+  // Screen Corner C
+  {  0x02E4, 0x0000, 0x0320, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
+  // Screen Corner D
+  {  0x02E4, 0x023A, 0x0320, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}}
+};
+
+//
+// 1.SimpleKeyboardBody
+// Follow below design
+//   (1).\KeyboardLayout\SimpleKeyboard.bmp
+// Based on keyboard's (startX, startY)
+// +-----+-----+
+// | Esc |Enter| Line 0
+// +-----+-----+
+// | Up  | Down| Line 1
+// +-----+-----+
+//
+// 2.Screen Corner
+// Follow below design
+//   (1).\KeyboardLayout\SimpleIcon.bmp # Screen Corner A/B
+//   (2).\KeyboardLayout\FullIcon.bmp   # Screen Corner C/D
+// +-+------------------------------------+-+
+// |A|                                    |C|
+// +-+                                    +-+
+// |                                        |
+// |                                        |
+// |                                        |
+// |                                        |
+// |                                        |
+// |                                        |
+// +-+                                    +-+
+// |B|                                    |D|
+// +-+------------------------------------+-+
+//
+VK_STRUCT mSimpleKeyboardBody[] = {
+  // StartX  StartY  EndX    EndY     Page0Font            Page1Font            Page2Font            Page3Font
+  // Line 0
+  {  0x0000, 0x0000, 0x0032, 0x0032, {VkKeyEsc,            VkKeyEsc,            VkKeyEsc,            VkKeyEsc        }},
+  {  0x0032, 0x0000, 0x0064, 0x0032, {VkKeyEnter,          VkKeyEnter,          VkKeyEnter,          VkKeyEnter      }},
+  // Line 1
+  {  0x0000, 0x0032, 0x0032, 0x0064, {VkKeyUp,             VkKeyUp,             VkKeyUp,             VkKeyUp         }},
+  {  0x0032, 0x0032, 0x0064, 0x0064, {VkKeyDown,           VkKeyDown,           VkKeyDown,           VkKeyDown       }},
+  // Screen Corner A
+  {  0x0000, 0x0000, 0x001E, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
+  // Screen Corner B
+  {  0x0000, 0x023A, 0x001E, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
+  // Screen Corner C
+  {  0x02E4, 0x0000, 0x0320, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
+  // Screen Corner D
+  {  0x02E4, 0x023A, 0x0320, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}}
+};
+
+EFI_STATUS
+ModifyShiftKeyColor (
+  IN     VK_CONTEXT                    *VkContext,
+  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer
+  )
+{
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *TempBltBuffer;
+  UINTN                         BltSize;
+  BOOLEAN                       IsPressed;
+
+  TempBltBuffer = *BltBuffer;
+  BltSize       = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
+  IsPressed     = VkContext->PageNumber <= VkPage1 ?
+                  VkContext->IsCapsLockFlag :
+                  VkContext->IsShiftKeyFlag;
+
+  while (BltSize-- != 0) {
+    //
+    // Color gradient issue
+    //
+    if (((TempBltBuffer->Red - TempBltBuffer->Green) > 0x20) &&
+        ((TempBltBuffer->Red - TempBltBuffer->Blue)  > 0x20)) {
+      if (IsPressed) {
+        TempBltBuffer->Red   = 0;
+        TempBltBuffer->Green = 255;
+        TempBltBuffer->Blue  = 255;
+      } else {
+        TempBltBuffer->Red   = 255;
+        TempBltBuffer->Green = 255;
+        TempBltBuffer->Blue  = 255;
+      }
+    }
+    TempBltBuffer++;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MakeKeyboardTransparent (
+  IN     VK_CONTEXT                    *VkContext,
+  IN     BOOLEAN                       IsTransparent,
+  IN     EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltIn,
+  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltOut
+  )
+{
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Keyboard;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background;
+  UINTN                         BltSize;
+
+  if (*BltOut == NULL) {
+    *BltOut = AllocateZeroPool (VkContext->VkBodyBltSize);
+    if (*BltOut == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+  Compound   = *BltOut;
+  Keyboard   = BltIn;
+  Background = VkContext->VkBodyBackgroundBltBuffer;
+  BltSize    = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
+  while (BltSize-- != 0) {
+    if (IsTransparent) {
+      Compound->Red   = (Keyboard->Red * TRANSPARENCY_WEIGHT) / 100 + (Background->Red * (100 - TRANSPARENCY_WEIGHT)) / 100;
+      Compound->Green = (Keyboard->Green * TRANSPARENCY_WEIGHT) / 100 + (Background->Green * (100 - TRANSPARENCY_WEIGHT)) / 100;
+      Compound->Blue  = (Keyboard->Blue * TRANSPARENCY_WEIGHT) / 100 + (Background->Blue * (100 - TRANSPARENCY_WEIGHT)) / 100;
+    } else {
+      *Compound = *Keyboard;
+    }
+    Compound++;
+    Keyboard++;
+    Background++;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SaveVkBodyBackgroundBltBuffer (
+  IN VK_CONTEXT *VkContext,
+  IN UINTN      BltSize
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *CurrentBltBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *CurrentBltBufferSave;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *OldBltBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *OldBltBufferSave;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background;
+  UINTN                         Size;
+
+  CurrentBltBufferSave = NULL;
+  OldBltBufferSave     = NULL;
+
+  //
+  // Save original blt buffer first.
+  //
+  OldBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
+  if (OldBltBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  if (VkContext->VkBodyBackgroundBltBuffer != NULL) {
+    CopyMem (OldBltBuffer, VkContext->VkBodyBackgroundBltBuffer, VkContext->VkBodyBltSize);
+  }
+
+  if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
+    VkContext->VkBodyBltSize = BltSize;
+    VkContext->VkBodyBackgroundBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
+    ASSERT (VkContext->VkBodyBackgroundBltBuffer != NULL);
+    if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else if (BltSize > VkContext->VkBodyBltSize) {
+    VkContext->VkBodyBltSize = BltSize;
+    FreePool (VkContext->VkBodyBackgroundBltBuffer);
+    VkContext->VkBodyBackgroundBltBuffer = NULL;
+    VkContext->VkBodyBackgroundBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
+    ASSERT (VkContext->VkBodyBackgroundBltBuffer != NULL);
+    if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    ZeroMem (VkContext->VkBodyBackgroundBltBuffer, VkContext->VkBodyBltSize);
+  }
+
+  CurrentBltBuffer = NULL;
+  if (VkContext->IsBackgroundChanged == TRUE) {
+    //
+    // Background changed, merge current visioning blt buffer with old background blt buffer.
+    //
+    Compound   = VkContext->VkBodyCompoundBltBuffer;
+    Background = VkContext->VkBodyBackgroundBltBuffer;
+    CurrentBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
+    ASSERT (CurrentBltBuffer != NULL);
+    if (CurrentBltBuffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    Status = VkContext->GraphicsOutput->Blt (
+                                          VkContext->GraphicsOutput,
+                                          CurrentBltBuffer,
+                                          EfiBltVideoToBltBuffer,
+                                          VkContext->VkBodyBltStartX,
+                                          VkContext->VkBodyBltStartY,
+                                          0,
+                                          0,
+                                          VkContext->VkBodyBltWidth,
+                                          VkContext->VkBodyBltHeight,
+                                          VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                          );
+    CurrentBltBufferSave = CurrentBltBuffer;
+    OldBltBufferSave = OldBltBuffer;
+    Size = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
+    while (Size-- != 0) {
+      if ((Compound->Red   != CurrentBltBuffer->Red) ||
+          (Compound->Green != CurrentBltBuffer->Green) ||
+          (Compound->Blue  != CurrentBltBuffer->Blue)) {
+        *Background = *CurrentBltBuffer;
+      } else {
+        *Background = *OldBltBuffer;
+      }
+      Compound++;
+      Background++;
+      CurrentBltBuffer++;
+      OldBltBuffer++;
+    }
+  } else {
+    //
+    // Background NOT changed, save it to VkBodyBackgroundBltBuffer directly.
+    //
+    Status = VkContext->GraphicsOutput->Blt (
+                                          VkContext->GraphicsOutput,
+                                          VkContext->VkBodyBackgroundBltBuffer,
+                                          EfiBltVideoToBltBuffer,
+                                          VkContext->VkBodyBltStartX,
+                                          VkContext->VkBodyBltStartY,
+                                          0,
+                                          0,
+                                          VkContext->VkBodyBltWidth,
+                                          VkContext->VkBodyBltHeight,
+                                          VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                          );
+  }
+
+  if (CurrentBltBufferSave != NULL) {
+    FreePool (CurrentBltBufferSave);
+  }
+  if (OldBltBufferSave != NULL) {
+    FreePool (OldBltBufferSave);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+RestoreVkBodyBackgroundBltBuffer (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  EFI_STATUS Status;
+
+  if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = VkContext->GraphicsOutput->Blt (
+                                        VkContext->GraphicsOutput,
+                                        VkContext->VkBodyBackgroundBltBuffer,
+                                        EfiBltBufferToVideo,
+                                        0,
+                                        0,
+                                        VkContext->VkBodyBltStartX,
+                                        VkContext->VkBodyBltStartY,
+                                        VkContext->VkBodyBltWidth,
+                                        VkContext->VkBodyBltHeight,
+                                        VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                        );
+
+  FreePool (VkContext->VkBodyBackgroundBltBuffer);
+  VkContext->VkBodyBackgroundBltBuffer = NULL;
+
+  return Status;
+}
+
+EFI_STATUS
+SetCharacterPosition (
+  IN VK_CONTEXT *VkContext,
+  IN UINT32     DestX,
+  IN UINT32     DestY
+  )
+{
+  UINTN     Index;
+  VK_STRUCT *KeyArryPtr;
+  UINT32    KeyArrySize;
+
+  switch (VkContext->TargetKeyboardDisplay) {
+  case VkDisplayAttributeSimpleTop:
+  case VkDisplayAttributeSimpleBottom:
+    KeyArryPtr  = mSimpleKeyboardBody;
+    KeyArrySize = DIM (mSimpleKeyboardBody);
+    break;
+
+  case VkDisplayAttributeFullBottom:
+  case VkDisplayAttributeFullTop:
+    KeyArryPtr = mFullKeyboardBody;
+    KeyArrySize = DIM (mFullKeyboardBody);
+    break;
+
+  case VkDisplayAttributeNone:
+    KeyArryPtr = mFullKeyboardBody;
+    KeyArrySize = DIM (mFullKeyboardBody);
+    break;
+
+  default:
+    return EFI_UNSUPPORTED;
+  }
+
+  for (Index = 0; Index < KeyArrySize; Index++) {
+    VkContext->KeyboardBodyPtr[Index] = KeyArryPtr[Index];
+  }
+  VkContext->NumOfKeysInfo = KeyArrySize;
+
+  for (Index = 0; Index < (VkContext->NumOfKeysInfo - 4); Index++) {
+    VkContext->KeyboardBodyPtr[Index].DisStartX += (UINT16)DestX;
+    VkContext->KeyboardBodyPtr[Index].DisStartY += (UINT16)DestY;
+    VkContext->KeyboardBodyPtr[Index].DisEndX   += (UINT16)DestX;
+    VkContext->KeyboardBodyPtr[Index].DisEndY   += (UINT16)DestY;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SaveVkIconBackgroundBltBuffer (
+  IN VK_CONTEXT           *VkContext,
+  IN VK_DISPLAY_ATTRIBUTE IconType
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GraphicBlt;
+  UINTN                         BltSize;
+  UINTN                         Height;
+  UINTN                         Width;
+  INTN                          StartX;
+  INTN                          StartY;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *TempIconBackBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *IconBackBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
+  UINTN                         Size;
+  BOOLEAN                       SaveCursor;
+
+  Status             = EFI_SUCCESS;
+  StartX             = 0;
+  StartY             = 0;
+  TempIconBackBuffer = NULL;
+  IconBackBuffer     = NULL;
+  Compound           = NULL;
+
+  if ((IconType == VkDisplayAttributeFullTop) ||
+      (IconType == VkDisplayAttributeSimpleTop)) {
+    return EFI_SUCCESS;
+  }
+
+  SaveCursor = gST->ConOut->Mode->CursorVisible;
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+  if (IconType == VkDisplayAttributeFullBottom) {
+    GraphicBlt = VkContext->FullIcon->Bitmap;
+    BltSize    = VkContext->FullIcon->Height * VkContext->FullIcon->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+    Height     = VkContext->FullIcon->Height;
+    Width      = VkContext->FullIcon->Width;
+    StartX     = VkContext->FullIconBackStartX;
+    StartY     = VkContext->FullIconBackStartY;
+  } else if (IconType == VkDisplayAttributeSimpleBottom) {
+    GraphicBlt = VkContext->SmallIcon->Bitmap;
+    BltSize    = VkContext->SmallIcon->Height * VkContext->SmallIcon->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+    Height     = VkContext->SmallIcon->Height;
+    Width      = VkContext->SmallIcon->Width;
+    StartX     = VkContext->SimIconBackStartX;
+    StartY     = VkContext->SimIconBackStartY;
+  } else {
+    gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
+    return EFI_UNSUPPORTED;
+  }
+
+  IconBackBuffer = AllocateZeroPool (BltSize);
+  if (IconBackBuffer == NULL) {
+    gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  TempIconBackBuffer = IconBackBuffer;
+  Status = VkContext->GraphicsOutput->Blt (
+                                        VkContext->GraphicsOutput,
+                                        IconBackBuffer,
+                                        EfiBltVideoToBltBuffer,
+                                        StartX,
+                                        StartY,
+                                        0,
+                                        0,
+                                        Width,
+                                        Height,
+                                        Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                        );
+
+  if (IconType == VkDisplayAttributeFullBottom) {
+    //
+    // Store full icon background framebuffer
+    //
+    VkContext->FullIconBackHeight = Height;
+    VkContext->FullIconBackWidth  = Width;
+    if (VkContext->FullIconUpdatedFlag == FALSE) {
+      //
+      // No icon draw, save the buffer directly.
+      //
+      if (VkContext->FullIconBackBuffer == NULL) {
+        VkContext->FullIconBackBuffer = AllocateZeroPool (BltSize);
+        VkContext->FullIconBackSize = BltSize;
+      }
+      CopyMem (VkContext->FullIconBackBuffer, IconBackBuffer, BltSize);
+      VkContext->FullIconUpdatedFlag = TRUE;
+    } else {
+      if (CompareMem (VkContext->FullIconBackBuffer, IconBackBuffer, BltSize) != 0) {
+        Compound = VkContext->FullIconBackBuffer;
+        Size = Height * Width;
+        while (Size-- != 0) {
+          if ((GraphicBlt->Red   != IconBackBuffer->Red) ||
+              (GraphicBlt->Green != IconBackBuffer->Green) ||
+              (GraphicBlt->Blue  != IconBackBuffer->Blue)) {
+            *Compound = *IconBackBuffer;
+          }
+          Compound++;
+          GraphicBlt++;
+          IconBackBuffer++;
+        }
+      }
+    }
+  } else if (IconType == VkDisplayAttributeSimpleBottom) {
+    //
+    // Store simple icon background framebuffer
+    //
+    VkContext->SimIconBackHeight = Height;
+    VkContext->SimIconBackWidth  = Width;
+    if (VkContext->SimIconUpdatedFlag == FALSE) {
+      //
+      // No icon draw, save the buffer directly.
+      //
+      if (VkContext->SimIconBackBuffer == NULL) {
+        VkContext->SimIconBackBuffer = AllocateZeroPool (BltSize);
+        VkContext->SimIconBackSize = BltSize;
+      }
+      CopyMem (VkContext->SimIconBackBuffer, IconBackBuffer, BltSize);
+      VkContext->SimIconUpdatedFlag = TRUE;
+    } else {
+      if (CompareMem (VkContext->SimIconBackBuffer, IconBackBuffer, BltSize) != 0) {
+        Compound = VkContext->SimIconBackBuffer;
+        Size = Height * Width;
+        while (Size-- != 0) {
+          if ((GraphicBlt->Red   != IconBackBuffer->Red) ||
+              (GraphicBlt->Green != IconBackBuffer->Green) ||
+              (GraphicBlt->Blue  != IconBackBuffer->Blue)) {
+            *Compound = *IconBackBuffer;
+          }
+          Compound++;
+          GraphicBlt++;
+          IconBackBuffer++;
+        }
+      }
+    }
+  }
+
+  if (TempIconBackBuffer != NULL)  FreePool (TempIconBackBuffer);
+
+  gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
+  return Status;
+}
+
+/**
+  Use to draw the keyboard icon.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+  @param[in] VkImage    Image of keyboard to display on the screen.
+  @param[in] Attribute  Attribute of keyboard to display on the screen.
+
+  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard icon displayed.
+  @retval EFI_UNSUPPORTED       KeyboardFile not found
+  @retval EFI_INVALID_PARAMETER Attribute is unknown.
+
+**/
+EFI_STATUS
+EFIAPI
+DrawVkIcon (
+  IN VK_CONTEXT                    *VkContext,
+  IN EFI_IMAGE_INPUT               *VkImage,
+  IN VK_DISPLAY_ATTRIBUTE          Attribute
+  )
+{
+  EFI_STATUS                    Status;
+  UINT32                        SizeOfX;
+  UINT32                        SizeOfY;
+  INTN                          DestX;
+  INTN                          DestY;
+  UINTN                         CoordinateX;
+  UINTN                         CoordinateY;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  UINTN                         BltSize;
+  UINTN                         Height;
+  UINTN                         Width;
+
+  Status         = EFI_SUCCESS;
+  GraphicsOutput = VkContext->GraphicsOutput;
+  SizeOfX        = GraphicsOutput->Mode->Info->HorizontalResolution;
+  SizeOfY        = GraphicsOutput->Mode->Info->VerticalResolution;
+  CoordinateX    = 0;
+  CoordinateY    = 0;
+  Height         = VkImage->Height;
+  Width          = VkImage->Width;
+  Blt            = VkImage->Bitmap;
+  BltSize        = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * (UINT32)(Width * Height);
+
+  //
+  // Calculate the display position according to Attribute.
+  //
+  switch (Attribute) {
+  case VkDisplayAttributeSimpleTop:
+    DestX = CoordinateX;
+    DestY = CoordinateY;
+    break;
+
+  case VkDisplayAttributeFullTop:
+    DestX = (SizeOfX - Width - CoordinateX);
+    DestY = CoordinateY;;
+    break;
+
+  case VkDisplayAttributeFullBottom:
+    DestX                         = (SizeOfX - Width - CoordinateX);
+    DestY                         = (SizeOfY - Height - CoordinateY);
+    VkContext->FullIconBackStartX = DestX;
+    VkContext->FullIconBackStartY = DestY;
+    break;
+
+  case VkDisplayAttributeSimpleBottom:
+    DestX = CoordinateX;
+    DestY = (SizeOfY - Height - CoordinateY);
+
+    //
+    // Save to check icon/screen cleared
+    //
+    if (VkContext->IconBltBuffer == NULL) {
+      VkContext->IconBltSize   = BltSize;
+      VkContext->IconBltWidth  = Width;
+      VkContext->IconBltHeight = Height;
+      VkContext->IconBltBuffer = AllocateZeroPool (BltSize);
+    }
+    CopyMem (VkContext->IconBltBuffer, Blt, VkContext->IconBltSize);
+
+    VkContext->SimIconBackStartX = DestX;
+    VkContext->SimIconBackStartY = DestY;
+    break;
+
+  case VkDisplayAttributeNone:
+    return EFI_SUCCESS;
+
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((DestX >= 0) && (DestY >= 0)) {
+    //
+    // Store icon background framebuffer
+    //
+    SaveVkIconBackgroundBltBuffer (VkContext, Attribute);
+    Status = GraphicsOutput->Blt (
+                               GraphicsOutput,
+                               Blt,
+                               EfiBltBufferToVideo,
+                               0,
+                               0,
+                               (UINTN) DestX,
+                               (UINTN) DestY,
+                               Width,
+                               Height,
+                               Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                               );
+  }
+
+  return Status;
+}
+
+/**
+  Use to draw the keyboard.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+  @param[in] VkImage    Image of keyboard to display on the screen.
+  @param[in] Attribute  Attribute of keyboard to display on the screen.
+
+  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard displayed.
+  @retval EFI_UNSUPPORTED       KeyboardFile not found
+  @retval EFI_INVALID_PARAMETER Attribute is unknown.
+
+**/
+EFI_STATUS
+EFIAPI
+DrawVkBody (
+  IN VK_CONTEXT                    *VkContext,
+  IN EFI_IMAGE_INPUT               *VkImage,
+  IN VK_DISPLAY_ATTRIBUTE          Attribute
+  )
+{
+  EFI_STATUS                    Status;
+  UINT32                        SizeOfX;
+  UINT32                        SizeOfY;
+  INTN                          DestX;
+  INTN                          DestY;
+  UINTN                         BltSize;
+  UINTN                         Height;
+  UINTN                         Width;
+  UINTN                         CoordinateY;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltIn;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
+
+  Status         = EFI_SUCCESS;
+  GraphicsOutput = VkContext->GraphicsOutput;
+  SizeOfX        = GraphicsOutput->Mode->Info->HorizontalResolution;
+  SizeOfY        = GraphicsOutput->Mode->Info->VerticalResolution;
+  CoordinateY    = 0;
+  Height         = VkImage->Height;
+  Width          = VkImage->Width;
+  BltSize        = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * (UINT32)(Width * Height);
+  BltIn          = AllocateCopyPool (BltSize, VkImage->Bitmap);
+
+  if (BltIn == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Calculate the display position according to Attribute.
+  //
+  switch (Attribute) {
+  case VkDisplayAttributeSimpleTop:
+    DestX = ((SizeOfX / 2) - Width) / 4;
+    DestY = CoordinateY;
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeSimpleTop;
+    break;
+
+  case VkDisplayAttributeSimpleBottom:
+    DestX = ((SizeOfX / 2) - Width) / 4;
+    DestY = (SizeOfY - Height - CoordinateY);
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeSimpleBottom;
+    break;
+
+  case VkDisplayAttributeFullTop:
+    DestX = (SizeOfX - Width) / 2;
+    DestY = CoordinateY;
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeFullTop;
+    break;
+
+  case VkDisplayAttributeFullBottom:
+    DestX = (SizeOfX - Width) / 2;
+    DestY = (SizeOfY - Height - CoordinateY);
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeFullBottom;
+    break;
+
+  case VkDisplayAttributeNone:
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
+    goto DVKBODY_Exit;
+
+  default:
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
+    Status = EFI_INVALID_PARAMETER;
+    goto DVKBODY_Exit;
+  }
+  if ((DestX >= 0) && (DestY >= 0)) {
+    SetCharacterPosition (VkContext, (UINT32)DestX, (UINT32)DestY);
+
+    //
+    // Store current framebuffer
+    //
+    VkContext->VkBodyBltStartX = DestX;
+    VkContext->VkBodyBltStartY = DestY;
+    VkContext->VkBodyBltHeight = Height;
+    VkContext->VkBodyBltWidth  = Width;
+    SaveVkBodyBackgroundBltBuffer (VkContext, BltSize);
+
+    //
+    // Free compound buffer first.
+    //
+    if (VkContext->VkBodyCompoundBltBuffer != NULL) {
+      FreePool (VkContext->VkBodyCompoundBltBuffer);
+    }
+    VkContext->VkBodyCompoundBltBuffer = NULL;
+    ModifyShiftKeyColor (VkContext, &BltIn);
+    MakeKeyboardTransparent (VkContext, TRUE, BltIn, &(VkContext->VkBodyCompoundBltBuffer));
+
+    //
+    // Draw keyboard body
+    //
+    Status = GraphicsOutput->Blt (
+                               GraphicsOutput,
+                               VkContext->VkBodyCompoundBltBuffer,
+                               EfiBltBufferToVideo,
+                               0,
+                               0,
+                               (UINTN) DestX,
+                               (UINTN) DestY,
+                               Width,
+                               Height,
+                               Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                               );
+  }
+
+
+DVKBODY_Exit:
+  if (BltIn != NULL) {
+    FreePool (BltIn);
+  }
+
+  return Status;
+}
+
+/**
+  Clear the keyboard body
+
+  @param  VkContext             Code context.
+
+  @retval EFI_SUCCESS           Clear rectangle is done.
+
+**/
+EFI_STATUS
+HideVkBody (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  RestoreVkBodyBackgroundBltBuffer (VkContext);
+  VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Clear the keyboard icon
+
+  @param  VkContext             Code context.
+
+  @retval EFI_SUCCESS           Clear rectangle is done.
+
+**/
+EFI_STATUS
+HideVkIcon (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  EFI_STATUS                    Status;
+
+  if ((VkContext->FullIconBackBuffer == NULL) || (VkContext->SimIconBackBuffer == NULL)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if ((VkContext->FullIconUpdatedFlag == FALSE) || (VkContext->SimIconUpdatedFlag == FALSE)) {
+    return EFI_UNSUPPORTED;
+  }
+  Status = VkContext->GraphicsOutput->Blt (
+                                        VkContext->GraphicsOutput,
+                                        VkContext->FullIconBackBuffer,
+                                        EfiBltBufferToVideo,
+                                        0,
+                                        0,
+                                        VkContext->FullIconBackStartX,
+                                        VkContext->FullIconBackStartY,
+                                        VkContext->FullIconBackWidth,
+                                        VkContext->FullIconBackHeight,
+                                        VkContext->FullIconBackWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                        );
+
+  ZeroMem (VkContext->FullIconBackBuffer, VkContext->FullIconBackSize);
+  VkContext->FullIconUpdatedFlag = FALSE;
+
+
+  Status = VkContext->GraphicsOutput->Blt (
+                                        VkContext->GraphicsOutput,
+                                        VkContext->SimIconBackBuffer,
+                                        EfiBltBufferToVideo,
+                                        0,
+                                        0,
+                                        VkContext->SimIconBackStartX,
+                                        VkContext->SimIconBackStartY,
+                                        VkContext->SimIconBackWidth,
+                                        VkContext->SimIconBackHeight,
+                                        VkContext->SimIconBackWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                        );
+  if (!EFI_ERROR (Status)) {
+    if (VkContext->ScreenCheckBuffer == NULL) {
+      VkContext->ScreenCheckBufferSize = VkContext->SimIconBackHeight *
+                                         VkContext->SimIconBackWidth *
+                                         sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+      VkContext->ScreenCheckBuffer = AllocateZeroPool (VkContext->ScreenCheckBufferSize);
+    }
+
+    CopyMem (
+      VkContext->ScreenCheckBuffer,
+      VkContext->SimIconBackBuffer,
+      (VkContext->SimIconBackHeight * VkContext->SimIconBackWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))
+      );
+  }
+  ZeroMem (VkContext->SimIconBackBuffer, VkContext->SimIconBackSize);
+  VkContext->SimIconUpdatedFlag = FALSE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Draw key board on the display
+
+  @param[in] VkContext          Graphic Protocol for draw the alphabet.
+
+  @retval EFI_SUCCESS           Draw keyboard was done.
+  @retval EFI_UNSUPPORTED       Did not get key mapping table.
+
+**/
+EFI_STATUS
+DrawKeyboardLayout (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  EFI_STATUS Status;
+  if (!VkContext->IsIconShowed) {
+    Status = DrawVkIcon (VkContext, VkContext->SmallIcon, VkDisplayAttributeSimpleTop);
+    ASSERT_EFI_ERROR (Status);
+
+    Status = DrawVkIcon (VkContext, VkContext->SmallIcon, VkDisplayAttributeSimpleBottom);
+    ASSERT_EFI_ERROR (Status);
+
+    Status = DrawVkIcon (VkContext, VkContext->FullIcon,  VkDisplayAttributeFullTop);
+    ASSERT_EFI_ERROR (Status);
+
+    Status = DrawVkIcon (VkContext, VkContext->FullIcon,  VkDisplayAttributeFullBottom);
+    ASSERT_EFI_ERROR (Status);
+    VkContext->IsIconShowed = TRUE;
+  }
+
+  if (VkContext->TargetKeyboardDisplay != VkContext->CurrentKeyboardDisplay) {
+    switch (VkContext->TargetKeyboardDisplay) {
+    case VkDisplayAttributeSimpleTop:
+    case VkDisplayAttributeSimpleBottom:
+      DrawVkBody (VkContext, VkContext->SimKeyBody, VkContext->TargetKeyboardDisplay);
+      break;
+
+    case VkDisplayAttributeFullTop:
+    case VkDisplayAttributeFullBottom:
+      if (VkContext->PageNumber <= VkPage1) {
+        DrawVkBody (VkContext, VkContext->CapLeKeyBody, VkContext->TargetKeyboardDisplay);
+      } else {
+        DrawVkBody (VkContext, VkContext->DigKeyBody, VkContext->TargetKeyboardDisplay);
+      }
+
+    case VkDisplayAttributeNone:
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+KeyboardLayoutHandler (
+  IN VK_CONTEXT *VkContext,
+  IN UINT32     Index
+  )
+{
+  EFI_STATUS Status;
+
+  Status = EFI_SUCCESS;
+
+  if (Index == (VkContext->NumOfKeysInfo - 4)) {
+    //
+    // Touch the LeftTop icon
+    //
+    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeSimpleTop) {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
+    } else {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeSimpleTop;
+    }
+  } else if (Index == (VkContext->NumOfKeysInfo - 3)) {
+    //
+    // Touch the LeftBottom icon
+    //
+    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeSimpleBottom) {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
+    } else {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeSimpleBottom;
+    }
+  } else if (Index == (VkContext->NumOfKeysInfo - 2)) {
+    //
+    // Touch the RightTop icon
+    //
+    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeFullTop) {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
+    } else {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeFullTop;
+    }
+  } else {
+    //
+    // Touch the RightBottom icon
+    //
+    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeFullBottom) {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
+    } else {
+      VkContext->TargetKeyboardDisplay = VkDisplayAttributeFullBottom;
+    }
+  }
+
+  if (VkContext->TargetKeyboardDisplay == VkDisplayAttributeNone) {
+    //
+    // Just hide the current keyboard
+    //
+    HideVkBody (VkContext);
+    VkContext->KeyTouchedTimeOut = VK_REPEAT_TIMEOUT;
+
+  } else {
+    //
+    // If current keyboard status is NOT none,
+    // hide current keyboard first and then draw the target keyboard
+    //
+    if (VkContext->CurrentKeyboardDisplay != VkDisplayAttributeNone) {
+      HideVkBody (VkContext);
+    }
+    Status = DrawKeyboardLayout (VkContext);
+  }
+
+  return Status;
+}
+
+/**
+  This routine is used to check if icon has been cleared.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+
+  @retval EFI_SUCCESS   Function completed.
+
+**/
+EFI_STATUS
+CheckIconCleared (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  EFI_STATUS                    Status;
+  UINT32                        VerticalResolution;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+
+  Status = EFI_SUCCESS;
+  BltBuffer = NULL;
+  VkContext->IconReDrawCheck++;
+  if (VkContext->IconReDrawCheck <= 10) {
+    //
+    // Check it every 10 * 100ms.
+    //
+    return Status;
+  }
+
+  //
+  // Check if right-bottomed region is black, if yes, clean screen happened, need to re-draw keyboard.
+  //
+  VerticalResolution    = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
+  BltBuffer             = AllocateZeroPool (VkContext->IconBltSize);
+  if (BltBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  Status = VkContext->GraphicsOutput->Blt (
+                                        VkContext->GraphicsOutput,
+                                        BltBuffer,
+                                        EfiBltVideoToBltBuffer,
+                                        0,
+                                        (VerticalResolution - VkContext->IconBltHeight),
+                                        0,
+                                        0,
+                                        VkContext->IconBltWidth,
+                                        VkContext->IconBltHeight,
+                                        VkContext->IconBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                        );
+  if (EFI_ERROR (Status)) {
+    FreePool (BltBuffer);
+    return Status;
+  }
+  VkContext->IsIconShowed = TRUE;
+  if (VkContext->IconBltBuffer == NULL) {
+    //
+    // No icon has been drawn.
+    //
+    VkContext->IsIconShowed = FALSE;
+  } else {
+    if (CompareMem (BltBuffer, VkContext->IconBltBuffer, VkContext->IconBltSize) != 0) {
+      //
+      // Icon has been overridden, need to re-draw.
+      //
+      VkContext->IsIconShowed = FALSE;
+    }
+  }
+
+  if (VkContext->IsIconShowed == FALSE) {
+    if (VkContext->ScreenCheckBuffer != NULL) {
+      if (CompareMem (BltBuffer, VkContext->ScreenCheckBuffer, VkContext->IconBltSize) == 0) {
+        //
+        // Icon has been overridden, force to re-draw the keyboard.
+        //
+        Status = DrawKeyboardLayout (VkContext);
+      } else {
+        //
+        // Save blt buffer of icon position and use it to check if icon is overridden.
+        //
+        CopyMem (VkContext->ScreenCheckBuffer, BltBuffer, VkContext->IconBltSize);
+      }
+    } else {
+      //
+      // Draw the keyboard.
+      //
+      Status = DrawKeyboardLayout (VkContext);
+    }
+  }
+
+  if (BltBuffer != NULL) {
+    FreePool (BltBuffer);
+  }
+
+  VkContext->IconReDrawCheck = 0;
+
+  return Status;
+}
+
+/**
+  ConvertCoordinate - Convert the touch panel's coordinate to display's coordinate.
+
+  @param[in]  VkContext             Virtual Keyboard context.
+  @param[in]  Point                 The coordinate reported from touch panel.
+  @param[out] TouchX                The coordinate X converted to display panel.
+  @param[out] TouchY                The coordinate Y converted to display panel..
+
+  @retval EFI_SUCCESS               Convert success.
+
+**/
+EFI_STATUS
+ConvertCoordinate (
+  IN  VK_CONTEXT                 *VkContext,
+  IN  EFI_ABSOLUTE_POINTER_STATE Point,
+  OUT UINT32                     *TouchX,
+  OUT UINT32                     *TouchY
+  )
+{
+  UINT64 AbsoluteMaxX;
+  UINT64 AbsoluteMaxY;
+  UINT32 HorizontalResolution;
+  UINT32 VerticalResolution;
+
+  AbsoluteMaxX         = VkContext->AbsolutePointer->Mode->AbsoluteMaxX;
+  AbsoluteMaxY         = VkContext->AbsolutePointer->Mode->AbsoluteMaxY;
+  HorizontalResolution = VkContext->GraphicsOutput->Mode->Info->HorizontalResolution;
+  VerticalResolution   = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
+  *TouchX              = (UINT32) MultU64x32 (Point.CurrentX, HorizontalResolution) / (UINT32) AbsoluteMaxX;
+  *TouchY              = (UINT32) MultU64x32 (Point.CurrentY, VerticalResolution) / (UINT32) AbsoluteMaxY;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This routine is used to check if screen has been cleared.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+
+  @retval EFI_SUCCESS   Function completed.
+
+**/
+EFI_STATUS
+CheckScreenCleared (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  EFI_STATUS                    Status;
+  UINT32                        HorizontalResolution;
+  UINT32                        VerticalResolution;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBufferIndex;
+  UINTN                         BltSize;
+  BOOLEAN                       IsScreenCleared;
+
+  //
+  // Check left-bottom side.
+  // If IconBltBuffer is null, checking is meaningless.
+  //
+  if (VkContext->IconBltBuffer == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  IsScreenCleared = FALSE;
+  Status          = EFI_SUCCESS;
+  if ((gST->ConOut->Mode->CursorColumn == 0) && (gST->ConOut->Mode->CursorRow == 0)) {
+    //
+    // System may call gST->ConOut->ClearScreen
+    //
+    HorizontalResolution  = VkContext->GraphicsOutput->Mode->Info->HorizontalResolution;
+    VerticalResolution    = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
+    BltBuffer             = AllocateZeroPool (VkContext->IconBltSize);
+    if (BltBuffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    BltBufferIndex = BltBuffer;
+    Status = VkContext->GraphicsOutput->Blt (
+                                          VkContext->GraphicsOutput,
+                                          BltBuffer,
+                                          EfiBltVideoToBltBuffer,
+                                          (HorizontalResolution - VkContext->IconBltWidth),
+                                          (VerticalResolution - VkContext->IconBltHeight),
+                                          0,
+                                          0,
+                                          VkContext->IconBltWidth,
+                                          VkContext->IconBltHeight,
+                                          VkContext->IconBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                          );
+    if (EFI_ERROR (Status)) {
+      FreePool (BltBuffer);
+      return Status;
+    }
+    BltSize = VkContext->IconBltHeight * VkContext->IconBltWidth;
+    IsScreenCleared = TRUE;
+    while (BltSize-- != 0) {
+      if ((BltBufferIndex->Red != 0) || (BltBufferIndex->Green != 0) || (BltBufferIndex->Blue != 0)) {
+        IsScreenCleared = FALSE;
+        break;
+      }
+      BltBufferIndex++;
+    }
+    FreePool (BltBuffer);
+  }
+
+  if (IsScreenCleared == TRUE) {
+    VkContext->IsIconShowed   = FALSE;
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
+
+    if (VkContext->VkBodyBackgroundBltBuffer != NULL) {
+      FreePool (VkContext->VkBodyBackgroundBltBuffer);
+      VkContext->VkBodyBackgroundBltBuffer = NULL;
+    }
+
+    if (VkContext->VkBodyCompoundBltBuffer != NULL) {
+      FreePool (VkContext->VkBodyCompoundBltBuffer);
+      VkContext->VkBodyCompoundBltBuffer = NULL;
+    }
+
+    if (VkContext->IconBltBuffer != NULL) {
+      FreePool (VkContext->IconBltBuffer);
+      VkContext->IconBltBuffer = NULL;
+    }
+
+  }
+
+  return Status;
+}
+
+/**
+  This routine is used to check if background beneath virtual keyboard has been cleared.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+
+  @retval EFI_SUCCESS   Function completed.
+
+**/
+EFI_STATUS
+CheckBackgroundChanged (
+  IN VK_CONTEXT *VkContext
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+
+  Status                         = EFI_SUCCESS;
+  VkContext->IsBackgroundChanged = FALSE;
+
+  if ((VkContext->CurrentKeyboardDisplay == VkDisplayAttributeNone) || (VkContext->VkBodyCompoundBltBuffer == NULL)) {
+    return EFI_SUCCESS;
+  }
+
+  BltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
+  if (BltBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  Status = VkContext->GraphicsOutput->Blt (
+                                        VkContext->GraphicsOutput,
+                                        BltBuffer,
+                                        EfiBltVideoToBltBuffer,
+                                        VkContext->VkBodyBltStartX,
+                                        VkContext->VkBodyBltStartY,
+                                        0,
+                                        0,
+                                        VkContext->VkBodyBltWidth,
+                                        VkContext->VkBodyBltHeight,
+                                        VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                                        );
+  if (EFI_ERROR (Status)) {
+    FreePool (BltBuffer);
+    return Status;
+  }
+  if (CompareMem (BltBuffer, VkContext->VkBodyCompoundBltBuffer, VkContext->VkBodyBltSize) != 0) {
+    VkContext->IsBackgroundChanged = TRUE;
+    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
+    DrawKeyboardLayout (VkContext);
+  }
+
+  if (BltBuffer != NULL) {
+    FreePool (BltBuffer);
+  }
+
+  return Status;
+}
+
+/**
+  Get unicode by VkContext->PageNumber and VkContext->KeyboardBodyPtr.
+
+  @param[in]  VkContext            Address of an VK_CONTEXT structure.
+  @param[in]  KeyItem              Key Item.
+  @param[out] FontPtr              Follow VkContext->PageNumber to translate
+                                   font unicode.
+
+  @retval EFI_SUCCESS              Finish translating FontPtr.
+  @retval EFI_INVALID_PARAMETER    VkContext or FontPtr is NULL.
+
+**/
+EFI_STATUS
+VkGetMappingFont (
+  IN  VK_CONTEXT *VkContext,
+  IN  VK_STRUCT  KeyItem,
+  OUT UINT32     *FontPtr
+  )
+{
+  if ((VkContext == NULL) || (FontPtr == NULL) || (VkContext->PageNumber>=VkPageMaximum)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  *FontPtr = (UINT32) KeyItem.PageFont[VkContext->PageNumber];
+
+  return EFI_SUCCESS;
+}
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf
new file mode 100644
index 0000000000..995bd0d859
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf
@@ -0,0 +1,12 @@
+// /** @file
+// Virtual Keyboard Layout
+//
+// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+#image IMG_VK_CAPITALLETTERKEYBOARD TRANSPARENT CapitalLetterKeyboard.bmp
+#image IMG_VK_DIGITKEYBOARD         TRANSPARENT DigitKeyboard.bmp
+#image IMG_VK_FULLICON              TRANSPARENT FullIcon.bmp
+#image IMG_VK_SIMPLEICON            TRANSPARENT SimpleIcon.bmp
+#image IMG_VK_SIMPLEKEYBOARD        TRANSPARENT SimpleKeyboard.bmp
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleIcon.bmp b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleIcon.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..16816f031eb98bf8169c7119b95ea3ed1371f41d
GIT binary patch
literal 2814
zcmeHDu?>JQ41<*mn3%bM1K9bStAMDgEvtknP%#v#jj<EA^|~EHm%hdJ+18X--;Igi
zvz~tHZ083bZvKJwS=AedIaS~0$e`HvNI;OvAp=5}kZlld1O%z<Y2HkwWx^;3ew~S4
zE{O5qpp83T)f<O7RWIkrpxE|EK#<BI145UOZ4hn*1gY$4-b|%s!YByBnW#Y!<5EEz
Lcf5u-&Un3EdmJn}

literal 0
HcmV?d00001

diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleKeyboard.bmp b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleKeyboard.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3004a534f026fe4906e64480f2239b7b7923640b
GIT binary patch
literal 30054
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
D{aYn_

literal 0
HcmV?d00001

diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h
new file mode 100644
index 0000000000..debd4346c7
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h
@@ -0,0 +1,777 @@
+/** @file
+  Header file for Virtual Keyboard driver.
+
+  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VIRTUAL_KEYBOARD_H_
+#define _VIRTUAL_KEYBOARD_H_
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HiiLib.h>
+#include <Protocol/AbsolutePointer.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiImageEx.h>
+#include <Protocol/HiiPackageList.h>
+#include <Guid/ConsoleInDevice.h>
+#include "ComponentName.h"
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL   gVirtualKeyboardDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gVirtualKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gVirtualKeyboardComponentName2;
+
+///
+/// Debug raw data points
+///
+#define DEBUG_VK_POINTS               0x40000000
+
+///
+/// Debug data point scaling
+///
+#define DEBUG_VK_POINT_SCALING        0x20000000
+
+///
+/// Debug key press
+///
+#define DEBUG_VK_KEYS                 0x10000000
+
+///
+/// Debug routine entry and exit
+///
+#define DEBUG_VK_ROUTINE_ENTRY_EXIT   0x08000000
+
+///
+/// Display the graphics info
+///
+#define DEBUG_VK_GRAPHICS_INFO        0x04000000
+
+///
+/// Display the timer entry and exit
+///
+#define DEBUG_VK_TIMER_ENTRY_EXIT     0x00100000
+
+///
+/// Signature
+///
+#define VK_SIGNATURE                  SIGNATURE_32 ('V', 'K', 'e', 'y')
+#define VK_NOTIFY_SIGNATURE           SIGNATURE_32 ('V', 'K', 'n', 's')
+
+///
+/// Poll interval
+///
+#define VK_POLL_INTERVAL              (1000 * 1000)
+
+///
+/// Define the touch timeout in poll intervals
+///
+#define VK_REPEAT_TIMEOUT             5
+
+///
+/// TPL used to synchronize add/remove from list
+///
+#define TPL_VK_SYNC                   TPL_NOTIFY
+
+///
+/// Dimension of an array ( number of elements )
+///
+#define DIM(x)      ( sizeof ( x ) / sizeof ( x [ 0 ]))
+
+///
+/// Define Key buffer
+///
+#define MAX_KEY_BUF_SIZE 64
+
+///
+/// Define Transparent Weight
+///
+#define TRANSPARENCY_WEIGHT 50
+
+typedef struct _VK_CONTEXT VK_CONTEXT;
+
+typedef enum _VK_KEY_TYPE {
+  VkKeyNull         = 0x0000 | CHAR_NULL,
+  VkKeyBackspace    = 0x0000 | CHAR_BACKSPACE,
+  VkKeyTab          = 0x0000 | CHAR_TAB,
+  VkKeyEnter        = 0x0000 | CHAR_CARRIAGE_RETURN,
+  VkKeyScanMask     = 0x1000,
+  VkKeyEsc          = 0x1000 | SCAN_ESC,
+  VkKeyLeft         = 0x1000 | SCAN_LEFT,
+  VkKeyRight        = 0x1000 | SCAN_RIGHT,
+  VkKeyUp           = 0x1000 | SCAN_UP,
+  VkKeyDown         = 0x1000 | SCAN_DOWN,
+  VkKeyF1           = 0x1000 | SCAN_F1,
+  VkKeyF2           = 0x1000 | SCAN_F2,
+  VkKeyF3           = 0x1000 | SCAN_F3,
+  VkKeyF4           = 0x1000 | SCAN_F4,
+  VkKeyF5           = 0x1000 | SCAN_F5,
+  VkKeyF6           = 0x1000 | SCAN_F6,
+  VkKeyF7           = 0x1000 | SCAN_F7,
+  VkKeyF8           = 0x1000 | SCAN_F8,
+  VkKeyF9           = 0x1000 | SCAN_F9,
+  VkKeyF10          = 0x1000 | SCAN_F10,
+  VkKeyF11          = 0x1000 | SCAN_F11,
+  VkKeyF12          = 0x1000 | SCAN_F12,
+  VkKeySpecificMask = 0x2000,
+  VkKeyShift        = 0x2000 | 0x0000,
+  VkKeyCapslock     = 0x2000 | 0x0001,
+  VkKeyTwoPage      = 0x2000 | 0x0002,
+  VkKeyTypeMaximum  = 0xFFFF
+} VK_KEY_TYPE;
+
+typedef enum _VK_PAGE_TYPE {
+  //
+  // +---+---+---+---+---+---+---+---+---+---+---+
+  // | q | w | e | r | t | y | u | i | o | p |<X|| Line 0
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // | | a | s | d | f | g | h | j | k | l | F2| | Line 1
+  // +-+---+---+---+---+---+---+---+---+---+---+-+
+  // |Caps | z | x | c | v | b | n | m |aU |Enter| Line 2
+  // +-----+---+---+---+---+---+---+---+---+---+-+
+  // | Esc |12#|       Space       |aL |aD |aR | | Line 3
+  // +-----+---+-------------------+---+---+---+-+
+  //
+  VkPage0,
+
+  //
+  // +---+---+---+---+---+---+---+---+---+---+---+
+  // | Q | W | E | R | T | Y | U | I | O | P |<X|| Line 0
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // | | A | S | D | F | G | H | J | K | L | F2| | Line 1
+  // +-+---+---+---+---+---+---+---+---+---+---+-+
+  // |Caps | Z | X | C | V | B | N | M |aU |Enter| Line 2
+  // +-----+---+---+---+---+---+---+---+---+---+-+
+  // | Esc |12#|       Space       |aL |aD |aR | | Line 3
+  // +-----+---+-------------------+---+---+---+-+
+  //
+  VkPage1,
+
+  //
+  // +---+---+---+---+---+---+---+---+---+---+---+
+  // | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |<X|| Line 0
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
+  // +-+---+---+---+---+---+---+---+---+---+---+-+
+  // |Shift| . | ; | ' | , | . | / |F11|F12|Enter| Line 2
+  // +-----+---+---+---+---+---+---+---+---+---+-+
+  // | Esc |12#|       Space       | \ | - | = | | Line 3
+  // +-----+---+-------------------+---+---+---+-+
+  //
+  VkPage2,
+
+  //
+  // +---+---+---+---+---+---+---+---+---+---+---+
+  // | ! | @ | # | $ | % | ^ | & | * | ( | ) |<X|| Line 0
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
+  // +-+---+---+---+---+---+---+---+---+---+---+-+
+  // |Shift| ~ | : | " | < | > | ? |F11|F12|Enter| Line 2
+  // +-----+---+---+---+---+---+---+---+---+---+-+
+  // | Esc |12#|       Space       | | | _ | + | | Line 3
+  // +-----+---+-------------------+---+---+---+-+
+  //
+  VkPage3,
+  VkPageMaximum
+} VK_PAGE_TYPE;
+
+typedef enum VK_DISPLAY_ATTRIBUTE {
+  VkDisplayAttributeNone,         /// No keyboard displayed
+  VkDisplayAttributeFullTop,      /// Full keyboard display at top
+  VkDisplayAttributeFullBottom,   /// Full keyboard display at bottom
+  VkDisplayAttributeSimpleTop,    /// Simple keyboard display at top
+  VkDisplayAttributeSimpleBottom, /// Simple keyboard display at bottom
+  VkDisplayAttributeMaximum
+} VK_DISPLAY_ATTRIBUTE;
+
+typedef struct _VK_STRUCT {
+  UINT16      DisStartX;
+  UINT16      DisStartY;
+  UINT16      DisEndX;
+  UINT16      DisEndY;
+  VK_KEY_TYPE PageFont[VkPageMaximum];
+} VK_STRUCT;
+
+typedef struct _VK_NOTIFY {
+  UINTN                               Signature;
+  EFI_KEY_DATA                        KeyData;
+  EFI_KEY_NOTIFY_FUNCTION             KeyNotificationFn;
+  LIST_ENTRY                          NotifyEntry;
+} VK_NOTIFY;
+
+///
+/// Virtual Keyboard context
+///
+struct _VK_CONTEXT {
+  ///
+  /// Structure identification
+  ///
+  UINTN                             Signature;
+
+  ///
+  /// Controller Handle
+  ///
+  EFI_HANDLE                        Controller;
+
+  ///
+  /// Upper level API
+  ///
+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL    SimpleTextIn;
+
+  ///
+  /// Simple Text In EX
+  ///
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleTextInEx;
+
+  ///
+  /// Lower level APIs
+  ///
+  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL      *GraphicsOutput;
+
+  ///
+  /// Flag when the last poll indicated a touch event
+  ///
+  BOOLEAN                           TouchActive;
+
+  ///
+  /// Time to poll for touch input
+  ///
+  EFI_EVENT                         TimerEvent;
+
+  ///
+  /// HII handle to get image data used
+  ///
+  EFI_HII_HANDLE                    HiiHandle;
+  EFI_HII_IMAGE_EX_PROTOCOL         *HiiImageEx;
+
+  ///
+  /// Keyboard body background buffer information
+  ///
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *VkBodyBackgroundBltBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *VkBodyCompoundBltBuffer;
+  UINTN                             VkBodyBltSize;
+  UINTN                             VkBodyBltStartX;
+  UINTN                             VkBodyBltStartY;
+  UINTN                             VkBodyBltHeight;
+  UINTN                             VkBodyBltWidth;
+  BOOLEAN                           IsBackgroundChanged;
+
+  ///
+  /// Icon buffer information
+  ///
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *IconBltBuffer;
+  UINTN                             IconBltSize;
+  UINTN                             IconBltHeight;
+  UINTN                             IconBltWidth;
+
+  ///
+  /// Full icon background buffer information
+  ///
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *FullIconBackBuffer;
+  UINTN                             FullIconBackStartX;
+  UINTN                             FullIconBackStartY;
+  UINTN                             FullIconBackHeight;
+  UINTN                             FullIconBackWidth;
+  UINTN                             FullIconBackSize;
+  BOOLEAN                           FullIconUpdatedFlag;
+
+  ///
+  /// Simple icon background buffer information
+  ///
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *SimIconBackBuffer;
+  UINTN                             SimIconBackStartX;
+  UINTN                             SimIconBackStartY;
+  UINTN                             SimIconBackHeight;
+  UINTN                             SimIconBackWidth;
+  UINTN                             SimIconBackSize;
+  BOOLEAN                           SimIconUpdatedFlag;
+
+  ///
+  /// Small Icon
+  ///
+  EFI_IMAGE_INPUT                   *SmallIcon;
+
+  ///
+  /// Full Icon
+  ///
+  EFI_IMAGE_INPUT                   *FullIcon;
+
+  ///
+  /// Simple Key body
+  ///
+  EFI_IMAGE_INPUT                   *SimKeyBody;
+
+  ///
+  /// Digital key body
+  ///
+  EFI_IMAGE_INPUT                   *DigKeyBody;
+
+  ///
+  /// Capital Letter Key board
+  ///
+  EFI_IMAGE_INPUT                   *CapLeKeyBody;
+
+  ///
+  /// Screen check buffer.
+  /// This is used to check if screen is kept scrolling up.
+  ///
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *ScreenCheckBuffer;
+  UINTN                             ScreenCheckBufferSize;
+
+  ///
+  /// Key state
+  ///
+  BOOLEAN                           KeyPressed;
+
+  ///
+  /// Keyboard display status
+  ///
+  VK_DISPLAY_ATTRIBUTE              CurrentKeyboardDisplay;
+  VK_DISPLAY_ATTRIBUTE              TargetKeyboardDisplay;
+
+  ///
+  /// Keyboard icon display status
+  ///
+  BOOLEAN                           IsIconShowed;
+  UINT8                             IconReDrawCheck;
+
+  ///
+  /// Keyboard body Image address
+  /// Size of KeyboardBodyPtr must larger than mFullKeyboardBody
+  ///
+  UINT32                            NumOfKeysInfo;
+  VK_STRUCT                         KeyboardBodyPtr[50];
+
+  ///
+  /// KeyBuffer
+  ///
+  EFI_EVENT                         KeyNotifyProcessEvent;
+  EFI_KEY_TOGGLE_STATE              KeyToggleState;
+  EFI_KEY_DATA                      Keybuffer[MAX_KEY_BUF_SIZE];
+  UINT8                             KeyStartIndex;
+  UINT8                             KeyEndIndex;
+  UINT16                            KeyTouchedTimeOut;
+  BOOLEAN                           IsShiftKeyFlag;
+  BOOLEAN                           IsCapsLockFlag;
+  BOOLEAN                           IsSupportPartialKey;
+  BOOLEAN                           IsRedrawUpdateUI;
+  VK_PAGE_TYPE                      PageNumber;
+  LIST_ENTRY                        NotifyList;
+};
+
+///
+/// Locate VK_CONTEXT from protocol
+///
+#define VK_CONTEXT_FROM_PROTOCOL(a)                CR (a, VK_CONTEXT, SimpleTextIn, VK_SIGNATURE)
+#define VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(a) CR (a, VK_CONTEXT, SimpleTextInEx, VK_SIGNATURE)
+#define VK_CONTEXT_FROM_VKBD_PROTOCOL(a)           CR (a, VK_CONTEXT, VkbdProtocol, VK_SIGNATURE)
+
+/**
+  Start the virtual keyboard driver
+
+  This routine allocates the necessary resources for the driver.
+
+  This routine is called by VirtualKeyboardDriverStart to complete the driver
+  initialization.
+
+  @param[in, out] VkContext        Address of an VK_CONTEXT structure
+  @param[in] Controller            Handle of device to work with.
+
+  @retval EFI_SUCCESS              Driver API properly initialized
+
+**/
+EFI_STATUS
+VkApiStart (
+  IN VK_CONTEXT *VkContext,
+  IN EFI_HANDLE Controller
+  );
+
+/**
+  Stop the virtual keyboard driver
+
+  This routine releases the resources allocated by VKApiStart.
+
+  This routine is called by VirtualKeyboardDriverStop to initiate the driver
+  shutdown.
+
+  @param[in] VkContext        Address of an VK_CONTEXT structure
+
+**/
+VOID
+VkApiStop (
+  IN VK_CONTEXT *VkContext
+  );
+
+/**
+  Resets the input device hardware.
+
+  The Reset() function resets the input device hardware. As part
+  of initialization process, the firmware/device will make a quick
+  but reasonable attempt to verify that the device is functioning.
+  If the ExtendedVerification flag is TRUE the firmware may take
+  an extended amount of time to verify the device is operating on
+  reset. Otherwise the reset operation is to occur as quickly as
+  possible. The hardware verification process is not defined by
+  this specification and is left up to the platform firmware or
+  driver to implement.
+
+  @param[in] This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param[in] ExtendedVerification Indicates that the driver may perform a more exhaustive
+                                  verification operation of the device during reset.
+
+  @retval EFI_SUCCESS             The device was reset.
+  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardReset (
+  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+  IN BOOLEAN                        ExtendedVerification
+  );
+
+/**
+  Reads the next keystroke from the input device. The WaitForKey Event can
+  be used to test for existence of a keystroke via WaitForEvent () call.
+
+  @param[in]  This         Protocol instance pointer.
+  @param[out] Key          Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS      The keystroke information was returned.
+  @retval EFI_NOT_READY    There was no keystroke data available.
+  @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+                           hardware errors.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardReadKeyStroke (
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+  OUT EFI_INPUT_KEY                  *Key
+  );
+
+/**
+  Resets the input device hardware.
+
+  The Reset() function resets the input device hardware. As part
+  of initialization process, the firmware/device will make a quick
+  but reasonable attempt to verify that the device is functioning.
+  If the ExtendedVerification flag is TRUE the firmware may take
+  an extended amount of time to verify the device is operating on
+  reset. Otherwise the reset operation is to occur as quickly as
+  possible. The hardware verification process is not defined by
+  this specification and is left up to the platform firmware or
+  driver to implement.
+
+  @param[in] This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param[in] ExtendedVerification Indicates that the driver may perform a more exhaustive
+                                  verification operation of the device during reset.
+
+  @retval EFI_SUCCESS             The device was reset.
+  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardResetEx (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN BOOLEAN                           ExtendedVerification
+  );
+
+/**
+  Reads the next keystroke from the input device.
+
+  @param[in]  This               Protocol instance pointer.
+  @param[out] KeyData            A pointer to a buffer that is filled in with the keystroke
+                                 state data for the key that was pressed.
+
+  @retval EFI_SUCCESS            The keystroke information was returned.
+  @retval EFI_NOT_READY          There was no keystroke data available.
+  @retval EFI_INVALID_PARAMETER  This or KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardReadKeyStrokeEx (
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  OUT EFI_KEY_DATA                      *KeyData
+  );
+
+/**
+  Set certain state for the input device.
+
+  @param[in] This                 Protocol instance pointer.
+  @param[in] KeyToggleState       A pointer to the EFI_KEY_TOGGLE_STATE to set the
+                                  state for the input device.
+
+  @retval EFI_SUCCESS             The device state was set appropriately.
+  @retval EFI_INVALID_PARAMETER   This or KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardSetState (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN EFI_KEY_TOGGLE_STATE              *KeyToggleState
+  );
+
+/**
+  Register a notification function for a particular keystroke for the input device.
+
+  @param[in]  This                        Protocol instance pointer.
+  @param[in]  KeyData                     A pointer to a buffer that is filled in with the keystroke
+                                          information data for the key that was pressed.
+  @param[in]  KeyNotificationFunction     Points to the function to be called when the key
+                                          sequence is typed specified by KeyData.
+  @param[out] NotifyHandle                Points to the unique handle assigned to the registered notification.
+
+  @retval EFI_SUCCESS                     The notification function was registered successfully.
+  @retval EFI_OUT_OF_RESOURCES            Unable to allocate resources for necessary data structures.
+  @retval EFI_INVALID_PARAMETER           KeyData or NotifyHandle or KeyNotificationFunction is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardRegisterKeyNotify (
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN  EFI_KEY_DATA                      *KeyData,
+  IN  EFI_KEY_NOTIFY_FUNCTION           KeyNotificationFunction,
+  OUT EFI_HANDLE                        *NotifyHandle
+  );
+
+/**
+  Remove a registered notification function from a particular keystroke.
+
+  @param[in] This                Protocol instance pointer.
+  @param[in] NotificationHandle  The handle of the notification function being unregistered.
+
+  @retval EFI_SUCCESS            The notification function was unregistered successfully.
+  @retval EFI_INVALID_PARAMETER  The NotificationHandle is invalid
+
+**/
+EFI_STATUS
+EFIAPI
+VkKeyboardUnregisterKeyNotify (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN EFI_HANDLE                        NotificationHandle
+  );
+
+/**
+  Draw key board on the display
+
+  @param[in] VkContext          Graphic Protocol for draw the alphabet.
+
+  @retval EFI_SUCCESS           Draw keyboard was done.
+  @retval EFI_UNSUPPORTED       Did not get key mapping table.
+
+**/
+EFI_STATUS
+DrawKeyboardLayout (
+  IN VK_CONTEXT *VkContext
+  );
+
+/**
+  Clear the keyboard body
+
+  @param[in] VkContext          Code context.
+
+  @retval EFI_SUCCESS           Clear rectangle is done.
+
+**/
+EFI_STATUS
+HideVkBody (
+  IN VK_CONTEXT *VkContext
+  );
+
+/**
+  Clear the keyboard icon
+
+  @param[in] VkContext          Code context.
+
+  @retval EFI_SUCCESS           Clear rectangle is done.
+
+**/
+EFI_STATUS
+HideVkIcon (
+  IN VK_CONTEXT *VkContext
+  );
+
+/**
+  Use to draw the keyboard icon.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+  @param[in] VkImage    Image of keyboard to display on the screen.
+  @param[in] Attribute  Attribute of keyboard to display on the screen.
+
+  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard icon displayed.
+  @retval EFI_UNSUPPORTED       KeyboardFile not found
+  @retval EFI_INVALID_PARAMETER Attribute is unknown.
+
+**/
+EFI_STATUS
+EFIAPI
+DrawVkIcon (
+  IN VK_CONTEXT                    *VkContext,
+  IN EFI_IMAGE_INPUT               *VkImage,
+  IN VK_DISPLAY_ATTRIBUTE          Attribute
+  );
+
+/**
+  Use to draw the keyboard.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+  @param[in] VkImage    Image of keyboard to display on the screen.
+  @param[in] Attribute  Attribute of keyboard to display on the screen.
+
+  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard displayed.
+  @retval EFI_UNSUPPORTED       KeyboardFile not found
+  @retval EFI_INVALID_PARAMETER Attribute is unknown.
+
+**/
+EFI_STATUS
+EFIAPI
+DrawVkBody (
+  IN VK_CONTEXT                    *VkContext,
+  IN EFI_IMAGE_INPUT               *VkImage,
+  IN VK_DISPLAY_ATTRIBUTE          Attribute
+  );
+
+/**
+  Get unicode by VkContext->PageNumber and VkContext->KeyboardBodyPtr.
+
+  @param[in]  VkContext            Address of an VK_CONTEXT structure.
+  @param[in]  KeyItem              Key Item.
+  @param[out] FontPtr              Follow VkContext->PageNumber to translate
+                                   font unicode.
+
+  @retval EFI_SUCCESS              Finish translating FontPtr.
+  @retval EFI_INVALID_PARAMETER    VkContext or FontPtr is NULL.
+
+**/
+EFI_STATUS
+VkGetMappingFont (
+  IN  VK_CONTEXT *VkContext,
+  IN  VK_STRUCT  KeyItem,
+  OUT UINT32     *FontPtr
+  );
+
+/**
+  This routine is used to check if icon has been cleared.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+
+  @retval EFI_SUCCESS   Function completed.
+
+**/
+EFI_STATUS
+CheckIconCleared (
+  IN VK_CONTEXT *VkContext
+  );
+
+/**
+  ConvertCoordinate - Convert the touch panel's coordinate to display's coordinate.
+
+  @param[in]  VkContext             Virtual Keyboard context.
+  @param[in]  Point                 The coordinate reported from touch panel.
+  @param[out] TouchX                The coordinate X converted to display panel.
+  @param[out] TouchY                The coordinate Y converted to display panel..
+
+  @retval EFI_SUCCESS               Convert success.
+
+**/
+EFI_STATUS
+ConvertCoordinate (
+  IN  VK_CONTEXT                 *VkContext,
+  IN  EFI_ABSOLUTE_POINTER_STATE Point,
+  OUT UINT32                     *TouchX,
+  OUT UINT32                     *TouchY
+  );
+
+/**
+  This routine is used to check if screen has been cleared.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+
+  @retval EFI_SUCCESS   Function completed.
+
+**/
+EFI_STATUS
+CheckScreenCleared (
+  IN VK_CONTEXT *VkContext
+  );
+
+/**
+  This routine is used to check if background beneath virtual keyboard has been cleared.
+
+  @param[in] VkContext  Pointer to virtual keyboard's context
+
+  @retval EFI_SUCCESS   Function completed.
+
+**/
+EFI_STATUS
+CheckBackgroundChanged (
+  IN VK_CONTEXT *VkContext
+  );
+
+/**
+  To prevent screen keyboard layout occur scroll up
+
+  @param[in]  VkContext            Address of an VK_CONTEXT structure.
+
+**/
+VOID
+PreventScreenScrollUp (
+  IN OUT VK_CONTEXT *VkContext
+  );
+
+EFI_STATUS
+SetCharacterPosition (
+  IN VK_CONTEXT *VkContext,
+  IN UINT32     DestX,
+  IN UINT32     DestY
+  );
+
+EFI_STATUS
+KeyboardLayoutHandler (
+  IN VK_CONTEXT *VkContext,
+  IN UINT32     Index
+  );
+
+EFI_STATUS
+EFIAPI
+SaveVkBodyBackgroundBltBuffer (
+  IN VK_CONTEXT *VkContext,
+  IN UINTN      BltSize
+  );
+
+EFI_STATUS
+EFIAPI
+RestoreVkBodyBackgroundBltBuffer (
+  IN VK_CONTEXT *VkContext
+  );
+
+EFI_STATUS
+EFIAPI
+SaveVkIconBackgroundBltBuffer (
+  IN VK_CONTEXT           *VkContext,
+  IN VK_DISPLAY_ATTRIBUTE IconType
+  );
+#endif
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c
new file mode 100644
index 0000000000..42ad493a9f
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c
@@ -0,0 +1,541 @@
+/** @file
+  Virtual Keyboard driver.
+
+  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VirtualKeyboard.h"
+
+UINT32         mOrigConOutRow      = 0;
+UINT32         mOrigSetupConOutRow = 0;
+EFI_HII_HANDLE mHiiHandle          = NULL;
+
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  );
+
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  );
+
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN  EFI_HANDLE                  Controller,
+  IN  UINTN                       NumberOfChildren,
+  IN  EFI_HANDLE                  *ChildHandleBuffer
+  );
+
+EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = {
+  VirtualKeyboardDriverSupported,
+  VirtualKeyboardDriverStart,
+  VirtualKeyboardDriverStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+/**
+  This is the declaration of an EFI image entry point. This entry point is
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+  both device drivers and bus drivers.
+
+  @param  ImageHandle           The firmware allocated handle for the UEFI image.
+  @param  SystemTable           A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval Others                An unexpected error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS                     Status;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverEntryPoint Start\n"));
+  //
+  // Install UEFI Driver Model protocol(s).
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gVirtualKeyboardDriverBinding,
+             ImageHandle,
+             &gVirtualKeyboardComponentName,
+             &gVirtualKeyboardComponentName2
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  mHiiHandle = HiiAddPackages (
+                 &gEfiCallerIdGuid,
+                 NULL,
+                 VirtualKeyboardDxeImages,
+                 NULL
+                 );
+  ASSERT (mHiiHandle != NULL);
+
+  mOrigConOutRow      = PcdGet32 (PcdConOutRow);
+  mOrigSetupConOutRow = PcdGet32 (PcdSetupConOutRow);
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverEntryPoint End\n"));
+  return Status;
+}
+
+/**
+  Verify the controller type
+
+  This routine determines if the pointer and GOP are available.
+
+  This routine is called by the UEFI driver framework during connect
+  processing.
+
+  @param[in] DriverBinding        Protocol instance pointer.
+  @param[in] Controller           Handle of device to test.
+  @param[in] RemainingDevicePath  Not used.
+
+  @retval EFI_SUCCESS             This driver supports this device.
+  @retval other                   This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
+  EFI_STATUS                    Status;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverSupported Start\n"));
+
+  //
+  // Verify that the driver is not already started
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiCallerIdGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
+    Status = EFI_ALREADY_STARTED;
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK has already initialized\n"));
+    goto Error;
+  }
+
+  //
+  // Determine if the pointer protocol is available.
+  // This should be installed in touch driver.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiAbsolutePointerProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Absolute pointer protocol not found\n"));
+    goto Error;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiTouchPanelGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Touch Panel Guid not found\n"));
+    goto Error;
+  }
+
+  //
+  // Determine if the graphics output protocol is available
+  //
+  Status = gBS->HandleProtocol (
+                  gST->ConsoleOutHandle,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  (VOID **)&GraphicsOutput
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Graphics output protocol not found\n"));
+    goto Error;
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO, "VirtualKeyboardDriverSupported Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverSupported Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverSupported End\n"));
+  return Status;
+}
+
+/**
+  Connect to the controller
+
+  This routine initializes an instance of the virutal keyboard driver for this
+  controller.
+
+  This routine is called by the UEFI driver framework during connect
+  processing if the controller passes the tests in I2cBusDriverSupported.
+
+  @param[in] DriverBinding        Protocol instance pointer.
+  @param[in] Controller           Handle of device to work with.
+  @param[in] RemainingDevicePath  Not used, always produce all possible children.
+
+  @retval EFI_SUCCESS             This driver is added to Controller.
+  @retval other                   This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  VK_CONTEXT *VkContext;
+  EFI_STATUS Status;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO, "VirtualKeyboardDriverStart Start\n"));
+
+  VkContext = AllocateZeroPool (sizeof (VK_CONTEXT));
+  if (VkContext == NULL) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - No memory for virtual keyboard driver\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    ASSERT_EFI_ERROR (Status);
+    goto Error;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiAbsolutePointerProtocolGuid,
+                  (VOID**) &VkContext->AbsolutePointer,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to open absolute pointer protocol, Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiTouchPanelGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - TouchPanel GUID not found, Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->HandleProtocol (
+                  gST->ConsoleOutHandle,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  (VOID**) &VkContext->GraphicsOutput
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Graphics output protocol not available, Status: %r\n", Status));
+    goto Error;
+  }
+
+  VkContext->HiiHandle = mHiiHandle;
+  Status = VkApiStart (VkContext, Controller);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to VkApiStart, Status: %r\n", Status));
+    goto Error;
+  }
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Controller,
+                  &gEfiCallerIdGuid,
+                  VkContext,
+                  &gEfiSimpleTextInProtocolGuid,
+                  &VkContext->SimpleTextIn,
+                  &gEfiSimpleTextInputExProtocolGuid,
+                  &VkContext->SimpleTextInEx,
+                  &gEfiConsoleInDeviceGuid,
+                  NULL,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to install VK protocols, Status: %r\n", Status));
+    ASSERT_EFI_ERROR (Status);
+    goto Error;
+  }
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO, "VirtualKeyboardDriverStart Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  if (VkContext != NULL) {
+    FreePool (VkContext);
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiAbsolutePointerProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  //
+  // Restore setting if connect device fail.
+  //
+  PcdSet32S (PcdConOutRow, mOrigConOutRow);
+  PcdSet32S (PcdSetupConOutRow, mOrigSetupConOutRow);
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStart Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStart End\n"));
+
+  return Status;
+}
+
+/**
+  Disconnect from the controller.
+
+  This routine disconnects from the controller.
+
+  This routine is called by DriverUnload when the I2C bus driver
+  is being unloaded.
+
+  @param[in] DriverBinding        Protocol instance pointer.
+  @param[in] Controller           Handle of device to stop driver on.
+  @param[in] NumberOfChildren     How many children need to be stopped.
+  @param[in] ChildHandleBuffer    Not used.
+
+  @retval EFI_SUCCESS             This driver is removed Controller.
+  @retval EFI_DEVICE_ERROR        The device could not be stopped due to a device error.
+  @retval other                   This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN  EFI_HANDLE                  Controller,
+  IN  UINTN                       NumberOfChildren,
+  IN  EFI_HANDLE                  *ChildHandleBuffer
+  )
+{
+  VK_CONTEXT                          *VkContext;
+  EFI_STATUS                          Status;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop Start\n"));
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiCallerIdGuid,
+                  (VOID**)&VkContext,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
+                  );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_SUCCESS;
+    goto Success;
+  }
+
+  //
+  // Done with the driver protocol
+  //
+  Status = gBS->CloseProtocol (
+                  Controller,
+                  &gEfiCallerIdGuid,
+                  This->DriverBindingHandle,
+                  Controller
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to close the VK protocol, Status: %r\n", Status));
+    goto Error;
+  }
+
+  //
+  // Remove ConsoleIn protocols first to close the link in ConSplitter
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiConsoleInDeviceGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to uninstall the protocols, Status: %r\n", Status));
+    goto Error;
+  }
+
+  //
+  // Remove the remaining protocols
+  //
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  Controller,
+                  &gEfiCallerIdGuid,
+                  VkContext,
+                  &gEfiSimpleTextInProtocolGuid,
+                  &VkContext->SimpleTextIn,
+                  &gEfiSimpleTextInputExProtocolGuid,
+                  &VkContext->SimpleTextInEx,
+                  &gEfiConsoleInDeviceGuid,
+                  NULL,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to uninstall the protocols, Status: %r\n", Status));
+    goto Error;
+  }
+
+  //
+  // Stop the driver
+  //
+  VkApiStop (VkContext);
+
+  //
+  // Release the pointer protocol upon failure
+  //
+  Status = gBS->CloseProtocol (
+                  Controller,
+                  &gEfiAbsolutePointerProtocolGuid,
+                  This->DriverBindingHandle,
+                  Controller
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to close absolute pointer protocol, Status: %r\n", Status));
+    goto Error;
+  }
+
+  //
+  // Release VkContext
+  //
+  if (VkContext != NULL) {
+    FreePool (VkContext);
+  }
+
+Success:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop End\n"));
+  return Status;
+}
+
+/**
+  Unloads an image.
+
+  @param[in] ImageHandle        Handle that identifies the image to be unloaded.
+
+  @retval EFI_SUCCESS           The image has been unloaded.
+  @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverUnload (
+  IN EFI_HANDLE ImageHandle
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_HANDLE                 *HandleBuffer;
+  UINTN                      HandleCount;
+  UINTN                      Index;
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload Start\n"));
+
+  //
+  // Retrieve array of all handles in the handle database
+  //
+  Status = gBS->LocateHandleBuffer (
+                  AllHandles,
+                  NULL,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to locate handle buffer, Status: %r\n", Status));
+    ASSERT_EFI_ERROR (Status);
+    goto Error;
+  }
+
+  //
+  // Disconnect the current driver from handles in the handle database
+  //
+  for (Index = 0; Index < HandleCount; Index++) {
+    gBS->DisconnectController (HandleBuffer[Index], ImageHandle, NULL);
+  }
+
+  //
+  // Free the array of handles
+  //
+  if (HandleBuffer != NULL) {
+    FreePool (HandleBuffer);
+  }
+
+  //
+  // Uninstall protocols installed in the driver entry point
+  //
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  ImageHandle,
+                  &gEfiDriverBindingProtocolGuid,
+                  &gVirtualKeyboardDriverBinding,
+                  &gEfiComponentNameProtocolGuid,
+                  &gVirtualKeyboardComponentName,
+                  &gEfiComponentName2ProtocolGuid,
+                  &gVirtualKeyboardComponentName2,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    goto Error;
+  }
+
+  HiiRemovePackages (mHiiHandle);
+
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload Success, Status: %r\n", Status));
+  goto End;
+
+Error:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload Failed, Status: %r\n", Status));
+
+End:
+  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload End\n"));
+  return Status;
+}
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
new file mode 100644
index 0000000000..9ecc99d5a7
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
@@ -0,0 +1,77 @@
+## @file
+# Instance of virtual keyboard driver binding protocol.
+#
+# Compliant with efi driver model, 1. VirtualKeyboardDriverSupported
+# determines if the pointer and GOP are available. 2.
+# VirtualKeyboardDriverStart initializes an instance of the virtual
+# keyboard driver for a particular controller. 3.
+# VirtualKeyboardDriverStop is called by DriverUnload when the I2C bus
+# driver is being unload.
+#
+# Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010017
+  BASE_NAME                      = VirtualKeyboardDxe
+  FILE_GUID                      = E4735AAC-9C27-493f-86EA-9EFF43D7ADCD
+  VERSION_STRING                 = 1.0
+  MODULE_TYPE                    = UEFI_DRIVER
+  ENTRY_POINT                    = VirtualKeyboardDriverEntryPoint
+  UNLOAD_IMAGE                   = VirtualKeyboardDriverUnload
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#  DRIVER_BINDING                = gVirtualKeyboardDriverBinding;
+#  COMPONENT_NAME                = gVirtualKeyboardComponentName;
+#  COMPONENT_NAME2               = gVirtualKeyboardComponentName2;
+#
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  PcdLib
+  HiiLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow
+
+[Sources]
+  CapitalLetterKeyboard.bmp
+  DigitKeyboard.bmp
+  FullIcon.bmp
+  SimpleIcon.bmp
+  SimpleKeyboard.bmp
+  KeyboardLayout.idf
+  KeyboardLayout.c
+  ComponentName.c
+  Keyboard.c
+  VirtualKeyboard.h
+  VirtualKeyboardDriver.c
+
+[Protocols]
+  gEfiAbsolutePointerProtocolGuid               ## TO_START
+  gEfiDriverBindingProtocolGuid                 ## PRODUCES
+  gEfiGraphicsOutputProtocolGuid                ## TO_START
+  gEfiSimpleTextInProtocolGuid                  ## BY_START
+  gEfiSimpleTextInputExProtocolGuid             ## BY_START
+  gEfiHiiImageExProtocolGuid                    ## TO_START
+
+[Guids]
+  gEfiConsoleInDeviceGuid                       ## SOMETIMES_PRODUCES
+  gEfiTouchPanelGuid                            ## TO_START
+
+[Depex]
+  gEfiHiiDatabaseProtocolGuid
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
new file mode 100644
index 0000000000..2742a04a8f
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
@@ -0,0 +1,26 @@
+## @file
+# This package provides advanced feature functionality for User Authentication support.
+# This package should only depend on EDK II Core packages, IntelSiliconPkg, and MinPlatformPkg.
+#
+# The DEC files are used by the utilities that parse DSC and
+# INF files to generate AutoGen.c and AutoGen.h files
+# for the build infrastructure.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION = 0x00010017
+  PACKAGE_NAME      = VirtualKeyboardFeaturePkg
+  PACKAGE_GUID      = A40DFD69-3552-40E8-8D3D-89741B03B9E1
+  PACKAGE_VERSION   = 0.1
+
+[Includes]
+  Include
+
+[Guids]
+  ## GUID used for VirtualKeyboardDriver to open TouchPanel protocol.
+  gEfiTouchPanelGuid                               = { 0x91b1d27b, 0xe126, 0x48d1, { 0x82, 0x34, 0xd2, 0x8b, 0x81, 0xc8, 0x83, 0x62 }}
diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc
new file mode 100644
index 0000000000..ab3605fa15
--- /dev/null
+++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc
@@ -0,0 +1,30 @@
+## @file
+# This is a build description file for the User Authentication advanced feature.
+# This package should only depend on EDK II Core packages, IntelSiliconPkg, and MinPlatformPkg.
+#
+# The DEC files are used by the utilities that parse DSC and
+# INF files to generate AutoGen.c and AutoGen.h files
+# for the build infrastructure.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  PLATFORM_NAME                  = VirtualKeyboardFeaturePkg
+  PLATFORM_GUID                  = 6D396683-C82B-41D5-84E7-BB6E13B7C2BF
+  PLATFORM_VERSION               = 0.1
+  DSC_SPECIFICATION              = 0x00010005
+  OUTPUT_DIRECTORY               = Build/$(PLATFORM_NAME)
+  SUPPORTED_ARCHITECTURES        = IA32|X64
+  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
+  SKUID_IDENTIFIER               = DEFAULT
+  PEI_ARCH                       = IA32
+  DXE_ARCH                       = X64
+
+#
+# This package always builds the feature.
+#
+!include Include/VirtualKeyboardFeature.dsc
-- 
2.24.0.windows.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [edk2-devel] [PATCH] Features/Intel/UserInterface: Add VirtualKeyboardFeaturePkg
  2020-03-26  0:43 [PATCH] Features/Intel/UserInterface: Add VirtualKeyboardFeaturePkg Tan, Ming
@ 2020-04-01  5:40 ` Dong, Eric
  2020-04-01  8:58 ` Ni, Ray
  1 sibling, 0 replies; 3+ messages in thread
From: Dong, Eric @ 2020-04-01  5:40 UTC (permalink / raw)
  To: devel@edk2.groups.io, Tan, Ming

Reviewed-by: Eric Dong <eric.dong@intel.com>

> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Tan, Ming
> Sent: Thursday, March 26, 2020 8:44 AM
> To: devel@edk2.groups.io
> Subject: [edk2-devel] [PATCH] Features/Intel/UserInterface: Add
> VirtualKeyboardFeaturePkg
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2603
> 
> It add a VirtualKeyboardDxe driver.
> It is used with a touch panel, simulate a keyboard in the screen.
> 
> Signed-off-by: Ming Tan <ming.tan@intel.com>
> ---
>  .../Include/PostMemory.fdf                    |   10 +
>  .../Include/PreMemory.fdf                     |    8 +
>  .../Include/VirtualKeyboardFeature.dsc        |   96 ++
>  .../VirtualKeyboardFeaturePkg/Readme.md       |   95 ++
>  .../CapitalLetterKeyboard.bmp                 |  Bin 0 -> 330454 bytes
>  .../VirtualKeyboardDxe/ComponentName.c        |  159 ++
>  .../VirtualKeyboardDxe/ComponentName.h        |   95 ++
>  .../VirtualKeyboardDxe/DigitKeyboard.bmp      |  Bin 0 -> 330454 bytes
>  .../VirtualKeyboardDxe/FullIcon.bmp           |  Bin 0 -> 5454 bytes
>  .../VirtualKeyboardDxe/Keyboard.c             | 1400 +++++++++++++++++
>  .../VirtualKeyboardDxe/KeyboardLayout.c       | 1364 ++++++++++++++++
>  .../VirtualKeyboardDxe/KeyboardLayout.idf     |   12 +
>  .../VirtualKeyboardDxe/SimpleIcon.bmp         |  Bin 0 -> 2814 bytes
>  .../VirtualKeyboardDxe/SimpleKeyboard.bmp     |  Bin 0 -> 30054 bytes
>  .../VirtualKeyboardDxe/VirtualKeyboard.h      |  777 +++++++++
>  .../VirtualKeyboardDriver.c                   |  541 +++++++
>  .../VirtualKeyboardDxe/VirtualKeyboardDxe.inf |   77 +
>  .../VirtualKeyboardFeaturePkg.dec             |   26 +
>  .../VirtualKeyboardFeaturePkg.dsc             |   30 +
>  19 files changed, 4690 insertions(+)
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMe
> mory.fdf
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMem
> ory.fdf
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKe
> yboardFeature.dsc
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/CapitalLetterKeyboard.bmp
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/ComponentName.c
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/ComponentName.h
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/DigitKeyboard.bmp
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/FullIcon.bmp
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/Keyboard.c
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/KeyboardLayout.c
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/KeyboardLayout.idf
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/SimpleIcon.bmp
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/SimpleKeyboard.bmp
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/VirtualKeyboard.h
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/VirtualKeyboardDriver.c
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardD
> xe/VirtualKeyboardDxe.inf
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardF
> eaturePkg.dec
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardF
> eaturePkg.dsc
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostM
> emory.fdf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostM
> emory.fdf
> new file mode 100644
> index 0000000000..bf4a4d5078
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostM
> emory.fdf
> @@ -0,0 +1,10 @@
> +## @file
> 
> +#  FDF file for post-memory modules that enable Virtual Keyboard.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +  INF
> UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyb
> oardDxe.inf
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMe
> mory.fdf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMe
> mory.fdf
> new file mode 100644
> index 0000000000..c39a057f94
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMe
> mory.fdf
> @@ -0,0 +1,8 @@
> +## @file
> 
> +#  FDF file for pre-memory modules that enable Virtual Keyboard.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/Virtual
> KeyboardFeature.dsc
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/Virtual
> KeyboardFeature.dsc
> new file mode 100644
> index 0000000000..c10fb2d567
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/Virtual
> KeyboardFeature.dsc
> @@ -0,0 +1,96 @@
> +## @file
> 
> +# This is a build description file for the Virtual Keyboard feature.
> 
> +# This file should be included into another package DSC file to build this
> feature.
> 
> +#
> 
> +# The DEC files are used by the utilities that parse DSC and
> 
> +# INF files to generate AutoGen.c and AutoGen.h files
> 
> +# for the build infrastructure.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +#########################################################
> #######################
> 
> +#
> 
> +# Defines Section - statements that will be processed to create a Makefile.
> 
> +#
> 
> +#########################################################
> #######################
> 
> +[Defines]
> 
> +!ifndef $(PEI_ARCH)
> 
> +  !error "PEI_ARCH must be specified to build this feature!"
> 
> +!endif
> 
> +!ifndef $(DXE_ARCH)
> 
> +  !error "DXE_ARCH must be specified to build this feature!"
> 
> +!endif
> 
> +
> 
> +#########################################################
> #######################
> 
> +#
> 
> +# Library Class section - list of all Library Classes needed by this feature.
> 
> +#
> 
> +#########################################################
> #######################
> 
> +[LibraryClasses]
> 
> +  #######################################
> 
> +  # Edk2 Packages
> 
> +  #######################################
> 
> +  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> 
> +  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> 
> +  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
> 
> +
> UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBo
> otServicesTableLib.inf
> 
> +
> UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntry
> Point.inf
> 
> +  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> 
> +  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> 
> +  HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
> 
> +  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> 
> +  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> 
> +
> UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiService
> sLib.inf
> 
> +
> UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib
> /UefiRuntimeServicesTableLib.inf
> 
> +
> 
> +[LibraryClasses.common.UEFI_DRIVER]
> 
> +  #######################################
> 
> +  # Edk2 Packages
> 
> +  #######################################
> 
> +
> MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemo
> ryAllocationLib.inf
> 
> +
> 
> +#########################################################
> ##########################################
> 
> +#
> 
> +# Components Section - list of the modules and components that will be
> processed by compilation
> 
> +#                      tools and the EDK II tools to generate PE32/PE32+/Coff image
> files.
> 
> +#
> 
> +# Note: The EDK II DSC file is not used to specify how compiled binary
> images get placed
> 
> +#       into firmware volume images. This section is just a list of modules to
> compile from
> 
> +#       source into UEFI-compliant binaries.
> 
> +#       It is the FDF file that contains information on combining binary files into
> firmware
> 
> +#       volume images, whose concept is beyond UEFI and is described in PI
> specification.
> 
> +#       Binary modules do not need to be listed in this section, as they should
> be
> 
> +#       specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT
> binary (Fat.efi),
> 
> +#       Logo (Logo.bmp), and etc.
> 
> +#       There may also be modules listed in this section that are not required
> in the FDF file,
> 
> +#       When a module listed here is excluded from FDF file, then UEFI-
> compliant binary will be
> 
> +#       generated for it, but the binary will not be put into any firmware
> volume.
> 
> +#
> 
> +#########################################################
> ##########################################
> 
> +#
> 
> +# Feature DXE Components
> 
> +#
> 
> +[Components.X64]
> 
> +  #####################################
> 
> +  # Virtual Keyboard Feature Package
> 
> +  #####################################
> 
> +
> UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyb
> oardDxe.inf
> 
> +
> 
> +#########################################################
> ##########################################
> 
> +#
> 
> +# BuildOptions Section - Define the module specific tool chain flags that
> should be used as
> 
> +#                        the default flags for a module. These flags are appended to
> any
> 
> +#                        standard flags that are defined by the build process. They can
> be
> 
> +#                        applied for any modules or only those modules with the
> specific
> 
> +#                        module style (EDK or EDKII) specified in [Components] section.
> 
> +#
> 
> +#                        For advanced features, it is recommended to enable
> [BuildOptions] in
> 
> +#                        the applicable INF file so it does not affect the whole board
> package
> 
> +#                        build when this DSC file is active.
> 
> +#
> 
> +#########################################################
> ##########################################
> 
> +[BuildOptions]
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
> new file mode 100644
> index 0000000000..17a3a00215
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
> @@ -0,0 +1,95 @@
> +# Overview
> 
> +* **Feature Name:** Virtual Keyboard
> 
> +* **PI Phase(s) Supported:** DXE
> 
> +* **SMM Required?** No
> 
> +
> 
> +## Purpose
> 
> +This feature provides a DXE virtual keyboard driver, used with a touch panel.
> 
> +
> 
> +# High-Level Theory of Operation
> 
> +This driver will use the following protocol:
> 
> +  gEfiAbsolutePointerProtocolGuid
> 
> +  gEfiTouchPanelGuid
> 
> +  gEfiGraphicsOutputProtocolGuid
> 
> +
> 
> +It will show a picture like a keyboard in the graphic output, then detect
> 
> +position when user touch the touch panel, then calculate the key which the
> 
> +user want to type.
> 
> +
> 
> +## Firmware Volumes
> 
> +*_TODO_*
> 
> +A bulleted list of the firmware volumes that feature module(s) are placed in.
> 
> +
> 
> +## Modules
> 
> +VirtualKeyboardDxe: The main driver of virtual keyboard
> 
> +
> 
> +## <Module Name>
> 
> +*_TODO_*
> 
> +Each module in the feature should have a section that describes the module
> in a level of detail that is useful
> 
> +to better understand the module source code.
> 
> +
> 
> +## <Library Name>
> 
> +*_TODO_*
> 
> +Each library in the feature should have a section that describes the library in
> a level of detail that is useful
> 
> +to better understand the library source code.
> 
> +
> 
> +## Key Functions
> 
> +*_TODO_*
> 
> +A bulleted list of key functions for interacting with the feature.
> 
> +
> 
> +Not all features need to be listed. Only functions exposed through external
> interfaces that are important for feature
> 
> +users to be aware of.
> 
> +
> 
> +## Configuration
> 
> +*_TODO_*
> 
> +Information that is useful for configuring the feature.
> 
> +
> 
> +Not all configuration options need to be listed. This section is used to
> provide more background on configuration
> 
> +options than possible elsewhere.
> 
> +
> 
> +## Data Flows
> 
> +*_TODO_*
> 
> +Architecturally defined data structures and flows for the feature.
> 
> +
> 
> +## Control Flows
> 
> +*_TODO_*
> 
> +Key control flows for the feature.
> 
> +
> 
> +## Build Flows
> 
> +*_TODO_*
> 
> +Any special build flows should be described in this section.
> 
> +
> 
> +This is particularly useful for features that use custom build tools or require
> non-standard tool configuration. If the
> 
> +standard flow in the feature package template is used, this section may be
> empty.
> 
> +
> 
> +## Test Point Results
> 
> +*_TODO_*
> 
> +The test(s) that can verify porting is complete for the feature.
> 
> +
> 
> +Each feature must describe at least one test point to verify the feature is
> successful. If the test point is not
> 
> +implemented, this should be stated.
> 
> +
> 
> +## Functional Exit Criteria
> 
> +*_TODO_*
> 
> +The testable functionality for the feature.
> 
> +
> 
> +This section should provide an ordered list of criteria that a board integrator
> can reference to ensure the feature is
> 
> +functional on their board.
> 
> +
> 
> +## Feature Enabling Checklist
> 
> +*_TODO_*
> 
> +An ordered list of required activities to achieve desired functionality for the
> feature.
> 
> +
> 
> +## Performance Impact
> 
> +A general expectation for the impact on overall boot performance due to
> using this feature.
> 
> +
> 
> +This section is expected to provide guidance on:
> 
> +* How to estimate performance impact due to the feature
> 
> +* How to measure performance impact of the feature
> 
> +* How to manage performance impact of the feature
> 
> +
> 
> +## Common Optimizations
> 
> +*_TODO_*
> 
> +Common size or performance tuning options for this feature.
> 
> +
> 
> +This section is recommended but not required. If not used, the contents
> should be left empty.
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/CapitalLetterKeyboard.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/CapitalLetterKeyboard.bmp
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..759c3d46a9f0cf6a69fa98563cd
> 04f7a082d3b4d
> GIT binary patch
> literal 330454
> zcmeI5zpw7cao(?FBtU``E>p0M1NK*`gbSt#SOkdw0sRRy;5G#XA}Z1nY7D4|3%
> XDn
> zwkD+z1_K0OWmyK;7zPUgqNK(K1CR{!=nT)J=g!Q|&iBW8&wJjxFYJ3~_d7fL*
> =J^V
> z-}gO7m;doU|J}d-7tenG`X2uO-{b%P-FKfo```HcJJ0?t{(ScAe|-D=uJP?3|8KpP
> z0!x9Vz*1l-a1jNbJ+o;({P4r?-qs5%QU$MMf!9fOTbW<0xfTVkv)UI`zdoE+FJ8RR
> z&nug3jI{&#?#@BrKE)IAq+nOI!0V)XLTO#7Pe_65toE%`n-161`8(hF&NORVsipx>
> zaUj*(Z@--`t>0<a&fT4J3fgrBv77bU*shc6+EiLRx1qpwR(qeSf2K}7rwQ#-
> O+%gN
> zU{ur9bsP|C-8m<wrXA`!E31va9G3zc6u8c6?^AV-
> (x%T;wLaA})QJv8)m&rkhEVIy
> zIWaZuP}f;mZT#i96xg7^byj<ysy;+FJ)Nr7r<#U3(ZQ%Tt#ss!Q0vY)F*WT_*I8L@
> z{N=b5*r335R(qdnbbRjUpQ_fUnua>j!KikuHx5Clb?2Ozns%t`tgJTva$E{*P~bY
> N
> zy-
> yVn&fPsz)%sM^P$xPV)$Ud6K!jR%&WWjMhq}(nYU3Yu)Eazs?9Oj49aZ)!$6sf)
> z_o+@S(P@7ARMSu=IvCX{Iv~`#b52Z6JJfYnRvZ7Q<0-
> }a<btd_XH+*QrgAhz?C<Zv
> zOXAg3mn2cejOvux5$e^ub52ptf@oSc*>z=Y3iTA7PfWoR3bpQ>QLUby#L-0B-
> `|5L
> z;weCC*Ho7zQ9PqMWp;#Gcg_JNH7%R$y0SKfdWy~mB!9v~*PSz})zgzYnn?T
> md+<a&
> z1xW1?6^aM16G>tyo1&nKLw5A6J7<SzyN0+-jw;K!-D-
> 1}gin4D_VleLv|d+H?H5j}
> zau!tT2D^rQ{q@(s_~MIizWL^>ufBTo%{Oaj7dbXZRCU<1o{mb?s7{#$p)T?{=M
> -2A
> z60=nI#2lUo(+}k!Bb9Tw?Pg!MTk;%j=-
> bXUR##N}h4ZUY7gXv7yMTP_t+&4X@=IJe
> z_WJtkuits+ox<Nmj?EEO5%a`HqY^c$Qzk;FU3bnYlkW=>vsCxQ9PXR<;3x+fsh
> q=Y
> zHxG*WM2C+y^lj%Ft1GJg!l_iL3o3PkJ%V%>PUqTjkz;d2HDWloe^jDIb;?`_weF
> l#
> zl$-@|#Wkud=XR^jnOe8`e6*o&HOpLAQSBGbG?8EwRO$vhg-
> kD;>9yk`$L5GCWjMWa
> zRH8<8%5(^|?wnJUoCR^kHL5J<cB{>qTDSRpw4rY`%UoAc?HA58kzf>5>IOSP7
> 8g!^
> z?YPLXIiiXT579F!QKLF#Mud8W?;QT{&&ovq{QUFJpFe+IIKcU%k3Q-
> r!4=o2vYgwk
> zHk-O>My}azE@!l%Z#BzYS5fV?bf0|kiRRsQWj&;RN+cKsmAb)pF{c-
> fF{eM<agk$l
> zMCBOz%}D#+d+&{gk4n_2Mx!?MBh(pp&gg9BFLJnb$3?3{nkz0VW~uIpIb^62
> HcDpQ
> zIkl<>pE3otq36vt+x05=bhM!lih2FR;~pe4#fgTya5lZgi_xry^TH^o)D5;qd-vUU
> zwG?s0{p@EyW6#GQe{8?Q#vXUpxyZ3OqEd#f_G_=b_St8j5ebH)V!%;}8Wr7
> +7zlOV
> zo%89ZpQbEW@jv{-
> Kk&B*?RwD)djI|RAp?8h|BwIpkE37zh*_$8Vh$rDb3z9C@G=}_
> z37%Gl=3t@X8!`tOshq=YHz{vz=q|ZtyIuvKjyCjd=NhXks-5CE!_EXIJ#I|r-)ySX
> z1(mwNX7G67;8;^saK?ACdUUwRu{ok5!#;yY93@pM#vGNXQPJ&)flv>B=R`of
> gW*RY
> zOJl#LVwUQjn8V1!grpd}c1D+~RT;;k2IEIH2N|iH!)-
> TX3eq0#59mqz8Vv9#QVJhC
> zM;rRKbB)y%)gDzskDlU4H+NR*ys1;AE~wNEHm6W9zOU3yL*;p5wW|Csa%_
> &M$gtaR
> zR4Cy1zJ64qMzwot9f(kmedp-
> ?qi7>LW~uIpIgF8+4XqA!<9intnm&b%Rq#>#AO{Br
> z8L6DZZ8x2Iqb9GHyCeSVk=y0_jfZ$mfYFA&?ObDZMYTui^azK-
> qc?hSV5di=E~wNE
> zHY1abn;nnX30fW?JW{k1&MtCnj;P3R#84`L#cO9&qDFOOYK}#yi{Cl+HLaDBX`l
> %t
> z+Q^7ms(WG%V`Qd+B~$pMwD`2fPi_{??G*<Zshq=YH>13154MHAQlCfZR4Uj
> _hS7$;
> z?ObDZMYTKW^!$dfZWB4@9Zi+GprV_b!tmS)pv-
> !Jq^AlakBkwOBiY^L+h?m`ckPTy
> z)Tnk(ssj<~Qg;qBfVDDdCcvi38s%!#A9JVzm`ye<nZk|y@Ubh@5}5vJ&JHh9Ifv
> VB
> zMs3p`r)TQ(D4qMjMjQIJbB)y%)voE&!y5{3Iu<leVXM>y72RB@AOHBrKl#Z|@
> Efh#
> zuh{MY!NCImzxa#4pg$vzj1d(h95;$<XH=p_b$n_>K&Xq{IsDn1p4OP(4tv*GuW
> Xd7
> zQGd)~jNiO-2#gKkiVKf$`EZxmdiAGt4lhzUhudz(6r?@-j`lRvxt;sKMjQIJbB)y%
> z)y}-|h;Z5-
> Y;sH5L@ISbMK|IVMserFQH(q?MpPDxC)Gh&+;DzJGb&M|ip$y2gHY$)
> zIc^>N)Mh$ySq>8!8$EKK)*R(()E{#g!!nccCW+4W;~K7x4!RI~C!x_CUZipkx80;
> @
> zuaq&`(6^mytgfhbD}V>OaBw26JI5W%qoy6gqY||Yp0ZmJ>byJ0rI&zqqK}^15k
> 7j#
> zAT+ja&{*#bMPt*QGji6?Hs+(B-
> yC+Nat^oMr1GznG1}0#oolSFsCE{>16@1rU{R?H
> zD!LJ`FxKasLY(*rvOoNtgK3c#{a}Fl($4@^ZmbR**w^#F&xx9$M}G~%eL0%Gjlj
> }a
> z#b$Ks-
> 3_^=W~%DVcdk1p*03gB5AXO9MLl=h3eeeuorx4%kF|8H0;KkcDvh?U(;ZoQ
> zGLK5ssP;|gMj_Ni?i@_Z|CLKxP5kg+XSV(%#384NDmr5hT|hKBdn_4X|Mg%0
> wGN>(
> zFG+i9{fuDi<w6``q;d|o-Bdka9ecE)Z#&mmT~X~W`+9z-2Zi(B+El3vD!O&zD>Ju$
> z9N5hMh$;r$*Hc_L2snZ?s(mxMQ3!RZJIBquyUB8B8Zn2Q+O7qB1NQyzf8YLXh
> *&c8
> z;V-
> MO#CV@DARh7iG|MgTB}W^noWpH5sn{!Jj5hRb=NhXksy!9}_m{o><PM6SJ9
> <>=
> zf{JdPDHJ#!AdJw={)mckju?EuY})E491A;wG^!(0b1Xu=@^_BOZ-1sGqcufm-
> YwJ;
> z2EHU@8ZEtaV-=e*sx0Srt4$T{)v-
> q#`c|{dbrsc~X5a0&bXTSWr=3KCQBcus8W0Xj
> zTc9?xKcec8)IQS-
> 2g65@MpegeK1HZk_|Bn7{Q2dmWZVbR+Ko?9jQo{6R<RkQ%5rYE
> z+NAQYlrh@Sx0+?HtEl!-0q8-
> FH+tMtBmZVUkzf>5bnApw)Pl2_{Sj4%r0{VU4kV3V
> z(_r`r(x{5~{YMCO-krnG05s11Tx`o?IW&!!!@fKxdOF%j<s5Fid7`jSDAZ^}-*&FC
> zx}w^P^tu1Fb#a^*LEIyix}c()8=f|=|ITS%I9T1NL`|!7`CB^?>Wn*Q>$FGwSq@
> Dj
> zR@RZ(caL?nk;*yTc5}CkPkP{JL*I6;vAUw#>x8;%hu>7!ql%|0bwNe9A`~B8`JH1
> w
> zk>=-s(I*^R&ZtC9D=ztnfl%wtIU-<tEUVazPQAM!x72LQc2ka{4Sh?QP1jOX`-Ky%
> zcm);RI(S!p=X91ppHYdLR&+aJAk?dO=dhrr#t~`VST|Rv-rbN}YC3UVk>+Sa-
> %@7N
> zwM?u1Vg;ahQz|%jz}B79QHeh5&e0+aHg!5~xY(U~cSBZlDey!U=v4dhE!K&k0-
> i;6
> znL9_xFK?Sx9fhYp2(>=vTt0*4H{6ebv*uh1JfH$+o$k}~%p964Ig4uDInBJ7+ZEh7
> z%>vo&)~T%B!FLb5PO9C@Sp$~>g#w*w-
> *j%(&IO4+I*V%EIdwYRQ^>ySbB?C&%I!{N
> zU49AINp*Q0){L)$0@qpX9V&NTrp<Ndq_T`UA^W;>9%I*c>isde)|^X$^A)(xY
> VS~u
> z4$d9@&EFvDP@SKlSwy4SvFbPkq1K%<)B7QwUuR`K#7bAprNDJodxt6>nY(+
> |onz9i
> zJLi!OgigIb655(}DR8m^*IDfys@*qC9JubBb?2PCueOEj)cdxG%X=wstqNRcwRf
> oE
> z)v>#0-8t*ddDIQssrN?(T$3*aPE+7ItGz?D`-X`F*PXNOoYQvHo<N;?-
> xGI@SqfaA
> z0@qpX9jbVB?Cx22&dYbs8*jXEeU*9w5!PjubyW+zPO1~+ULlqOL4oV6_9oTt8
> zv6y
> z+&N9Epz*_YkSZ=}M-L9<yWd;;@WT%u7W<K+V_kOVT-
> 5@vlj@ODw5Gjr1+KH&7gfLP
> zsMXtVzrEv<(IGEhytuz}@HYbEKI?;AxhK{_sd()?`U0<$>dI5O@Sdmw*IDh0s$
> Wh~
> zt0UKrT{v>**ulL1Tna1&mI6zGrNF}}aQEHX!-
> ZdwmjX+HrNB~PDL@78?;Ly+)&I=(
> zBs}AHYuA9isQOu0S}m>m3iLgnL|uLG!3X-2kQ=bEBD;3h?-
> 2BB^(0T0JdBe<o)BhH
> z^+jA-y;54?SI$m(O+{l}-QI;`ccxuCcX!TIjHl~hH|w?WFRFe<mR3uvz5;#EW?h~5
> z0i(laR3}b)ZK1Hh_MLM&yUW1t_%4oXHY>}Gdg$h&>MOjoT3YoL=zBKnYWK
> Mm2X@$u
> zDvrIG9xU+j?wqq!tTWlHtUAc)PZw2R(xuhXs;@xbvsqVX9aD(YVKb@|C%v{%S
> m5S6
> z=RZAr_D%MG|M%ImKfYhzpFDf^&*Gzx?p=QWw+r=y`)7ZCH})6Lp8c!)o<Dl_
> ?4$dD
> z_kH(&*O_cqRvqN@r;DmD>C$Rx)mNbJ*{rMkW9EdvJ8VXE!erMP0t-
> C<&iTpx<>0QS
> z|NgQHsheFp@y;>lFP}a84=)G#eXGu7v$E<Sr$3!i9sHT)KHw?UzOV;JEvmkNO
> RLkh
> ziU-c_o(`L3aQ76~KM)J--8r%p`*1S-=<+{hh}|K$g4`z=^r#yymh{f4E*#8KXYz^e
> zLQ(GovzCZYpQu*kzofCW>Z|>vwK`$@-
> G}HXW?J2kxWT`%z{Z{P^1_Qdhu?tdO=6?%
> z-mw0{&7Adfj@kJq9P_R-
> `9$meWzCPaYKi#tiE2guOBze7zS>i*@TtC2;{6#ro>M9d
> z(gADw^r@NwpQ0ONKl9G{m(QMke)q*1KhIDUy{QT}^XHxOU+$t+7Y+v0nQT
> ^89pv<<
> zQz{B~iqYhsQZ?h8>$a%+dOlIDns-
> k6g>zpV=h@WilnrP>96;JMsuL%@woq8$BiuQE
> za`zhs#ZAKR;_&5L;r6YXY3kV7tStIp#+Xu_TPe*&O{to3&UM>L)jYszg%PA)#a60
> 1
> z+F4I`Q|WPDE5oN8GKHT~osu$u5y=@T;grfoalNVW{`>ELbN~A2BmACI^-
> 3{Zr%_c=
> zp7=8?@Dc8u{^y+c?mp+lZ|Yu>-
> 6hR6o0VmwUW&W1fiibf7tJZv#>pq{1&KbIQmOOB
> z?5$L%9AMLIZl$7J?l_z_Ik01FrJB@D@9`9DN_9%g3fPozN@b&puz0lYoLZmw6t
> bUr
> z=U@W;xsA?e{rvT3*Hll~{BG^v-2aMnb?u}D#m;7Bb?VDey5{thA`*-
> #l?#5bsRx^4
> zID1Ov{LwskTEu{{XDih~B$IlY%}rFQ|JGDSL5iMDREV<`CiO3P?9r6!l$51x)|nDc
> zsccjc7LV4QQ|l9-LiUsI9Q(PA`-
> L=qSN4N@1iJAS!V_FX=D<4#|N9(%C>mZnX+g2G
> zSy`+vEu#Am&6B^s{`%{8-g#$wN)ZXhl<HonZ~y-
> 6v(E_e>8GE%r>^<QC!f&y^Uv`U
> zwm-aT$SIXB!R++37-
> <;4e24*K&sM4w2@+72i17!3?yXuVKyIQU(pzu6_2rjeGCR?D
> z?>&6B&tFrdCKX{Yjq(&z8<09%&0Bv=nd_NqWk`&#!Bq>^Rf_uVyYHHwak%5L
> =9J3Z
> z6d>9}!qn5cN-<ogQN@XFrUwf=`ObkfykT(j=>NG(BXx^+4g%WGe-
> O(3FMPgDgG-ug
> zHY>|UA)*#hJQC8L3*0%czyA6cUwpyY(>-T$aO1-
> HtFOL#^UXKEmFe!U`rPVhg$Vl6
> z;IMhF6EzyTHC?jOW`_y`LFHhysRH62e*XNqK8-e_r7-
> MlQkg&5G&@ll>xoCE;Z2b+
> zSBHu)2&+6rQNi=I*Iv^%J_<=qM#hxNkO-r}nHmL1-
> *&A#hgw~;fnqrS&cTBD;l%Eo
> z(eD8`H(n|FImhJF&qZF)QKeh|wBB_%LThP{P6gM0fjb9a+>w}lbZR>Ic#72LR!1
> v6
> zu{0Bk=k#&SN4ax&AQ?<lM%QBYajjTd6s@mPB&>P*)lL{!RB=Yt#0jX^0+%^5r
> gddV
> z6i0)Tflraa)PaQYX$m%_vQY#`4SkEMg`GO57_QT((&4w!i3L8$opVr~c;{3BUD8~
> $
> zSy?v9rrG+Qm~hxS`f?=NoKi8S8q)$-hxEN5@D#(@Q!4l)f+Cr%=YbvS>8)sZx-
> }g@
> z+U!t`z=&!ez<&GN-
> ~Q@XzXD+@4xMSFJl5HyGG~gWLb)^Ey<do*Q9)Jk^r^Ty7zK~I
> z>5j1c>bZWL%Jd<O1}BF52(49QKI_h*R@ZD`<E%SJwhVK{`o#{5)lIj;IC#3Jk@Z-L
> z`%({v^u$8UgH(`;$0rGu3UZC6roS3BPyZZE!8j2QGh8)xbTuKRG`xBGony3mvbs
> wN
> z4jv-3J5-bf29-hL;&k*>sz<qVw6+Z(zNz7!jawt=^!tvER&b*TsiE)krUyle;W~{f
> zoy&D<?o1Px8WY5oI(Mt1)rDv!Xg}iXo3%8)gN#iq@af+<SeDD1Hk*}YLsTK%XP
> N}{
> zDeU?*ol=b=YoWPq*8x6A1(o8RqgCmUMyp_d&0|TKYGrN_jI)psdF08|$*Dz7
> |7=n@
> zHcej&pbomfZ7nH@c6O*J3k;nu<$(_s!;$mzpa0x`2SU$v1xW2FmF12w8r*1^K
> @`~E
> z{_Wq|;p%|N8HewqvQa8mv<U_zcZx^n6vK6zR&i|Xp<Jd0|K#%1J0ZPuD4hyR
> PewL_
> z%S_`(PS=A4t~*DPuJY(xEB9VO-
> 9~nOnof7&C@lK5%(?BfYT{YNXa}hvl{?zCFj?%J
> zZfev#mYJzmkxJ(!q1}hBsh-i6((q=7ieo66o)gTS&Z|`y^T>cBqeG?BZRKH^X|6{w
> z?4MGZK7`TWpk>N%=Hb92gVTroZa5;4M2#txIjdaJ*3HPnIJ#Mn&OWk@Y7{~
> HO|H0D
> z`j{Z@?4p=TYpZacT$&atVsc;_pR<n)EO7IkGm3R$|F)m!VB%2%(ci2ri{RG4Dn_x
> p
> z0(YLVS)ZmOsu(BsuxdbMWfFVhDC^lrrSiJSJSTQYgitk)%{$UcsqD~lY}O<p_lj+%
> zVzV-iPT}kh6^9UyFpx{PGG|nWSaJ+FGCEY83x-
> aY^6<m6RT_7MsyBjR|CGw~A&drB
> zNbBdd?A%f|TP#V`m{P%6wMuOs%t$B;EcHaE&OWk@Y7{~HO)e*bI;3|3&kCi
> rENi_{
> zWOdWvu+#X?CpNLbYrJzJ=%i<qK=gMii^JnI+;gKtA`Y>h`ZOI;jiR}J?oK=DweZu
> E
> zgTwbxQ6Cr#Wk!E$H_)0jkIg&MN~!G7N~ef74Am?4lZDbLoZX?~5aMy_Q90F
> mGT_MQ
> zP^n5aPkfr5>mwNUPpM2FPUp^1?m-@k?9mLSY(*ZYRNz;wQd{$-
> FsU;IDGZ}Zhr3Rb
> z%W0)P>7CHLbEd&DQ5s(XQX2~#+&QWH)pkyESUB)ex;ozXI3(O>&(xot^=Ue)
> cMhK#
> zTI^u67dPc-_&zF11j9upMp652h&F2;n|Gv@QrV%Uk<DiM^aoAccG?-
> oqDQB2c87{X
> zh{t0U`Eu_LNM)%^*%)wSbf|QtO&-=&dajRP*gvH*eF&qq#0;up^i-
> 8nHd`!7)R<Di
> zS+z=S)<5uW@6NGOjDK3`KCwH;{`WSc{|HZ--KtYd$=RLCvLT}hSm4l}n{VXI{`xc>
> zQE~Xxa7Pr_I#=R8DwWiM@f~Mpb~hHyn#blHX{A(lXvO$EhunF<es}P@2s(w
> cJ5(G(
> zJgud;mDw{AlL1FYhf3F|JWdLprV2yd^ja9fuzyNr`VdBg6T_|-
> i>bv=?3B$GOA<Av
> zRB%?UQk!_lovX3vud|PAql#l=kIAK4IUf^5(+3Air?j?<^>EXxo@Gg6-
> 8pws*Et+L
> z)qa;TZE9t)#?>L(^=Ue)_ZX+>;U2YG=z#5`Dpb1iJIC<izT}qDeHNwGg*$tcLFZ=8
> zO?OU_$27QhcBpijT0%On_Uqx4p6d#b+Ec30ox=l?C%VPQ5=g=fvL~i{9~DNaR
> ;jHg
> zg9?>8rx>o&v`UA&PR$W-
> 0}2Ia3Zj{1<tuHxbEteAOL^1y4l*{ez{mM+?c~onSeZ*5
> zo6~xyXOxFM%m7mA-
> Z#+48T(Fm7o=z^l2x33&oCOekBSn(aFMy^nzFdzHIL2P$)Fut
> zE;zRrk0o`meO6=Z!kyir;t=AE&Iz6wbrKnHWOS%h1m)rBqNU|{c+BwNL9`JJ`=?
> Z<
> z4`CQQ_E=0z%H%SGDVr^pBx+2l;H+AuHtSyx`_vPiI{U~rs!;^(r#LJgGkBS#f~4=l
> z;+=zuY&dg)9$RcjaOHG17P#)5`|LYyTvIdbHlp*iW__BD>OBpWcCw(f;#h9!5On
> UN
> zx>xA;f4j)sb6T6ur)btZHt$F)rLsfIO++@Hrs_Ze)2HUCQ#iXr#UaGgD$;rNnCG5
> W
> z+9{9C)uGa`DG!y2IZYpNnImILW%>|?^V(U63g^29o5GgB{94(kY=v%9D$J!?{rJZ}
> z{>e{%;{K&RG5|8}zCXWvF~~?C?Kdh8DGZZ~T18J21m*OzpZ!cv3D`Wrl%GDV
> OzO`^
> zF!+@5|Nig)-W(7%Vz?eGaNRj~8Rx0s6w;>VC)SsG!bU(XC1;Q7-
> 31vn`6dsk#&#rF
> zQGga|AC<y8B%Tu>nQG$3qFM9Uyd$lYDyEO8_~;0y1NUFV(<z+Yq2dtYsa)K<
> oR?dC
> zgv5X&V@gF5n>6xhX~l%5=lTeS{Y@&uSQ#q`wX&GD3i_K|DO*uvQ!32G)WE
> P^=2FA0
> z=jxx;r5aL@!Z0eGcVyf0i!IMP0sqi1#Q~=-
> LHY5>UQ`=X>p(Xb<NxWO{;B=@uZTRN
> zWj_|U^UiVqJSYAwPyJ`3|LFd|dxL)aMFIPt+|WnATeJU`j{R$(KOowjp^w}YFFT
> Gu
> zw{|KECE)g=kABx?9U(JL{^*Z@)5?ktF;3dU!zu1gEvPtlAC+>tn0heOQ@erIta)tS
> zP6lK8cp&jDas;pqSEN!G?(7Z~hY*icC?Vb1##TRt4+D;jDHTaZGqSYOZ1MzB(MB
> -r
> zpHjgSJY2p7=W(bc7L%(WEyPUO5EjlPQKLy^LgCMphn+|$uNOTi*og=_`^YvbP
> Fffy
> zmnNcct{<6<#ZIY*Z+eOa?zwZ^RbbZzuNS>=>=CY=|Mv2K@zd@c{Cm@X_ws
> -5Krfbf
> zt>LNu_jX=dYMsN;Q}(lpUkVx;{Udf%={Do2-
> ou1R2ltkixpo${vyX}@!H7V*?czBa
> z{k5m&skKt7m_AY!NIc~9U{E}r!r7w?IyY+)k29usj#gJhN+Y|@DHTa<nU055G&;
> #r
> z2geYbQz{Gr4`DF-kACzc{-
> +aE3JcCvkOwtS+rh&*BB7^A#d=^xA$R=ntewWG7mn^w
> z#7Qw+r%`dz!Z5kqVhjJ`(Y4<>yl~uaI{(SDXTN>+?2ohm+>L$6(fh>i9Q0@qMz&
> 8o
> zxO4v3vuF6vw%H5u|M~8Ma-
> W61ee6=lW~Z{?%qqU0ZumD#+ZB`>FsgI|8&SC+v8l%r
> z3*X%Mo-
> aMm%x51J#e`8KZQTJiPpy?wx%6@0>s#bVK6TS6oIT2*bF(J#c&w&5(x>r_
> zLmJt2PN|#-
> I^$1&`cwWln&Rv>kj1Zwb_}sOrNR)zCk%rB)nEOU{ljjq$Qj%uWd`B)
> zmw)+}P!%s_Ls$-
> RMw5z)5zl5ZFn8yW$9(XozU6TMY161UX<;}X&RExc8qh+GlAaFP
> z-
> H8Qm`<%nOg5Q$Gx$Sb$%LG1lpKz4LiT_<4=cd8=v4{Ve9esMJvXFe93NHm6G
> <dqZ
> z>Q;9IOl!(INA<1|Qkzq|a)xtp9Wm5CDqRResllTNRD~uw#O#`<)=H^d`pBbik>l
> *>
> zp{Je=^wcSwJ<6bSvnKKMoQN~J1B@7Eq>)|cl*+{<53=^lU;fh0EqBc85Xz-
> lb_}sO
> zrNR(Ml)|`!kijV_Mf=4seqsE|26zr}Mu$q*4x5A&N`E~6H-
> Gat{A^|pF2xQYZ5oxE
> zH*Go?n-PERxO39@57dbTZo6~rPH^{$gR{%Q-
> 6zG*b9A`fMKL}<DY>wJ7@H;#ot?^p
> z8%y{P5yzIE?xPGN;0URp8qfLrC*1L)%2EfnSuOHDDqYBkkXzqs-
> |c%FWq5iI)I2tC
> zCxb41b~C38j-RPa<<f;ayF<kx#M5)a9Y{_<_p~Dvrkhf^<tq;lEjP6eVS%Z(T;|A_
> zQehw#NEihF&2N5VJPw9aL`i@5yWhos^BV9R;*1WJuH9@xQm&EV$O{q$Gp
> ac6&GcY_
> z8}6LRCk;`BR|J0i@?YgAHtusyyj$Fz<9;+Wyl{$qb}9=wX9**e+x?@OV!s}u6rny
> O
> zMpPUg4W5peS9iSgEItU;NDyH}rF+6nr_H8rD%TXLNu}wdP@}g4$_(2SOW)k<!
> kyjG
> zibIIkJh37<L)FHV%B?-}q<1ezUFOc=&MI`Eq|6{kx!o~RY^oIoa^Y%3(Kt1Yc;O(z
> zh(!C1N~gOq8w=cU=h&BK_#w;>8Zy}J0cZWct#=N8!V_;NkDz%|yHi>4*Ai}?ov
> bey
> zvBVHiF`PZ3@~e`zUM9uCz!Mi#?i{U=KscgOcp*wmon7@&`=Rd~o{KtB!g}9D|
> CmHw
> zxU)N2aR{rcb6mxP7NiVS8&j(LMSuIZ<8cM!oYACKdal<<csiwm4<vFhsF|2Sor|i
> H
> z%F0aHz^p^m?odSqtS6$f!rkl|L1!P?Mx~=}%*FyA>dtXWrQfZ^>&x8im(%#Ms
> &mC1
> zsx0K6^$YGRymNF{^$!N@0~}z?1lBmJbn8E|3ptA!dP8zMnxO~D6bWD*Dovk
> #r#@AQ
> z!2G$dYGqFgxjIxFPQ2o*f;a^;L)FHVimNum@x)u#`Lho7WUZ0#bV>yuNaSErH
> FPej
> z$_!e8DI558h}s=0w|s4;Z?D|c>R*sVDmU<!nvi|NozuSr@QLXE$giAnAb<SNPe
> J;1
> z89U95U##)d5qj{+hrh}8QYJKSYIiCN{;c1Zf*xofpkg?CM0H@o`Oq2(gd-
> }2pHH*J
> zV~W(II+#9PVAJksrJ=T{;(a?R*<4d9ANq{8E;F^KR2bFFpvK=ZM2B~%YI)qXQ(rg;
> zrL&K0qpIh9(oeC#!JVU$+%GX+0{2h+-?($^_nP&KHT{0ft{3#!|88gG#-9t(!9D`{
> z`OsEiwL6ss|7QIr6W?|9PX%KeQH|oC(m#b9QK_D%kTA#;2~&5d4yI2R*t9!T8j
> 4Ha
> zVRTfoxu#S*W}gnxWv2F&3Zt4COylqC>`+bD&TD6S;UH9p)2OENK3xYaaKoL0b
> =oDM
> zx5sGl?%Hufc<11M&ttaTD)CBjarl|X&pXOzr?N1%S@M3?`*#0SFwPOxeY|u22
> 9<k_
> zRH~_T)DbekXsD(=(n^OT@)0l%)wDZQ8tMpMU$-gM5scATU1n-
> esW7UU!8HE9&JNXR
> z$@}^{oJO@T{*xGm1#Y`@_$^ty93El8{Txm`n<YP5WdBq!l2N^n;y3$&p|9zxox
> _Mq
> z-
> I^q+8`v~d)9z3qaynzPvq_?E9V+!7*_yAy9u0T>Q>vyQo7@~jY)+{#q?y4Oe0N
> WW
> zYLgCA=MJh-
> O+!6h2P|;gor9(FV~PGK2L1RzV*d`o<>ct+aO&AC`O(@id^&|XjOx8O
> zbvlo9iXHZdN<(!p3Lg#Cv^!MIP$#-
> QQL0e^yZ$1B@zGS(j#dck7}Dl+uD(NuDrMN+
> z*<mxP-
> BVouKrC?cor6`m@4NWJ7WW0(gRj4z!>MPp<VQ=w@aYul(5ZLzzl^=8`Z_;R
> ztwsf`{acH9Dq2S?Oxk%(=juCjs8p8Yc8ATVj?Z<q5wO5LcaE*c{eb@gzisQ}YUI<Y
> zER03HAITDij{wsCCRIB2;W`&pU)v|DRj0_e7V}iJC#n_J)sd_3GZhLBrd2=Ylk>y^
> z_un}WyV_2EIzG*MKX~VKNYtlEr9&=YFRH%CORHBwt8>q|j$&3<=gxao(XhZv
> -8mh-
> zAHt`3Hmo}b;y1N=h%^;37gZsSd$hE2f)ve;R_C791q>e<)w%OtRWvN{?#_ARj
> W@XH
> zTQaaN%i(l^m%MZORF}-
> fqUx)?w0fnqI(Rtn$e)VFx_a^A1xMYIfpy*AIUj!b;Z%>O
> z=zw+EoiknF!Lr&UPM>O1*n`fCsxRQu>Xp*!;NieaV=5Z!>VpqH;HX<Nu&(<%2
> Y+L^
> zxMioRJQWA5g$d-
> fQ!MacSv6(ZO4ST|&}~um1zcLaf?DBlIOSDH7wZbg^DTYa!CLIX
> zkvqo@=Jn@NU@5Q^SPCo!9!`O~pXWSW_!W66uoPGdECrSVRN(&3!H2uzqh
> I|9V;K(y
> zzSOGyFY`2hw|1F%>sc06t&cukTB#bfy|k+J(Wg&Bt1J1D4!;ny6aL88efA3kh;w)
> 6
> z{P2fA)ST?FdF>#dJBB~d5Ej>>nku}sno2~6r4^-
> ^8cVCGM0B85S90OluP^Z0dHe0R
> z5B@@fT|0Mo4i|mIu#50WgohZrsQRidt(I1O1^S+=uC{7*@Mu4MxMlE^un4v
> 8oPIr=
> z=ec%aU(2P{(yFgO-}9R5>Xg&{#2}{CDFG2`-8ua#J<s!+>;1e{o)c+l)z@)pbsJip
> za=M=w#OmslfC#njoPL#_=ef>?zLra?rBz>nzUMX9)hVa@i9t-
> OQvxE?x^wzfdY<Ps
> z*ZX;^JSWo9s;}eH>Nd1G<#azWh}G380TJp^@0^4G>)uX%tzFnr$$XYpORK&D
> ea}@_
> zTeUjnbU!hOW$=`M2=&-^&XIM*D=X%<S?@8_rk*%&-
> P5G1gPi_!QS~KVS}m>m3iLg#
> zu8y3F4>9&cDulZ1o%0ZSFeYw^nA_&rfU%6T!-
> (_NJx!`Q$mvfPRbSFu(yCMN>E>$6
> zbxT@pdMj$qO_j{ewCZH!l0GL=A=J8a?s9!qcg~Kwo(}00{w<viZoN}|%)yN+n)
> |eB
> zV$iJsNFVj7FvX@r3;yYhoz6a0C)!y)`>3|+rXqL9jY>ydgMA_uLajUJt`d%v5{jZz
> zP3lwE`{`BIJTPi1<-eqT3RN?|{dM)Jnp4+FKRts-sQN0IXJ4zWk&pQAqk3rFjH)h%
> z%RfDl3Zd4Wb62-VN(m*fwf5_JKfR_-Ke6I^|Lo8H?8`5|{O0cU-
> h1ywhuuB3RxvCV
> z%hy&VW3*9Ep9(NrF`_?$j7YTqGE_Qa$L>=V(U{ZPC?dE=o2X(&cJw%av}sg3f<
> Nex
> z6R8mDk?x$&KKsnhr?0>M`ki;)=?M1LTW|4H`~36I<B)V;HY*EbV?dqJXzfqT{`~
> oK
> z^-
> s&E=&Y$Uve_dNQsJ17qu7%w6Y**)`cJj0VHl@rG^x1Q)Oh{%*T4AU3(7^~tFO
> L#
> z^UXIoq=^K#CKWtQE(Q4LqmMXaYP|pc`$kB-
> b2CUPot=|nYR;<;wEHTVXJ0Gxw~3mH
> zDK^OaY@4XK_Q=LsiiX<=9X6wK(`i$W0vBK1%zpRXcOzBW6VEh_Hl<SM+D52
> Hx^q;F
> z=@zs_XmO=tr~9&5S?(NFyfj7VjQcVLNDHl|ib>N#8}XojR5(qrnu-f?S{bbprrF`5
> z7^i78sTkiGS~gSZnn-
> YKQc<hs32N|UW{sVjLGTmIW=soyv@x476tk%n{SB$3n8QZl
> zG04=|MCFP~*@~ia8)1qB2cvS+X|uo4Fv{suppK3Xn|ey6gtd)Ok96l~((2{f3SN8
> d
> zHGVYWMs$lyw?ebBI$JPi%za2p0n$RNsoc8I)Iy6GuE$k6hBv`#DlWunWwc5d0
> dz%-
> z(=-aIl!S9>%{YnD=BJ;2+C+j|L8U<mqXj=Y%jtY2cMeoaQJdvN9hzFv-
> *lKNrX^>n
> zo4__vF*T7bttIPp8-WWf45M<>X;WA2;;Wn4>(2S^cU2W`EO&CN4{a4M-
> 3RbYE3R2t
> z?)2hx@ji4XnL4BZX?@jHTs4il(DbPldz2`}aGf<3ot;(&sSNd2V4S8=P^BcsqbHVW
> z65p!0RKDVO4r@kJneNSgom+~F46+7dDm8;-
> <Brg$$geqU0_#u_kMqXrifqoAO-3sW
> zqvDWgXm;w2W@A73<P)p^G?g)a+B2m}N2Q$z^+=y{fTQ9~^VU%=t+-
> }oxsu17qnAk(
> zFXc%A()y~Y;&iIjsL*&%T8TNg6vK7aRCIP)8EuEqJQ=5H6jUjR&B6phjd<HoVZC-
> <
> z<vWLhn4#H>d$V8Xmf|9Vtbv$Hy;U58W)1m8;tYEeSci&uPM?C!d1{l<3d5*$l(
> RK8
> zZjU=pHgzvFhj6SJQ!3|QG!g3Y?i?+g`heFA7oKUwH7hHYd?6bi=>g9)rT}Su)l_ln
> zW}&H@J7`l3*I84U^GGP2nu5fIpvO%*ZH}l$BrZEn2Zy9Zxb7T^qq3wsZkjc97-dj>
> zVm5WxyE{h@QN`<TKuq1CA|aJAqhNEM+GMoCFe)A8?EXg6fvQ-
> &J#`fADHT1Z20}gF
> zodY^Ox$WKg^iNlPy2P~NVr9WCzBEq9R&pXCY*9`6C{pRu2+%LI6bu11{>ZMW
> Y*b{k
> zo<8Ad_EG<c3Tme?dR|VyPf+J|=cu0i>N~x(N6AY2M;TP-n9b3-PO$h1w!Z-
> }b%)9b
> z`)n#;v~|5B+o<AL_VhOzhnR8X+L=<hxr!!2J?fpKWi`ERVu`txr4<(|D^`$;(`lv&
> zOaap3id5<r0s4iehp3(w8h>QhR5mKISx=vEH2bK3L^aBzlJHxX5w^;;?i^K#Z(h=
> S
> zdz7rSf0RLWj@i`1fp6<bh0`E{^*11<?ob(FlTFo2ZC&rkHmY>Eb!vHU{lt=<TE$#^
> zG^L{F)Ig|5y>kGlGEA?X`UpuYE>>2ops7yIL7DYjPXW^6id5?6rbBa6q4ABNZc2?
> m
> zvTG_E71^w(PdJ)=)IXvc<x!8N>84zF&M2XjQLBi~qhzK1qYSEZ%x1iEw8m1Z{sz
> R<
> z9V#R2uu+-9(DjaNqbh=^2-EV8arEr!51&%SiAFsL_1JfgO2~IJ%G(zyt+-fOv4V8E
> z+U9Z2>rwNT0;I(isnjhps7g9x^hA$3Q&NpTvTG_EmCooUr8v$o^3m+0{t?wEkI
> Yee
> zEa@fV@LsjgIS|mjG`ZJy=V(<Uap^9=az<4Y`$u&ZJrP!wfgSHdb8vdPW{ezrjLJ=?
> zP1PY4L7h{Z8)PJ795tniLq<Ia_1Jfgo&oyfKttBt#;0ysX~o6LiWTJIq)om0cvkU5
> zw;?G&EGzUxDs_thn+i>xNvQEhc1>lYBAfN-q}0b5>&|h4Oq=`^-
> 7Kw621nUPziy4I
> zx^q7M_+$NNBv{q18k;Ja0)4Gi7MoGeCBkf)eUt^Ga_iD&f1~LrXK%fBrc^F|(L|
> `n
> zzH>lV2*AR}?qqI93rceyD=SveD4_MHw@vyUIt56JD^jUj<k3Q#zPZs2!EYlq{>Z
> MW
> zY*b{k9wi(dr5C<)cwj5DzQ=K#&<YuJuOnJvET`6_xOs~vmoUO`{hbWDA+AYaZ
> oRbB
> z-
> Ke_Rp@Qt3+KiE6ENSPDCW6!?`m{r3{xuuVrA@OdiP}aLm&Ts{M&ppw;IYOUO
> Wmw<
> zN>z+?j}Yn#?i?*HS5OotEqu3{H0QChVg<Q4Y$})@45L#&1<-
> <`9jW*T1_5Yjp^avz
> zvtn~YX#9~~Q`soa;*37wX!cS6h-#EazJ=-
> 3j9W!)Zl!Ym45&%bTB>cH2QKWWInrw6
> zANvVh-#PtK#}pl^m`zpe*T4QXg>pv(fH9V@xS~-
> {hswqxIAt+I*|^2vHkzy7Z&YqN
> zZR$p&CeD~15eTSnzM`Z$BkU=a^DmkRbp>}00C~4?lc7@+J5>e#Y0hJ1#R^Ilin
> *Ph
> zVJSdbZjnmeB9FpM3rd~2AvFHTuBmKPWV0Tfv?d(QKI$J)jq=FD5*x858LdV8w
> ^BKO
> zhSFkYQux#vyf(QVT-
> Z@_q}9kj_LGD%re)tRbxhHrirI9EQ4^$fB;e^(rq7hkMB6lb
> zRNi__D`p`Y{f!pKx}JWhDV2*{G!g1L?woY>tor8Rk>)(sd#s>TAzp*_9-?!4r2uJh
> zMJjcRJgGj>&3aPZH2%o0sch6}(mvs6_EG<cYLrJM868feRmA?SRMFpJx)U@`q
> &+-e
> zFMsDyRaViJ+&R!kx8!s`#zeTDQC&GVG^q)5lxDNP{o@quF)B_J4K44f2ywXUp
> ``Vj
> z`YDwQTQm{sI_{kGgC6zZ&MTIJM`_MuWyK1LVKuSM*+&4ZCN(0JKCOACg+|
> @<w9xn?
> zyQZ>Hk<EHkv6^r+`>20JHOiyb()9OEM$2LUR;uW4q0&=|vp8ejIS?c&rkT~+cIsI
> (
> zCc^cM>dLvH87nQaVbb*ciP7pFqe@p~o&Akg1mPoATD?=IR17#Z5bCmb4$@
> +;h{o01
> z8J}jAqY$J{9iPU^!dS)`8JgJsd*vfk1cni*l&3z?)l=(8<B#m9RrHK()}!;*gfV8_
> zGomW;$XY7ChZ!xz^^e#_RMFo8*7fWrB|qQq#IR{kpDG=WPO5r^pL3v+%2;1
> JqXn|R
> zuN5_6niNCN2L|757!@aqMt`Hlv9TvsTJ%BBlqwySb|Tbe?;NHg;%FLiXq{E^v9e
> +X
> zMHo%2)>QP=9z^B>Ya>#rzs59Md5RNV-
> w3+nR^yNCn#x8+woQa^9?d@LA5j%~bUGA@
> zjh4gytyIz9LTPzVD=MA@F>Km1(kgXMJE`hf8xXT}s5mc`A1S7Lfp;=T(MVUPog
> FIk
> z@3U$AeYR0?717Y;A1Q2$94jr(h@L4`Ix6i%sH?ei0LU+e@Z}<HeY4I*pbDBPjg=
> KE
> zh+%1Hy{7>5RO1L$x*P`Y6q+*Q!g1R%jqf_6R?Y!UA~~Z&XhUMmx~HIW4BAv
> 4s8R1u
> zNcT_w^iTR93}vVhTS4W9SiNa>)}7-
> dLNo5lLNVTl$n0o)#wlFS)(o;FV2s$@6g!$m
> zrE@u33%jmr8wjmN66q>NJ{Dw3<sgeDLS56H!&3U~Z-
> 4u%U;PRNg;%QUk<&d^cd8IC
> zJusx7;w|}lejK4n%adSrp=s^hX_n}g#&?~aT}UKnC?Oe~VRh{$oi+<9$KaYQCt}1}
> zBDTAt8ES-AP`M#iZ<-
> ^m8BU}|eD~>Mj+%X{Q3UP|s+Sgjztk~Nhl=x3hgva8gyg0_
> z{~j%n{T(WE?z1uYZo{Z3LNr*hSa_`G=+8X5TSetXsJbSnRB_%>4?<njo#Va|ffA
> #W
> zpkMN_vSJ0L@<bT$#Fysk2vu671k*x`46!E`V;bLeMy;F!nnZF&hw#F84hTC`rrx
> O1
> zq5{^_(aJon-
> gJv=%{UpY$pe*CBMjHyr*Z??<nG{Eb)9z(gwl6~QBtmGWc0P7CQQ~S
> zo1?k<{YJ%!qR}a7y<V8dcuKH`WfrHio+;I6VC+YzYr1m)$lYdor0-
> zhcI0%A6%>VG
> zkJdF)qy~x|0r_ecSF_%U(J3^e(sJW)7#*+<mBv)NLkPC-
> eeZi667?ylD7%tGdzwT@
> zH`;beqIN;0Zm<Cfq|qrAY0<-7Kq?n=)a+A@BB0-
> pcvfBQo#WmWy7yVd0_{;>E6bo}
> zYLw0Cq*Di@(z%@7+-T3AKj*-D2y2Y~(U?-
> jA)_9IdZarC+NV$|Pg?9Y3RN)8o;k$I
> ziWQWSXeZAAy=~0Kozo;yw@9T=X_G-
> ^i45o|w6Y+KSr{EEBJD8xSyRZfs74yrdrnEz
> z?ogS()!XQlN@Zldkxi#A>^@Zy#E`E4&H<;Yid~?ec8UesqfJ`5H0ivXCT&u=>9jd2
> zV?7qqH=fFD&eKDK^O{y{9x)K=%I=)zYWk;FtgIb(PC?Zt(Q=Da`jmDt@770*Sr{
> Fv
> zt@En?!)c|noNJHd>S$$SPpP*NhU@QBxq;g32)HSg9ja4QQgU5UYImqOP$L&
> M{dXHi
> zRZQ_Hk4~gQsCDNYOX8-@$4YG0`w_GqU>&LpBSEo;riv@-
> NY|mVbR*j66{n6p7|XJm
> z8hxrFRAh)fr&A$doaIPQu|RvYNvkHwbkeDVQ8lN#nA?d|2(|8<V~N|e`B-
> tydOw1;
> z1FS=JVI(Nlp`x%@_3jsgbc{_@qktVTv7FKH*#C5?u*{AcSaRPp>Z3iIwCb?IN8|6
> a
> zjjB1_#oSJ$La24;9827$BY|butoI{mJHVP$T*YOK8>Z^ycT*lu(ds&>SZola^P>OA
> z*rXL^?8q{jtKV-_ow+XQb0QT&J>H$uDV)NmnZ`|()r@)Etx0vHtRUT1&L-
> 8?um}Bb
> zn5rmmebg856s<Z{x2d{Lq3Vm!^xQ;+^>$=wPF=VeRcEeC`kY9GP>*-
> #6vChQXj5gK
> zIBy-
> QNp+;GHk}Ga+oY<OcKXvr)t7W>^*~y!I|rq8<T&EkyEyoxpQyrf)q5e1d$hE2
> zf)vfARUwXhw6t=96wPbaiYN4y7^c-JFbK6i=M-i6V2`f3-XCnyI|DDR`ob-(ZbPe6
> zPWKaoSY4eG5TVwc)34I=JlEOK*K%pKwCXF+_q^u1I^}dfF^Fk(N<f4<`_6gejW
> _yf
> ze`rs@m|BZ!D)rK8DiIx)R+M6DEUl&z(ScgMc=6(t1OAjCfO&vB=Z8Q1A=kanpjs
> b(
> z_~E_?4>1Zbrq-
> gG%Dc3hN<@dH6{VOOORK3wbf8ureDJ|3*TpG80Ar`<+i$;pFrZyu
> zcb{_*^2oKr3x@|hdMM<h7yw`b7ge2trB$tuK3!U=8nwN&s`b&QQ7fGEkN#-
> ~0K9OH
> zUpw-
> 7$%3svmjX+HrNB~PDe%w=+<(q_=y_KBrNB~PDX<h+3f$j0_$Ep}>phkozYu#Y
> z5}kKZsT#Gtw5s*dr%NkUqqdh;wLbdPX>}z(9pcw?cXtjL75Q;(3bv@GiC9`qC8E
> R9
> zic(CCrPWj-I$XI{S90OlFCW;ob9d)Zzbi59<L8yY5MxnMim9=*no2~6r4^-^8aJR7
> z{u!O-zoetTBxa-
> HpM_$kl?J&68&vDgDYEwRqZ_FAmlyPat)*38+@;kkqSfg~KCYlb
> zI;*SGCp{PtR9o(xgR|-ILMl93yRg<rpDwLbjoMyX)%xhurIo5t+fA+X06fti-8@Eh
> z;zXx}0#)zMIb}8ta!L;CAg4cVR@UkB)&VzBp*%GUBfFll^K=tcC*UbQi>fc<(&|L
> 5
> zn)`0FAM5^g=hXV#Kdtk*>b=%SpKj8sS^FA)pS_7{-
> xNDWEvmj~ORE#LYVN!H({c0P
> zDXL{~bF2p*0ICQ3ob&qYuYd8y7vIS1(@#I;dQy?tx$2!#OpQ%i?WlbWiLZ01rqR
> xF
> z*re52lTPC-s;NYDc#2wK`|#X*AcOj-VOl-VjJv~v>H+SYc-
> z>;v+f+Nh_mcXyYQ6q
> zN02G}CaP()vm6#xU&*D_Sz4X4>FP5+MYRmp126v+RA=8gZ@u-
> _mtTG<pKktOzOr`?
> zif+>@t)Nlorn3PU$EyrMMlkH(M8#1LZ7iz3!n?KV6j-
> N(Qq<j4X|%ICYpUj^gBxER
> z4b>-Ih*7EAHQ1m!_0D<s-
> FN?R#eDP4=bwN6{Q2{Ap{YphtaC`WG_vbN8tH$~Xj0iM
> zEFTySY1-
> Vxxs_@<`_!Q$=_aa8>pkMUsQT*d)@oWmaOjj!in@uaL!v(EjGfM!syG4g
> z2(Qi*=A*P~rxA=w-
> LAm~)p>W0UN~QW{q;NVyi+VO6^Wg74(V3J=OfE1n}xx!Bcn-W
> z!!d6$SN&)NkoI4Uip-
> r|vWY5P*F$tJs=lhbwPKwVMyG^Q)J;?cK>cVdUQJaT1?d`#
> z&JlJx#HdC?9;+Wz<(<>#(y!FM`s%AU-
> +XgAHr2^G(;Q9%p6=iXQ!3}fW>IKUP6p{1
> z7o#F}XGd<La?3>g&dZJJG<Q>hhs!UF4ny?mQ`NE*VEQNmq&<BqH(ci$*;t4h)
> of0w
> zRHD)B)Bde^H5H<zGj5#)5^V})RO!@@*a@lwcg}0Cz4qB>pXrxru&1AJxZI-
> 3(j0PN
> zG~R#zePR?}=waX|pL{}3{rOUii5^FoQaK-
> Mx@e<csvwCOAAR(Z8yFelbbTs}WzFh)
> zg!kTiFV1T{>W0i(XJ@aZRHIo&{aRoytsRDgTIq1=W~lr~@2Xvg^zBruba*P1=7<
> &5
> zdEZxS*r#%+P9h?iVZ~NY?E-
> 3ZO64*Y71OhVY;Nmq#jB|bBt03(P|Q9Gl@2kgsKDd)
> zfNIyBqlW?W=8UZ;`n0kNsq`js$AFG<*wcNfNU-b5QfHkMwpNx?Nt-
> M>9j;+hyHADT
> ztXVy%Mt6>ri*9LwJGPWc*VVBVVBI-
> T*ome|)Iy?NS9qPrG=nb7Y11HiEfdC!N4#_N
> zlyFqm)Ea|0_Da|2I%};E$0d$UJsG(D;qT(JISQ2yF)Geg8>t|>JBztMwf)YSRys-R
> zlBbZ-NOL$^hvv<uX7=0=M_$}cHqe2kRL;kmZr(^piPT83)A-
> uir@|=KtV+Sl#9`~P
> zq3<Bl0#_v1DV2*qZC=TpL(vFKWn2lt6E7#lw3%v^jv@dIGH3}!+YxGn8nsX5P;H
> 74
> z-lN<(%?$|koLsd;TzIV&f~f3jD;T$bG3h8&I>e}Sx{)2r=3vigBJ_i5<DH{tm2tTf
> z%Q+O+4l@>wG>4;g#Ol@qQb)y))y%WH(RN@dmGiMCBbbp^mh%}k)A-
> uir@|=Ktft9j
> zFfzL&rUkA@up`xIfkpq5yK}IXjyO}ToCBNGN-
> GN6&?QK9!&80x&InV~m_cIHhEBn~
> zx$i8G6HTdD;lyxSK@eB)x)+?7&1}|G5h-
> QkSyW6q3Y88qD$X@Buw;1R&l6vxxzLZf
> zw%j?*T1H?!-A5%K3yM8y4oB<YN9N!C?sxV-
> 4RTwM1L^teU;o+!9<kXF@|clQIUj3s
> zMl-
> bPSy|3!)J)@RXP*kAShKp%+!izvY6YR3Lt5a91UpiV7FhIay}3+v7#vbc6@6k4
> zMI-
> 9yD22lgu&7mJupR>F{_4ELN~^9$?Nd2gLc$mcRZr~#YI92ElBFetN_JJGs46Ml
> znw&M2L()k{Cj*AqOV<t?ojRO0`kg15Mn#|0fF|Y!!#UW`>L~@EQc^r(rx^%hF
> W0Y4
> zOt<CEVFe*@WYNH|i$lviqe$#YbLiq*lL7$g<Bvb)zqaF!NjPhIfBy5I*SAwjm{O5
> h
> z4Tq{zr@P<zYg5CfcApBvS+n(>qlu13T3X<aEmG;Cnzkm_)mw+bA)y(mqEGChX
> vC&I
> z?(I7qc7XM%44{yOgfOOVHEN&ADW(h~q3Wq!Ky6N`T(StT`^eJSM|Mr+kW`=
> P$$+tZ
> z+3Y%;HhdzRQPC$Fc0a%kMtn*(cVyY+oW8HOfN3<w$8_yGM@u+vHHM@?
> WFWW$!+fGh
> z>`8OT$ZEK=lNX)S2}9@!_#ge~NBoVucsnsZdCW+uoR2jb!3>omf;nf`Oyg^3p9-
> TG
> zoN6FDP64G&D=RH<MS>lvICbC9l8YteX6!U0)pQgV8-
> aO}r5mB6kIvhtG7`;QT~2)O
> zz9Wx)DqRa~m1`u_R*5*pluGlZ^^;~wQDJN4v)(v$VboNLRLoeXl8U(q*5p%#G
> ^*4e
> zo!I#1P+Sp~K9!CVxkJNdK`48TCPhCcZQnUs>G8d9Itfc&sp+ZmI6KWD2dd$wV
> 2!h6
> z=uA(0#M`M@ONYw&Sd){Q!9*b;b!EAMXr}SCGu28R)Mk9mrYj#R16udUhNlIt
> v%rp2
> zoVsu5nGqA}X6!U0)pS&PV6e>6!tUs!^Y*DsI?g^y5EZ894$eN6t_3z{hcN=!DiN
> oc
> zQfa=l$ct^Rz&s_W7^g0bno5y$F4+B(fr_~Z*5p%#G^*4em19p~qz>$~(}3!^Cf
> &?H
> zG<&&zZDQW`ox}1$)buFQz-
> DXC<5{cnI6KW@jE^23kai|<MwX0?($mXGxSV*HaiR{D
> z^RXr)n9;8+HxSJ<zILWsse{^#PoXrMsuKER%4~RA;5rNJNX4o9hVsNTxfwgnNH
> ram
> z9vG~;RHcqSI&YuKq+{v2B9FqRS*Baf*{9OAz-D|HBh-
> 3o7f_p1D$N&XPt&BFwBwKt
> zYE7j`oX8A4835^CJn79DaYmuguPT{sRBlEzF^fHd5udsq65`A^anjGsHj4Z%h&C~
> G
> z`_75)05no+lNT&bKln$H*puckPNDJbfYeh;k4*Kn3zOTi*tq1;9J<c5=}>icrE+d*
> zGmWpEsaEQsHmBh7StiaXIMV{xSzt#hPTe;&n~!qmq+48%C5V=8!Hz^!ENaC^
> &M@f+
> zP?WBDYL?^s#2T_sl|t62_0%q)Hm6jYvQv(%4r)!MNUr$xWN;gh&3JOUAZVtL
> M&+Cl
> z*7{+%N28|I8;b2WzxfSD#X{mhGP5Tdn7w`H@V(u%(m9VR8kN&ha(0?ShNZ#
> Hr%JHU
> zbVhpegwXSBbiQ_|oR2k0Xol**v^Zmw$uz!prdp|k+62?n$dOocqzNLV1+KHej
> #Qkw
> zZ)lF<or5@T(rGhN)k7kxB2hQ3G!CgF>(f4!1!pl&ccNxF7FeCfK9#NoHWh$Tpt@
> 1b
> z=9Eeg_*0IoS|!7tQmH0tcTNVBSz7!WCxtXBb+d|%{pyq2R5C4f4&jbqPc$(5_B)
> 5i
> zc8uqGRM7}qR9VcSi)>9Qp-
> 9|k+DT8%9y=qO#dm~}$~my<XjKQM#ToHPNEtW<jXo8I
> z5R5803~i2%G)`R@k&09I4L#sBag0y^q>mz1>c&n^M1zMYgyL^Mrb02u)JUmti
> o};;
> zkRhFys4z6kvA__&U`weAe?C%x0+s%oj42fsMF4JaJqq|VHFT@mu~4gI@KdU
> EE_CX2
> z?p>bd4#hS)qbza?X;f}%gtC4Z?orXCk`B@hK}>tOer;m*_MOAe57SEL4610<tf;
> k^
> zL&l^rI*@cy+h^*jnsG&=l5~WT$~mw}NHY}aJ}dt3cqG_Z#vB=aDnuZdR<xU%
> =L8Vb
> zT#rb!KT>h(zM+Y`hC9dceE<93=Wjo5DsL4EcGL=;g-
> T3NnjIZjWEpPhK}EKdicbqe
> z0SeS2Lh)!yrFRZD_*5t|>sCGG&QTuDLPMw1qsbh!-
> s&Z!sWh!P7Y#dl@Dv6+3&WDg
> z|MjCgE_5IdHSKgZ=6$kvj_xOyE_W-
> _)8%c{Pmx^hPwSojj9^AxS<cxt8FOUxskHpL
> zc9cmhB7GVU`w@xuM=H0jPE+?>#6SeB$X+^iVMnTwbBf0k6rx$lvB#AbhXZd
> k1^ZJf
> zMu^6AQV!8P#w^!tDHWK%RebyxXNOUsG5~ex7$Yi<MOXqn^*aX((G0p%j?
> 09BRZ{^P
> zrj@$UMgiMX80<_9o?WOP({uC=9m5gLUTG-n#Juf0hvkE)#p-
> podI+_NhE|r<riL}U
> zC@9Wr2Nj!6Ey_7skpojI_sBIJ?Q|mNuT2*@Hv3e%9krI@X#{|gylHiJsB}?Hdw
> S<E
> zP6SAM`dTqE4TWJLX=nVXgRvdCQYy|H4c7DMqT`S{%Qag{1y!|*IMK-
> Hpr)A`b&ja$
> zuXvn&w80~G98#-
> f^A=Rf6Q`S=4C;^;n8i#XjVexRJ<!A)V2pgwZ|~nZwQIV82xTwV
> zuT4zazH@Z->6=asY&Op=fW(81WfBd|;V5bRFvA0Y07SJ-Nlz+APd-
> Xl<iM25J#tOP
> zH-kLTp?O_1f{PrReJWM5K8-
> NDZa&RjTHPHguBdP5iJm5ip&~%q)7OfTX{aEYME0jQ
> zKu4~Wit|RJo>BelEZ1x)6;#zK(z#N*gPLY))H$M}zvAh>tLumG@yM!GvUv+C<
> >4$e
> zlu(O`4$Uo)LK+oAMZ@j~xWR}|(PQb;!X|J^YXL{mYzj=*zH=~wC$v(eu;?Tm5a
> P7}
> z2bM`RG>2)@G<dv8G*LhO=}-
> 9&;zXTTVjV)Iip<*MG*Q~f;GA7k!=`qhN|mfnBQWr^
> zK>Cz9t?mdGsoc6cP0eF{W<-
> FrCsH{#tj=BzPf1*<=%ZMQh=YJ`7S~Lv9Dp{Nn&~#I
> zvs{CvR3OJFg{kchs#BwGj;J`w;T=D+YL#r>g39qYxuz$BIuu(Vg)}NRqibS!n_Ijn
> zIJItn47Z|6YY#!}<z~?)rrUDou!0b{5Wr^OaSmrkZ4NAxXlM@8q$x=noU`*sU#U
> p-
> zrgUIR<sP}FY7Cp%8%g2(wdo?qW}ixxtQQUdRruBUoTCzH7F3N`Z+x287~;gNX-
> }F#
> zo!!~f>F8f)IX$QdmQvyANFq+EMhBHMc8n1f$2vS!V0vWng3^6jt7P*QRE|f*fj
> vDL
> zls|n(V*yi0qjEFGCKd}%{CVOl&cYtdwdKyiI895DLmv59hkIYh$yp}R&>W^oBgS
> Z#
> zGgrKGQd-S<OsNA?D)-1WxkfW|mUv=0XV-
> L*W3x}CN>U#rNUs!|UEjMqg(E=P6RF&~
> zI!(n$)5jnwL+p%H&POF;aK&(Hn2$Q7oNgA^OsP0~G&%>ljjFSp9#mvYsqi$FC_
> -9K
> z2bD8+j1d*bMm(MsDD^ZuhB`X3YL#r>f-3T;R@0L~;p0AKs1(wu=u;Rc-
> ZmDhm<v=J
> z?;I7$!n;FM%N!2r9yKDCNi;NvF=@KRM;BV;j8}?bFsrd19hg$NN3Q84R~RRk^N
> dXw
> zIX3%Ls-
> &jL)w0qegHDzRkoH8XxU^}HCfZ@Ru_;6Bj8x7?CE^r3IHAU<iqyyHi8yW+
> z*G#E6do(y#vAJwik!3if2Nl^;Dm+akijdaRLFJ4cV??E69idjyjw7p9$>uGn9E=l6
> z_nJEy^bxQ}2b~2>A&tt-IBJ?QXZ<;v1^uAfc;{e{6QjVa_k@;-vo(h?X}Xg}X8<^P
> znHXU_2}~HizlpR3m3!ox7MXu`6dTo)iyWJ(ReY*Fs-
> $XIWDt*>ZW^$#BNf#c89bkA
> z9(_u-
> f<zxhDt!uDB{EJuv0{aAE$SApM>mUWrc{g^4GLB8*eK01wPL{ZpdwpJl}f~b
> zY7kQM70U@jIAg~cQR&z^iH;{Wolvz(Hg7={VN|8g$zX(zN`t^oA&ts;K6(>W+w
> UBs
> zb|-pF-
> RKbIqP0w%tvQTI<1K+ni&SXU7rRsUrF*MUP`O90$u*kMsjQJ)E^=(DR`IF!
> zsFJ$sm^=1Fc{N~RM=GaDY-
> +v;P#eT6Nc2&p(x<RhA|q6);tdX*)stWr#LeQGDOJ>m
> zJ)EehYID{sJ0v)y2Nl^;s#GF^sX<7W!HB^bJI07g$HpWYn4TMs%9?QxYS_Xqs75
> e`
> z)HxZz7DZF3VW(_H<vbs~397w!j<Khe72oHj3r%&hPR(IV8n3&0&uKmjBz1F#iX
> &7i
> z_sBKfdUcAl*wGp5-GaEtvDv3mCG|8)k=*sm6-
> 9uwCsHxO$Vh7`Wn(AzV#*LZBbD<}
> ziHwu~(m-8oaMq7H$fhpS&ElFVl@50{g_<I1mZ=q^VX=-
> xn<*6>qC^a+1|gX&Ga`mg
> zI<-
> esI<O{8!A9qUhAr%Zs)m`K3{fr>nRd!%RP?zL160TEoFnT<b+S&)VV$%i0MoIK
> zP^sJ_*PKS~JGjWP*{3>1$q114M5_LhcX*}@u`^ORpHn1?{B9Q4OsQg!x(DPtU
> XDbY
> zDHR+rOHH!%sZKhzM^tX$S&%O5s98{*MN+7WDN-
> <_Dh58vBT$uhjxOaOpoW^-n!{$&
> z7_;eLFDFf-
> QgOP}sDp2Mn#R}8K2=j0xD_v*y09bFrd4lsE=crIq|&FbvGA=^cl_Nf
> zt~sT0{+DTvs7{w?({e^sF33Sh*1rooY8F%nNmyM)96U<FjEWJi!~oU0bFy5dX)
> G!$
> z<~)nq>Px4N@!8X-
> Lgdbik&hUWs<rsNPEFKE<px5Z4gzKDIK#)y;+j(`=YN^zh^i@3
> zQ<<qaZm}aO=XL}VV_mdqv!FUc($sK-XH?A~7jpwu`_37ytSRbfc-
> pTy+#0{>Uu%pY
> z5lpG#)5q$0Dpa-LTc099X^!eFOtnJH4hd)3>d%2{OsUlQV)mlyOI>KytdLICjeJI&
> zMl~AsSpA?n<IaJu)7MCtw7<w<>ObuS-
> X@LVA7h?Q6{pzI^Hiud=|6SeAryv8wQAN0
> zXW#12foe>t)cIoeqUuXsXw|HcX~7o`BTl0#20qFoP#wN=Mk_wjU*zye*n?viR
> bRj-
> zs#WuZpblI8IZ%x!s+BI`V)m2Ms#zgNj{lMPrqz+i4>1;0>&_XaEc8FQdJikOT*uO?
> zul3UEhP7IEj=Q+lozt)O#y2xtf}Q5OPOQF^ORJ?-
> UxB`7QCAOr=OF%w)2Q5$|L9Fn
> zt<O25l!gAHvV!mBIu=!5>!sDws;@xbv#6_wzH<slqk8m9#sPrp?#_ARjW-
> JR3qJyk
> zskNx4$}g>^647C4MJcAn(rPLZ9crzP-#Lg-
> yolipQoVTb!kzk$*aXb|o%7*`A3Eem
> zYy!saoJBRw!qRFg5gnFRlwxWut)>#u;mWo8;DZky@se><1LpqD!QW60S0jad6
> axTE
> zAg`T8mF8k;mCBNKF0E2o($1w-
> Dofh=RJ6iL|LC7~0ALr6+&Ol}uRoUpOM#`pQeY|Y
> Ka0)zo_WuC{9xg=y
> 
> literal 0
> HcmV?d00001
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/ComponentName.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/ComponentName.c
> new file mode 100644
> index 0000000000..6ac28ab90b
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/ComponentName.c
> @@ -0,0 +1,159 @@
> +/** @file
> 
> +  Virtual Keyboard driver name.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +//
> 
> +// EFI Component Name Protocol
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName = {
> 
> +  VirtualKeyboardComponentNameGetDriverName,
> 
> +  VirtualKeyboardComponentNameGetControllerName,
> 
> +  "eng"
> 
> +};
> 
> +
> 
> +//
> 
> +// EFI Component Name 2 Protocol
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2
> = {
> 
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)
> VirtualKeyboardComponentNameGetDriverName,
> 
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)
> VirtualKeyboardComponentNameGetControllerName,
> 
> +  "en"
> 
> +};
> 
> +
> 
> +//
> 
> +// Table of driver names
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> mVirtualKeyboardDriverNameTable[] = {
> 
> +  {
> 
> +    "eng;en",
> 
> +    L"UEFI Virtual Keyboard Driver"
> 
> +  },
> 
> +  {
> 
> +    NULL,
> 
> +    NULL
> 
> +  }
> 
> +};
> 
> +
> 
> +//
> 
> +// Controller name string table
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> mVirtualKeyboardControllerNameStringTable[] = {
> 
> +  {
> 
> +    "eng",
> 
> +    L"UEFI Virtual Keyboard Driver"
> 
> +  },
> 
> +  {
> 
> +    NULL,
> 
> +    NULL
> 
> +  }
> 
> +};
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  Language          A pointer to a three-character ISO 639-2
> language identifier.
> 
> +                                This is the language of the driver name that that the caller
> 
> +                                is requesting, and it must match one of the languages
> specified
> 
> +                                in SupportedLanguages.  The number of languages
> supported by a
> 
> +                                driver is up to the driver writer.
> 
> +  @param[out] DriverName        A pointer to the Unicode string to return.
> This Unicode string
> 
> +                                is the name of the driver specified by This in the language
> 
> +                                specified by Language.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
> This
> 
> +                                and the language specified by Language was returned
> 
> +                                in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetDriverName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **DriverName
> 
> +  )
> 
> +{
> 
> +  return LookupUnicodeString2 (
> 
> +           Language,
> 
> +           This->SupportedLanguages,
> 
> +           mVirtualKeyboardDriverNameTable,
> 
> +           DriverName,
> 
> +           (BOOLEAN)(This == &gVirtualKeyboardComponentName)
> 
> +           );
> 
> +}
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user readable name of the controller
> 
> +  that is being managed by an EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  ControllerHandle  The handle of a controller that the driver
> specified by
> 
> +                                This is managing.  This handle specifies the controller
> 
> +                                whose name is to be returned.
> 
> +  @param[in]  ChildHandle       The handle of the child controller to retrieve
> the name
> 
> +                                of.  This is an optional parameter that may be NULL.  It
> 
> +                                will be NULL for device drivers.  It will also be NULL
> 
> +                                for a bus drivers that wish to retrieve the name of the
> 
> +                                bus controller.  It will not be NULL for a bus driver
> 
> +                                that wishes to retrieve the name of a child controller.
> 
> +  @param[in]  Language          A pointer to a three character ISO 639-2
> language
> 
> +                                identifier.  This is the language of the controller name
> 
> +                                that the caller is requesting, and it must match one
> 
> +                                of the languages specified in SupportedLanguages.  The
> 
> +                                number of languages supported by a driver is up to the
> 
> +                                driver writer.
> 
> +  @param[out] ControllerName    A pointer to the Unicode string to return.
> This Unicode
> 
> +                                string is the name of the controller specified by
> 
> +                                ControllerHandle and ChildHandle in the language specified
> 
> +                                by Language, from the point of view of the driver specified
> 
> +                                by This.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the user-readable name
> in the
> 
> +                                language specified by Language for the driver
> 
> +                                specified by This was returned in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid EFI_HANDLE.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
> managing
> 
> +                                the controller specified by ControllerHandle and
> 
> +                                ChildHandle.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetControllerName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  ControllerHandle,
> 
> +  IN  EFI_HANDLE                  ChildHandle, OPTIONAL
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **ControllerName
> 
> +  )
> 
> +{
> 
> +  //
> 
> +  // ChildHandle must be NULL for a Device Driver
> 
> +  //
> 
> +  if (ChildHandle != NULL) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +  return LookupUnicodeString2 (
> 
> +           Language,
> 
> +           This->SupportedLanguages,
> 
> +           mVirtualKeyboardControllerNameStringTable,
> 
> +           ControllerName,
> 
> +           (BOOLEAN)(This == &gVirtualKeyboardComponentName)
> 
> +           );
> 
> +}
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/ComponentName.h
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/ComponentName.h
> new file mode 100644
> index 0000000000..327ce9f9cb
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/ComponentName.h
> @@ -0,0 +1,95 @@
> +/** @file
> 
> +  Header file for Virtual Keyboard driver name.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#ifndef _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
> 
> +#define _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
> 
> +
> 
> +#include <Uefi.h>
> 
> +#include <Protocol/ComponentName.h>
> 
> +#include <Protocol/ComponentName2.h>
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  Language          A pointer to a three-character ISO 639-2
> language identifier.
> 
> +                                This is the language of the driver name that that the caller
> 
> +                                is requesting, and it must match one of the languages
> specified
> 
> +                                in SupportedLanguages.  The number of languages
> supported by a
> 
> +                                driver is up to the driver writer.
> 
> +  @param[out] DriverName        A pointer to the Unicode string to return.
> This Unicode string
> 
> +                                is the name of the driver specified by This in the language
> 
> +                                specified by Language.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
> This
> 
> +                                and the language specified by Language was returned
> 
> +                                in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetDriverName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **DriverName
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user readable name of the controller
> 
> +  that is being managed by an EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the
> EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  ControllerHandle  The handle of a controller that the driver
> specified by
> 
> +                                This is managing.  This handle specifies the controller
> 
> +                                whose name is to be returned.
> 
> +  @param[in]  ChildHandle       The handle of the child controller to retrieve
> the name
> 
> +                                of.  This is an optional parameter that may be NULL.  It
> 
> +                                will be NULL for device drivers.  It will also be NULL
> 
> +                                for a bus drivers that wish to retrieve the name of the
> 
> +                                bus controller.  It will not be NULL for a bus driver
> 
> +                                that wishes to retrieve the name of a child controller.
> 
> +  @param[in]  Language          A pointer to a three character ISO 639-2
> language
> 
> +                                identifier.  This is the language of the controller name
> 
> +                                that the caller is requesting, and it must match one
> 
> +                                of the languages specified in SupportedLanguages.  The
> 
> +                                number of languages supported by a driver is up to the
> 
> +                                driver writer.
> 
> +  @param[out] ControllerName    A pointer to the Unicode string to return.
> This Unicode
> 
> +                                string is the name of the controller specified by
> 
> +                                ControllerHandle and ChildHandle in the language specified
> 
> +                                by Language, from the point of view of the driver specified
> 
> +                                by This.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the user-readable name
> in the
> 
> +                                language specified by Language for the driver
> 
> +                                specified by This was returned in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
> valid EFI_HANDLE.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
> managing
> 
> +                                the controller specified by ControllerHandle and
> 
> +                                ChildHandle.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not
> support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetControllerName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  ControllerHandle,
> 
> +  IN  EFI_HANDLE                  ChildHandle, OPTIONAL
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **ControllerName
> 
> +  );
> 
> +#endif
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/DigitKeyboard.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/DigitKeyboard.bmp
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..b64d62034817e7407120ee218
> 1c935e07bef5a8c
> GIT binary patch
> literal 330454
> zcmeHwF|TDua^71RHeg2%9gwMIknzxwG@t_+B;Y`al<6mM04EB$7&vieOuT
> ^=P(MH>
> zASl=wEf~mvu!ICbgaASUK@Ok=L}3#x$i;9>e|#U`$C~Qy>N@B2x%b@r`eOI7
> x=(fW
> z*I!jvoj&)xH~;0oee&=A_04ymxA6b}g#Z7?-?+K?zxeNuZvF#)-
> rW4}@2}rBzW?$6
> z=4Uc68JG-A1||b1Vc_P5(>#0j>^H9KgB4i@53;~xqPi~6&($1-
> fn!GdM3s*Z$JN7!
> z5AAtnk&LlS$hS2IhVv*cNK=FzYJtZ@bwO^OP%nsqV@CT@REv^pRryCh`cc<
> wOHp+V
> z4p9)Q_uqfNy0m;J%g$}h83OH?Mp#*ohV7WBj>gi&a~%vEGujuS%BR(qW~S!
> A-HTA2
> zEIf#+wX{Y3Fg0t=$sA`UI%Z@UfK!|d3}fJ!(VjuID4WL0v*wVWS#yT%t7V2V@x
> ILB
> z)Se6+m4RbMdj?fpMiyP2HD}hGvu@B#yq^`|oP07cjDZ!={^-
> %87cX9X^UXKIKoo{D
> zs1{X~Sb5f*S#ydQJY`2F-
> cN~V&NUg>kAW4@{^ZG%Z@>Na(@#G=BdWNDEWJ8w&a656
> z1#`mkid~qndNC?X_v>}&C$rAQcrguhMYMnX@yDn+AAImZdXmM8T~uSEF6
> sR)s>SOZ
> zF@UIs5CT*49fA=)S!&~$k+pOctM!Kj@5LEOW}Vfn9(Lf;Xn*s~H^2JoD?C_x_u
> Y5*
> zTT~a-*Z@m<zl&-=LITS~HG~kDx_>oi2y-
> +NcqzVg%*cu{54<|i1s7y0nRN#8d=OJh
> zqx}RA*1${`)!5KVdcTTFNIv}VLmdC|pN~HJNMk9i3kjlfrq(rKYSx@})ZLC+=fF(7
> zueN*<12<59!9$Z-
> =OR3~2xK*n(n8gpe6UvL%c^pwvx+uA6=2IuSJg>+zlur*x7Qq*
> zDg_{Hfh4MO$ci4Anl)zyZ_9_csINwr)4Ag2a{jJiL~BD|v7@=PAlgg6zV_N{&!0bk
> z`SRuC$B)aa>w2mT2dJpOZm!m-
> r1z_+S~iFGw?Gorkm+FRBsFIUSQ@E@PtaNVa3Gkx
> zDTlB`<rJ>Fndj}AG+P_`x_yn+1<_vm_r3St!&}l{e);8t2M@}t>w2mT2dJozxd^6
> w
> zmbIcJCcR%pwQkibMzuf^)e3{<5SUt3b4p7m>#2rM&{_KMWKiuy4q=JPDO`8c
> GIM|A
> z)`q@rUt@Jaw3puJ<D-EO)-
> Xkt;Q$r&F>ux#QbDdtXRYXgsabPY@V0!2i~4T7JN+wb
> zF6ZwWM$DR1hOzVO9uL+qML92ex_i)J+t^Hczlusz@A`cXW@&*WD#6$yz|^
> ccTL?^#
> zbx~i9ET?nD%`|OSrP$igSL|pmEr@pK;5{C!VTvll0V?V{Y#W<N?^jW2>REF{#R-
> LK
> z_ynD$4+Zv(H*UWA>gL;TEC2iQ%NsmR4iqq|cnwj8D}qB<qH+q?-K-
> E)>nfk4AG4>1
> zz0#M=I@jm=Ale;GdP~~%Z){d64Ny^k<D_nQ()(3Z&eVR*7D%ERGA~SxIOn|
> a#vAw@
> zt}-9sx4PbW=N%w*k45q8#SXqzh`*n!hELF0`cP8`C1uu}fYR-
> k<bqfzBkGtv@hWt+
> zwV}83d2kEm9u#1aLqUIj!1ZrzYC0<fsHnDaQa3#5{VFPFYQJU+BvB2S7pBJ59Q
> <*l
> zDkwao{p_>PSbU(s@?yUubl)06|MSm3Z@npLqb4JlJ}g1L_S((!=ii-
> n%A?DB@7=t3
> z@!h4OO#Wcz$&()xXo@B42aV!%U!uya<!W>+Gl6`}3R9vAmS8WnHuTlFwY88
> S+ATl4
> zb=8fky|huT0t--4f8(TXc+&e-
> RL<0X%@#<a8Zs|T?O$_Bq_~?=Wbrg@OHiqAd#d3R
> zbe2A})+h%x2MQ`Xjhg!XBRJKo4?nzl`SQm7a)CowqH+q?-
> 7H;D?NN5e(O2>j1mLld
> zs^H7c)`q@rUt@Jav|E;Tda#BmstgCHsBf`tmy_PFqS`)t(n1R)Q6-
> JUYA|)~nq%uv
> z43<}`;S+S0J}hU6YYz1F6s|nL(Aviz-{=x+luA$)c8Mxj!u4G$T~O^&d0~#P>YSyM
> zcmywrp|zo}&%bU(L9|=yc6zXeDI6X)15{M7*tW|_?^jW6pFL@z1(K+eMq)LXI
> (f}u
> zWbr{9UyWS!`(M@Y2|7z3mXvgB4u(iawZ+=O<F#+Txw-
> xB>U&LhC~^o(R8HZ#o0hsj
> zR#K-
> BXrB1eI$*60eciss>VjyO<M?0=#k}=UU79O|D#HOP>aUn67?SjU6;)t%?4=e+
> zq8c(6Or5Icu)J`ys>m?VT3-ZJmsky-ptJO0X;$^b9ZsC4)NI+o38(tzn>wlN5SFN%
> z!gV(tv90F1)ZVf-uzww})`q@rUt@Jaw96?wy(LZiRfYpp)EBlPLel$HR6_t{jI=-!
> zRmMVB2c}L^bNHkdJ5|+&&@Skla|gKjwgHNd&NlX~0uFRhUyUrMbH&YWU{
> YaSYEK&9
> zqP7lLYeQeLqq(#o+T{iJB9Z!s2vvpyRMa0bwTvXaUqvM&dkZa)L^Wh~m>O4e
> +(y(f
> znT16!4LIP4wbmu4$!0Ztg3i*1rCA+d;&ToM^6Q%NEdjhbpvP<c{>NH#2uoB>;k
> uip
> z3+_WtYeQeRud%uy+U57*f7er%AygR-
> P*LAn*e)l%Uq!Wj_N0XtNTNy_iPd0gT+L}c
> zB4f>IUFDg&b+v?F4WFR1^kHdpQO#*7+p`UI>?1gbuten)uDe;f;6C)UHuQD-
> 8mkMU
> z{WN~BG8~|y{#a~D?^jWcMG{zRfh4M6VEz(J?O$^M2ZtFQd(gzAHv4k4dq)yA
> >Nvlj
> zQ{|H1;qXbCUTM=8IHdqh7xmT1aynPstg?FbovjUh#g69Ef@t5v>9~#k^{;<z-
> $kf0
> z9H659SZqn}S5b{c5?E`2B&uLw{t`@`q~-t-&og}fR-
> S5j7ShwX@(&egP1W!TI!hnQ
> zl!VsN<renMPk$=K?*u99+Z$eHzn-
> V@5uARL)FCWUIfd(PzC!4|X|y)<b^98t3!;4w
> z=g*q6n$=c_(u1qb+JP{2s+wb`-6AjDpk=&kc9sP^0sF1rYQ7mD9sOe-
> _}+#m8PyXR
> z#3emX<M~H*$-
> ypBIfd(Pim`hov^Mm0`x>hYqJ575m^EiLtE~{F2UnZ517Ygk*BtvO
> zOs5n}l8TJgRBf@E_)16b7Pzl;TwV!wq0_v|rX}tE$gK^1l`gi63Zi`v@6VdEn$=c_
> z&YEN6xhI$LUOI$d|D&W-YYz0?mo~AQuG%-
> *9Ly4xQ@HMC>4N*v)7sG2?Q5(qi1t1F
> zK5NcuR$C!@)S9DjV<eQ{+pH!-1D9^lGTvqCl!Aj@qH+q?-
> 8?1p$C<0Op|9K5SX~h9
> zdw6G5%>nW)@RSBi0WVawoL=Q>3yei$TOmqRi%hkYVQR#)wU+rk`dhwg^_
> M=}169|i
> zgIA(*3fJB2(sh*ztqpzMzQ*c;Xy3!p2dO!3X-V%_xpJnqH%p3Wvjvi<w$BR-
> Fg0t=
> z5GH#@TwbY0meaZ7W{<7wyx!W-
> SL|pmEr|9#JY6Q#D#HOP=?{dL^nMl9Ko~StQpEli
> zNTM171E%g@%~3#gg&`c%h?}b#Sx)DQn*)ixAXBXkeZ`LE(t>E;!+m8!tuh>-
> lKwz=
> zN$<B%4MYM{B}KH~0!dUuFu>HTISQ~s7{W1)INPnra%!_V8Mp!lP8{uz9zEjkg
> vQim
> zPz}rgt#s}{W>C2yE1F4)WSOXjumMxE=7`u63a5#z6E0{@H5q6!aN=lBCe#e7Az
> 7A2
> zX3ZfF2dFvCKpk`;6Ip|%T43gws1__>s!j&d44gRHXU(a4hW~I``4Sy_@E8B9qu5
> Cg
> z4ynK}wd$M`pgY>76UTdU`Nu?+1V7a#1B)0qakS5x)Adf0BH5t_XU!2Ip>X1O53
> &4k
> z@tCN7z&EAIz&Hj@9PP=3nn5)r%hJevwniR6`#k52+go`{nRw4zo0^k>BQtQ~X
> rDEw
> z8w^Q`WQQIcQh{g95v!*aPP_|GySO>qWZ)GBP8{vYgqlG$B+Jfoj-
> _$doLBb7=^B}M
> zKOLGm(_~;z22LF9v*vW2nWRW|=s{aLR?D;Ih}F{yC*FmpUEG{)GVlrm$Bgz2s
> @0jb
> z9C)bjb6#;zqCu|8MXl(8srh|Qg7V=inRp*Q=`=VQI12;EjP?ww6*;vvWY!!qb60c
> T
> ze*5jS1moV5VqJ`^LoM)_sP^{7w0}PtIA*jbQMC%livCQ^NuoM&APLoqRhL8V
> YR<D~
> z&rZCK(@ckTvF03VfyYF38js9b?i&NgjP{8tABW=V{rBH5YsjLWhYug#)g1g6hEdP
> *
> zKn|{nwTLQ}owG0Sn5Yi!$_ej688~LNPgMDED!JNHc35ys&0%7mKPLl|fyuyRU
> ^1{D
> z1Gn!G>}P&jo(xO|CIgd!$$%KRt2uZQl|OS`gl73{?Fg_Zs=OB_SCgwe19{Dhh^w
> bh
> zpDy~U<oL>15zEeP&4Cm09=jk-
> 1=pb#I8o(8XmT~V$}^DHTohM$<!s2O3s0!7ui&sG
> zvh2*?&*?_O4hpRII~d+%a-
> z!9H@Uh$T%q6$IYnd`yE_RCned24u)tY!GLbM^XJ)KC
> zqm!#WxO)El`OB9tA3uJaH@;f)(mgn9&cNa|YtHI@v~A#}@4{`XUp9JjmFFwZ)r
> TK`
> zh<~i>qmMqy8(*!NN40v26$6u~2BzB#NTM1z>CsGKf%BY`iG<NQ$#@?<ZO7h
> 3)gj1S
> zzI3keR~}!yc!7T%@~yYtGRxXUylAcl=Iji)<Z9rgM>B;5&YF{ngwZ<PU1-
> 0veDA&Y
> zkRCqx-~-
> zk%j@uVQLQt(anwbl(mx1%v=hbaufKk>$7>hu!GSqDvk}PEz)6p03JY9Y
> zb9P!v#x09<E;Qa9y(~N5eDlpa@4VwKWtvIGE|e>*?#YuUcv6J2oLuR4wG3B$e
> #L)p
> z{xn~nWKe1CCwsiM2$kUNEhJH8_E%CTvm&BO8oWd`EHF`X_FkD>fr%uK5|W
> WMYPzJI
> zE~=9A*Is)KH>P+P^5DUP@@m{O3RTk1ShX%!nhuAGPe1)s&0U2Is)N^@lRa
> MRa+Um&
> zeyl^gs5o7`vld;=;3uj@W-
> m(_3p_y0>2j9wRZAxsS*_ta^><NKIpN(rp3+pW2A#=O
> zbWtVkj8$8N3T5XwPqFy?iszi;pptjqeDlq(zWNG>=Xc+ISDkwZT@NN}PW5^6Y
> QSAo
> zv>a@!rI#{LiE63k3)05|XU)k(!f2gtyjO$hjW^yvl2~!nNy6`<O4=E#wg?sO-M{|&
> z>vc~cE$2vY@hTRficJl?x)c?^ZgO80S{?#f6`+g1iz-=j0x-NJNKU9C?4shR?xcBz
> zDh$_2RC${hr-=p5nq!>4#eoQOW2qx{<J}@*sp0K1ey;ddr-
> SD1au?N|;z|Fz2o;VN
> zpMU;2e(l5(xI*rFa}g@bmrIA;rXAarm!jgy84n~^P^2N-
> QGo<m+e4@#Oma04PZfsi
> zB&vav9?cXMIBSk^`WF9mvy_?VH@fj|k?7qgmYo&n9GloI3@3L{Iej!YW{c8b*
> ^@zK
> zpJMUbdQ0F6x$DggDy_xxzZ8s&WQ0YiV34;nEAC?KD!RbBs5VBC1yhx)2)n2_s
> %mgu
> zXBCF)B&v1xFJcrHIBSk^`WB~kvy_=<Q_WfNeU8=@gG}y1yO539!kTKy8C3i_e
> 05D0
> zKN4c105yY3E855sQFS3DQ8_Sryr#7;6|~Hj(B;ZOS_+`6Uj^1h#Zg`3d4(zr*GW`)
> zn-
> `~v1vYBVMJ&a+tJ+LP7RPQ`btWYUVHcG}!Z+5KP`4Bu*o;ATQ2{?J*pJ1zLKY!`
> zkU@pv%$-
> 9HIbEVKT@n@71;$p8<A%UUz!EQIP&qK$AFr)LW#80xkhE|c`HX+}Q)m8+
> zru*&JDpwX2*Cj9#GIQbO(ykiTQoh|!RGRDh1T1jY9J6J%csP?1G*va;brr%EB*E
> Ai
> zWET~HwbDZ{X>iFdxg}>%4F?9y+qu$;hL9HH;anN69GLBo*R;%*P(@|4yMv^F
> >89;j
> zbHvr92ndE*bIeZJ=r?Q~`!R;SSlxwIX(N)>aKN*(IJt`o`mg}w_#M?>{NfiYepAQ+
> za{#K%3@QP0_BS@Gc-WalMP-
> t<5e$Y0c=D)97#kn2twWWmISwjuW{&z!vx>0lL5qr`
> z9EP&#=CTU>Rc@WVt1w(AQCTBbCS!q%YtFyAxxw#;d|UkQf4<7if4x=s`sU`}n
> |_Uz
> z@^9YU{OacB#m&uszEdl8?ylVYcQff9px3#p+N?%aRTG`Cso!YVtm}l0*?rxl-
> BBA+
> zfg+|)u(a`uXF`qf&`n7X5?GgkMGCDrL4OhzEsVkz;NhhVs*-_?kJr|rve`Y!PmtZ+
> zqMT+GVU;V3ildz6vgzh>3gkBbS15?e8L2i|(A>jDG*#j_wcDpUI=a%$h0_|I_-
> RJl
> zkE`|-$Etk|YzbK4u$qG^WGl?@nnQ!Cb>Gz-
> e5%o8JFAgp6|78xbztWd>wd=Bw2Nxp
> zq}@>)QGqL_2N0#u?oJvg#CYhME>~0|uwbqgmuze}If-
> g4Hiw~XW>A$p?EROOs;Icv
> zkomBRr0?SFZr9~BOQO)zMa5CpY*lu1l{$;c4pEgx%ASEWhX_@^SaVdJ)K5Xh>
> eMyo
> z|Gdfpk1Hq$>K|Tnc*wD3?K=q7XtJHv$g&EO89U%rq`tbwWvw`yc2O;xEUmo}
> 6}V!0
> zAXoN&C=KBi#TXA=)8$I2UNJqQq1Y&e3@VKxY1<LWU`xoLDq%3YtiFk8fl+@I)
> %~eC
> zAUt1o$W`g1vd2BRD;26WL6yX2Ir_q#h}emIXtz0RYGBoV3B&bZfs4;M&V-t-
> CJe7R
> zKe>IdrkeKsyo&3VP>pw|O!8R89r0S;QX$T!EmTWqS*pJdm8A<aR>O8F66(izIB
> $z9
> zi)vI-cdM{dI5~q#Lq@@q!IqFg<<`iiDnRvW+}Q%7{wgZX2(=_X-4lgyI!z(5LKhX4
> zWwRx?xms#WGTn!4MAb54`v=w>F2O!G)9<0H!q}-
> PpTFj?Cg>b;Ni|22Sn|5MC(fqT
> zcn6Hubh_uTanVu^`q!ZnKSZc_-
> 2M<U#>07ATv=4fq!lnzy=13wat4)#jDjbFEg^%d
> zx>6=EIJ9~-?recke-+hzt2y8>Q+CKzOgOLZT64O_wVb6l=~&=^bB@0C-
> }Twrj^`Y1
> zj*Or4I&n6w?n1z*+PBBBjgS7;p;Gc7!dY{`L(7AfE6K;NIeNTSjlj55%WMf%u5=s4
> z=L_~{>)twfq5xW_Sp{}_RDhwgLF@0T5>-
> q%uXf9V=CXf&u=<dqJm=83b&8eww5@8t
> ziyRBwRCE5#%?)mh^u7My-
> rW4#yE!lKoO6eK%zxKq_v+k7t2x!Mts?Js#w;;aRC9yN
> zBBPSJ1MFt8%?v8(kAf$IEg^%-t#Ny^1xEc<RQI#yfD<kpM@siQs-
> %ltWt_5W&Cz|O
> zEj5zQQ*-
> RuhBfE=7s>9}V$H!N+pik6;$7+cd(Hu++Mq{xwsz;@0soyfXAz0Y;w_<?
> z-
> JSBH88gbxe%Y*|Vo2ji1N~%8cBhvBo6{^Ip{I+Aqk>s@$;}n$3x<ZMN5ayYqdFi#
> zr$pVW+Lr)SOr!?D#A9=d?kmf&de@|CKUh95VS#JTIVv61YD3eiIrevNST}4T`px
> w3
> z=iKX>)AeLhA<psDU8vnaAvsY}EylwcGpLeDD~U>KZtb?2K_&fB@MN$hWKd~
> !ql6Y1
> z^;c2d=b97z%SGfW<C@mvFBKEj1XT%`WqGkZ>a;Znog8j8=`wwRQ?=hkjs>o
> %Ir`m9
> z9aqYk^la^an1^qyQT7p>t2wevP5ea3`d@{GAF7t(x+PTOy{cTUVM|Y(O<Sn8%
> $OOw
> z4wa=VGfQ44#>07ATv=43lDb1~r*Luxm4=LhCxa~^gUYROd$R>b{Z&-
> =x#oZw=6;+a
> z#1aK^m2pb`+1j7~`Jd|)L_u%=&<pOW&Nc+uy2_e^67+X}_jfYeMUDk7t~q+D
> W=lso
> zlWGqB4guw|;9%5IYR;&vAR^*yTHS>RIt|}RScl4Pi?P6BJa!ja45d8WeOzWak$P
> Gl
> zl!6sT!Lv52au?MoBsL7HNNi^n)s~vmT?LaR@A#o?!AS0+qNZJGRkm|g71XJzA!
> wBC
> zgiKT#5(xR4gLepYCP8sf!GZC(=0L#?v}Yb&Le2Tz-
> ~HX^&!5wB0GOAsz*E$mE)J`p
> zn&u8s`#xLiMzMvMkz0|@5Ua*JE@dol(OHMeZi_9mmt$i*F;^DVaQ6|aox;g2
> 4>~nA
> zN5QKax1C*7qmWovS^!nKiptg;jIst>vhs9y71D$$D6dA90cPiFA!omZp;5LIGP#
> QF
> z@M^c_WQ<UUVBE8{{P0DZSYV^(SSAXSdIDyDLzA`Q5AKxhIp?k~_1{@@QZ%
> hoYVAL|
> zyP6wpBtTv_Z);SHCy%O|gjxXNez$hp%y1?BA@F1^5W1*_AaSGxczCIbDpPa#
> g|~8{
> z@^rb1mL{M=xr#7@3Ip9@(G2Et%J?S!v(G-$tIC4G?{jc4*!9_(0~0hapymL*-
> UiSY
> zFBF#69KMcV-!qVL{dy_M;!`+V<-
> Y5e8(Ts(vP$JLiaG1*pRGve)Gbu2r%Mi8hsx5G
> zoG7Ul<B7SlsD`_b`0W%<Zh6qDu{i`@)w1jCqDuNDsm8j|dhJ)(s;Kfchu;<GC!Uz
> W
> zvZGY5V@VAHpREao6EdhUq@*I4%PH&aFP2RLP{F}dsq(jUh|1ZiHe2ry*hgp8f
> n_I6
> zskWC21ADN*HRl{6aBr{u@V)-
> +<>WbsY8Y#uq_MoHn%PT!@h*<aW;L=(H5bBun&oX6
> zEN4+q3)S*@mW^14O0Xd;o3E!G<Ket5t}LqI?jvwJg_AR=G-L=oSqp?Ns-
> 8m@T(_yW
> zykEB<tEgCWY>AMpH=~Hgex<-l0^?OmOHEj?NUS^@Rh2u-k`@So-
> ;G#2l!>Zp%5@H`
> zInMH~O)PMI&54mEYfkl?1IxCc&6*Qa-MMOSw&EOL-
> Gy#jbS7JPImTmmp@ZR?)eN){
> zOGO>e9B}jJ=E|eez@_jwuLYDL3e$BxXl-
> tnx1V!t8kX#8j&L%|R?j)op&(5(<pn2H
> zxyn~U&1mORrxRQ;3{Hkb<%VBV6AMh#9Qf)`i*~USH>;6V4q2KNx`f0@qJ^q!
> c7=lC
> zy>)9PHd?5p0AU4yU`Wgo=gpuR>ppu2*}8+zpb~FO;W?LqK$(h#E~>y6t1rcnaJ
> 7pH
> zI!TH&S5iNqE`tiwt)`_MDDZ(mROQ&K>A?bL&AAPLd<Z9<4};yvDixB(7pd8EPC2
> 9P
> z$?U>KQ&*LdQ2C%8SHTkQEL(Y<*fOYwxKBjkhTA@Xw-
> iavppx=Bcot7^XRKKubWv43
> zvZeDc|MD-(FC{Fb3@Yd(DYBMV46(zzTv2%oIc}_-
> y(JTs8+c7kEbu~VPRm8z{$yk&
> z<F|DF7hil~|A}V%_%=wTEmWobfjwAbOjiq)9km^geQ*RwX!2=^oyE!-
> RIA;`<&@_N
> z_FEWE&Y;qejqoz(F3#0OwcUNr!k_%fpFDp2SSzgxT~rvAq{!M|F~knfpn|?z@
> 0O;W
> zy(JUXmRSxy77ILl&1pF&*`JK8Wc-
> %?{Q1v+jy;EdRU6*K<0kd<&p&U0Y@sUc5A4Aj
> zTX@*tLS;v7#KU`cJ+LQf@lAXN)oS-)IVgHO*w|%u<qRroWD9R{To-
> B=)fO1lvGibY
> zdj%4@sGyVdprv%h5Ia1B3i{Pmuj{n4w`8JPXa6EbVS%&e+<HG5zol1IYLK_w&
> coev
> z99iYn(*D36rLJ;b_GEV9Mm)S_*Do~lfKh#ER3I~`R=bbOapxRO9S9jzcK8<Fj(pC
> +
> zy7;|&>tzd&kl`xnK}+dIIfDvQY;l|$n*mHzZs0XFvA|h#ZX+QX@-63g)42<`R=l_D
> zuj>aYe!BO^gx5l4!LLKYQ2?Xt&gW@*O~{pNJ7WeFEN=nE>0W>Rb^Zwt+&;u
> dFX(4b
> z*;TB7cM;#`U|sr!lh!lR3|C1HT1q#{8B~~Jh2vU7GJuJyW#J0?vA|h#ZX+QX@-
> 3fZ
> zcqX8v(~9?&{bWC2*bk?B^ytxx7cY=U&;H&TurWUg39+61oFl(D#>%s+G+Q2&
> LQ=5)
> zlB~*1qR^kT)<u;Jq^_FIHqcb9ZWZb-
> Dy$A`>`n@WBo7(23@X^kpi1iGQ6&vtq8ezQ
> zHRm=Gk|E!6ay~0C?ppB<J6k@jpdNV6*#Zw^TL^>x7FWTLQJ275>ygo}sDgRp
> rFBuY
> z0@(F;y{w3Wrp`ID<~SN%Gxi;?(t~c`H8ruoS#xfEjjglAu}iaQH#cO$bGXh#m8b
> MV
> zxyl52CYW&&(_vK)NH;!P!@S*3-
> a%c>qz5yMC3U)xpg>efgO{j=1s<>FWIU7CNk$fe
> zeTxGzJP%2cwP?r*l#^VY0EwMqqOxqna+j-
> 2kSBv#&usAo5}#JV0pKpGcu_lDO`^&$
> zmek2Cgs74RFHsE(JWS2WIAn!RGO{+-oTb2$sFs@Ds6SEV37lNr6Rrm4^$cT-
> tAUdq
> z%@h`xt2r6Aj;WK(4YTIJeMzoP?C6OqPx$0&I9CI6b_N?gIB?RVnZg2ZYtGwmzn
> $UZ
> z;&iYs`mnpeQ`Ve3s#6j^QRUg5T-
> __KHYNvU{Vr*WtA`ICYSc9eSl3<6dG_pCmyb(S
> zz`9s-
> x(nPGR*T5VqgrHkqw++RCvb9guejQn98@&Aq$#eRK7FcD*Cb$FcQpt9#d1+)
> zyR2M_0@fl2s_X;{+!$6#T9%?pn%$^2QRNAoT-
> `&ikQ|150_w`RLVCWY(+<|cf@5k9
> z6Z8Bz8JG-
> A1||cOf&Cb`{XS<u^V9NVU@|Znm<&t?#K2w6!Qn1A`o)(pR`wv^p;oMa
> znyclrwbRTS&oWWP{Mf6LE6YYKPp)Eq?A43l>L6d~=z$nB{FcXke1QOVZfnkufB
> a+X
> zlNGYc4*a=d_)bF<ToYB7;mK8(A}LI+L`7GaTy-
> gug19<J!Qtx*Dm(AL|Nh1o8d!F2
> zYmOGZMPMP^VquT56IGto$<^d4&p=*t#??};Hm3IB!|A~xW?^d9oP0ct)1137
> &*kK5
> za+PNwuX*IS8j{@y8X;Fh48qi`Ir%6Zr+MUfAGgXemL^wu9w%4V!PSuLKF|o`Y
> KTFY
> znl&dMrQ<YbZpd>vxtd(%8OUoMIj)9e_kl*p)ewU)HET{jO2=s)Io`*ua*U<PRi4
> Mm
> z)pc++B)bnZ!nhh@5T?#rb2k2VZzjIxF3hk*oypbYD$hV(bH>$Du7+gyfkx=TAqH
> XU
> z+%;#*I?9q&`ZgKwrKv?d<-
> BoE5>;$u_|=IjPwC`pa+PNwugSRDk`?zDI}jC2ownxe
> z!G~<3N|e4$<_3(FofSekZ`_ka6&o3Tb)w2sdQDtq0=~Mrl5|}YSBq{%shnhqYU
> C>8
> zkyGjnL<Li`=G^-FP&H>oTz7|L0{@zFgIjNxA1b&}L315fNf=TK08}sKQDKTjNelYb
> z88e-ER2gfdbk?C-%9|xQgPf@Bs3XV&QNh%#Ik%CpC6o{pnP{>)al8+YvSh-
> DQCa+_
> zl!u^7`ZvF>JgVf>vD1fpa0{wDOVrGBwbb$!{dK7J=8dT0U^xBNfv8|=)|}h8-
> 4aR&
> zfu*q@$NTV@8lJJ1u6K)m%vEU_i`8c-
> lclv*PaYM(EQL|(!$=E>?LQ4FJ7Y%9qYA9a
> zr?C)NaF-ULDm}8I#{sA|iE4%MU55-r1yd)iId8uC=2u^R_3gLce)Q2t8HS!bc>?9`
> z=YtPEptb70>_*liR3Co$VHXb+zWnmbx88cI8dL0yQDHf6yz#~&uE@a0AAfA&y
> ?pud
> z@#Dw1RAr`w7o&pyBCZIj{0TesEa8<fT+dFZN>?I~+|)sHCsd&8wbx#I{`|T1Blg
> P~
> zJt#bg>IV-
> V0AWB&_0l4)V4;keYL9?fuJTS?gsKXl?9{duB%AB1<hV|vDlMP4XCNw=
> znl)!hB`gz_g3Ai0uQ~6%_uh*aFDwSh$<&V6-
> (we+dj%7nx8_uHmFP+)t(~}P1z6IF
> zJE5}vf<u!9P}y`5DvT;)rtE1EML%YoxCm7VpzI0mk%0&LA|w!qsx*Gyo`I-f>cBO}
> z(af}}dv|vg&FWSd8(F%K(LJAqQ3X(quNW0<Y9f1|WaqN7lt2CSQ`>I~(OGt(1tS
> @R
> z*c?{n$94u>fpD1B@-
> tjPpXutGZ@ziwop*%FCX91&B@8yYw7N{$3AiGq>rSe|K!)>i
> z&Pf-c!Vo#7C8*%IY#^MdJY6R)Le)ZI`{BL-52&+I-I9sQnuW~u#^D{`Nr4a>RJ1P|
> zan&Jr0IH~*PO=G8v*s*0=YUtmb?L+WUX0`2&JqV2{R~K7eDMXJdpOT45|Lux
> efQl~
> zq_aOp1)X&n%Rz#jv)3HncRFD5>{+<d?C!<^Amv1a+?HpyTRdnBbw1Abh$|6Q
> -GHyZ
> z{yLvbcAa>dXoveqUFMbnbP<({%;7ah5yfMnewMLEBvn)nWU>iUv*s+UIiOb
> O2N(7E
> zy%@(krqIU9)STGcLfgI5icxLJSQa7doVVs!Fiw8-
> =n)@Lo}Mdm;!a<JCnv_Y@B4Ys
> z0?5bt9yP}XkNBZLU~=NQxN@kJ;JddBTWXG*lwa+(vWHGMy7`iSt3w!9Zi;nHn
> 3^?b
> zdCdXYa*-
> `N`MntD2G}21a}@HpiD3?C{ftpz)S=EfV4G1tkSpCKchkdgu9zfRH=0Q&
> z4o7A43K25kTOm~KAB)PKxGX%#+<-
> Ppt9aNs7L`NdnoJj&qYhEI;hA%e8xqtU?H3gs
> zjwQ(IT~8I2n=#phsry%R5SaEO4^#_$KxA2VU^a+xdnt~0Ou8CX6|l0!X`aj|LF&
> vN
> z3-
> M!+7FS@Kiyg=ne58~XKZ<Ojl9z4ft2)JYc9(#~swioSQW%TMB7|%Y80FMK&sbE!
> zfsh-}GJi5ujw{#Hj!543x#44L4hgh3%bJcc=4uhH(t}dlBEZzWtT~pm?sm7zPFC6B
> z?ddUVj^h1f_wJf8E;YJ3YmNe`-
> 0loHQ5rjOY<73iZg)zM%gak+Q3YIa12U%~x<F<L
> zMm=LuIj+hk>qhK8U?VCwd~D4LjzFBKJZx7{IgrUFOwF3J>NjCTuyz0(b<CP0gs
> 1$D
> zf|FKXhQY>KbjRGv4PcvIu(?ovStkJ7iO+<@sWjO-
> Y^&zPH_9!plxXc4U<F0YN%1{`
> z=8`ZLm8dB1)DaR|U>D?AR9!NYF;7&^+Q6D4_NsR`+_ojLRa6dSvI$eO=4`7uVA
> >`O
> z?Xy^j;~h3f<xz!LcMAe=j0y_c(5=*H<Bl7pj9=JE?mu$aLbXTD(E{VtKAbCsP)Qdl
> zP2M=PxFVDIsRhD=AkclR`>L{F#778CM`01F>b$N~FdSXlHQhrFfDK0lkmQrMEj
> q^Y
> zZd90K>WIp%cX-XI-
> V9<=f^@8+zlzF%Og3R^)||~X2V^T}!~vzf7{@ydYWHNad&}Dl
> zRm6Vg%gf=ru(bqCbj+Hg`h5C~rTD?rrN;%V>&G~*z`U(Fibe@YnXOo2zmOm;
> #orCe
> zCWJ+(VgS0T6fVYWrq67{;i$l#^&^1kgFC+8|NY<RUlxh65tWunK^s{HC6v*^A*}
> ~!
> z+?B1G!>d4Re{~H8tEe2vWD};&QFBC?6UzE(*TE=ju?0=|+(tU(GP2ypQfhQy)Q
> nLH
> zA>*Q(6<Vk)a@bsfO8G#@DG<N4-
> ;ztNoTf6Cn?g;;m8~rz3N~%Oo1$#CP|1%gxDpr%
> zHe2w<6!!5c@vx_bO8Seq5+P5YJ_VVUM!PyB7}>81V^N75D+nt7tWp(2*|{Go
> TW1vQ
> z$znJhl`Vs|u#mA|{_>ZZ*YJtT5)OIRoHD3xdxrba5r6QSqm++?(T)0;D=ge*8fA1
> V
> z*tA5V1i-54HmKpWSGr?VP+gQqiHcbPSzO+Poke-
> 8g$f0MHkWc$B}$}OsIdPEL8j3{
> zC6z^7DP18~wGs?~$#_c`i%KrDg4pgBK!My36$44WgJ6@r091vss1#JyhuHd+As
> ~!-
> zBPvTcWQK(Hvb$Pst~=*24zKZ?vxqz~x_8Z4hf44u*vwH4b9Kh?4pVk#+bQz0H
> bL^}
> z1#B@YC@7ESxza+A3<w@}cB(l^RAR>FD#&FS2Vl9(31hi(EGdwPu$smk9yS-
> Ds#?ed
> z7*pU*s4@VcW1Yy`1f6*@H+@+9BCfiq<T3<dl~~<Mv=pod-E;$M4tZ-
> mE#fL>&AH>B
> ze6-
> ktR`p3p8CkkNreSUOWX8IKQ~56}>$biccj_!r=@JB(9))U1b{Do4H3w@U1_d&#
> z4M8P8F6Bz;${lGc9z9jf5u{cS$_23y#}&p}4^~Zy)hZk8RDMk!Di)y%=CzkpVRSEp
> zs{%ImOxSXY#lx}?+~4V_6O%@+tYydpYYwcDI?J1;<Hjs+zN)A+YLNg_=lDJ+<H
> K?t
> z7g2K<9o<{Nco$;rOY>++7kiY<PQME+B!)Ttj#M{mjwOdODJr)+uU6|r*%`+b^o
> P_O
> z1=U$j6d**krOYG@Eu0VI)D9{ZaaH=u^>jD>acWLb!FZ{>7b910$?KXhb(u8>cV
> p#-
> ztM-
> (U<?iH0Wp{W0mKpNLsX0K!ILf4lk}F54%~*>fjwI_YaMqlXJw=XtWr&*25v}GT
> z4_1x1-BIFX&kzp^z|y!<f-kvJJ?!3OE#j)hgZc%j_2(;+j1iU0QlRm&z&bVCw0C*7
> zA2N}YcQ>N0oT!S*nN2ofYSx?)?@E(z?ALDSai7KU4r>D|VG<I6#i*dLG&k5VBn
> +0m
> z<o=7fQg&R*mG)M7KW70`CWi9oaIWH2lmMzdi%?Z9h}Dt`+hfsI?byymsO&5)
> IX)BW
> zYWynCSXAARPHsb@atr6!vJ_Y~dPE@|)EvdXd%PArNUEZ;v*%@)I&jSa)ArjN
> O9^&{
> z4eCHHBg^e7yL&RsA-J5cGzyl_67K>~6$q(&^a6(^SB}^%HAj(-
> t<&A0cHRIL*Spk%
> zLZS^?<&B*diIoFXR9nFnQ;Usx0kcyF@*-
> 4KJ8pLffD@pWOrn@&5h^!PwW+C(bI!4k
> z`$}T<w_}s1FSly0H&b)mYcZ`M+<<%n$+?8Tx+&;EhiY9DrjA{6EQLS&+0XETJ9i{P
> zzI1H0r;K;EtCnUgx~u9;>$fTxb(W}fiNey1g{eRJ<dZTA@{lm^a8wQt!Jzv6(I5R0
> zJgY}-ZtboaprZYy9z1N#5in5XvZ>>w)eN}e5F1xjBW`y%52^{Z<QEi}Wf3Y(5eQ0|
> z<u+8n<5G2j>Ku-WH+R*jws#W(P!)*Et)0VdGL-
> B>Ma)p4<VTjPHp>TY)UTqFsYL=z
> z9k}LTDT*L*eD<0HR604>#2{~<<wQZENRC24>{a(c8S=w-
> p^!*mr2o@D{SzFz9Tm-9
> zP0hh_<TCJMkJG$S9{as`835?X*BsrucfTs!Bd)jy!IHf%Kkpt?9MX59*FsfiOQ>e|
> zYJI>g__&&*jmAI<YK{vwm<p7us5I9i0jADTb8gA1|7fjSe%r6+)B)Z0mZ(}$usx4
> 5
> z7<E6IN2Lu{4(aA9PMXgR<rL~Exl%|XpD9s6e>+z&h>zXtg5d;<O2-
> MOqo&=*ac*c`
> zMgIy9lBi%gT|W-=U;slzQRw<{AS%TY1m%RKc=n6-
> !0FwmY8I7U<`HCia0n8Zx{#W~
> z<zgTF>Q}$QAKgHv3AVevRK`2TTJkb`%VsQ%EmIfN?9_o=qH@YX@M?!uQMr
> w%yFh2Z
> z+T0HnNu$^FOs1Qw2y!^8(s81c!g*^Bxv~cyqUshL&^3^&%)StBapVs~rQJuN1
> gT9?
> zjd0t!2P)ckcYnz^=UAe0%RGB?AS#$TVa>4)hrETzfi-6f42;bqvCHqqJC!$Lv%~G|
> zEjfeA+FUB{$JJ6KdHpS1aV%DypRT3Zg5mlz9&|&>W($MuU*yURsv#^{gyp(iP
> X?8S
> zSj&Md{nY|d1yh{m(m+%&HEYf`CobB2io|5RZ-
> KS~SO(RJA%U^IQI#voP?tePcf(ri
> zQ%+s>V64KXE96lHrb-ND&u~;QSkAJgCs-
> gaE#fMPq&sO>fvA$xolI>YDwvuzXPe^|
> zZ9YX@GTyg9TLCPC>co)1SO%4d#j00-
> WF#XjLe(;uArs4K4KMpI7ZsM7VFOFfYnJ@j
> zo<&?`utCS#Undh)a=MeL4MYV~v*v7b+@h4AFigh#7HBJgB~fV=rxC6gRmQ)I
> {5XWG
> zW1>>9fso8c`YmA*SC}zFOKYxtKT&1oI;GA)R4{eEnv)5fKqu+OMUj=Xxm_)ZYD
> -vw
> zx}`XisFs@DsDH(%g7CJN@&pdyDid{!qH74MJPAq7MX0de3@yp212v+`%ymk
> gfv8~W
> zd^IN^e&D4=ku`AM*i;hLmatls6^J&8Dqh;~s}oh8(#h3MT+Nz;(AtuYH1^gGe&i
> h$
> zXwG;K$Z?k@SB{XNIk^hRahE1nj*y^vWUiE<4<eAOAz)x?o^yh*-
> 0jkl<9)Y9uQWWl
> z$`d!ax(=>}WcPta7*|6K!qlue`6wNyIdemv%gNQ`D$hV(^T=^EB)bnZLav4wgsI
> Ur
> z=k2%O&bxhYO@JX=6IGY$$yJvkDNL?JMOT<ybt#g9xO({T;gAGB#0bFbP;-
> 9#;~#6?
> z>jbg&?Afz*7WNngFl1|@>e4&8>QW?y$(5++3X`iYMN$w~PoF*=QZ9xV0T^b
> {_uqei
> zqd}Ih+j9;~ZYet|I7;y75s_yR06-3$sA3mPu3~=d)yb7*BbFyuF+cWd$rUpF*-
> twF
> zpn|i#?3nWsjm@8vfyuyRU@|Zn*qed7bI#uLO#738$-
> rb_GB6pqt2uZQWzTx&lFJ8T
> z=R#uVov17uu{^no`LS0gSC)-
> fo?ONJ*sG4KgM2%r$8@(f2N*5n^U5M@qUt(ga@D0s
> z3X>~Q(G@0FU5cb|aIOwgaQN~8%g$}h5q}2}c>FvF7{QpRL`7GaTy-
> gu!sJR+bcHM6
> z3V%i?`ImI;OJW>V{tOr+SJuc8WT2WgC-
> B;<m#!e*UtQ3St;toM+{x8F;c9rwM+pk3
> zV_XfNbfZC_T2ga1&Sr-
> PRN>Oxg)u+&>g39@5zCXSm>+v}a%I_w<s?@&0S=T~m4~PX
> zPBg?6P~~dQklCz}AwG<a48NL;tl{&<1{a}1cv>&C<aox+)kUZ>28ZZORCyXFR|C
> 09
> z?z`50jQeNJiTSy^8vAp`d(4l$x`?Y}>|6Wm<VC2~O|fFsM3pCPay5{v<i5Mhj*I_
> W
> zg-
> Q=DwzcyBpql5Ls=sQTSFj6L#6E_UpBg={^j!g0udHX!#^fr`?j>@C?Xz<pum79a
> z<ZAD!m)ZxaS##0>e~Iz#7B?jPVZ@m&n^(Y9xu~6bCRcf4FOjPun=Vf6RRYOXJ
> n-~a
> zfoj&As=sQTtK%I(x9C%wyxF%16<}<SG8k#1xx26k)!m@o|GN~`haZ0Ut@*rs`
> SS7O
> z$HP%BMKv5i)!=GWnE=a#&{$MeYoj`2u9BM$YWie2v^v#=5S3Lsf(%rNn)B$<
> qZcn;
> zn7vmQxg(Rys*<G6*oRPi^5jV!MA7@@mtVg1)?2c?Md+fk#!G~Geyp9Yya*
> M7+B)dH
> z_uivtzxn2yciwr&UJ7Iw8Hnoj*I$4B{JHZR@Vxu(yWLrqD&)BeVt!ym5q}buC2B
> Z^
> zlF1}04s^vC-i)I?6G9~<^dwPPt{7S|9!7h0#!P37%5Azg-gx7yufDPY|LLcnW@dp-
> zYgbl>6IE--
> x%z?X9@Lx%4<2L)uKLY(#*rn>H{X2I#gvV&;jy1YMR+d!&t7xN%51qB
> zUU`yS1qFxj#sW*Cf(JzxqevmQhmb@iNY-(ZThYF2%?Tj2@VNZ26kg1g-
> E<#+{ISS!
> z!UrFG(DkFksb+N`QAy_@0#JoDhcK0y97(R3^rx0y<%ykDA8H_kAgmlJ+z}>gj<
> rwO
> zA*`ZuI%o!AC2WYVays>tHiModDq67NkLl#ubDeX#eq>MqcKHc7X<f>2<!+Hb`
> sgEA
> z!|b5TdKUMl@|T3xym5a96)o6XWB_oS2u3W#V01Nus_Q-
> md>QRPu89^2T~x5#MOET)
> zj4g#1qk=WsFHeI?2qG$GL#8r-
> iOOl7y$Mu_n&V(9Q7tVp&Q8E?)rW4l62L|n&a7=Z
> zgjG~d2TcMiYn=cizVet$`>rR6ilbc2%9W?7IhI?>Ob;#x*vty9s@Rrh1uj3smCaZH
> z=6F-usCv-
> 3CfUrOqA8Fj099H_hJ&7%!!9a!p4S5+&M2H!55`jmyme8*GCWv%$Kolk
> zI+m8gi&4QE>}#*N?Qi?((_nU*a%j=44k4;i`Mf<qb+I)E%-
> JmN^41VuUF^q^CFP(0
> z{O9<lxeCDMGu%K|bzG;+wuB@q4tFuDcwdyjssZlcRZ+R6#Z8+eO0F^(93(WW
> sGORD
> z%6?}e-fTTAQ8`n|W(E~afibxZsjCDKQ|hk99ClIJU{-MkPR-&J)DIz^I^eB~N}jUQ
> zQMS}okEwPD?C=wS(WMv_?7*_(s;qbx7<>wSS#|<VS)7!sLx`$WuJ$0D27anju
> oI{*
> zx#nOI@+1fwUUr<r<H)kgEy`be?KOR0ULJ(1qpaDg9HX-
> QWMV2)e5wKNuvJl27uf2w
> zT$LFjgTX;Uvx>^9*?V{FeqOR0y^CrEur4YgBv<ljGK5+T$56YdbW?zsu`hgRI?I(S
> zkMY!6Zz*(9S!W4}1eL)u@k_@FNt`h%7_ql1WiVq#=hJfG>}jp8ij%19a$0gGGc3
> |+
> zO@w}+y6~EVMaW&l%Z~GW99dR5pj>E^3B#JL$}uWUmkgQxYEHmO>yp5iTv
> az&l^@#~
> za|KQN_JHo)-
> 9`^kVIeDkbx~;vB+A|vZ@JHkp>|PSV$BK4U^NJ1isYA=D;Vjz%oRgf
> zb^=W0aS~Nk-
> *zH1Kr@*il4{nzlQGxj*Bq=#X#kXL*@ccC=kPePtg^GCrVaV(?T$1h
> zShH0*My14%43<OH9Dy%UC6j?;EanQzi)v2QgDZe_QE3&7iWO0$aI!)SwTr6C6
> `*Pg
> z<<W9i##3v(rO-
> tM%K}gpgsQxeDfN>$V^lDrNN%04Tv5UhejEenEJ30N{Z122qN?hv
> z6Rx2e1a(s26Pc1Fg&!`tAxbi?-!?JbRn#1;X^*nw+!#leRkj>kS@90%xTg(P&C1qn
> zRgO{VEi66&aWSh%FO#~(;N)t6J8UH?XQbOyXoIUV@G}@3Bs5D@PRBY3C52
> ZlY2Ak;
> zD}Z%T38Y99&Q=bSW+22+yQmaea1f)5I60$2i&x!mf5lU4y`|7aWu2u=4-
> EKl#|c=H
> zx)MX#6QcqoA!%(i8&@_nV5~lzx9U*nv`|&`*-2Ue9zv-
> mNEQ#&xR&ZdXs~Kc_A%YH
> z)Etq)bq_i1I5)<TWtBy+1UZoK$|NdHCs?ypxr<8oqvd_M_FpxE91=CF0q(Gss5C
> q&
> zD6N9A5;=^x88giil^bOzWlq9kEnp=NplZcfh95g`7nPKS#1>?i5~R}=Vw@RN3N1
> !8
> ztF*<&{*tJ8YOS{vx~S+c1vUZbC*u6~e((4A>vN~9Il3cmZG1~wHQL2k)vdZ}86#I!
> zeRP5oDnMxIa64F{l*dY+(k7{H8ALxOy`q|f1!Yn~z=ykJ9SFG_@6vZj6!H{Wapz`
> d
> zQ#M;d1{G<su|wn9nun@6cK?yFYJj&03HrNS*_u;MZKEq-
> teOC}pwd_yAp#R1vHGPP
> z<Lq)pRIco}P%lG{Fyg7T-
> csnIf@S4J2Zqgm_=kVcuWVQ2$`Ms!D0^a5fONE)11g9a
> zf?Ka^61mEtYdU2S?)q&L^IliY!Q$lJ)q7D4x!{T;%PPZyQiA*dVZ|+}HCvT4sPsCP
> zD|bhzIr5h!%F2p&`GrE2jkvSRl`<%jCI0Pp3&Y8QE0-qJE-
> Ed`GGH@nCU@Gglw+KE
> zRDf63YS0y+il^3kOQDO(CU{`50dE<jHv=b%t_;)|m4#&SXbK4SKC2b*u!D~sB^
> muK
> zuB0OYYbRg`>TC%j4c?@egS<*sW3!n0>S|8Ldo6-pzjI?8SymZ#sx=4R$b`9tVa-
> <M
> zBr0VE3*h)Q$D*~gK(4Y8cXqi_afYX`$yPhDngd$cx~MeJF`#nY%4AO8HDi!@RF
> *Vl
> z9SE)52^jIzT5l<IQ7NPWprl0^lsJRv5?2|hF)CQ-dTL|Vs)8gcErbFV&VC5)Qme_-
> zfxEDO{^x(jsNhzDtj3lx`_<JPFlXZ~V5r5h`d!G!k!6)-L4wU*!CsWU1Z%b`=TR~6
> z?QM#PvYnc`B~%04VJlI!tZ6$cU@2r+a+7wOB`P<>elO01B#MYCPn5G9G`pxY)
> ^R9o
> ztw&f+-
> !)@DCQ<2R2!22geo@D!&wws1YLU=IrF*LuCsF|5)6^U+P}{#OgLH}|Efe_}
> zSCT8M$rvvCtxi?eCXKPtK7Lk>uoJUiNX-
> crQN5HTsXA7jZZ~w}UHY<M1$&Q`33iT^
> z&6bcyrTb9@j*?c88|)I2kN~wrRoY>XJeB7}rdph|`b$)$rtpX*O}9uWEw_5As8A
> 5f
> zPYGZPTG($vLVp#N(^o_x&44amCCF};b*7TdE-
> KC23TeeWFlTN^W0nYeJF0cbLGe%p
> zNmSCIfK{_Ut_*IJ!YtmTu*r`bZkw3>N^6cnuXST#X=urAA9N#2`YnSiP|0RX$fJS
> <
> z-Q;n%Y5%o0XmueiB(}dqRW*gqWH?uc+Zi)*iK-
> kWidr|yRU~C+X}Q%?MO7NC_6Y4F
> z57JaMQ3+%fm9A1yJY#nKDFPa|H}2I$<xC};T~vb9+W3ljWXBWK9FPn`<fc|oSy
> WZJ
> zs@_*;)s^H*IuckGa20|&1A*Xw`O9DO-
> #rOPqvhBv=Dqfsvtlobezy<0@h*K?aDp~O
> z9+hmigghz)rZNEmDAMzIu%Z?c+h3w`RH(V7=3qtq*r@}#L{%!=$7>spI#?s%l~
> cH$
> zDk||43vwtn`qEq#W2>S9^6weH{f~SHqSP<IiuNjv(syjc%@!(+(xk1B?xug?rvRK
> Z
> zj>RI~Y9cEHs4yIMw9(+EYR(p_mV!kEYoC1biR}@{5|vexj9G{of;y{$4q$*yZd=4+
> zIIQtgHN{TMd-$5e*bEj?z0?gojgsaaUq1webs*#*vYe)jJ3(^=ese>d<+7Pa<-
> #8+
> zN?Re1ryAWERBl~rDsL@KnX&+(1W@fsa%B_17E}P1p{t6@t}d2^wsmLU8XjY-
> q5`Xo
> zBHEPis#QhN9s{d-s@2&-
> C4I4h?Oe_7!W^R#X;?2GAtDkqixUD=q|4qKROc0{<W9sg
> zt!CAgM5To|0sK$_g1cm!1SbEwrqzV36zckI6O$%tj$5A+RqLE+X9#5HH`}y6v@v
> e2
> z0aev|&{1s$2Q3|_aZi*<1-x=;77}EO%3ZQe+$ewc*=Oz-uQ8pCI~y-
> {QKf7xSLGxs
> zj1`kyIM(>bfBeTw|DDikbeF(NROQmxquo|IqBW%KF9B40N>o)fbP5$hsB{*tR`
> Xd2
> zEJIfnRcWf#W1~HZil$<0Ra9U`Q3NAmsZ0en+Jij^BP|zH`&+1_Y}qL1wG}BDZ!`#
> E
> zHAN`|s6>}4Fe1viNf{NFl-*nIR=-WlRaX*~^h*KL;R7}NEU%)6bXn($-
> YR>y_P+a3
> zwZ=|Nm#aB4hN;Am#S%=?x>UMOJ=TYEnzN(uagilfh`GuQOkukO?&Xegfo4$
> &YANX9
> zjGfw{3Z{0;EbY6VBr1#&lgbBrMq8#;2SZI8-PlHsB4I00$$}G<w=7*wr`y!Lu~4FN
> z`dA%5qDYbN1eZ1fgfQr4am^~Kz+ibv`79q-FcJf+q5^V^5&-
> Q%kYlrfV=wlsV<T?1
> zP-zt4i4CB#$-
> $z{2Rsvn>{o>VmFRLAK=Gq=>Nph1fq<3L<5gD@RWKZvFe%j_I86a|
> z?jvC9ZViMHe$-P6m~LUsxik9Rf2-
> 4$lh_`vgAT8HkDb<sa+<XR*+!5>W#v|6$yd&%
> zYw};h5l)Lrou#0fW06=n!y9((=bwL$e}@P5VNh~8T@n=rS|%NPEutJDXfnE0D7
> db&
> z@|37bQ|xi3EK!uJ*qGI{8!Rn)nTkByOC>6M)lmd^0XF4~*1BxJo5eM&s5IQ=?~
> )(e
> zQ{_sgoKQ_v!d6AKh@!xK7Kvue2rX0^%ODRNM^s7oA;13m*T3dA)D)!<pt76J
> mKW<a
> z$%}3oz@gw(T}f1y>Z**{p(zYQgz7}>#9WD*LtT6KKwO#J=_Vgob6`34VQc>Z!
> @vB?
> zzm(6u98@%s>=C?gz4aEOEQl-
> @hPp*49hfH#ge#W=hGaKa9+eG$tj_Ms7FQ)F%;>m%
> z1T93!@`dzoft9FAQ|z%YO1jX~!ltqeJDQpWAA1))u#B;Kp9(!CDh;IID1zl`%C~pV
> zt##RcH;ZdlQE7M;K$R$Vst(Hn1Q(FZxLE9p`dm^Jc(CO=i_NhSH>+IPA%Yj6s#0
> Vj
> zNk)V-)a?|d9H0^&+I07N){jdI4h%9jFc7n}P-!iJU||fAgSo&}y5?9j^k+VO+Od*L
> zlGI~;=$xkE65M_QXE89uk%CTv3BTFRO$Fe=ue|;Ar#~eyi%L+d0<o3xrFjKD5H
> Os%
> z6H^d#b*?-
> r$E4*glN$&XSqc@KiJUbDs6b;kySG*<7qo&sz=kF8_Cd^$bJk}oQ=!Y1
> zqo{>>X}{oAg(@mdVZ*XTk?k*IOpewi9^hSka@Po96&0>lDJnt6dr+%`z!|a8z
> W(}a
> zdxIb(R%oHJIzm{YT6D9(;o5_C3MU7s1ja5I8^^jVh;TcqDs$`M4%$INlc=hr%1(=
> C
> zyIk5=4^XYDIWn+CC`nR}^<mX%Tjtfj9nE7BHzM}mU;M>i;E(^YiJ&O&Z!9W7tq
> NP<
> zX)NIV;upW*DGTsgv7bjZgh|w#zy9mL=Bib5Aapa9)-
> _ge%rK9#=I~eK;ZXUg%heEy
> z$^{BQRj8sWjjZk=CpO*MWURPyOjc0=|8R=P31)X8l;_H6jzY*<Eq>fAw%OteI-
> |g}
> zykBlT0VAr`z;pEj)yZoPf{RCcaZ?J`hhv?lJ7ZAJy+|-<!h0z22r+sCS8ciiNQ<h(
> zY<sr*vvv1h?#n!?Axzq3vgX*QZMs^b+RjPK0$|8f@+pv5nZQa^0!(2DMZigB1e
> jn1
> z(oI@LrLo%u@}R(mL3{FXVAQOl!qrg}ab2u_sE5DvJHPYA7hnALZ~r#_sjwi;w@
> ?Z8
> zK!my{wZ^M*fNCsVWiTMp%A7!uL{$zsZx2wNyyj>-R=sE0qCD1V*lh^y2M-
> >Ac<x1H
> z0y=@=Z_l~w-
> XQ?&AzlR@y*d!QMi9iiV|WOY)+Su}v!DG8Z(Em9U!oeqNy`XIG|x7}
> zzt3sS828&SgQojp&~ga5<O-
> d!{Y6)m*BSO~;`R!W&&}xYuvtZgOGBc_;s*xa>;2&$
> z{vrQu%2sj4>@8Gw38N6snq%EGN`?o|QFEB)ZJ0ROM%JhZB4_rT!@E6u|ED`+
> D%&q}
> zlJU-
> kjPj3CDa=~g(q*}_{iQsFNtxBx&*ei%=#;2NaRNJZ9G^P#m}<Xe60l4q)N&{c
> zp@=I*Ea?bM+0CV9$rUawr3=V|4;jP0gAQ{%AGKkkrEvudOR>fJ<N*|w{t`tJs$
> A)+
> zgdreBn#{I@0M!sA0fF#li#MVQ#-
> 8O8P=z%I91p}rk0Hi`vom$950g$)IK=vhBm2@C
> zz|dn{CZi1SU<3w{z4YA$niiF&s|uq?!$uTW2(Ie=UmjJ=j4(qj_;9_<Tgdu6U6dr0
> zsAPYmVDH-
> PhQkelzWyrlu%|@jG_mlF@H8Aa5nVW1P|(|tZbme_sLCPhdgL{mrCQ0p
> zg=!#0<cg^N{_p?(CqMbgkaG^m*$9&H&q&h-
> 3^;FbwH=AVskI`+SoNk4Qxlae97F)B
> zUd<8H8zIvUAAPh)(p=VuEwUXRjg9pgN4f#k@tM|mm5<k8&^;2ds5D(maPaa
> ?;D=3w
> z67S>PPn#_`bsiNgXFjbJsh>##dlACvYmRl9WMTuJYFQTYE?3|u<0;V?EAx26pTb
> ZI
> zT~y_e)jf(U5(R7uFt;mPsFD=L%;+k29Ht)leGbUk0up0IZ;;WY1EIy$MkHdXCB#*
> c
> zs9Iys)eltZnqxV(a?-sVa`u`7rjePDFGV?;I_l7ex_#eLb1X%xW%tMk-$a$S%R#)a
> zo;Mh1J*b)koPYYKe`-gSs6_ZifoT%84uQwVX!cGNNupH-
> 0k1@5F+*My%w2ti(_j77
> zU;WMB{7vaKJ8u`2Ro)_#F5FV#m1Oy@W$<LE2mr^_jlX@_TF93E?WmFwwQ
> f`3o+}`Y
> z9$aU6zfnLnqUM0t?uVYYQ6I#@@OTG2u?R=uHv#PLgd$P#Y=dWO|M-
> vph%d#N#*knC
> z?9cv8IESN><(2>d-
> PZ_CjH+65PzT%rqeLbCHwyM_gOmVg*{Km=`t_lb)e@D{v2haM
> z)Tpk0_mBfqT~wNGqd>Y;qTMSp&iKhtao+9O-QgeAL~;;gEt>&X-
> 3ST7ta~ZOMpRuR
> zCsqKe%{8axhiX4-PWgbyDF;4un(LaSuW;Lk;|+l+Z($$k7eX=7-l(c;0aV?%TUpAd
> zN2QY?@0ICOoA`I-
> $`!pbmf*G47du_9k{LqeFV)vTD|As=<t;L6jywhTNiNNv3{^RG
> z&~tiJ3~%khDz*SsGD21)e%#LJTYv!73d_3=0avH3IZPNl-
> B)>HXW+wNRQ^&mO}gRs
> zjBy%N4gi}rF<4p3dvm3UtiT6c{3@W#`q11J6{Co=SCavVa^Fr6{H~}hKa1p(p|ZP
> =
> z@~k--Pj$;q;K7}04kDZd2lb(~1ftrtfUGbMRHv;uEqYvk;6tamy4fu|I8?YDc>+}B
> za_n6@GJSc>KMN}2MBrCbKCYe-
> Rmq`xCMsL5%UBXo(}R`@%GIX~ycERM9yJG#m-TP9
> z!F~zVqFPZFb{zt)?rY6~TeSaN;^a-
> dD>%>(BCF;06ZB71d6FkrldC)fdCefM_NY0w
> zCIldf$|@g02CCbd^Y+_s2iQ-
> 131G<9X;7*1@L3IhRv*ip7*&$<i7H7H)FxMxt2_gF
> z%{Z>M*Bn>~J}sO=_3+`tBa|9q0GPX)^X%EP7WUKk0}N}<MAapKa@D0s3X>
> ~Q(G@0F
> zU5cb|aIT&{eR`al12A_r2mb|gD2*cWECK+?fhs!_Rn-
> @ht12zk&dF7kmTKqZs!B_>
> l^HR7%ra${>2LM=bOwD1ApFbx9lYz;=WMDF|9|Jcx{~rV^Pj3JK
> 
> literal 0
> HcmV?d00001
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/FullIcon.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/FullIcon.bmp
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..b940505c8bc74ad6550bc3226
> 29d7975c1e1c1fc
> GIT binary patch
> literal 5454
> zcmdUyTS!(}6o56!L@l#1k<1H~<*msK=EYIGfJHUFgo!=$AR-
> O~g3Ln$_Tv5C7@{FW
> zuaziT6L~3b87f|a5!5uTbW}2D5<@ff*ZKTcvp6&*5#z(Z`TxV--
> &uR@b@o|%t#u-Q
> zirH&rZa;AK<^LmpPyW_cZd|Rb+&<nn4?bRUiz^!H>wdS8R##V7QBl$K<d1cW
> YA;{D
> ztZVAFD3jL*2L~Hl`%J6LZf@c|8xF%GjEsyJ{RdKAU2P;=(N9lLXQANWU{&7M)&
> |ib
> zoyp0`=g*%vw)L&AuN^pWKyM*7F)?9hXD7tQ#s+ft?p+nwqR!Q;S6L`LJY4m6b
> #+0u
> zZ{MzDW@ct|bX06Ubm)+BvDx0<UI<el_wL<Ofi3EY%@Gk1s$XojwY3#uZEbD
> oHhXz_
> z>C>^R<KyGTHv*}xtyO_7>J%0hvQTJfsOs<N=zy@jN?yNyjc+ux_O7p)LPA3J?c
> 3++
> z>FMO;BsL#Bc+kVc!`<E8$Hxa!UtjO&=*XjOQDfb*vN9GrckZ04t1GKGI5_n5^g
> z75
> zz4!0mk1<@|ym`YJtZUwgb&HFO@87>)T3UMd?j1wg!omWC#w~`ctE&(Mwy
> 2?ed3l+I
> z(9eooA!}=E5V1`y85$b0#P}@x{Fk}?ZEkdDXJ>gplgWhtz!<)L`xf%y!v{{T5P2hW
> zb93B<z*kmQkfDzTuFPdf69FJ^mLXzvM9KX8JOoujm?BD8PG%vdO{TNY4Xu4
> ^rqvTC
> zPVC;jd#|}UJ39vk2J&_W1_pNR+U4Tnf+xqv$D_QmvU10c9Y_%gFI~C>NlHq>
> @sNRc
> zcW<~^OiawqojboXH;fq@8{?$x*|P_=etv!kG&D5G6vWP+JqzLViCT`^qeqV*i
> HV8G
> zh&^&eA4+&A%_;b~o=rNWMV^-
> |sqoaPQ>eOg=Z+Grg~Y|hDe3L)g%}S$PWa-*i*4Js
> zi40~VK%Jvg$RLo+%uFR>vr(<yqVuKr%q>nRhmN<P@@LMRK{@-
> ZBsn=5a^b=SC4GIQ
> z)OBN0;AK(Lu!kbUjv+t@(kW3<QIPEHY$Z)iO`oXMTbtw*WGupFBC|dY9X15tz
> @HUH
> zM@RGcw{PE8g3Cc-
> V`G(wZxHI0;2Zd}4kh?Mc<?|;SXdZJGBPrhJbd^Na{l~zCB_c^
> ztU2ZM>C+sL@6FBM-
> =9}Th`={|eSMD}J$m@?VL5SB9aK{g>XWpzG?ZVye3?E3{`Bcn
> zNJ2uwkt0Vq#Wcdgt5>f$-
> ~j;vsKsp%XlZF7Pca3tix)3K%FD}{&f+AF_V#v2YHBJn
> zVvk(Wh7v*tHK#?!XA7+P>zg-
> nI@L&PYb!N2hngXN$Qy*v=s<WW#8m`{MMOvlbrik_
> zflIXS?CeAsLNr5wCQ2ZUjg1V+&N%bq$BzjP{r&wA5{IZo6%hu)p=fSy7PXRb5X
> KA$
> zoHY0B*)!^AlWB#7qOQ(FtkNMJh%w5gq@+M{b8}UOyAX1R5<(?JhoWR^YD
> &q;lP3|V
> zsi{#S-zoUH5={L>3EwH-R`XxEas^eTrKPI;{{8!qpr9ZnQr?h2l^{Sy(4iz&W2}~%
> zKQb~>Wu)fU@V-
> fWMmgVBn|!By$>w9nj_Gn@Gx=A^SK4e$N&n+_%GcZc4g36Gn?JkH
> z)JPOL#tkth0ytY#RaK<|1W!moL4gwPLX1VrXZ?A4dRnJQF<|^OCWE8o`0?W^
> Be7bC
> zbT|?CbA8K3+_-V$2JTc+Qj(LC!;lK|w}0EUYu6y0N^a55&(G)JL-
> >fu%gckXmPC@9
> zH*Xdf7emNv;v1p^wPFv|JGT&^kmF+wC2USsRu+U4EuL`e)~%wVA_yD{kzt4
> )l+dAo
> p86F<C#GKOBxe+HVs7?Mk@$)bFIfd8L^U5+T;g?l#J@wbDe*hRVpnL!T
> 
> literal 0
> HcmV?d00001
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/Keyboard.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/Keyboard.c
> new file mode 100644
> index 0000000000..a2c9a3bfc4
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/Keyboard.c
> @@ -0,0 +1,1400 @@
> +/** @file
> 
> +  Virtural Keyboard Control Engine
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +/**
> 
> +  Notify all keyboards pressed specific key need to hidden Virtual
> 
> +  Keyboard.
> 
> +
> 
> +  @param[in] KeyData          Keyboard pressed specific key data
> 
> +
> 
> +  @retval EFI_SUCCESS         Success for the function.
> 
> +  @retval EFI_NOT_FOUND       Not found Virtual Keyboard protocol.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkNotifyKeyCallback (
> 
> +  IN EFI_KEY_DATA *KeyData
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +  UINTN      MaxColumn;
> 
> +  UINTN      MaxRow;
> 
> +  UINT32     HorizontalPixel;
> 
> +  UINT32     VerticalPixel;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkNotifyKeyCallback
> Start\n"));
> 
> +
> 
> +  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, (VOID **)
> &VkContext);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    return Status;
> 
> +  }
> 
> +
> 
> +  gST->ConOut->QueryMode (
> 
> +                 gST->ConOut,
> 
> +                 gST->ConOut->Mode->Mode,
> 
> +                 &MaxColumn,
> 
> +                 &MaxRow
> 
> +                 );
> 
> +  HorizontalPixel = VkContext->GraphicsOutput->Mode->Info-
> >HorizontalResolution;
> 
> +  VerticalPixel   = VkContext->GraphicsOutput->Mode->Info-
> >VerticalResolution;
> 
> +
> 
> +  //
> 
> +  // CursorRow and CursorColumn are started from 0, so need to add 2 not 1.
> 
> +  //
> 
> +  if (((UINTN)(gST->ConOut->Mode->CursorColumn * EFI_GLYPH_WIDTH) <
> VkContext->SimIconBackWidth) &&
> 
> +      ((UINTN)((gST->ConOut->Mode->CursorRow + 2) *
> EFI_GLYPH_HEIGHT) > (VerticalPixel - VkContext->SimIconBackHeight))) {
> 
> +    SaveVkIconBackgroundBltBuffer (VkContext,
> VkDisplayAttributeSimpleBottom);
> 
> +  } else if (((UINTN)((gST->ConOut->Mode->CursorColumn + 2) *
> EFI_GLYPH_WIDTH) > (HorizontalPixel - VkContext->FullIconBackWidth)) &&
> 
> +             ((UINTN)((gST->ConOut->Mode->CursorRow + 2) *
> EFI_GLYPH_HEIGHT) > (VerticalPixel - VkContext->FullIconBackHeight))){
> 
> +    SaveVkIconBackgroundBltBuffer (VkContext,
> VkDisplayAttributeFullBottom);
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Hide icon/keyboard to prevent screen scroll up.
> 
> +  //
> 
> +  if ((KeyData->Key.UnicodeChar         == CHAR_CARRIAGE_RETURN)    ||
> 
> +      (KeyData->Key.ScanCode            == SCAN_ESC)                ||
> 
> +      ((gST->ConOut->Mode->CursorColumn >= (INT32) (MaxColumn - 2)) &&
> 
> +       (gST->ConOut->Mode->CursorRow    == (INT32) (MaxRow - 1)))) {
> 
> +    HideVkBody (VkContext);
> 
> +    HideVkIcon (VkContext);
> 
> +    VkContext->IconReDrawCheck = 0;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkNotifyKeyCallback
> End\n"));
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Judge whether is a registed key.
> 
> +
> 
> +  @param[in] RegsiteredData   A pointer to a buffer that is filled in with the
> keystroke
> 
> +                              state data for the key that was registered.
> 
> +  @param[in] InputData        A pointer to a buffer that is filled in with the
> keystroke
> 
> +                              state data for the key that was pressed.
> 
> +
> 
> +  @retval TRUE                Key be pressed matches a registered key.
> 
> +  @retval FLASE               Match failed.
> 
> +
> 
> +**/
> 
> +BOOLEAN
> 
> +IsKeyRegistered (
> 
> +  IN EFI_KEY_DATA  *RegsiteredData,
> 
> +  IN EFI_KEY_DATA  *InputData
> 
> +  )
> 
> +{
> 
> +  ASSERT (RegsiteredData != NULL && InputData != NULL);
> 
> +
> 
> +  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
> 
> +      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
> 
> +    return FALSE;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means
> these state could be ignored.
> 
> +  //
> 
> +  if (RegsiteredData->KeyState.KeyShiftState != 0 &&
> 
> +      RegsiteredData->KeyState.KeyShiftState != InputData-
> >KeyState.KeyShiftState) {
> 
> +    return FALSE;
> 
> +  }
> 
> +  if (RegsiteredData->KeyState.KeyToggleState != 0 &&
> 
> +      RegsiteredData->KeyState.KeyToggleState != InputData-
> >KeyState.KeyToggleState) {
> 
> +    return FALSE;
> 
> +  }
> 
> +
> 
> +  return TRUE;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Pop the key from the keybuffer.
> 
> +
> 
> +  @param[in, out] VkContext    Address of an VK_CONTEXT structure.
> 
> +  @param[out]     KeyData      The EFI stand key infomation when code get
> the key will put
> 
> +                               correct mapping key.
> 
> +
> 
> +  @retval EFI_SUCCESS          The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY        The keystroke data is empty.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkPopTheKey (
> 
> +  IN OUT VK_CONTEXT   *VkContext,
> 
> +     OUT EFI_KEY_DATA *KeyData OPTIONAL
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  UINT8      IndexSt;
> 
> +  UINT8      IndexEd;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Start\n"));
> 
> +  //
> 
> +  // KeyBuffer
> 
> +  // [         0          ]
> 
> +  // [         1          ]<-*IndexSt/IndexEd
> 
> +  // [         2          ]
> 
> +  // [        ...         ]
> 
> +  // [MAX_KEY_BUF_SIZE - 1]
> 
> +  //
> 
> +  Status  = EFI_SUCCESS;
> 
> +  IndexSt = VkContext->KeyStartIndex;
> 
> +  IndexEd = VkContext->KeyEndIndex;
> 
> +
> 
> +  if (IndexEd == IndexSt) {
> 
> +    DEBUG ((DEBUG_VK_KEYS, "ERROR - Keyboard buffer is empty.\n"));
> 
> +    Status = EFI_NOT_READY;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey
> Unicode:    %08x\n", VkContext->Keybuffer[IndexSt].Key.UnicodeChar));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey
> ScanCode:   %08x\n", VkContext->Keybuffer[IndexSt].Key.ScanCode));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey
> ShiftState: %08x\n", VkContext-
> >Keybuffer[IndexSt].KeyState.KeyShiftState));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey
> ToggleState:%08x\n", VkContext-
> >Keybuffer[IndexSt].KeyState.KeyToggleState));
> 
> +
> 
> +  if (KeyData != NULL) {
> 
> +    *KeyData = VkContext->Keybuffer[IndexSt];
> 
> +  }
> 
> +  VkContext->KeyStartIndex = ++IndexSt % MAX_KEY_BUF_SIZE;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Success,
> Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Failed,
> Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Push the event mapping key index to the input key buffer.
> 
> +
> 
> +  @param[in, out] VkContext    Address of an VK_CONTEXT structure.
> 
> +  @param[in]      Unicode      The font's unicode number.
> 
> +
> 
> +  @retval EFI_SUCCESS          The maping key index did put the key buffer.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkPushTheKey (
> 
> +  IN OUT VK_CONTEXT *VkContext,
> 
> +  IN     UINT16     Unicode
> 
> +  )
> 
> +{
> 
> +  UINT8        IndexSt;
> 
> +  UINT8        IndexEd;
> 
> +  EFI_KEY_DATA KeyData;
> 
> +  EFI_STATUS   Status;
> 
> +  LIST_ENTRY   *Link;
> 
> +  VK_NOTIFY    *CurrentNotify;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPushTheKey Start\n"));
> 
> +  //
> 
> +  // KeyBuffer
> 
> +  // [         0          ]
> 
> +  // [         1          ]<-IndexSt/*IndexEd
> 
> +  // [         2          ]
> 
> +  // [        ...         ]
> 
> +  // [MAX_KEY_BUF_SIZE - 1]
> 
> +  //
> 
> +  IndexSt = VkContext->KeyStartIndex;
> 
> +  IndexEd = VkContext->KeyEndIndex;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +
> 
> +  //
> 
> +  // Check Keyboard Buffer if is full that will pop the first key
> 
> +  //
> 
> +  if (VkContext->IsSupportPartialKey &&
> 
> +    ((VkContext->KeyEndIndex + 2) % MAX_KEY_BUF_SIZE) == IndexSt) {
> 
> +    VkPopTheKey (VkContext, NULL);
> 
> +  }
> 
> +
> 
> +  if (((VkContext->KeyEndIndex + 1) % MAX_KEY_BUF_SIZE) == IndexSt) {
> 
> +    VkPopTheKey (VkContext, NULL);
> 
> +  }
> 
> +
> 
> +  KeyData.Key.ScanCode             = SCAN_NULL;
> 
> +  KeyData.Key.UnicodeChar          = CHAR_NULL;
> 
> +  KeyData.KeyState.KeyShiftState   = EFI_SHIFT_STATE_VALID;
> 
> +  KeyData.KeyState.KeyToggleState  = VkContext->KeyToggleState;
> 
> +  KeyData.KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
> 
> +  KeyData.KeyState.KeyToggleState |= VkContext->IsCapsLockFlag ?
> EFI_CAPS_LOCK_ACTIVE : 0;
> 
> +
> 
> +  switch (Unicode) {
> 
> +  case VkKeyShift:
> 
> +    VkContext->IsShiftKeyFlag = !VkContext->IsShiftKeyFlag;
> 
> +    if (VkContext->PageNumber >= VkPage2 && VkContext->PageNumber
> <= VkPage3) {
> 
> +      VkContext->IsShiftKeyFlag ? VkContext->PageNumber++ : VkContext-
> >PageNumber--;
> 
> +    }
> 
> +    VkContext->IsRedrawUpdateUI = TRUE;
> 
> +    break;
> 
> +
> 
> +  case VkKeyTwoPage:
> 
> +    switch (VkContext->PageNumber) {
> 
> +    case VkPage0:
> 
> +    case VkPage1:
> 
> +      VkContext->IsShiftKeyFlag = FALSE;
> 
> +      VkContext->PageNumber     = VkContext->IsShiftKeyFlag ? VkPage3 :
> VkPage2;
> 
> +      break;
> 
> +
> 
> +    case VkPage2:
> 
> +    case VkPage3:
> 
> +      VkContext->IsShiftKeyFlag = FALSE;
> 
> +      VkContext->PageNumber     = VkContext->IsCapsLockFlag ? VkPage1 :
> VkPage0;
> 
> +      break;
> 
> +
> 
> +    default:
> 
> +      break;
> 
> +    }
> 
> +    VkContext->IsRedrawUpdateUI = TRUE;
> 
> +    break;
> 
> +
> 
> +  case VkKeyCapslock:
> 
> +    VkContext->IsCapsLockFlag = !VkContext->IsCapsLockFlag;
> 
> +    if (VkContext->PageNumber >= VkPage0 && VkContext->PageNumber
> <= VkPage1) {
> 
> +      VkContext->IsCapsLockFlag ? VkContext->PageNumber++ : VkContext-
> >PageNumber--;
> 
> +    }
> 
> +    KeyData.KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
> 
> +    KeyData.KeyState.KeyToggleState |= VkContext->IsCapsLockFlag ?
> EFI_CAPS_LOCK_ACTIVE : 0;
> 
> +    VkContext->IsRedrawUpdateUI      = TRUE;
> 
> +    break;
> 
> +
> 
> +  default:
> 
> +    if ((Unicode & VkKeyScanMask) != 0) {
> 
> +      KeyData.Key.ScanCode    = Unicode & ~VkKeyScanMask;
> 
> +    } else {
> 
> +      KeyData.Key.UnicodeChar = Unicode;
> 
> +    }
> 
> +    break;
> 
> +  }
> 
> +
> 
> +  if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar
> == CHAR_NULL) {
> 
> +    if (!VkContext->IsSupportPartialKey) {
> 
> +      goto End;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  for (Link = GetFirstNode (&VkContext->NotifyList); !IsNull (&VkContext-
> >NotifyList, Link); Link = GetNextNode (&VkContext->NotifyList, Link)) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry,
> VK_NOTIFY_SIGNATURE);
> 
> +    //
> 
> +    // The key notification function needs to run at TPL_CALLBACK
> 
> +    // while current TPL is TPL_NOTIFY. It will be invoked in
> 
> +    // VkKeyNotifyProcessHandler() which runs at TPL_CALLBACK.
> 
> +    //
> 
> +    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
> 
> +      VkContext->Keybuffer[IndexEd] = KeyData;
> 
> +      VkContext->KeyEndIndex        = ++IndexEd % MAX_KEY_BUF_SIZE;
> 
> +      gBS->SignalEvent (VkContext->KeyNotifyProcessEvent);
> 
> +    }
> 
> +  }
> 
> +  VkContext->Keybuffer[IndexEd] = KeyData;
> 
> +  VkContext->KeyEndIndex        = ++IndexEd % MAX_KEY_BUF_SIZE;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkPushTheKey Success,
> Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkPushTheKey End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Process key notify.
> 
> +
> 
> +  @param[in] Event                 Indicates the event that invoke this function.
> 
> +  @param[in] Context               Indicates the calling context.
> 
> +
> 
> +**/
> 
> +VOID
> 
> +EFIAPI
> 
> +VkKeyNotifyProcessHandler (
> 
> +  IN  EFI_EVENT Event,
> 
> +  IN  VOID      *Context
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS   Status;
> 
> +  VK_CONTEXT   *VkContext;
> 
> +  EFI_KEY_DATA KeyData;
> 
> +  LIST_ENTRY   *Link;
> 
> +  LIST_ENTRY   *NotifyList;
> 
> +  VK_NOTIFY    *CurrentNotify;
> 
> +  EFI_TPL      OldTpl;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler
> Start\n"));
> 
> +  VkContext = (VK_CONTEXT *) Context;
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +
> 
> +  //
> 
> +  // Invoke notification functions.
> 
> +  //
> 
> +  NotifyList = &VkContext->NotifyList;
> 
> +  Status = VkPopTheKey (VkContext, &KeyData);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link =
> GetNextNode (NotifyList, Link)) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry,
> VK_NOTIFY_SIGNATURE);
> 
> +    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
> 
> +      CurrentNotify->KeyNotificationFn (&KeyData);
> 
> +    }
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler
> Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler
> Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler
> End\n"));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Push the event mapping key index to the input key buffer.
> 
> +
> 
> +  @param[in]  VkContext        Address of an VK_CONTEXT structure.
> 
> +  @param[out] KeyItem          Key Item.
> 
> +  @param[out] Index            Index of Key Item.
> 
> +  @param[in]  TouchX           X position of finger touch.
> 
> +  @param[in]  TouchY           Y position of finger touch.
> 
> +
> 
> +  @retval TRUE                 Touch on Virtual Keyboard.
> 
> +  @retval FALSE                Not touch on Virtual Keyboard.
> 
> +
> 
> +**/
> 
> +BOOLEAN
> 
> +IsTouchVk (
> 
> +  IN  VK_CONTEXT *VkContext,
> 
> +  OUT VK_STRUCT  *KeyItem,
> 
> +  OUT UINT32     *Index,
> 
> +  IN  UINT32     TouchX,
> 
> +  IN  UINT32     TouchY
> 
> +  )
> 
> +{
> 
> +  for (*Index = 0; *Index < VkContext->NumOfKeysInfo; (*Index)++) {
> 
> +    if (VkContext->KeyboardBodyPtr[*Index].DisStartX < TouchX &&
> 
> +        VkContext->KeyboardBodyPtr[*Index].DisEndX   > TouchX &&
> 
> +        VkContext->KeyboardBodyPtr[*Index].DisStartY < TouchY &&
> 
> +        VkContext->KeyboardBodyPtr[*Index].DisEndY   > TouchY) {
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +  if (*Index != VkContext->NumOfKeysInfo) {
> 
> +    *KeyItem = VkContext->KeyboardBodyPtr[*Index];
> 
> +  }
> 
> +
> 
> +  return *Index != VkContext->NumOfKeysInfo;
> 
> +}
> 
> +
> 
> +VOID
> 
> +EFIAPI
> 
> +VkReadyToBootCallBack (
> 
> +  IN EFI_EVENT Event,
> 
> +  IN VOID      *Context
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT                    *VkContext;
> 
> +  VkContext = (VK_CONTEXT *)Context;
> 
> +
> 
> +  HideVkBody (VkContext);
> 
> +  VkContext->TargetKeyboardDisplay  = VkDisplayAttributeNone;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Timer event
> 
> +
> 
> +  This routine is called at TPL_VK_SYNC.
> 
> +
> 
> +  This routine polls for touch panel input.
> 
> +
> 
> +  @param[in] Event    Event whose notification function is being invoked.
> 
> +  @param[in] Context  Pointer to the notification function's context,
> 
> +                      which is implementation-dependent. Context corresponds
> 
> +                      to NotifyContext in CreateEventEx().
> 
> +
> 
> +**/
> 
> +VOID
> 
> +EFIAPI
> 
> +VkTimer (
> 
> +  IN EFI_EVENT Event,
> 
> +  IN VOID      *Context
> 
> +  )
> 
> +{
> 
> +  EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer;
> 
> +  EFI_ABSOLUTE_POINTER_STATE    Point;
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        TouchX;
> 
> +  UINT32                        TouchY;
> 
> +  VK_CONTEXT                    *VkContext;
> 
> +  UINT32                        Index;
> 
> +  VK_STRUCT                     KeyItem;
> 
> +  UINT32                        Font;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Start\n"));
> 
> +  VkContext = (VK_CONTEXT *)Context;
> 
> +
> 
> +  //
> 
> +  // Update keyboard UI layout
> 
> +  //
> 
> +  CheckIconCleared (VkContext);
> 
> +  CheckScreenCleared (VkContext);
> 
> +  CheckBackgroundChanged (VkContext);
> 
> +  if (VkContext->IsRedrawUpdateUI) {
> 
> +    HideVkBody (VkContext);
> 
> +    DrawKeyboardLayout (VkContext);
> 
> +    VkContext->IsRedrawUpdateUI = FALSE;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Error handle for invalid information
> 
> +  //
> 
> +  AbsolutePointer = VkContext->AbsolutePointer;
> 
> +  Status = gBS->CheckEvent (AbsolutePointer->WaitForInput);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS, "ERROR
> - VkContext->AbsolutePointer->WaitForInput->CheckEvent failed!
> Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = AbsolutePointer->GetState (AbsolutePointer, &Point);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS, "ERROR
> - GetState failed, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxX <=
> Point.CurrentX) {
> 
> +    DEBUG ((
> 
> +      DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +      "ERROR - X value exceeds maximum: X: 0x%016Lx, MaxX: 0x%016Lx\n",
> 
> +      Point.CurrentX,
> 
> +      VkContext->AbsolutePointer->Mode->AbsoluteMaxX
> 
> +      ));
> 
> +    Status = EFI_PROTOCOL_ERROR;
> 
> +    goto Error;
> 
> +  }
> 
> +  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxY <=
> Point.CurrentY) {
> 
> +    DEBUG ((
> 
> +      DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +      "ERROR - Y value exceeds maximum: Y: 0x%016Lx, MaxY: 0x%016Lx\n",
> 
> +      Point.CurrentY,
> 
> +      VkContext->AbsolutePointer->Mode->AbsoluteMaxY
> 
> +      ));
> 
> +    Status = EFI_PROTOCOL_ERROR;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Update the touch active status
> 
> +  //
> 
> +  VkContext->TouchActive = ((Point.ActiveButtons &
> EFI_ABSP_TouchActive) != 0) ? TRUE : FALSE;
> 
> +  if (!VkContext->TouchActive) {
> 
> +    VkContext->KeyPressed = FALSE;
> 
> +  }
> 
> +  ConvertCoordinate (VkContext, Point, &TouchX, &TouchY);
> 
> +
> 
> +  if (!VkContext->KeyPressed &&
> 
> +      VkContext->TouchActive &&
> 
> +      IsTouchVk (VkContext, &KeyItem, &Index, TouchX, TouchY)) {
> 
> +    VkGetMappingFont (VkContext, KeyItem, &Font);
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO,                   "VK
> Touch event is trigger!\n" ));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "TouchActive:            0x%04x  \n", VkContext-
> >TouchActive));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "CurrentKeyboardDisplay: 0x%04x  \n", VkContext-
> >CurrentKeyboardDisplay));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "X:                      0x%016Lx\n", Point.CurrentX));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "Y:                      0x%016Lx\n", Point.CurrentY));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "Z:                      0x%016Lx\n", Point.CurrentZ));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "Buttons:                0x%08x  \n", Point.ActiveButtons));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "MapKey Index:           0x%04x  \n", Index));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO |
> DEBUG_VK_POINTS, "Key Unicode:            0x%08x  \n", Font));
> 
> +
> 
> +    switch (Font) {
> 
> +    //
> 
> +    // Touch the small keyboard icon, show/hide the keyboard.
> 
> +    //
> 
> +    case VkKeyTypeMaximum:
> 
> +      KeyboardLayoutHandler (VkContext, Index);
> 
> +      break;
> 
> +
> 
> +    //
> 
> +    // Touch the key raw.
> 
> +    //
> 
> +    default:
> 
> +      if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeNone) {
> 
> +        break;
> 
> +      }
> 
> +      VkPushTheKey (VkContext, (UINT16) Font);
> 
> +    }
> 
> +    VkContext->KeyPressed = TRUE;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Success, Status: %r\n",
> Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Failed, Status: %r\n",
> Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer End\n"));
> 
> +  return;
> 
> +}
> 
> +
> 
> +/**
> 
> +  VkTouchWaitForKey - SignalEvent when the keybuffer has keys.
> 
> +
> 
> +  @param[in] Event    Event whose notification function is being invoked.
> 
> +  @param[in] Context  Pointer to the notification function's context,
> 
> +                      which is implementation-dependent.  Context corresponds
> 
> +                      to NotifyContext in CreateEventEx().
> 
> +
> 
> +**/
> 
> +VOID
> 
> +EFIAPI
> 
> +VkTouchWaitForKey (
> 
> +  IN EFI_EVENT Event,
> 
> +  IN VOID      *Context
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT *VkContext;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkTouchWaitForKey
> Start\n"));
> 
> +  VkContext = (VK_CONTEXT*) Context;
> 
> +
> 
> +  if (VkContext->KeyStartIndex != VkContext->KeyEndIndex) {
> 
> +    DEBUG ((DEBUG_VK_KEYS, "Signal VkTouchWaitForKey\n"));
> 
> +    gBS->SignalEvent (Event);
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkTouchWaitForKey
> End\n"));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get image file data from BIOS image through specific ImageId.
> 
> +
> 
> +  @param[in] VkContext      Address of an VK_CONTEXT structure.
> 
> +  @param[in] ImageId        Guid to get specific image file used.
> 
> +
> 
> +  @retval EFI_IMAGE_INPUT   Image data on BIOS image.
> 
> +
> 
> +**/
> 
> +EFI_IMAGE_INPUT*
> 
> +VkGetImage (
> 
> +  IN VK_CONTEXT   *VkContext,
> 
> +  IN EFI_IMAGE_ID ImageId
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS      Status;
> 
> +  EFI_IMAGE_INPUT Image;
> 
> +  EFI_IMAGE_INPUT *VkImage;
> 
> +
> 
> +
> 
> +  Status = VkContext->HiiImageEx->GetImageEx (
> 
> +                                    VkContext->HiiImageEx,
> 
> +                                    VkContext->HiiHandle,
> 
> +                                    ImageId,
> 
> +                                    &Image
> 
> +                                    );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +  }
> 
> +
> 
> +  VkImage = AllocateCopyPool (sizeof (EFI_IMAGE_INPUT), &Image);
> 
> +  if (VkImage == NULL) {
> 
> +    ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
> 
> +    return NULL;
> 
> +  }
> 
> +
> 
> +  return VkImage;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Dump partial debug message on VkContext.
> 
> +
> 
> +  @param[in] VkContext        Address of an VK_CONTEXT structure.
> 
> +
> 
> +**/
> 
> +VOID
> 
> +VkDumpContext (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT,
> 
> +    "VkContext->Signature: 0x%016x\n",
> 
> +    VkContext->Signature
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT,
> 
> +    "VkContext->Controller: 0x%016x\n",
> 
> +    VkContext->Controller
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->MaxMode: 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->MaxMode
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->Mode: 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->Mode
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->Info->HorizontalResolution:
> 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->Info->HorizontalResolution
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->Info->VerticalResolution:
> 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->Info->VerticalResolution
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode X: 0x%016Lx - 0x%016Lx\n",
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMinX,
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMaxX
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode Y: 0x%016Lx - 0x%016Lx\n",
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMinY,
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMaxY
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode Z: 0x%016Lx - 0x%016Lx\n",
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMinZ,
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMaxZ
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode->Attributes: 0x%08x\n",
> 
> +    VkContext->AbsolutePointer->Mode->Attributes
> 
> +    ));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Start the virtual keyboard driver
> 
> +
> 
> +  This routine allocates the necessary resources for the driver.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStart to complete the driver
> 
> +  initialization.
> 
> +
> 
> +  @param[in, out] VkContext        Address of an VK_CONTEXT structure
> 
> +  @param[in]      Controller       Handle of device to work with.
> 
> +
> 
> +  @retval EFI_SUCCESS              Driver API properly initialized
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkApiStart (
> 
> +  IN OUT VK_CONTEXT *VkContext,
> 
> +  IN EFI_HANDLE     Controller
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                        Status;
> 
> +  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
> 
> +  EFI_KEY_DATA                      KeyData;
> 
> +  EFI_HANDLE                        NotifyHandle;
> 
> +  EFI_EVENT                         ReadyToBootEvent;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Start\n"));
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_NOTIFY_SIGNAL,
> 
> +                  TPL_CALLBACK,
> 
> +                  VkKeyNotifyProcessHandler,
> 
> +                  VkContext,
> 
> +                  &VkContext->KeyNotifyProcessEvent
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to create VkContext->KeyNotifyProcessEvent, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_NOTIFY_WAIT,
> 
> +                  TPL_NOTIFY,
> 
> +                  VkTouchWaitForKey,
> 
> +                  VkContext,
> 
> +                  &(VkContext->SimpleTextIn.WaitForKey)
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to create VkContext->SimpleTextIn.WaitForKey, Status: %r\n",
> Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_NOTIFY_WAIT,
> 
> +                  TPL_NOTIFY,
> 
> +                  VkTouchWaitForKey,
> 
> +                  VkContext,
> 
> +                  &(VkContext->SimpleTextInEx.WaitForKeyEx)
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to create VkContext->SimpleTextInEx.WaitForKeyEx, Status %r\n",
> Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
> 
> +                  TPL_VK_SYNC,
> 
> +                  VkTimer,
> 
> +                  (VOID *)VkContext,
> 
> +                  &(VkContext->TimerEvent)
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to create the timer event, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->SetTimer (
> 
> +                  VkContext->TimerEvent,
> 
> +                  TimerPeriodic,
> 
> +                  (UINT64) VK_POLL_INTERVAL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to set the timer event, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Create event to clear keyboard before boot into OS.
> 
> +  //
> 
> +  Status = EfiCreateEventReadyToBootEx (
> 
> +             TPL_CALLBACK,
> 
> +             VkReadyToBootCallBack,
> 
> +             (VOID *)VkContext,
> 
> +             &ReadyToBootEvent
> 
> +             );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to create ReadyToBootEvent, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->LocateProtocol (
> 
> +                  &gEfiHiiImageExProtocolGuid,
> 
> +                  NULL,
> 
> +                  (VOID **) &VkContext->HiiImageEx
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to open HiiImageEx protocol, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Initialize VkContext
> 
> +  //
> 
> +  VkContext->Signature                          = VK_SIGNATURE;
> 
> +  VkContext->Controller                         = Controller;
> 
> +  VkContext->SimpleTextIn.Reset                 = VkKeyboardReset;
> 
> +  VkContext->SimpleTextIn.ReadKeyStroke         =
> VkKeyboardReadKeyStroke;
> 
> +  VkContext->SimpleTextInEx.Reset               = VkKeyboardResetEx;
> 
> +  VkContext->SimpleTextInEx.ReadKeyStrokeEx     =
> VkKeyboardReadKeyStrokeEx;
> 
> +  VkContext->SimpleTextInEx.SetState            = VkKeyboardSetState;
> 
> +  VkContext->SimpleTextInEx.RegisterKeyNotify   =
> VkKeyboardRegisterKeyNotify;
> 
> +  VkContext->SimpleTextInEx.UnregisterKeyNotify =
> VkKeyboardUnregisterKeyNotify;
> 
> +  VkContext->IsIconShowed                       = FALSE;
> 
> +  VkContext->IsBackgroundChanged                = FALSE;
> 
> +  VkContext->PageNumber                         = 0;
> 
> +  VkContext->CurrentKeyboardDisplay             = VkDisplayAttributeNone;
> 
> +  VkContext->TargetKeyboardDisplay              = VkDisplayAttributeNone;
> 
> +  VkContext->VkBodyBackgroundBltBuffer          = NULL;
> 
> +  VkContext->VkBodyCompoundBltBuffer            = NULL;
> 
> +  VkContext->VkBodyBltSize                      = 0;
> 
> +  VkContext->VkBodyBltStartX                    = 0;
> 
> +  VkContext->VkBodyBltStartY                    = 0;
> 
> +  VkContext->VkBodyBltHeight                    = 0;
> 
> +  VkContext->VkBodyBltWidth                     = 0;
> 
> +  VkContext->IconBltBuffer                      = NULL;
> 
> +  VkContext->IconBltSize                        = 0;
> 
> +  VkContext->IconReDrawCheck                    = 0;
> 
> +  VkContext->FullIconUpdatedFlag                = FALSE;
> 
> +  VkContext->SimIconUpdatedFlag                 = FALSE;
> 
> +  VkContext->KeyStartIndex                      = 0;
> 
> +  VkContext->KeyEndIndex                        = 0;
> 
> +  VkContext->KeyToggleState                     = EFI_TOGGLE_STATE_VALID;
> 
> +  VkContext->SmallIcon                          = VkGetImage (VkContext,
> IMAGE_TOKEN (IMG_VK_SIMPLEICON));
> 
> +  VkContext->FullIcon                           = VkGetImage (VkContext,
> IMAGE_TOKEN (IMG_VK_FULLICON));
> 
> +  VkContext->SimKeyBody                         = VkGetImage (VkContext,
> IMAGE_TOKEN (IMG_VK_SIMPLEKEYBOARD));
> 
> +  VkContext->DigKeyBody                         = VkGetImage (VkContext,
> IMAGE_TOKEN (IMG_VK_DIGITKEYBOARD));
> 
> +  VkContext->CapLeKeyBody                       = VkGetImage (VkContext,
> IMAGE_TOKEN (IMG_VK_CAPITALLETTERKEYBOARD));
> 
> +
> 
> +  InitializeListHead (&VkContext->NotifyList);
> 
> +
> 
> +  Status = SetCharacterPosition (VkContext, 800, 600);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  Status = DrawKeyboardLayout (VkContext);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  Status = HideVkBody (VkContext);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  Status = HideVkIcon (VkContext);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  DEBUG_CODE (
> 
> +    VkDumpContext (VkContext);
> 
> +  );
> 
> +
> 
> +  Status = gBS->HandleProtocol (
> 
> +                  gST->ConsoleInHandle,
> 
> +                  &gEfiSimpleTextInputExProtocolGuid,
> 
> +                  (VOID **)&SimpleEx
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to found ConIn Protocol, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  KeyData.KeyState.KeyToggleState = 0;
> 
> +  KeyData.KeyState.KeyShiftState  = 0;
> 
> +  KeyData.Key.ScanCode            = SCAN_ESC;
> 
> +  KeyData.Key.UnicodeChar         = CHAR_NULL;
> 
> +  NotifyHandle                    = NULL;
> 
> +  Status = SimpleEx->RegisterKeyNotify (
> 
> +                       SimpleEx,
> 
> +                       &KeyData,
> 
> +                       VkNotifyKeyCallback,
> 
> +                       &NotifyHandle
> 
> +                       );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to register 'Esc', Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  KeyData.KeyState.KeyToggleState = 0;
> 
> +  KeyData.KeyState.KeyShiftState  = 0;
> 
> +  KeyData.Key.ScanCode            = SCAN_NULL;
> 
> +  KeyData.Key.UnicodeChar         = CHAR_CARRIAGE_RETURN;
> 
> +  Status = SimpleEx->RegisterKeyNotify (
> 
> +                       SimpleEx,
> 
> +                       &KeyData,
> 
> +                       VkNotifyKeyCallback,
> 
> +                       &NotifyHandle
> 
> +                       );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to register 'Enter', Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  for (KeyData.Key.UnicodeChar = L' '; KeyData.Key.UnicodeChar <= L'~';
> KeyData.Key.UnicodeChar++) {
> 
> +    Status = SimpleEx->RegisterKeyNotify (
> 
> +                         SimpleEx,
> 
> +                         &KeyData,
> 
> +                         VkNotifyKeyCallback,
> 
> +                         &NotifyHandle
> 
> +                         );
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      DEBUG ((
> 
> +        DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR,
> 
> +        "ERROR - Failed to register '%c', Status: %r\n",
> 
> +        KeyData.Key.UnicodeChar,
> 
> +        Status
> 
> +        ));
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +  if (EFI_ERROR(Status)) {
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Success,
> Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  VkApiStop (VkContext);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Failed,
> Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Stop the virtual keyboard driver
> 
> +
> 
> +  This routine releases the resources allocated by VKApiStart.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStop to initiate the driver
> 
> +  shutdown.
> 
> +
> 
> +  @param[in] VkContext        Address of an VK_CONTEXT structure
> 
> +
> 
> +**/
> 
> +VOID
> 
> +VkApiStop (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_NOTIFY  *NotifyNode;
> 
> +  LIST_ENTRY *NotifyList;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop Start\n"));
> 
> +
> 
> +  Status = gBS->SetTimer (VkContext->TimerEvent, TimerCancel, 0);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  if (VkContext->KeyNotifyProcessEvent != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->KeyNotifyProcessEvent);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->KeyNotifyProcessEvent = NULL;
> 
> +  }
> 
> +
> 
> +  if (VkContext->TimerEvent != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->TimerEvent);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->TimerEvent = NULL;
> 
> +  }
> 
> +
> 
> +  if (VkContext->SimpleTextIn.WaitForKey != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->SimpleTextIn.WaitForKey);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->SimpleTextIn.WaitForKey = NULL;
> 
> +  }
> 
> +
> 
> +  if (VkContext->SimpleTextInEx.WaitForKeyEx != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->SimpleTextInEx.WaitForKeyEx);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->SimpleTextInEx.WaitForKeyEx = NULL;
> 
> +  }
> 
> +
> 
> +  NotifyList = &VkContext->NotifyList;
> 
> +  if (NotifyList != NULL) {
> 
> +    while (!IsListEmpty (NotifyList)) {
> 
> +      NotifyNode = CR (NotifyList->ForwardLink, VK_NOTIFY, NotifyEntry,
> VK_NOTIFY_SIGNATURE);
> 
> +      RemoveEntryList (NotifyList->ForwardLink);
> 
> +      gBS->FreePool (NotifyNode);
> 
> +    }
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop End\n"));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Reset the input device and optionally run diagnostics
> 
> +
> 
> +  @param[in] This                 Protocol instance pointer.
> 
> +  @param[in] ExtendedVerification Driver may perform diagnostics on reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning properly and
> could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReset (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  IN BOOLEAN                        ExtendedVerification
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReset Start\n"));
> 
> +  Status = EFI_SUCCESS;
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReset End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Resets the input device hardware.
> 
> +
> 
> +  The Reset() function resets the input device hardware. As part
> 
> +  of initialization process, the firmware/device will make a quick
> 
> +  but reasonable attempt to verify that the device is functioning.
> 
> +  If the ExtendedVerification flag is TRUE the firmware may take
> 
> +  an extended amount of time to verify the device is operating on
> 
> +  reset. Otherwise the reset operation is to occur as quickly as
> 
> +  possible. The hardware verification process is not defined by
> 
> +  this specification and is left up to the platform firmware or
> 
> +  driver to implement.
> 
> +
> 
> +  @param[in] This                 A pointer to the
> EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
> 
> +
> 
> +  @param[in] ExtendedVerification Indicates that the driver may perform a
> more exhaustive
> 
> +                                  verification operation of the device during reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and
> could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardResetEx (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN BOOLEAN                           ExtendedVerification
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx
> Start\n"));
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  Status = VkContext->SimpleTextIn.Reset (&VkContext->SimpleTextIn,
> ExtendedVerification);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_KEYS, "ERROR - Failed to VK reset, Status: %r\n",
> Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx
> Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx Failed,
> Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx
> End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device. The WaitForKey Event
> can
> 
> +  be used to test for existence of a keystroke via WaitForEvent () call.
> 
> +
> 
> +  @param[in]  This         Protocol instance pointer.
> 
> +  @param[out] Key          Driver may perform diagnostics on reset.
> 
> +
> 
> +  @retval EFI_SUCCESS      The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY    There was no keystroke data available.
> 
> +  @retval EFI_DEVICE_ERROR The keystroke information was not returned
> due to
> 
> +                           hardware errors.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStroke (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  OUT EFI_INPUT_KEY                  *Key
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS    Status;
> 
> +  VK_CONTEXT    *VkContext;
> 
> +  EFI_KEY_DATA  TmpKeyData;
> 
> +  EFI_TPL       OldTpl;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke
> Start\n"));
> 
> +
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  if (This == NULL || Key == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_PROTOCOL (This);
> 
> +
> 
> +  Status = VkKeyboardReadKeyStrokeEx (&VkContext->SimpleTextInEx,
> &TmpKeyData);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    goto Error;
> 
> +  }
> 
> +  *Key = TmpKeyData.Key;
> 
> +
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke
> Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke
> Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke
> End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device.
> 
> +
> 
> +  @param[in]  This               Protocol instance pointer.
> 
> +  @param[out] KeyData            A pointer to a buffer that is filled in with the
> keystroke
> 
> +                                 state data for the key that was pressed.
> 
> +
> 
> +  @retval EFI_SUCCESS            The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY          There was no keystroke data available.
> 
> +  @retval EFI_INVALID_PARAMETER  This or KeyData is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStrokeEx (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  OUT EFI_KEY_DATA                      *KeyData
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT        *VkContext;
> 
> +  EFI_STATUS        Status;
> 
> +  EFI_TPL           OldTpl;
> 
> +  EFI_KEY_DATA      TmpKeyData;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardReadKeyStrokeEx Start\n"));
> 
> +
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  if (This == NULL || KeyData == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  while (TRUE) {
> 
> +    Status = VkPopTheKey (VkContext, &TmpKeyData);
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      DEBUG ((DEBUG_VK_KEYS, "ERROR - Failed to VkPopTheKey check
> whether keybuffer is empty, Status: %r\n", Status));
> 
> +      goto Error;
> 
> +    }
> 
> +    if (TmpKeyData.Key.ScanCode != SCAN_NULL ||
> TmpKeyData.Key.UnicodeChar != CHAR_NULL) {
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +  *KeyData = TmpKeyData;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardReadKeyStrokeEx Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardReadKeyStrokeEx Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardReadKeyStrokeEx End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Set certain state for the input device.
> 
> +
> 
> +  @param[in] This                 Protocol instance pointer.
> 
> +  @param[in] KeyToggleState       A pointer to the EFI_KEY_TOGGLE_STATE
> to set the
> 
> +                                  state for the input device.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device state was set appropriately.
> 
> +  @retval EFI_INVALID_PARAMETER   This or KeyToggleState is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardSetState (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_KEY_TOGGLE_STATE              *KeyToggleState
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState
> Start\n"));
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL || KeyToggleState == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  VkContext->KeyToggleState      = *KeyToggleState;
> 
> +  VkContext->IsCapsLockFlag      = (*KeyToggleState &
> EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE;
> 
> +  VkContext->IsSupportPartialKey = (*KeyToggleState &
> EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED;
> 
> +
> 
> +  if (VkContext->PageNumber >= VkPage0 && VkContext->PageNumber <=
> VkPage1) {
> 
> +    VkContext->PageNumber = VkContext->IsCapsLockFlag ? VkPage1 :
> VkPage0;
> 
> +  }
> 
> +
> 
> +  HideVkBody (VkContext);
> 
> +  DrawKeyboardLayout (VkContext);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext-
> >KeyToggleState:      %02x\n", VkContext->KeyToggleState));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext-
> >IsCapsLockFlag:      %02x\n", VkContext->IsCapsLockFlag));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext-
> >IsSupportPartialKey: %02x\n", VkContext->IsSupportPartialKey));
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState
> Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState Failed,
> Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState
> End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Register a notification function for a particular keystroke for the input
> device.
> 
> +
> 
> +  @param[in]  This                        Protocol instance pointer.
> 
> +  @param[in]  KeyData                     A pointer to a buffer that is filled in with
> the keystroke
> 
> +                                          information data for the key that was pressed.
> 
> +  @param[in]  KeyNotificationFunction     Points to the function to be called
> when the key
> 
> +                                          sequence is typed specified by KeyData.
> 
> +  @param[out] NotifyHandle                Points to the unique handle assigned to
> the registered notification.
> 
> +
> 
> +  @retval EFI_SUCCESS                     The notification function was registered
> successfully.
> 
> +  @retval EFI_OUT_OF_RESOURCES            Unable to allocate resources for
> necessary data structures.
> 
> +  @retval EFI_INVALID_PARAMETER           KeyData or NotifyHandle or
> KeyNotificationFunction is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardRegisterKeyNotify (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN  EFI_KEY_DATA                      *KeyData,
> 
> +  IN  EFI_KEY_NOTIFY_FUNCTION           KeyNotificationFunction,
> 
> +  OUT EFI_HANDLE                        *NotifyHandle
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  EFI_TPL    OldTpl;
> 
> +  VK_CONTEXT *VkContext;
> 
> +  LIST_ENTRY *Link;
> 
> +  VK_NOTIFY  *CurrentNotify;
> 
> +  VK_NOTIFY  *NewNotify;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardRegisterKeyNotify Start\n"));
> 
> +
> 
> +  //
> 
> +  // Enter critical section
> 
> +  //
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL || KeyData == NULL || NotifyHandle == NULL ||
> KeyNotificationFunction == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +
> 
> +  //
> 
> +  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already
> registered.
> 
> +  //
> 
> +  for (Link = VkContext->NotifyList.ForwardLink; Link != &VkContext-
> >NotifyList; Link = Link->ForwardLink) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry,
> VK_NOTIFY_SIGNATURE);
> 
> +    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
> 
> +      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
> 
> +        *NotifyHandle = CurrentNotify;
> 
> +        Status = EFI_SUCCESS;
> 
> +        goto End;
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Allocate resource to save the notification function
> 
> +  //
> 
> +  NewNotify = (VK_NOTIFY *) AllocateZeroPool (sizeof (VK_NOTIFY));
> 
> +  if (NewNotify == NULL) {
> 
> +    Status = EFI_OUT_OF_RESOURCES;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  NewNotify->Signature         = VK_NOTIFY_SIGNATURE;
> 
> +  NewNotify->KeyNotificationFn = KeyNotificationFunction;
> 
> +  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
> 
> +  InsertTailList (&VkContext->NotifyList, &NewNotify->NotifyEntry);
> 
> +
> 
> +  *NotifyHandle = NewNotify;
> 
> +  Status        = EFI_SUCCESS;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardRegisterKeyNotify Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardRegisterKeyNotify Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  //
> 
> +  // Leave critical section and return
> 
> +  //
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardRegisterKeyNotify End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Remove a registered notification function from a particular keystroke.
> 
> +
> 
> +  @param[in] This                Protocol instance pointer.
> 
> +  @param[in] NotificationHandle  The handle of the notification function
> being unregistered.
> 
> +
> 
> +  @retval EFI_SUCCESS            The notification function was unregistered
> successfully.
> 
> +  @retval EFI_INVALID_PARAMETER  The NotificationHandle is invalid
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardUnregisterKeyNotify (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                        NotificationHandle
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +  EFI_TPL    OldTpl;
> 
> +  LIST_ENTRY *Link;
> 
> +  VK_NOTIFY  *CurrentNotify;
> 
> +  BOOLEAN    IsFindNotifyHandle;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardUnregisterKeyNotify Start\n"));
> 
> +
> 
> +  //
> 
> +  // Enter critical section
> 
> +  //
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL || NotificationHandle == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  IsFindNotifyHandle = FALSE;
> 
> +  for (Link = VkContext->NotifyList.ForwardLink; Link != &VkContext-
> >NotifyList; Link = Link->ForwardLink) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry,
> VK_NOTIFY_SIGNATURE);
> 
> +    if (CurrentNotify == NotificationHandle) {
> 
> +      //
> 
> +      // Remove the notification function from NotifyList and free resources
> 
> +      //
> 
> +      RemoveEntryList (&CurrentNotify->NotifyEntry);
> 
> +
> 
> +      gBS->FreePool (CurrentNotify);
> 
> +      IsFindNotifyHandle = TRUE;
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (!IsFindNotifyHandle) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardUnregisterKeyNotify Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardUnregisterKeyNotify Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  //
> 
> +  // Leave critical section and return
> 
> +  //
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VkKeyboardUnregisterKeyNotify End\n"));
> 
> +  return Status;
> 
> +}
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/KeyboardLayout.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/KeyboardLayout.c
> new file mode 100644
> index 0000000000..dcf78985ee
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/KeyboardLayout.c
> @@ -0,0 +1,1364 @@
> +/** @file
> 
> +  Virtural Keyboard Layout Engine
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +//
> 
> +// 1.FullKeyboardBody
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\CapitalLetterKeyboard.bmp
> 
> +//   (2).\KeyboardLayout\DigitKeyboard.bmp
> 
> +// Based on keyboard's (startX, startY)
> 
> +//
> 
> +// Page0Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | q | w | e | r | t | y | u | i | o | p |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | | a | s | d | f | g | h | j | k | l | F2| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Caps | z | x | c | v | b | n | m |aU |Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// Page1Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | Q | W | E | R | T | Y | U | I | O | P |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | | A | S | D | F | G | H | J | K | L | F2| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Caps | Z | X | C | V | B | N | M |aU |Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// Page2Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Shift| . | ; | ' | , | . | / |F11|F12|Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       | \ | - | = | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// Page3Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | ! | @ | # | $ | % | ^ | & | * | ( | ) |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Shift| ~ | : | " | < | > | ? |F11|F12|Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       | | | _ | + | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// 2.Screen Corner
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\SimpleIcon.bmp # Screen Corner A/B
> 
> +//   (2).\KeyboardLayout\FullIcon.bmp   # Screen Corner C/D
> 
> +// +-+------------------------------------+-+
> 
> +// |A|                                    |C|
> 
> +// +-+                                    +-+
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// +-+                                    +-+
> 
> +// |B|                                    |D|
> 
> +// +-+------------------------------------+-+
> 
> +//
> 
> +VK_STRUCT mFullKeyboardBody[] = {
> 
> +  // StartX  StartY  EndX    EndY     Page0Font            Page1Font            Page2Font
> Page3Font
> 
> +  // Line 0
> 
> +  {  0x0000, 0x0000, 0x0032, 0x0032, {L'q',                L'Q',                L'1',
> L'!'            }},
> 
> +  {  0x0032, 0x0000, 0x0064, 0x0032, {L'w',                L'W',                L'2',
> L'@'            }},
> 
> +  {  0x0064, 0x0000, 0x0096, 0x0032, {L'e',                L'E',                L'3',
> L'#'            }},
> 
> +  {  0x0096, 0x0000, 0x00C8, 0x0032, {L'r',                L'R',                L'4',
> L'$'            }},
> 
> +  {  0x00C8, 0x0000, 0x00FA, 0x0032, {L't',                L'T',                L'5',
> L'%'            }},
> 
> +  {  0x00FA, 0x0000, 0x012C, 0x0032, {L'y',                L'Y',                L'6',
> L'^'            }},
> 
> +  {  0x012C, 0x0000, 0x015E, 0x0032, {L'u',                L'U',                L'7',
> L'&'            }},
> 
> +  {  0x015E, 0x0000, 0x0190, 0x0032, {L'i',                L'I',                L'8',
> L'*'            }},
> 
> +  {  0x0190, 0x0000, 0x01C2, 0x0032, {L'o',                L'O',                L'9',
> L'('            }},
> 
> +  {  0x01C2, 0x0000, 0x01F4, 0x0032, {L'p',                L'P',                L'0',
> L')'            }},
> 
> +  {  0x01F4, 0x0000, 0x0226, 0x0032, {VkKeyBackspace,      VkKeyBackspace,
> VkKeyBackspace,      VkKeyBackspace  }},
> 
> +  // Line 1
> 
> +  {  0x0000, 0x0032, 0x0019, 0x0064, {VkKeyNull,           VkKeyNull,
> VkKeyNull,           VkKeyNull       }},
> 
> +  {  0x0019, 0x0032, 0x004B, 0x0064, {L'a',                L'A',                VkKeyF1,
> VkKeyF1         }},
> 
> +  {  0x004B, 0x0032, 0x007D, 0x0064, {L's',                L'S',                VkKeyF2,
> VkKeyF2         }},
> 
> +  {  0x007D, 0x0032, 0x00AF, 0x0064, {L'd',                L'D',                VkKeyF3,
> VkKeyF3         }},
> 
> +  {  0x00AF, 0x0032, 0x00E1, 0x0064, {L'f',                L'F',                VkKeyF4,
> VkKeyF4         }},
> 
> +  {  0x00E1, 0x0032, 0x0113, 0x0064, {L'g',                L'G',                VkKeyF5,
> VkKeyF5         }},
> 
> +  {  0x0113, 0x0032, 0x0145, 0x0064, {L'h',                L'H',                VkKeyF6,
> VkKeyF6         }},
> 
> +  {  0x0145, 0x0032, 0x0177, 0x0064, {L'j',                L'J',                VkKeyF7,
> VkKeyF7         }},
> 
> +  {  0x0177, 0x0032, 0x01A9, 0x0064, {L'k',                L'K',                VkKeyF8,
> VkKeyF8         }},
> 
> +  {  0x01A9, 0x0032, 0x01DB, 0x0064, {L'l',                L'L',                VkKeyF9,
> VkKeyF9         }},
> 
> +  {  0x01DB, 0x0032, 0x020D, 0x0064, {VkKeyF2,             VkKeyF2,
> VkKeyF10,            VkKeyF10        }},
> 
> +  // Line 2
> 
> +  {  0x0000, 0x0064, 0x004B, 0x0096, {VkKeyCapslock,       VkKeyCapslock,
> VkKeyShift,          VkKeyShift      }},
> 
> +  {  0x004B, 0x0064, 0x007D, 0x0096, {L'z',                L'Z',                L'`',
> L'~'            }},
> 
> +  {  0x007D, 0x0064, 0x00AF, 0x0096, {L'x',                L'X',                L';',
> L':'            }},
> 
> +  {  0x00AF, 0x0064, 0x00E1, 0x0096, {L'c',                L'C',                L'\'',
> L'"'            }},
> 
> +  {  0x00E1, 0x0064, 0x0113, 0x0096, {L'v',                L'V',                L',',
> L'<'            }},
> 
> +  {  0x0113, 0x0064, 0x0145, 0x0096, {L'b',                L'B',                L'.',
> L'>'            }},
> 
> +  {  0x0145, 0x0064, 0x0177, 0x0096, {L'n',                L'N',                L'/',
> L'?'            }},
> 
> +  {  0x0177, 0x0064, 0x01A9, 0x0096, {L'm',                L'M',                VkKeyF11,
> VkKeyF11        }},
> 
> +  {  0x01A9, 0x0064, 0x01DB, 0x0096, {VkKeyUp,             VkKeyUp,
> VkKeyF12,            VkKeyF12        }},
> 
> +  {  0x01DB, 0x0064, 0x0226, 0x0096, {VkKeyEnter,          VkKeyEnter,
> VkKeyEnter,          VkKeyEnter      }},
> 
> +  // Line 3
> 
> +  {  0x0000, 0x0096, 0x004B, 0x00C8, {VkKeyEsc,            VkKeyEsc,
> VkKeyEsc,            VkKeyEsc        }},
> 
> +  {  0x004B, 0x0096, 0x007D, 0x00C8, {VkKeyTwoPage,        VkKeyTwoPage,
> VkKeyTwoPage,        VkKeyTwoPage    }},
> 
> +  {  0x007D, 0x0096, 0x0177, 0x00C8, {L' ',                L' ',                L' ',                L'
> '            }},
> 
> +  {  0x0177, 0x0096, 0x01A9, 0x00C8, {VkKeyLeft,           VkKeyLeft,           L'\\',
> L'|'            }},
> 
> +  {  0x01A9, 0x0096, 0x01DB, 0x00C8, {VkKeyDown,           VkKeyDown,           L'-
> ',                L'_'            }},
> 
> +  {  0x01DB, 0x0096, 0x020D, 0x00C8, {VkKeyRight,          VkKeyRight,          L'=',
> L'+'            }},
> 
> +  // Screen Corner A
> 
> +  {  0x0000, 0x0000, 0x001E, 0x001E, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
> 
> +  // Screen Corner B
> 
> +  {  0x0000, 0x023A, 0x001E, 0x0258, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
> 
> +  // Screen Corner C
> 
> +  {  0x02E4, 0x0000, 0x0320, 0x001E, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
> 
> +  // Screen Corner D
> 
> +  {  0x02E4, 0x023A, 0x0320, 0x0258, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}}
> 
> +};
> 
> +
> 
> +//
> 
> +// 1.SimpleKeyboardBody
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\SimpleKeyboard.bmp
> 
> +// Based on keyboard's (startX, startY)
> 
> +// +-----+-----+
> 
> +// | Esc |Enter| Line 0
> 
> +// +-----+-----+
> 
> +// | Up  | Down| Line 1
> 
> +// +-----+-----+
> 
> +//
> 
> +// 2.Screen Corner
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\SimpleIcon.bmp # Screen Corner A/B
> 
> +//   (2).\KeyboardLayout\FullIcon.bmp   # Screen Corner C/D
> 
> +// +-+------------------------------------+-+
> 
> +// |A|                                    |C|
> 
> +// +-+                                    +-+
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// +-+                                    +-+
> 
> +// |B|                                    |D|
> 
> +// +-+------------------------------------+-+
> 
> +//
> 
> +VK_STRUCT mSimpleKeyboardBody[] = {
> 
> +  // StartX  StartY  EndX    EndY     Page0Font            Page1Font            Page2Font
> Page3Font
> 
> +  // Line 0
> 
> +  {  0x0000, 0x0000, 0x0032, 0x0032, {VkKeyEsc,            VkKeyEsc,
> VkKeyEsc,            VkKeyEsc        }},
> 
> +  {  0x0032, 0x0000, 0x0064, 0x0032, {VkKeyEnter,          VkKeyEnter,
> VkKeyEnter,          VkKeyEnter      }},
> 
> +  // Line 1
> 
> +  {  0x0000, 0x0032, 0x0032, 0x0064, {VkKeyUp,             VkKeyUp,
> VkKeyUp,             VkKeyUp         }},
> 
> +  {  0x0032, 0x0032, 0x0064, 0x0064, {VkKeyDown,           VkKeyDown,
> VkKeyDown,           VkKeyDown       }},
> 
> +  // Screen Corner A
> 
> +  {  0x0000, 0x0000, 0x001E, 0x001E, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
> 
> +  // Screen Corner B
> 
> +  {  0x0000, 0x023A, 0x001E, 0x0258, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
> 
> +  // Screen Corner C
> 
> +  {  0x02E4, 0x0000, 0x0320, 0x001E, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}},
> 
> +  // Screen Corner D
> 
> +  {  0x02E4, 0x023A, 0x0320, 0x0258, {VkKeyTypeMaximum,
> VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum}}
> 
> +};
> 
> +
> 
> +EFI_STATUS
> 
> +ModifyShiftKeyColor (
> 
> +  IN     VK_CONTEXT                    *VkContext,
> 
> +  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer
> 
> +  )
> 
> +{
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *TempBltBuffer;
> 
> +  UINTN                         BltSize;
> 
> +  BOOLEAN                       IsPressed;
> 
> +
> 
> +  TempBltBuffer = *BltBuffer;
> 
> +  BltSize       = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
> 
> +  IsPressed     = VkContext->PageNumber <= VkPage1 ?
> 
> +                  VkContext->IsCapsLockFlag :
> 
> +                  VkContext->IsShiftKeyFlag;
> 
> +
> 
> +  while (BltSize-- != 0) {
> 
> +    //
> 
> +    // Color gradient issue
> 
> +    //
> 
> +    if (((TempBltBuffer->Red - TempBltBuffer->Green) > 0x20) &&
> 
> +        ((TempBltBuffer->Red - TempBltBuffer->Blue)  > 0x20)) {
> 
> +      if (IsPressed) {
> 
> +        TempBltBuffer->Red   = 0;
> 
> +        TempBltBuffer->Green = 255;
> 
> +        TempBltBuffer->Blue  = 255;
> 
> +      } else {
> 
> +        TempBltBuffer->Red   = 255;
> 
> +        TempBltBuffer->Green = 255;
> 
> +        TempBltBuffer->Blue  = 255;
> 
> +      }
> 
> +    }
> 
> +    TempBltBuffer++;
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +MakeKeyboardTransparent (
> 
> +  IN     VK_CONTEXT                    *VkContext,
> 
> +  IN     BOOLEAN                       IsTransparent,
> 
> +  IN     EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltIn,
> 
> +  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltOut
> 
> +  )
> 
> +{
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Keyboard;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background;
> 
> +  UINTN                         BltSize;
> 
> +
> 
> +  if (*BltOut == NULL) {
> 
> +    *BltOut = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +    if (*BltOut == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +  }
> 
> +  Compound   = *BltOut;
> 
> +  Keyboard   = BltIn;
> 
> +  Background = VkContext->VkBodyBackgroundBltBuffer;
> 
> +  BltSize    = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
> 
> +  while (BltSize-- != 0) {
> 
> +    if (IsTransparent) {
> 
> +      Compound->Red   = (Keyboard->Red * TRANSPARENCY_WEIGHT) / 100
> + (Background->Red * (100 - TRANSPARENCY_WEIGHT)) / 100;
> 
> +      Compound->Green = (Keyboard->Green * TRANSPARENCY_WEIGHT) /
> 100 + (Background->Green * (100 - TRANSPARENCY_WEIGHT)) / 100;
> 
> +      Compound->Blue  = (Keyboard->Blue * TRANSPARENCY_WEIGHT) / 100
> + (Background->Blue * (100 - TRANSPARENCY_WEIGHT)) / 100;
> 
> +    } else {
> 
> +      *Compound = *Keyboard;
> 
> +    }
> 
> +    Compound++;
> 
> +    Keyboard++;
> 
> +    Background++;
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINTN      BltSize
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *CurrentBltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *CurrentBltBufferSave;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *OldBltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *OldBltBufferSave;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background;
> 
> +  UINTN                         Size;
> 
> +
> 
> +  CurrentBltBufferSave = NULL;
> 
> +  OldBltBufferSave     = NULL;
> 
> +
> 
> +  //
> 
> +  // Save original blt buffer first.
> 
> +  //
> 
> +  OldBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +  if (OldBltBuffer == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  if (VkContext->VkBodyBackgroundBltBuffer != NULL) {
> 
> +    CopyMem (OldBltBuffer, VkContext->VkBodyBackgroundBltBuffer,
> VkContext->VkBodyBltSize);
> 
> +  }
> 
> +
> 
> +  if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +    VkContext->VkBodyBltSize = BltSize;
> 
> +    VkContext->VkBodyBackgroundBltBuffer = AllocateZeroPool (VkContext-
> >VkBodyBltSize);
> 
> +    ASSERT (VkContext->VkBodyBackgroundBltBuffer != NULL);
> 
> +    if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +  } else if (BltSize > VkContext->VkBodyBltSize) {
> 
> +    VkContext->VkBodyBltSize = BltSize;
> 
> +    FreePool (VkContext->VkBodyBackgroundBltBuffer);
> 
> +    VkContext->VkBodyBackgroundBltBuffer = NULL;
> 
> +    VkContext->VkBodyBackgroundBltBuffer = AllocateZeroPool (VkContext-
> >VkBodyBltSize);
> 
> +    ASSERT (VkContext->VkBodyBackgroundBltBuffer != NULL);
> 
> +    if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +  } else {
> 
> +    ZeroMem (VkContext->VkBodyBackgroundBltBuffer, VkContext-
> >VkBodyBltSize);
> 
> +  }
> 
> +
> 
> +  CurrentBltBuffer = NULL;
> 
> +  if (VkContext->IsBackgroundChanged == TRUE) {
> 
> +    //
> 
> +    // Background changed, merge current visioning blt buffer with old
> background blt buffer.
> 
> +    //
> 
> +    Compound   = VkContext->VkBodyCompoundBltBuffer;
> 
> +    Background = VkContext->VkBodyBackgroundBltBuffer;
> 
> +    CurrentBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +    ASSERT (CurrentBltBuffer != NULL);
> 
> +    if (CurrentBltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +    Status = VkContext->GraphicsOutput->Blt (
> 
> +                                          VkContext->GraphicsOutput,
> 
> +                                          CurrentBltBuffer,
> 
> +                                          EfiBltVideoToBltBuffer,
> 
> +                                          VkContext->VkBodyBltStartX,
> 
> +                                          VkContext->VkBodyBltStartY,
> 
> +                                          0,
> 
> +                                          0,
> 
> +                                          VkContext->VkBodyBltWidth,
> 
> +                                          VkContext->VkBodyBltHeight,
> 
> +                                          VkContext->VkBodyBltWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                          );
> 
> +    CurrentBltBufferSave = CurrentBltBuffer;
> 
> +    OldBltBufferSave = OldBltBuffer;
> 
> +    Size = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
> 
> +    while (Size-- != 0) {
> 
> +      if ((Compound->Red   != CurrentBltBuffer->Red) ||
> 
> +          (Compound->Green != CurrentBltBuffer->Green) ||
> 
> +          (Compound->Blue  != CurrentBltBuffer->Blue)) {
> 
> +        *Background = *CurrentBltBuffer;
> 
> +      } else {
> 
> +        *Background = *OldBltBuffer;
> 
> +      }
> 
> +      Compound++;
> 
> +      Background++;
> 
> +      CurrentBltBuffer++;
> 
> +      OldBltBuffer++;
> 
> +    }
> 
> +  } else {
> 
> +    //
> 
> +    // Background NOT changed, save it to VkBodyBackgroundBltBuffer
> directly.
> 
> +    //
> 
> +    Status = VkContext->GraphicsOutput->Blt (
> 
> +                                          VkContext->GraphicsOutput,
> 
> +                                          VkContext->VkBodyBackgroundBltBuffer,
> 
> +                                          EfiBltVideoToBltBuffer,
> 
> +                                          VkContext->VkBodyBltStartX,
> 
> +                                          VkContext->VkBodyBltStartY,
> 
> +                                          0,
> 
> +                                          0,
> 
> +                                          VkContext->VkBodyBltWidth,
> 
> +                                          VkContext->VkBodyBltHeight,
> 
> +                                          VkContext->VkBodyBltWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                          );
> 
> +  }
> 
> +
> 
> +  if (CurrentBltBufferSave != NULL) {
> 
> +    FreePool (CurrentBltBufferSave);
> 
> +  }
> 
> +  if (OldBltBufferSave != NULL) {
> 
> +    FreePool (OldBltBufferSave);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +RestoreVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        VkContext->VkBodyBackgroundBltBuffer,
> 
> +                                        EfiBltBufferToVideo,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->VkBodyBltStartX,
> 
> +                                        VkContext->VkBodyBltStartY,
> 
> +                                        VkContext->VkBodyBltWidth,
> 
> +                                        VkContext->VkBodyBltHeight,
> 
> +                                        VkContext->VkBodyBltWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +
> 
> +  FreePool (VkContext->VkBodyBackgroundBltBuffer);
> 
> +  VkContext->VkBodyBackgroundBltBuffer = NULL;
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +SetCharacterPosition (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     DestX,
> 
> +  IN UINT32     DestY
> 
> +  )
> 
> +{
> 
> +  UINTN     Index;
> 
> +  VK_STRUCT *KeyArryPtr;
> 
> +  UINT32    KeyArrySize;
> 
> +
> 
> +  switch (VkContext->TargetKeyboardDisplay) {
> 
> +  case VkDisplayAttributeSimpleTop:
> 
> +  case VkDisplayAttributeSimpleBottom:
> 
> +    KeyArryPtr  = mSimpleKeyboardBody;
> 
> +    KeyArrySize = DIM (mSimpleKeyboardBody);
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullBottom:
> 
> +  case VkDisplayAttributeFullTop:
> 
> +    KeyArryPtr = mFullKeyboardBody;
> 
> +    KeyArrySize = DIM (mFullKeyboardBody);
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeNone:
> 
> +    KeyArryPtr = mFullKeyboardBody;
> 
> +    KeyArrySize = DIM (mFullKeyboardBody);
> 
> +    break;
> 
> +
> 
> +  default:
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  for (Index = 0; Index < KeyArrySize; Index++) {
> 
> +    VkContext->KeyboardBodyPtr[Index] = KeyArryPtr[Index];
> 
> +  }
> 
> +  VkContext->NumOfKeysInfo = KeyArrySize;
> 
> +
> 
> +  for (Index = 0; Index < (VkContext->NumOfKeysInfo - 4); Index++) {
> 
> +    VkContext->KeyboardBodyPtr[Index].DisStartX += (UINT16)DestX;
> 
> +    VkContext->KeyboardBodyPtr[Index].DisStartY += (UINT16)DestY;
> 
> +    VkContext->KeyboardBodyPtr[Index].DisEndX   += (UINT16)DestX;
> 
> +    VkContext->KeyboardBodyPtr[Index].DisEndY   += (UINT16)DestY;
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkIconBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT           *VkContext,
> 
> +  IN VK_DISPLAY_ATTRIBUTE IconType
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GraphicBlt;
> 
> +  UINTN                         BltSize;
> 
> +  UINTN                         Height;
> 
> +  UINTN                         Width;
> 
> +  INTN                          StartX;
> 
> +  INTN                          StartY;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *TempIconBackBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *IconBackBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
> 
> +  UINTN                         Size;
> 
> +  BOOLEAN                       SaveCursor;
> 
> +
> 
> +  Status             = EFI_SUCCESS;
> 
> +  StartX             = 0;
> 
> +  StartY             = 0;
> 
> +  TempIconBackBuffer = NULL;
> 
> +  IconBackBuffer     = NULL;
> 
> +  Compound           = NULL;
> 
> +
> 
> +  if ((IconType == VkDisplayAttributeFullTop) ||
> 
> +      (IconType == VkDisplayAttributeSimpleTop)) {
> 
> +    return EFI_SUCCESS;
> 
> +  }
> 
> +
> 
> +  SaveCursor = gST->ConOut->Mode->CursorVisible;
> 
> +  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
> 
> +
> 
> +  if (IconType == VkDisplayAttributeFullBottom) {
> 
> +    GraphicBlt = VkContext->FullIcon->Bitmap;
> 
> +    BltSize    = VkContext->FullIcon->Height * VkContext->FullIcon->Width *
> sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
> 
> +    Height     = VkContext->FullIcon->Height;
> 
> +    Width      = VkContext->FullIcon->Width;
> 
> +    StartX     = VkContext->FullIconBackStartX;
> 
> +    StartY     = VkContext->FullIconBackStartY;
> 
> +  } else if (IconType == VkDisplayAttributeSimpleBottom) {
> 
> +    GraphicBlt = VkContext->SmallIcon->Bitmap;
> 
> +    BltSize    = VkContext->SmallIcon->Height * VkContext->SmallIcon-
> >Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
> 
> +    Height     = VkContext->SmallIcon->Height;
> 
> +    Width      = VkContext->SmallIcon->Width;
> 
> +    StartX     = VkContext->SimIconBackStartX;
> 
> +    StartY     = VkContext->SimIconBackStartY;
> 
> +  } else {
> 
> +    gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  IconBackBuffer = AllocateZeroPool (BltSize);
> 
> +  if (IconBackBuffer == NULL) {
> 
> +    gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  TempIconBackBuffer = IconBackBuffer;
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        IconBackBuffer,
> 
> +                                        EfiBltVideoToBltBuffer,
> 
> +                                        StartX,
> 
> +                                        StartY,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        Width,
> 
> +                                        Height,
> 
> +                                        Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +
> 
> +  if (IconType == VkDisplayAttributeFullBottom) {
> 
> +    //
> 
> +    // Store full icon background framebuffer
> 
> +    //
> 
> +    VkContext->FullIconBackHeight = Height;
> 
> +    VkContext->FullIconBackWidth  = Width;
> 
> +    if (VkContext->FullIconUpdatedFlag == FALSE) {
> 
> +      //
> 
> +      // No icon draw, save the buffer directly.
> 
> +      //
> 
> +      if (VkContext->FullIconBackBuffer == NULL) {
> 
> +        VkContext->FullIconBackBuffer = AllocateZeroPool (BltSize);
> 
> +        VkContext->FullIconBackSize = BltSize;
> 
> +      }
> 
> +      CopyMem (VkContext->FullIconBackBuffer, IconBackBuffer, BltSize);
> 
> +      VkContext->FullIconUpdatedFlag = TRUE;
> 
> +    } else {
> 
> +      if (CompareMem (VkContext->FullIconBackBuffer, IconBackBuffer,
> BltSize) != 0) {
> 
> +        Compound = VkContext->FullIconBackBuffer;
> 
> +        Size = Height * Width;
> 
> +        while (Size-- != 0) {
> 
> +          if ((GraphicBlt->Red   != IconBackBuffer->Red) ||
> 
> +              (GraphicBlt->Green != IconBackBuffer->Green) ||
> 
> +              (GraphicBlt->Blue  != IconBackBuffer->Blue)) {
> 
> +            *Compound = *IconBackBuffer;
> 
> +          }
> 
> +          Compound++;
> 
> +          GraphicBlt++;
> 
> +          IconBackBuffer++;
> 
> +        }
> 
> +      }
> 
> +    }
> 
> +  } else if (IconType == VkDisplayAttributeSimpleBottom) {
> 
> +    //
> 
> +    // Store simple icon background framebuffer
> 
> +    //
> 
> +    VkContext->SimIconBackHeight = Height;
> 
> +    VkContext->SimIconBackWidth  = Width;
> 
> +    if (VkContext->SimIconUpdatedFlag == FALSE) {
> 
> +      //
> 
> +      // No icon draw, save the buffer directly.
> 
> +      //
> 
> +      if (VkContext->SimIconBackBuffer == NULL) {
> 
> +        VkContext->SimIconBackBuffer = AllocateZeroPool (BltSize);
> 
> +        VkContext->SimIconBackSize = BltSize;
> 
> +      }
> 
> +      CopyMem (VkContext->SimIconBackBuffer, IconBackBuffer, BltSize);
> 
> +      VkContext->SimIconUpdatedFlag = TRUE;
> 
> +    } else {
> 
> +      if (CompareMem (VkContext->SimIconBackBuffer, IconBackBuffer,
> BltSize) != 0) {
> 
> +        Compound = VkContext->SimIconBackBuffer;
> 
> +        Size = Height * Width;
> 
> +        while (Size-- != 0) {
> 
> +          if ((GraphicBlt->Red   != IconBackBuffer->Red) ||
> 
> +              (GraphicBlt->Green != IconBackBuffer->Green) ||
> 
> +              (GraphicBlt->Blue  != IconBackBuffer->Blue)) {
> 
> +            *Compound = *IconBackBuffer;
> 
> +          }
> 
> +          Compound++;
> 
> +          GraphicBlt++;
> 
> +          IconBackBuffer++;
> 
> +        }
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (TempIconBackBuffer != NULL)  FreePool (TempIconBackBuffer);
> 
> +
> 
> +  gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard icon.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics
> and keyboard icon displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkIcon (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        SizeOfX;
> 
> +  UINT32                        SizeOfY;
> 
> +  INTN                          DestX;
> 
> +  INTN                          DestY;
> 
> +  UINTN                         CoordinateX;
> 
> +  UINTN                         CoordinateY;
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
> 
> +  UINTN                         BltSize;
> 
> +  UINTN                         Height;
> 
> +  UINTN                         Width;
> 
> +
> 
> +  Status         = EFI_SUCCESS;
> 
> +  GraphicsOutput = VkContext->GraphicsOutput;
> 
> +  SizeOfX        = GraphicsOutput->Mode->Info->HorizontalResolution;
> 
> +  SizeOfY        = GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +  CoordinateX    = 0;
> 
> +  CoordinateY    = 0;
> 
> +  Height         = VkImage->Height;
> 
> +  Width          = VkImage->Width;
> 
> +  Blt            = VkImage->Bitmap;
> 
> +  BltSize        = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * (UINT32)(Width
> * Height);
> 
> +
> 
> +  //
> 
> +  // Calculate the display position according to Attribute.
> 
> +  //
> 
> +  switch (Attribute) {
> 
> +  case VkDisplayAttributeSimpleTop:
> 
> +    DestX = CoordinateX;
> 
> +    DestY = CoordinateY;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullTop:
> 
> +    DestX = (SizeOfX - Width - CoordinateX);
> 
> +    DestY = CoordinateY;;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullBottom:
> 
> +    DestX                         = (SizeOfX - Width - CoordinateX);
> 
> +    DestY                         = (SizeOfY - Height - CoordinateY);
> 
> +    VkContext->FullIconBackStartX = DestX;
> 
> +    VkContext->FullIconBackStartY = DestY;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeSimpleBottom:
> 
> +    DestX = CoordinateX;
> 
> +    DestY = (SizeOfY - Height - CoordinateY);
> 
> +
> 
> +    //
> 
> +    // Save to check icon/screen cleared
> 
> +    //
> 
> +    if (VkContext->IconBltBuffer == NULL) {
> 
> +      VkContext->IconBltSize   = BltSize;
> 
> +      VkContext->IconBltWidth  = Width;
> 
> +      VkContext->IconBltHeight = Height;
> 
> +      VkContext->IconBltBuffer = AllocateZeroPool (BltSize);
> 
> +    }
> 
> +    CopyMem (VkContext->IconBltBuffer, Blt, VkContext->IconBltSize);
> 
> +
> 
> +    VkContext->SimIconBackStartX = DestX;
> 
> +    VkContext->SimIconBackStartY = DestY;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeNone:
> 
> +    return EFI_SUCCESS;
> 
> +
> 
> +  default:
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  if ((DestX >= 0) && (DestY >= 0)) {
> 
> +    //
> 
> +    // Store icon background framebuffer
> 
> +    //
> 
> +    SaveVkIconBackgroundBltBuffer (VkContext, Attribute);
> 
> +    Status = GraphicsOutput->Blt (
> 
> +                               GraphicsOutput,
> 
> +                               Blt,
> 
> +                               EfiBltBufferToVideo,
> 
> +                               0,
> 
> +                               0,
> 
> +                               (UINTN) DestX,
> 
> +                               (UINTN) DestY,
> 
> +                               Width,
> 
> +                               Height,
> 
> +                               Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                               );
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics
> and keyboard displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkBody (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        SizeOfX;
> 
> +  UINT32                        SizeOfY;
> 
> +  INTN                          DestX;
> 
> +  INTN                          DestY;
> 
> +  UINTN                         BltSize;
> 
> +  UINTN                         Height;
> 
> +  UINTN                         Width;
> 
> +  UINTN                         CoordinateY;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltIn;
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
> 
> +
> 
> +  Status         = EFI_SUCCESS;
> 
> +  GraphicsOutput = VkContext->GraphicsOutput;
> 
> +  SizeOfX        = GraphicsOutput->Mode->Info->HorizontalResolution;
> 
> +  SizeOfY        = GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +  CoordinateY    = 0;
> 
> +  Height         = VkImage->Height;
> 
> +  Width          = VkImage->Width;
> 
> +  BltSize        = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * (UINT32)(Width
> * Height);
> 
> +  BltIn          = AllocateCopyPool (BltSize, VkImage->Bitmap);
> 
> +
> 
> +  if (BltIn == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Calculate the display position according to Attribute.
> 
> +  //
> 
> +  switch (Attribute) {
> 
> +  case VkDisplayAttributeSimpleTop:
> 
> +    DestX = ((SizeOfX / 2) - Width) / 4;
> 
> +    DestY = CoordinateY;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeSimpleTop;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeSimpleBottom:
> 
> +    DestX = ((SizeOfX / 2) - Width) / 4;
> 
> +    DestY = (SizeOfY - Height - CoordinateY);
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeSimpleBottom;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullTop:
> 
> +    DestX = (SizeOfX - Width) / 2;
> 
> +    DestY = CoordinateY;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeFullTop;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullBottom:
> 
> +    DestX = (SizeOfX - Width) / 2;
> 
> +    DestY = (SizeOfY - Height - CoordinateY);
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeFullBottom;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeNone:
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    goto DVKBODY_Exit;
> 
> +
> 
> +  default:
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto DVKBODY_Exit;
> 
> +  }
> 
> +  if ((DestX >= 0) && (DestY >= 0)) {
> 
> +    SetCharacterPosition (VkContext, (UINT32)DestX, (UINT32)DestY);
> 
> +
> 
> +    //
> 
> +    // Store current framebuffer
> 
> +    //
> 
> +    VkContext->VkBodyBltStartX = DestX;
> 
> +    VkContext->VkBodyBltStartY = DestY;
> 
> +    VkContext->VkBodyBltHeight = Height;
> 
> +    VkContext->VkBodyBltWidth  = Width;
> 
> +    SaveVkBodyBackgroundBltBuffer (VkContext, BltSize);
> 
> +
> 
> +    //
> 
> +    // Free compound buffer first.
> 
> +    //
> 
> +    if (VkContext->VkBodyCompoundBltBuffer != NULL) {
> 
> +      FreePool (VkContext->VkBodyCompoundBltBuffer);
> 
> +    }
> 
> +    VkContext->VkBodyCompoundBltBuffer = NULL;
> 
> +    ModifyShiftKeyColor (VkContext, &BltIn);
> 
> +    MakeKeyboardTransparent (VkContext, TRUE, BltIn, &(VkContext-
> >VkBodyCompoundBltBuffer));
> 
> +
> 
> +    //
> 
> +    // Draw keyboard body
> 
> +    //
> 
> +    Status = GraphicsOutput->Blt (
> 
> +                               GraphicsOutput,
> 
> +                               VkContext->VkBodyCompoundBltBuffer,
> 
> +                               EfiBltBufferToVideo,
> 
> +                               0,
> 
> +                               0,
> 
> +                               (UINTN) DestX,
> 
> +                               (UINTN) DestY,
> 
> +                               Width,
> 
> +                               Height,
> 
> +                               Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                               );
> 
> +  }
> 
> +
> 
> +
> 
> +DVKBODY_Exit:
> 
> +  if (BltIn != NULL) {
> 
> +    FreePool (BltIn);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Clear the keyboard body
> 
> +
> 
> +  @param  VkContext             Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkBody (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  RestoreVkBodyBackgroundBltBuffer (VkContext);
> 
> +  VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  Clear the keyboard icon
> 
> +
> 
> +  @param  VkContext             Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkIcon (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +
> 
> +  if ((VkContext->FullIconBackBuffer == NULL) || (VkContext-
> >SimIconBackBuffer == NULL)) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  if ((VkContext->FullIconUpdatedFlag == FALSE) || (VkContext-
> >SimIconUpdatedFlag == FALSE)) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        VkContext->FullIconBackBuffer,
> 
> +                                        EfiBltBufferToVideo,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->FullIconBackStartX,
> 
> +                                        VkContext->FullIconBackStartY,
> 
> +                                        VkContext->FullIconBackWidth,
> 
> +                                        VkContext->FullIconBackHeight,
> 
> +                                        VkContext->FullIconBackWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +
> 
> +  ZeroMem (VkContext->FullIconBackBuffer, VkContext->FullIconBackSize);
> 
> +  VkContext->FullIconUpdatedFlag = FALSE;
> 
> +
> 
> +
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        VkContext->SimIconBackBuffer,
> 
> +                                        EfiBltBufferToVideo,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->SimIconBackStartX,
> 
> +                                        VkContext->SimIconBackStartY,
> 
> +                                        VkContext->SimIconBackWidth,
> 
> +                                        VkContext->SimIconBackHeight,
> 
> +                                        VkContext->SimIconBackWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +  if (!EFI_ERROR (Status)) {
> 
> +    if (VkContext->ScreenCheckBuffer == NULL) {
> 
> +      VkContext->ScreenCheckBufferSize = VkContext->SimIconBackHeight *
> 
> +                                         VkContext->SimIconBackWidth *
> 
> +                                         sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
> 
> +      VkContext->ScreenCheckBuffer = AllocateZeroPool (VkContext-
> >ScreenCheckBufferSize);
> 
> +    }
> 
> +
> 
> +    CopyMem (
> 
> +      VkContext->ScreenCheckBuffer,
> 
> +      VkContext->SimIconBackBuffer,
> 
> +      (VkContext->SimIconBackHeight * VkContext->SimIconBackWidth *
> sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))
> 
> +      );
> 
> +  }
> 
> +  ZeroMem (VkContext->SimIconBackBuffer, VkContext->SimIconBackSize);
> 
> +  VkContext->SimIconUpdatedFlag = FALSE;
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Draw key board on the display
> 
> +
> 
> +  @param[in] VkContext          Graphic Protocol for draw the alphabet.
> 
> +
> 
> +  @retval EFI_SUCCESS           Draw keyboard was done.
> 
> +  @retval EFI_UNSUPPORTED       Did not get key mapping table.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +DrawKeyboardLayout (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  if (!VkContext->IsIconShowed) {
> 
> +    Status = DrawVkIcon (VkContext, VkContext->SmallIcon,
> VkDisplayAttributeSimpleTop);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +    Status = DrawVkIcon (VkContext, VkContext->SmallIcon,
> VkDisplayAttributeSimpleBottom);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +    Status = DrawVkIcon (VkContext, VkContext->FullIcon,
> VkDisplayAttributeFullTop);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +    Status = DrawVkIcon (VkContext, VkContext->FullIcon,
> VkDisplayAttributeFullBottom);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->IsIconShowed = TRUE;
> 
> +  }
> 
> +
> 
> +  if (VkContext->TargetKeyboardDisplay != VkContext-
> >CurrentKeyboardDisplay) {
> 
> +    switch (VkContext->TargetKeyboardDisplay) {
> 
> +    case VkDisplayAttributeSimpleTop:
> 
> +    case VkDisplayAttributeSimpleBottom:
> 
> +      DrawVkBody (VkContext, VkContext->SimKeyBody, VkContext-
> >TargetKeyboardDisplay);
> 
> +      break;
> 
> +
> 
> +    case VkDisplayAttributeFullTop:
> 
> +    case VkDisplayAttributeFullBottom:
> 
> +      if (VkContext->PageNumber <= VkPage1) {
> 
> +        DrawVkBody (VkContext, VkContext->CapLeKeyBody, VkContext-
> >TargetKeyboardDisplay);
> 
> +      } else {
> 
> +        DrawVkBody (VkContext, VkContext->DigKeyBody, VkContext-
> >TargetKeyboardDisplay);
> 
> +      }
> 
> +
> 
> +    case VkDisplayAttributeNone:
> 
> +      break;
> 
> +
> 
> +    default:
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +KeyboardLayoutHandler (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     Index
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +
> 
> +  if (Index == (VkContext->NumOfKeysInfo - 4)) {
> 
> +    //
> 
> +    // Touch the LeftTop icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeSimpleTop)
> {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeSimpleTop;
> 
> +    }
> 
> +  } else if (Index == (VkContext->NumOfKeysInfo - 3)) {
> 
> +    //
> 
> +    // Touch the LeftBottom icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay ==
> VkDisplayAttributeSimpleBottom) {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeSimpleBottom;
> 
> +    }
> 
> +  } else if (Index == (VkContext->NumOfKeysInfo - 2)) {
> 
> +    //
> 
> +    // Touch the RightTop icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeFullTop) {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeFullTop;
> 
> +    }
> 
> +  } else {
> 
> +    //
> 
> +    // Touch the RightBottom icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeFullBottom)
> {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeFullBottom;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (VkContext->TargetKeyboardDisplay == VkDisplayAttributeNone) {
> 
> +    //
> 
> +    // Just hide the current keyboard
> 
> +    //
> 
> +    HideVkBody (VkContext);
> 
> +    VkContext->KeyTouchedTimeOut = VK_REPEAT_TIMEOUT;
> 
> +
> 
> +  } else {
> 
> +    //
> 
> +    // If current keyboard status is NOT none,
> 
> +    // hide current keyboard first and then draw the target keyboard
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay != VkDisplayAttributeNone) {
> 
> +      HideVkBody (VkContext);
> 
> +    }
> 
> +    Status = DrawKeyboardLayout (VkContext);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This routine is used to check if icon has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckIconCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        VerticalResolution;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +  BltBuffer = NULL;
> 
> +  VkContext->IconReDrawCheck++;
> 
> +  if (VkContext->IconReDrawCheck <= 10) {
> 
> +    //
> 
> +    // Check it every 10 * 100ms.
> 
> +    //
> 
> +    return Status;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Check if right-bottomed region is black, if yes, clean screen happened,
> need to re-draw keyboard.
> 
> +  //
> 
> +  VerticalResolution    = VkContext->GraphicsOutput->Mode->Info-
> >VerticalResolution;
> 
> +  BltBuffer             = AllocateZeroPool (VkContext->IconBltSize);
> 
> +  if (BltBuffer == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        BltBuffer,
> 
> +                                        EfiBltVideoToBltBuffer,
> 
> +                                        0,
> 
> +                                        (VerticalResolution - VkContext->IconBltHeight),
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->IconBltWidth,
> 
> +                                        VkContext->IconBltHeight,
> 
> +                                        VkContext->IconBltWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    FreePool (BltBuffer);
> 
> +    return Status;
> 
> +  }
> 
> +  VkContext->IsIconShowed = TRUE;
> 
> +  if (VkContext->IconBltBuffer == NULL) {
> 
> +    //
> 
> +    // No icon has been drawn.
> 
> +    //
> 
> +    VkContext->IsIconShowed = FALSE;
> 
> +  } else {
> 
> +    if (CompareMem (BltBuffer, VkContext->IconBltBuffer, VkContext-
> >IconBltSize) != 0) {
> 
> +      //
> 
> +      // Icon has been overridden, need to re-draw.
> 
> +      //
> 
> +      VkContext->IsIconShowed = FALSE;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (VkContext->IsIconShowed == FALSE) {
> 
> +    if (VkContext->ScreenCheckBuffer != NULL) {
> 
> +      if (CompareMem (BltBuffer, VkContext->ScreenCheckBuffer,
> VkContext->IconBltSize) == 0) {
> 
> +        //
> 
> +        // Icon has been overridden, force to re-draw the keyboard.
> 
> +        //
> 
> +        Status = DrawKeyboardLayout (VkContext);
> 
> +      } else {
> 
> +        //
> 
> +        // Save blt buffer of icon position and use it to check if icon is
> overridden.
> 
> +        //
> 
> +        CopyMem (VkContext->ScreenCheckBuffer, BltBuffer, VkContext-
> >IconBltSize);
> 
> +      }
> 
> +    } else {
> 
> +      //
> 
> +      // Draw the keyboard.
> 
> +      //
> 
> +      Status = DrawKeyboardLayout (VkContext);
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (BltBuffer != NULL) {
> 
> +    FreePool (BltBuffer);
> 
> +  }
> 
> +
> 
> +  VkContext->IconReDrawCheck = 0;
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  ConvertCoordinate - Convert the touch panel's coordinate to display's
> coordinate.
> 
> +
> 
> +  @param[in]  VkContext             Virtual Keyboard context.
> 
> +  @param[in]  Point                 The coordinate reported from touch panel.
> 
> +  @param[out] TouchX                The coordinate X converted to display panel.
> 
> +  @param[out] TouchY                The coordinate Y converted to display panel..
> 
> +
> 
> +  @retval EFI_SUCCESS               Convert success.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +ConvertCoordinate (
> 
> +  IN  VK_CONTEXT                 *VkContext,
> 
> +  IN  EFI_ABSOLUTE_POINTER_STATE Point,
> 
> +  OUT UINT32                     *TouchX,
> 
> +  OUT UINT32                     *TouchY
> 
> +  )
> 
> +{
> 
> +  UINT64 AbsoluteMaxX;
> 
> +  UINT64 AbsoluteMaxY;
> 
> +  UINT32 HorizontalResolution;
> 
> +  UINT32 VerticalResolution;
> 
> +
> 
> +  AbsoluteMaxX         = VkContext->AbsolutePointer->Mode-
> >AbsoluteMaxX;
> 
> +  AbsoluteMaxY         = VkContext->AbsolutePointer->Mode-
> >AbsoluteMaxY;
> 
> +  HorizontalResolution = VkContext->GraphicsOutput->Mode->Info-
> >HorizontalResolution;
> 
> +  VerticalResolution   = VkContext->GraphicsOutput->Mode->Info-
> >VerticalResolution;
> 
> +  *TouchX              = (UINT32) MultU64x32 (Point.CurrentX,
> HorizontalResolution) / (UINT32) AbsoluteMaxX;
> 
> +  *TouchY              = (UINT32) MultU64x32 (Point.CurrentY, VerticalResolution)
> / (UINT32) AbsoluteMaxY;
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This routine is used to check if screen has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckScreenCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        HorizontalResolution;
> 
> +  UINT32                        VerticalResolution;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBufferIndex;
> 
> +  UINTN                         BltSize;
> 
> +  BOOLEAN                       IsScreenCleared;
> 
> +
> 
> +  //
> 
> +  // Check left-bottom side.
> 
> +  // If IconBltBuffer is null, checking is meaningless.
> 
> +  //
> 
> +  if (VkContext->IconBltBuffer == NULL) {
> 
> +    return EFI_SUCCESS;
> 
> +  }
> 
> +
> 
> +  IsScreenCleared = FALSE;
> 
> +  Status          = EFI_SUCCESS;
> 
> +  if ((gST->ConOut->Mode->CursorColumn == 0) && (gST->ConOut->Mode-
> >CursorRow == 0)) {
> 
> +    //
> 
> +    // System may call gST->ConOut->ClearScreen
> 
> +    //
> 
> +    HorizontalResolution  = VkContext->GraphicsOutput->Mode->Info-
> >HorizontalResolution;
> 
> +    VerticalResolution    = VkContext->GraphicsOutput->Mode->Info-
> >VerticalResolution;
> 
> +    BltBuffer             = AllocateZeroPool (VkContext->IconBltSize);
> 
> +    if (BltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +
> 
> +    BltBufferIndex = BltBuffer;
> 
> +    Status = VkContext->GraphicsOutput->Blt (
> 
> +                                          VkContext->GraphicsOutput,
> 
> +                                          BltBuffer,
> 
> +                                          EfiBltVideoToBltBuffer,
> 
> +                                          (HorizontalResolution - VkContext->IconBltWidth),
> 
> +                                          (VerticalResolution - VkContext->IconBltHeight),
> 
> +                                          0,
> 
> +                                          0,
> 
> +                                          VkContext->IconBltWidth,
> 
> +                                          VkContext->IconBltHeight,
> 
> +                                          VkContext->IconBltWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                          );
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      FreePool (BltBuffer);
> 
> +      return Status;
> 
> +    }
> 
> +    BltSize = VkContext->IconBltHeight * VkContext->IconBltWidth;
> 
> +    IsScreenCleared = TRUE;
> 
> +    while (BltSize-- != 0) {
> 
> +      if ((BltBufferIndex->Red != 0) || (BltBufferIndex->Green != 0) ||
> (BltBufferIndex->Blue != 0)) {
> 
> +        IsScreenCleared = FALSE;
> 
> +        break;
> 
> +      }
> 
> +      BltBufferIndex++;
> 
> +    }
> 
> +    FreePool (BltBuffer);
> 
> +  }
> 
> +
> 
> +  if (IsScreenCleared == TRUE) {
> 
> +    VkContext->IsIconShowed   = FALSE;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +
> 
> +    if (VkContext->VkBodyBackgroundBltBuffer != NULL) {
> 
> +      FreePool (VkContext->VkBodyBackgroundBltBuffer);
> 
> +      VkContext->VkBodyBackgroundBltBuffer = NULL;
> 
> +    }
> 
> +
> 
> +    if (VkContext->VkBodyCompoundBltBuffer != NULL) {
> 
> +      FreePool (VkContext->VkBodyCompoundBltBuffer);
> 
> +      VkContext->VkBodyCompoundBltBuffer = NULL;
> 
> +    }
> 
> +
> 
> +    if (VkContext->IconBltBuffer != NULL) {
> 
> +      FreePool (VkContext->IconBltBuffer);
> 
> +      VkContext->IconBltBuffer = NULL;
> 
> +    }
> 
> +
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This routine is used to check if background beneath virtual keyboard has
> been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckBackgroundChanged (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
> 
> +
> 
> +  Status                         = EFI_SUCCESS;
> 
> +  VkContext->IsBackgroundChanged = FALSE;
> 
> +
> 
> +  if ((VkContext->CurrentKeyboardDisplay == VkDisplayAttributeNone) ||
> (VkContext->VkBodyCompoundBltBuffer == NULL)) {
> 
> +    return EFI_SUCCESS;
> 
> +  }
> 
> +
> 
> +  BltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +  if (BltBuffer == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        BltBuffer,
> 
> +                                        EfiBltVideoToBltBuffer,
> 
> +                                        VkContext->VkBodyBltStartX,
> 
> +                                        VkContext->VkBodyBltStartY,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->VkBodyBltWidth,
> 
> +                                        VkContext->VkBodyBltHeight,
> 
> +                                        VkContext->VkBodyBltWidth * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    FreePool (BltBuffer);
> 
> +    return Status;
> 
> +  }
> 
> +  if (CompareMem (BltBuffer, VkContext->VkBodyCompoundBltBuffer,
> VkContext->VkBodyBltSize) != 0) {
> 
> +    VkContext->IsBackgroundChanged = TRUE;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    DrawKeyboardLayout (VkContext);
> 
> +  }
> 
> +
> 
> +  if (BltBuffer != NULL) {
> 
> +    FreePool (BltBuffer);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get unicode by VkContext->PageNumber and VkContext-
> >KeyboardBodyPtr.
> 
> +
> 
> +  @param[in]  VkContext            Address of an VK_CONTEXT structure.
> 
> +  @param[in]  KeyItem              Key Item.
> 
> +  @param[out] FontPtr              Follow VkContext->PageNumber to translate
> 
> +                                   font unicode.
> 
> +
> 
> +  @retval EFI_SUCCESS              Finish translating FontPtr.
> 
> +  @retval EFI_INVALID_PARAMETER    VkContext or FontPtr is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkGetMappingFont (
> 
> +  IN  VK_CONTEXT *VkContext,
> 
> +  IN  VK_STRUCT  KeyItem,
> 
> +  OUT UINT32     *FontPtr
> 
> +  )
> 
> +{
> 
> +  if ((VkContext == NULL) || (FontPtr == NULL) || (VkContext-
> >PageNumber>=VkPageMaximum)) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +  *FontPtr = (UINT32) KeyItem.PageFont[VkContext->PageNumber];
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/KeyboardLayout.idf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/KeyboardLayout.idf
> new file mode 100644
> index 0000000000..995bd0d859
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/KeyboardLayout.idf
> @@ -0,0 +1,12 @@
> +// /** @file
> 
> +// Virtual Keyboard Layout
> 
> +//
> 
> +// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +//
> 
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +//
> 
> +#image IMG_VK_CAPITALLETTERKEYBOARD TRANSPARENT
> CapitalLetterKeyboard.bmp
> 
> +#image IMG_VK_DIGITKEYBOARD         TRANSPARENT DigitKeyboard.bmp
> 
> +#image IMG_VK_FULLICON              TRANSPARENT FullIcon.bmp
> 
> +#image IMG_VK_SIMPLEICON            TRANSPARENT SimpleIcon.bmp
> 
> +#image IMG_VK_SIMPLEKEYBOARD        TRANSPARENT
> SimpleKeyboard.bmp
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/SimpleIcon.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/SimpleIcon.bmp
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..16816f031eb98bf8169c7119b9
> 5ea3ed1371f41d
> GIT binary patch
> literal 2814
> zcmeHDu?>JQ41<*mn3%bM1K9bStAMDgEvtknP%#v#jj<EA^|~EHm%hdJ+18
> X--;Igi
> zvz~tHZ083bZvKJwS=AedIaS~0$e`HvNI;OvAp=5}kZlld1O%z<Y2HkwWx^;3ew
> ~S4
> zE{O5qpp83T)f<O7RWIkrpxE|EK#<BI145UOZ4hn*1gY$4-
> b|%s!YByBnW#Y!<5EEz
> Lcf5u-&Un3EdmJn}
> 
> literal 0
> HcmV?d00001
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/SimpleKeyboard.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/SimpleKeyboard.bmp
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..3004a534f026fe4906e64480f2
> 239b7b7923640b
> GIT binary patch
> literal 30054
> zcmeI4u}<Vj5QcZfOI*MMoQN*rh)6CYxVKncNOmv4BfvB82Bbvfq#z*?AOZqJ
> ghT*n
> z_unb@zyGS-
> J?$BL#!R;*ta5dA_1~YXjc085>+gU5{W9DB#Qt~ueEazM`sKHo|BsLM
> z*}=!|d)xXGP=M>Qqv~}j(Q%zBZCbCb!q%%qN2e-vPQf-
> |Q&6HB3RQjm|E3w{+S+w%
> zYin*i0t!_jQj?oqlAkf?LVK=JsLDy2n^ps~Z)2roqTN_UCMnMvSsfl8o}ZtmguxG
> O
> znO4`d{2JWZ*?D<+u{>{YZwChlZiscU0;t#5R|q>jJ#~_JSRpIUod!YKNlf8ttQ@Ee
> zuF6?;f=c14nU!8VjgQ;A#aJz?xu9Zo)yc|%dU|?#cz7^4@9*zdS65nKtgZ@KIZ%
> &}
> zkNf-k_xJZ?b#!!ec6LTwpa&0rY1YOng4*5P-QM1ItU%`S^3vfNn-
> %Y2%uuPTzZX>|
> z;DCw(C<s$OtEdx~n@;A?IA;Q^3H-
> Ua;OVf^GnHZm@vJUo=qA;9xG}606lR)X#ilx0
> zIZ%04Y^{*h-
> QAu2QqzUQ;=#h{WP*Usj+(^TpM4G5Rn$!ihjUq_F26AqJ&hGn%r!QH
> zRjjU7SMk(yDZ$Xz&&W#W0(;bF6OEM;h_;>!ZEba>G|ZkLD+t49ndj%{_~>EoX
> B>8{
> zWDOcCJg<p&$az-
> QYQ1V>g?kKsmbX=qVa1C^wX7Vj6f1&4e9f#BS0^h4RUs>^IQKZ|
> z=H`aiF#sVGIQbnBoc!oo&-
> Kc#P7znEt4>hpUK=Y++2Ojqz18;_uCK3WCH8a2iZad>
> zvWmC}M-
> 2z6&bqQ9an+@iVnx+lS9x5qq8cj@h}D$>h2T1`S5_ysKR!Oz1<1$W8e?{2
> z1rEfO0fn%}%4!C<@}O4C%2Z|cIB~XRVqB9gALopRzY_P(k5t-
> sW#5a&DL4;RIe+G`
> zvC6=4O^dPON$G10URQ29qaIF>l}W;W)QR^^PF2$prjjPB%86`;jlfU@`Yz!y;^S
> P#
> z7^QDcr>bxF@#0n3c%$^qOjUh5jva5p#vY|_{-
> &y&SYy>#l@lnBY<1OGl@lnBY<1OG
> zl@lnB{B(6y_^nPkf$~Vl3QCsW%11{ehtpmuRTi(2YU81j9xiF~t2yTBRK?a3gOjC
> E
> z(u*;jy*gDP61{BC?lkb{f%p#tJS;a-2{)CMy=`)FaZ!$lk@c{`i(Y&!htuz648n>U
> zY(==ez6lv4Q_sKLJ8Z~_Vt`s~IzhJvwMipgHVrGcHDT<9l}M*k^;7gO*^z+aA}jq
> n
> zVhxCI;ie*yYHx3kl3+Mh+C+JH?~8w>Yw>tSxxjXEa>8CZklCwY1^xEopADJ<g|
> G!!
> z;a47C`Z7?1?3ZViT2O?bOyJ}TAuKI@_s_i?g44PHEBmK9gYeNLW3!6+c^M%q78
> O10
> zHCy!mEqwEve#WR_YY?YT=QxzD14Y}ZGUXP=>s7w4Tuv4hGPB<DsdP}w=2Y
> nr#tNQ@
> z3&Sn85w#8!ZKq0Q=O^e==_<3FT0)k}tv+VZLCxt@F%kw@!FISbtlUPzRkGp|<
> Dl-g
> za3od^S2-Vz9F`Rc(9oLcTy!c1Heou37PfF*S$9^K8?^9nm8{4ib6LX;jB!@ToXe7|
> zkjHSLdYQA_SPLuOotjQ4Cq4dVG-
> C845*Qb_XNV|}6W7D&pX(Wxl};@Vt!t2rG&0GA
> z4Z;e-;(uv~YMsYQnzCK1JG3x5bvf7t83B1#=*wluLCtU-
> Q@Dm=#aWaat7ipmZk2%*
> zZgn~}JFp1T6J%Wsb!T@3clsA|u7%ZNQmt2GRZee{Sh=f^9d_O+mGjZaUaYj^
> ^0s|Z
> z%n9Zbx+{aq=Cz%v)M%{gWW`V13)Gbn%kT4Pd$sBbvW~9Wdu8htY-
> _Nyi#5&tUNlcB
> zPOWn+b@olTVXR7~-
> z!Ghu8frq>g)mQsuzcnV3pcf<%wljSw{_6f!*qA8OT$p_Nc$9
> zicC_T#wtZ7`WvgrB;{$WQe>jPv5HJmp2jLg#`z5t_RhcFL#mpNFqJe}RZe6(>?H6
> 5
> D{aYn_
> 
> literal 0
> HcmV?d00001
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboard.h
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboard.h
> new file mode 100644
> index 0000000000..debd4346c7
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboard.h
> @@ -0,0 +1,777 @@
> +/** @file
> 
> +  Header file for Virtual Keyboard driver.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#ifndef _VIRTUAL_KEYBOARD_H_
> 
> +#define _VIRTUAL_KEYBOARD_H_
> 
> +
> 
> +#include <Uefi.h>
> 
> +#include <Library/BaseMemoryLib.h>
> 
> +#include <Library/DebugLib.h>
> 
> +#include <Library/MemoryAllocationLib.h>
> 
> +#include <Library/UefiBootServicesTableLib.h>
> 
> +#include <Library/UefiDriverEntryPoint.h>
> 
> +#include <Library/UefiLib.h>
> 
> +#include <Library/BaseLib.h>
> 
> +#include <Library/PcdLib.h>
> 
> +#include <Library/HiiLib.h>
> 
> +#include <Protocol/AbsolutePointer.h>
> 
> +#include <Protocol/GraphicsOutput.h>
> 
> +#include <Protocol/SimpleTextIn.h>
> 
> +#include <Protocol/SimpleTextInEx.h>
> 
> +#include <Protocol/SimpleTextOut.h>
> 
> +#include <Protocol/HiiDatabase.h>
> 
> +#include <Protocol/HiiImageEx.h>
> 
> +#include <Protocol/HiiPackageList.h>
> 
> +#include <Guid/ConsoleInDevice.h>
> 
> +#include "ComponentName.h"
> 
> +
> 
> +//
> 
> +// Global Variables
> 
> +//
> 
> +extern EFI_DRIVER_BINDING_PROTOCOL   gVirtualKeyboardDriverBinding;
> 
> +extern EFI_COMPONENT_NAME_PROTOCOL
> gVirtualKeyboardComponentName;
> 
> +extern EFI_COMPONENT_NAME2_PROTOCOL
> gVirtualKeyboardComponentName2;
> 
> +
> 
> +///
> 
> +/// Debug raw data points
> 
> +///
> 
> +#define DEBUG_VK_POINTS               0x40000000
> 
> +
> 
> +///
> 
> +/// Debug data point scaling
> 
> +///
> 
> +#define DEBUG_VK_POINT_SCALING        0x20000000
> 
> +
> 
> +///
> 
> +/// Debug key press
> 
> +///
> 
> +#define DEBUG_VK_KEYS                 0x10000000
> 
> +
> 
> +///
> 
> +/// Debug routine entry and exit
> 
> +///
> 
> +#define DEBUG_VK_ROUTINE_ENTRY_EXIT   0x08000000
> 
> +
> 
> +///
> 
> +/// Display the graphics info
> 
> +///
> 
> +#define DEBUG_VK_GRAPHICS_INFO        0x04000000
> 
> +
> 
> +///
> 
> +/// Display the timer entry and exit
> 
> +///
> 
> +#define DEBUG_VK_TIMER_ENTRY_EXIT     0x00100000
> 
> +
> 
> +///
> 
> +/// Signature
> 
> +///
> 
> +#define VK_SIGNATURE                  SIGNATURE_32 ('V', 'K', 'e', 'y')
> 
> +#define VK_NOTIFY_SIGNATURE           SIGNATURE_32 ('V', 'K', 'n', 's')
> 
> +
> 
> +///
> 
> +/// Poll interval
> 
> +///
> 
> +#define VK_POLL_INTERVAL              (1000 * 1000)
> 
> +
> 
> +///
> 
> +/// Define the touch timeout in poll intervals
> 
> +///
> 
> +#define VK_REPEAT_TIMEOUT             5
> 
> +
> 
> +///
> 
> +/// TPL used to synchronize add/remove from list
> 
> +///
> 
> +#define TPL_VK_SYNC                   TPL_NOTIFY
> 
> +
> 
> +///
> 
> +/// Dimension of an array ( number of elements )
> 
> +///
> 
> +#define DIM(x)      ( sizeof ( x ) / sizeof ( x [ 0 ]))
> 
> +
> 
> +///
> 
> +/// Define Key buffer
> 
> +///
> 
> +#define MAX_KEY_BUF_SIZE 64
> 
> +
> 
> +///
> 
> +/// Define Transparent Weight
> 
> +///
> 
> +#define TRANSPARENCY_WEIGHT 50
> 
> +
> 
> +typedef struct _VK_CONTEXT VK_CONTEXT;
> 
> +
> 
> +typedef enum _VK_KEY_TYPE {
> 
> +  VkKeyNull         = 0x0000 | CHAR_NULL,
> 
> +  VkKeyBackspace    = 0x0000 | CHAR_BACKSPACE,
> 
> +  VkKeyTab          = 0x0000 | CHAR_TAB,
> 
> +  VkKeyEnter        = 0x0000 | CHAR_CARRIAGE_RETURN,
> 
> +  VkKeyScanMask     = 0x1000,
> 
> +  VkKeyEsc          = 0x1000 | SCAN_ESC,
> 
> +  VkKeyLeft         = 0x1000 | SCAN_LEFT,
> 
> +  VkKeyRight        = 0x1000 | SCAN_RIGHT,
> 
> +  VkKeyUp           = 0x1000 | SCAN_UP,
> 
> +  VkKeyDown         = 0x1000 | SCAN_DOWN,
> 
> +  VkKeyF1           = 0x1000 | SCAN_F1,
> 
> +  VkKeyF2           = 0x1000 | SCAN_F2,
> 
> +  VkKeyF3           = 0x1000 | SCAN_F3,
> 
> +  VkKeyF4           = 0x1000 | SCAN_F4,
> 
> +  VkKeyF5           = 0x1000 | SCAN_F5,
> 
> +  VkKeyF6           = 0x1000 | SCAN_F6,
> 
> +  VkKeyF7           = 0x1000 | SCAN_F7,
> 
> +  VkKeyF8           = 0x1000 | SCAN_F8,
> 
> +  VkKeyF9           = 0x1000 | SCAN_F9,
> 
> +  VkKeyF10          = 0x1000 | SCAN_F10,
> 
> +  VkKeyF11          = 0x1000 | SCAN_F11,
> 
> +  VkKeyF12          = 0x1000 | SCAN_F12,
> 
> +  VkKeySpecificMask = 0x2000,
> 
> +  VkKeyShift        = 0x2000 | 0x0000,
> 
> +  VkKeyCapslock     = 0x2000 | 0x0001,
> 
> +  VkKeyTwoPage      = 0x2000 | 0x0002,
> 
> +  VkKeyTypeMaximum  = 0xFFFF
> 
> +} VK_KEY_TYPE;
> 
> +
> 
> +typedef enum _VK_PAGE_TYPE {
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | q | w | e | r | t | y | u | i | o | p |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | | a | s | d | f | g | h | j | k | l | F2| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Caps | z | x | c | v | b | n | m |aU |Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage0,
> 
> +
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | Q | W | E | R | T | Y | U | I | O | P |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | | A | S | D | F | G | H | J | K | L | F2| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Caps | Z | X | C | V | B | N | M |aU |Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage1,
> 
> +
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Shift| . | ; | ' | , | . | / |F11|F12|Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       | \ | - | = | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage2,
> 
> +
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | ! | @ | # | $ | % | ^ | & | * | ( | ) |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Shift| ~ | : | " | < | > | ? |F11|F12|Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       | | | _ | + | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage3,
> 
> +  VkPageMaximum
> 
> +} VK_PAGE_TYPE;
> 
> +
> 
> +typedef enum VK_DISPLAY_ATTRIBUTE {
> 
> +  VkDisplayAttributeNone,         /// No keyboard displayed
> 
> +  VkDisplayAttributeFullTop,      /// Full keyboard display at top
> 
> +  VkDisplayAttributeFullBottom,   /// Full keyboard display at bottom
> 
> +  VkDisplayAttributeSimpleTop,    /// Simple keyboard display at top
> 
> +  VkDisplayAttributeSimpleBottom, /// Simple keyboard display at bottom
> 
> +  VkDisplayAttributeMaximum
> 
> +} VK_DISPLAY_ATTRIBUTE;
> 
> +
> 
> +typedef struct _VK_STRUCT {
> 
> +  UINT16      DisStartX;
> 
> +  UINT16      DisStartY;
> 
> +  UINT16      DisEndX;
> 
> +  UINT16      DisEndY;
> 
> +  VK_KEY_TYPE PageFont[VkPageMaximum];
> 
> +} VK_STRUCT;
> 
> +
> 
> +typedef struct _VK_NOTIFY {
> 
> +  UINTN                               Signature;
> 
> +  EFI_KEY_DATA                        KeyData;
> 
> +  EFI_KEY_NOTIFY_FUNCTION             KeyNotificationFn;
> 
> +  LIST_ENTRY                          NotifyEntry;
> 
> +} VK_NOTIFY;
> 
> +
> 
> +///
> 
> +/// Virtual Keyboard context
> 
> +///
> 
> +struct _VK_CONTEXT {
> 
> +  ///
> 
> +  /// Structure identification
> 
> +  ///
> 
> +  UINTN                             Signature;
> 
> +
> 
> +  ///
> 
> +  /// Controller Handle
> 
> +  ///
> 
> +  EFI_HANDLE                        Controller;
> 
> +
> 
> +  ///
> 
> +  /// Upper level API
> 
> +  ///
> 
> +  EFI_SIMPLE_TEXT_INPUT_PROTOCOL    SimpleTextIn;
> 
> +
> 
> +  ///
> 
> +  /// Simple Text In EX
> 
> +  ///
> 
> +  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleTextInEx;
> 
> +
> 
> +  ///
> 
> +  /// Lower level APIs
> 
> +  ///
> 
> +  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL      *GraphicsOutput;
> 
> +
> 
> +  ///
> 
> +  /// Flag when the last poll indicated a touch event
> 
> +  ///
> 
> +  BOOLEAN                           TouchActive;
> 
> +
> 
> +  ///
> 
> +  /// Time to poll for touch input
> 
> +  ///
> 
> +  EFI_EVENT                         TimerEvent;
> 
> +
> 
> +  ///
> 
> +  /// HII handle to get image data used
> 
> +  ///
> 
> +  EFI_HII_HANDLE                    HiiHandle;
> 
> +  EFI_HII_IMAGE_EX_PROTOCOL         *HiiImageEx;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard body background buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *VkBodyBackgroundBltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *VkBodyCompoundBltBuffer;
> 
> +  UINTN                             VkBodyBltSize;
> 
> +  UINTN                             VkBodyBltStartX;
> 
> +  UINTN                             VkBodyBltStartY;
> 
> +  UINTN                             VkBodyBltHeight;
> 
> +  UINTN                             VkBodyBltWidth;
> 
> +  BOOLEAN                           IsBackgroundChanged;
> 
> +
> 
> +  ///
> 
> +  /// Icon buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *IconBltBuffer;
> 
> +  UINTN                             IconBltSize;
> 
> +  UINTN                             IconBltHeight;
> 
> +  UINTN                             IconBltWidth;
> 
> +
> 
> +  ///
> 
> +  /// Full icon background buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *FullIconBackBuffer;
> 
> +  UINTN                             FullIconBackStartX;
> 
> +  UINTN                             FullIconBackStartY;
> 
> +  UINTN                             FullIconBackHeight;
> 
> +  UINTN                             FullIconBackWidth;
> 
> +  UINTN                             FullIconBackSize;
> 
> +  BOOLEAN                           FullIconUpdatedFlag;
> 
> +
> 
> +  ///
> 
> +  /// Simple icon background buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *SimIconBackBuffer;
> 
> +  UINTN                             SimIconBackStartX;
> 
> +  UINTN                             SimIconBackStartY;
> 
> +  UINTN                             SimIconBackHeight;
> 
> +  UINTN                             SimIconBackWidth;
> 
> +  UINTN                             SimIconBackSize;
> 
> +  BOOLEAN                           SimIconUpdatedFlag;
> 
> +
> 
> +  ///
> 
> +  /// Small Icon
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *SmallIcon;
> 
> +
> 
> +  ///
> 
> +  /// Full Icon
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *FullIcon;
> 
> +
> 
> +  ///
> 
> +  /// Simple Key body
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *SimKeyBody;
> 
> +
> 
> +  ///
> 
> +  /// Digital key body
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *DigKeyBody;
> 
> +
> 
> +  ///
> 
> +  /// Capital Letter Key board
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *CapLeKeyBody;
> 
> +
> 
> +  ///
> 
> +  /// Screen check buffer.
> 
> +  /// This is used to check if screen is kept scrolling up.
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *ScreenCheckBuffer;
> 
> +  UINTN                             ScreenCheckBufferSize;
> 
> +
> 
> +  ///
> 
> +  /// Key state
> 
> +  ///
> 
> +  BOOLEAN                           KeyPressed;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard display status
> 
> +  ///
> 
> +  VK_DISPLAY_ATTRIBUTE              CurrentKeyboardDisplay;
> 
> +  VK_DISPLAY_ATTRIBUTE              TargetKeyboardDisplay;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard icon display status
> 
> +  ///
> 
> +  BOOLEAN                           IsIconShowed;
> 
> +  UINT8                             IconReDrawCheck;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard body Image address
> 
> +  /// Size of KeyboardBodyPtr must larger than mFullKeyboardBody
> 
> +  ///
> 
> +  UINT32                            NumOfKeysInfo;
> 
> +  VK_STRUCT                         KeyboardBodyPtr[50];
> 
> +
> 
> +  ///
> 
> +  /// KeyBuffer
> 
> +  ///
> 
> +  EFI_EVENT                         KeyNotifyProcessEvent;
> 
> +  EFI_KEY_TOGGLE_STATE              KeyToggleState;
> 
> +  EFI_KEY_DATA                      Keybuffer[MAX_KEY_BUF_SIZE];
> 
> +  UINT8                             KeyStartIndex;
> 
> +  UINT8                             KeyEndIndex;
> 
> +  UINT16                            KeyTouchedTimeOut;
> 
> +  BOOLEAN                           IsShiftKeyFlag;
> 
> +  BOOLEAN                           IsCapsLockFlag;
> 
> +  BOOLEAN                           IsSupportPartialKey;
> 
> +  BOOLEAN                           IsRedrawUpdateUI;
> 
> +  VK_PAGE_TYPE                      PageNumber;
> 
> +  LIST_ENTRY                        NotifyList;
> 
> +};
> 
> +
> 
> +///
> 
> +/// Locate VK_CONTEXT from protocol
> 
> +///
> 
> +#define VK_CONTEXT_FROM_PROTOCOL(a)                CR (a, VK_CONTEXT,
> SimpleTextIn, VK_SIGNATURE)
> 
> +#define VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(a) CR (a,
> VK_CONTEXT, SimpleTextInEx, VK_SIGNATURE)
> 
> +#define VK_CONTEXT_FROM_VKBD_PROTOCOL(a)           CR (a,
> VK_CONTEXT, VkbdProtocol, VK_SIGNATURE)
> 
> +
> 
> +/**
> 
> +  Start the virtual keyboard driver
> 
> +
> 
> +  This routine allocates the necessary resources for the driver.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStart to complete the driver
> 
> +  initialization.
> 
> +
> 
> +  @param[in, out] VkContext        Address of an VK_CONTEXT structure
> 
> +  @param[in] Controller            Handle of device to work with.
> 
> +
> 
> +  @retval EFI_SUCCESS              Driver API properly initialized
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkApiStart (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN EFI_HANDLE Controller
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Stop the virtual keyboard driver
> 
> +
> 
> +  This routine releases the resources allocated by VKApiStart.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStop to initiate the driver
> 
> +  shutdown.
> 
> +
> 
> +  @param[in] VkContext        Address of an VK_CONTEXT structure
> 
> +
> 
> +**/
> 
> +VOID
> 
> +VkApiStop (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Resets the input device hardware.
> 
> +
> 
> +  The Reset() function resets the input device hardware. As part
> 
> +  of initialization process, the firmware/device will make a quick
> 
> +  but reasonable attempt to verify that the device is functioning.
> 
> +  If the ExtendedVerification flag is TRUE the firmware may take
> 
> +  an extended amount of time to verify the device is operating on
> 
> +  reset. Otherwise the reset operation is to occur as quickly as
> 
> +  possible. The hardware verification process is not defined by
> 
> +  this specification and is left up to the platform firmware or
> 
> +  driver to implement.
> 
> +
> 
> +  @param[in] This                 A pointer to the
> EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
> 
> +
> 
> +  @param[in] ExtendedVerification Indicates that the driver may perform a
> more exhaustive
> 
> +                                  verification operation of the device during reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and
> could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReset (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  IN BOOLEAN                        ExtendedVerification
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device. The WaitForKey Event
> can
> 
> +  be used to test for existence of a keystroke via WaitForEvent () call.
> 
> +
> 
> +  @param[in]  This         Protocol instance pointer.
> 
> +  @param[out] Key          Driver may perform diagnostics on reset.
> 
> +
> 
> +  @retval EFI_SUCCESS      The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY    There was no keystroke data available.
> 
> +  @retval EFI_DEVICE_ERROR The keystroke information was not returned
> due to
> 
> +                           hardware errors.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStroke (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  OUT EFI_INPUT_KEY                  *Key
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Resets the input device hardware.
> 
> +
> 
> +  The Reset() function resets the input device hardware. As part
> 
> +  of initialization process, the firmware/device will make a quick
> 
> +  but reasonable attempt to verify that the device is functioning.
> 
> +  If the ExtendedVerification flag is TRUE the firmware may take
> 
> +  an extended amount of time to verify the device is operating on
> 
> +  reset. Otherwise the reset operation is to occur as quickly as
> 
> +  possible. The hardware verification process is not defined by
> 
> +  this specification and is left up to the platform firmware or
> 
> +  driver to implement.
> 
> +
> 
> +  @param[in] This                 A pointer to the
> EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
> 
> +
> 
> +  @param[in] ExtendedVerification Indicates that the driver may perform a
> more exhaustive
> 
> +                                  verification operation of the device during reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and
> could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardResetEx (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN BOOLEAN                           ExtendedVerification
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device.
> 
> +
> 
> +  @param[in]  This               Protocol instance pointer.
> 
> +  @param[out] KeyData            A pointer to a buffer that is filled in with the
> keystroke
> 
> +                                 state data for the key that was pressed.
> 
> +
> 
> +  @retval EFI_SUCCESS            The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY          There was no keystroke data available.
> 
> +  @retval EFI_INVALID_PARAMETER  This or KeyData is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStrokeEx (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  OUT EFI_KEY_DATA                      *KeyData
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Set certain state for the input device.
> 
> +
> 
> +  @param[in] This                 Protocol instance pointer.
> 
> +  @param[in] KeyToggleState       A pointer to the EFI_KEY_TOGGLE_STATE
> to set the
> 
> +                                  state for the input device.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device state was set appropriately.
> 
> +  @retval EFI_INVALID_PARAMETER   This or KeyToggleState is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardSetState (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_KEY_TOGGLE_STATE              *KeyToggleState
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Register a notification function for a particular keystroke for the input
> device.
> 
> +
> 
> +  @param[in]  This                        Protocol instance pointer.
> 
> +  @param[in]  KeyData                     A pointer to a buffer that is filled in with
> the keystroke
> 
> +                                          information data for the key that was pressed.
> 
> +  @param[in]  KeyNotificationFunction     Points to the function to be called
> when the key
> 
> +                                          sequence is typed specified by KeyData.
> 
> +  @param[out] NotifyHandle                Points to the unique handle assigned to
> the registered notification.
> 
> +
> 
> +  @retval EFI_SUCCESS                     The notification function was registered
> successfully.
> 
> +  @retval EFI_OUT_OF_RESOURCES            Unable to allocate resources for
> necessary data structures.
> 
> +  @retval EFI_INVALID_PARAMETER           KeyData or NotifyHandle or
> KeyNotificationFunction is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardRegisterKeyNotify (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN  EFI_KEY_DATA                      *KeyData,
> 
> +  IN  EFI_KEY_NOTIFY_FUNCTION           KeyNotificationFunction,
> 
> +  OUT EFI_HANDLE                        *NotifyHandle
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Remove a registered notification function from a particular keystroke.
> 
> +
> 
> +  @param[in] This                Protocol instance pointer.
> 
> +  @param[in] NotificationHandle  The handle of the notification function
> being unregistered.
> 
> +
> 
> +  @retval EFI_SUCCESS            The notification function was unregistered
> successfully.
> 
> +  @retval EFI_INVALID_PARAMETER  The NotificationHandle is invalid
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardUnregisterKeyNotify (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                        NotificationHandle
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Draw key board on the display
> 
> +
> 
> +  @param[in] VkContext          Graphic Protocol for draw the alphabet.
> 
> +
> 
> +  @retval EFI_SUCCESS           Draw keyboard was done.
> 
> +  @retval EFI_UNSUPPORTED       Did not get key mapping table.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +DrawKeyboardLayout (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Clear the keyboard body
> 
> +
> 
> +  @param[in] VkContext          Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkBody (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Clear the keyboard icon
> 
> +
> 
> +  @param[in] VkContext          Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkIcon (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard icon.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics
> and keyboard icon displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkIcon (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics
> and keyboard displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkBody (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Get unicode by VkContext->PageNumber and VkContext-
> >KeyboardBodyPtr.
> 
> +
> 
> +  @param[in]  VkContext            Address of an VK_CONTEXT structure.
> 
> +  @param[in]  KeyItem              Key Item.
> 
> +  @param[out] FontPtr              Follow VkContext->PageNumber to translate
> 
> +                                   font unicode.
> 
> +
> 
> +  @retval EFI_SUCCESS              Finish translating FontPtr.
> 
> +  @retval EFI_INVALID_PARAMETER    VkContext or FontPtr is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkGetMappingFont (
> 
> +  IN  VK_CONTEXT *VkContext,
> 
> +  IN  VK_STRUCT  KeyItem,
> 
> +  OUT UINT32     *FontPtr
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This routine is used to check if icon has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckIconCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  ConvertCoordinate - Convert the touch panel's coordinate to display's
> coordinate.
> 
> +
> 
> +  @param[in]  VkContext             Virtual Keyboard context.
> 
> +  @param[in]  Point                 The coordinate reported from touch panel.
> 
> +  @param[out] TouchX                The coordinate X converted to display panel.
> 
> +  @param[out] TouchY                The coordinate Y converted to display panel..
> 
> +
> 
> +  @retval EFI_SUCCESS               Convert success.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +ConvertCoordinate (
> 
> +  IN  VK_CONTEXT                 *VkContext,
> 
> +  IN  EFI_ABSOLUTE_POINTER_STATE Point,
> 
> +  OUT UINT32                     *TouchX,
> 
> +  OUT UINT32                     *TouchY
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This routine is used to check if screen has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckScreenCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This routine is used to check if background beneath virtual keyboard has
> been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckBackgroundChanged (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  To prevent screen keyboard layout occur scroll up
> 
> +
> 
> +  @param[in]  VkContext            Address of an VK_CONTEXT structure.
> 
> +
> 
> +**/
> 
> +VOID
> 
> +PreventScreenScrollUp (
> 
> +  IN OUT VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +SetCharacterPosition (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     DestX,
> 
> +  IN UINT32     DestY
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +KeyboardLayoutHandler (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     Index
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINTN      BltSize
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +RestoreVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkIconBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT           *VkContext,
> 
> +  IN VK_DISPLAY_ATTRIBUTE IconType
> 
> +  );
> 
> +#endif
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboardDriver.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboardDriver.c
> new file mode 100644
> index 0000000000..42ad493a9f
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboardDriver.c
> @@ -0,0 +1,541 @@
> +/** @file
> 
> +  Virtual Keyboard driver.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +UINT32         mOrigConOutRow      = 0;
> 
> +UINT32         mOrigSetupConOutRow = 0;
> 
> +EFI_HII_HANDLE mHiiHandle          = NULL;
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverSupported (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStart (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStop (
> 
> +  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  Controller,
> 
> +  IN  UINTN                       NumberOfChildren,
> 
> +  IN  EFI_HANDLE                  *ChildHandleBuffer
> 
> +  );
> 
> +
> 
> +EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = {
> 
> +  VirtualKeyboardDriverSupported,
> 
> +  VirtualKeyboardDriverStart,
> 
> +  VirtualKeyboardDriverStop,
> 
> +  0x10,
> 
> +  NULL,
> 
> +  NULL
> 
> +};
> 
> +
> 
> +/**
> 
> +  This is the declaration of an EFI image entry point. This entry point is
> 
> +  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
> 
> +  both device drivers and bus drivers.
> 
> +
> 
> +  @param  ImageHandle           The firmware allocated handle for the UEFI
> image.
> 
> +  @param  SystemTable           A pointer to the EFI System Table.
> 
> +
> 
> +  @retval EFI_SUCCESS           The operation completed successfully.
> 
> +  @retval Others                An unexpected error occurred.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverEntryPoint (
> 
> +  IN EFI_HANDLE       ImageHandle,
> 
> +  IN EFI_SYSTEM_TABLE *SystemTable
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                     Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverEntryPoint Start\n"));
> 
> +  //
> 
> +  // Install UEFI Driver Model protocol(s).
> 
> +  //
> 
> +  Status = EfiLibInstallDriverBindingComponentName2 (
> 
> +             ImageHandle,
> 
> +             SystemTable,
> 
> +             &gVirtualKeyboardDriverBinding,
> 
> +             ImageHandle,
> 
> +             &gVirtualKeyboardComponentName,
> 
> +             &gVirtualKeyboardComponentName2
> 
> +             );
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  mHiiHandle = HiiAddPackages (
> 
> +                 &gEfiCallerIdGuid,
> 
> +                 NULL,
> 
> +                 VirtualKeyboardDxeImages,
> 
> +                 NULL
> 
> +                 );
> 
> +  ASSERT (mHiiHandle != NULL);
> 
> +
> 
> +  mOrigConOutRow      = PcdGet32 (PcdConOutRow);
> 
> +  mOrigSetupConOutRow = PcdGet32 (PcdSetupConOutRow);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverEntryPoint End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Verify the controller type
> 
> +
> 
> +  This routine determines if the pointer and GOP are available.
> 
> +
> 
> +  This routine is called by the UEFI driver framework during connect
> 
> +  processing.
> 
> +
> 
> +  @param[in] DriverBinding        Protocol instance pointer.
> 
> +  @param[in] Controller           Handle of device to test.
> 
> +  @param[in] RemainingDevicePath  Not used.
> 
> +
> 
> +  @retval EFI_SUCCESS             This driver supports this device.
> 
> +  @retval other                   This driver does not support this device.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverSupported (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  )
> 
> +{
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
> 
> +  EFI_STATUS                    Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverSupported Start\n"));
> 
> +
> 
> +  //
> 
> +  // Verify that the driver is not already started
> 
> +  //
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (!EFI_ERROR (Status)) {
> 
> +    Status = EFI_ALREADY_STARTED;
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK has already
> initialized\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Determine if the pointer protocol is available.
> 
> +  // This should be installed in touch driver.
> 
> +  //
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiAbsolutePointerProtocolGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Absolute
> pointer protocol not found\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiTouchPanelGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Touch Panel
> Guid not found\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Determine if the graphics output protocol is available
> 
> +  //
> 
> +  Status = gBS->HandleProtocol (
> 
> +                  gST->ConsoleOutHandle,
> 
> +                  &gEfiGraphicsOutputProtocolGuid,
> 
> +                  (VOID **)&GraphicsOutput
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Graphics
> output protocol not found\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO,
> "VirtualKeyboardDriverSupported Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverSupported Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverSupported End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Connect to the controller
> 
> +
> 
> +  This routine initializes an instance of the virutal keyboard driver for this
> 
> +  controller.
> 
> +
> 
> +  This routine is called by the UEFI driver framework during connect
> 
> +  processing if the controller passes the tests in I2cBusDriverSupported.
> 
> +
> 
> +  @param[in] DriverBinding        Protocol instance pointer.
> 
> +  @param[in] Controller           Handle of device to work with.
> 
> +  @param[in] RemainingDevicePath  Not used, always produce all possible
> children.
> 
> +
> 
> +  @retval EFI_SUCCESS             This driver is added to Controller.
> 
> +  @retval other                   This driver does not support this device.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStart (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT *VkContext;
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO,
> "VirtualKeyboardDriverStart Start\n"));
> 
> +
> 
> +  VkContext = AllocateZeroPool (sizeof (VK_CONTEXT));
> 
> +  if (VkContext == NULL) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> No memory for virtual keyboard driver\n"));
> 
> +    Status = EFI_OUT_OF_RESOURCES;
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiAbsolutePointerProtocolGuid,
> 
> +                  (VOID**) &VkContext->AbsolutePointer,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to open absolute pointer protocol, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiTouchPanelGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> TouchPanel GUID not found, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->HandleProtocol (
> 
> +                  gST->ConsoleOutHandle,
> 
> +                  &gEfiGraphicsOutputProtocolGuid,
> 
> +                  (VOID**) &VkContext->GraphicsOutput
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Graphics output protocol not available, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext->HiiHandle = mHiiHandle;
> 
> +  Status = VkApiStart (VkContext, Controller);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to VkApiStart, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> 
> +                  &Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  VkContext,
> 
> +                  &gEfiSimpleTextInProtocolGuid,
> 
> +                  &VkContext->SimpleTextIn,
> 
> +                  &gEfiSimpleTextInputExProtocolGuid,
> 
> +                  &VkContext->SimpleTextInEx,
> 
> +                  &gEfiConsoleInDeviceGuid,
> 
> +                  NULL,
> 
> +                  NULL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR -
> Failed to install VK protocols, Status: %r\n", Status));
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO,
> "VirtualKeyboardDriverStart Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  if (VkContext != NULL) {
> 
> +    FreePool (VkContext);
> 
> +  }
> 
> +
> 
> +  gBS->CloseProtocol (
> 
> +         Controller,
> 
> +         &gEfiAbsolutePointerProtocolGuid,
> 
> +         This->DriverBindingHandle,
> 
> +         Controller
> 
> +         );
> 
> +
> 
> +  //
> 
> +  // Restore setting if connect device fail.
> 
> +  //
> 
> +  PcdSet32S (PcdConOutRow, mOrigConOutRow);
> 
> +  PcdSet32S (PcdSetupConOutRow, mOrigSetupConOutRow);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStart
> Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStart
> End\n"));
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Disconnect from the controller.
> 
> +
> 
> +  This routine disconnects from the controller.
> 
> +
> 
> +  This routine is called by DriverUnload when the I2C bus driver
> 
> +  is being unloaded.
> 
> +
> 
> +  @param[in] DriverBinding        Protocol instance pointer.
> 
> +  @param[in] Controller           Handle of device to stop driver on.
> 
> +  @param[in] NumberOfChildren     How many children need to be stopped.
> 
> +  @param[in] ChildHandleBuffer    Not used.
> 
> +
> 
> +  @retval EFI_SUCCESS             This driver is removed Controller.
> 
> +  @retval EFI_DEVICE_ERROR        The device could not be stopped due to a
> device error.
> 
> +  @retval other                   This driver was not removed from this device.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStop (
> 
> +  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  Controller,
> 
> +  IN  UINTN                       NumberOfChildren,
> 
> +  IN  EFI_HANDLE                  *ChildHandleBuffer
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT                          *VkContext;
> 
> +  EFI_STATUS                          Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop
> Start\n"));
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  (VOID**)&VkContext,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER |
> EFI_OPEN_PROTOCOL_EXCLUSIVE
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    Status = EFI_SUCCESS;
> 
> +    goto Success;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Done with the driver protocol
> 
> +  //
> 
> +  Status = gBS->CloseProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to close the
> VK protocol, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Remove ConsoleIn protocols first to close the link in ConSplitter
> 
> +  //
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiConsoleInDeviceGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to uninstall
> the protocols, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Remove the remaining protocols
> 
> +  //
> 
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  VkContext,
> 
> +                  &gEfiSimpleTextInProtocolGuid,
> 
> +                  &VkContext->SimpleTextIn,
> 
> +                  &gEfiSimpleTextInputExProtocolGuid,
> 
> +                  &VkContext->SimpleTextInEx,
> 
> +                  &gEfiConsoleInDeviceGuid,
> 
> +                  NULL,
> 
> +                  NULL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to uninstall
> the protocols, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Stop the driver
> 
> +  //
> 
> +  VkApiStop (VkContext);
> 
> +
> 
> +  //
> 
> +  // Release the pointer protocol upon failure
> 
> +  //
> 
> +  Status = gBS->CloseProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiAbsolutePointerProtocolGuid,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to close
> absolute pointer protocol, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Release VkContext
> 
> +  //
> 
> +  if (VkContext != NULL) {
> 
> +    FreePool (VkContext);
> 
> +  }
> 
> +
> 
> +Success:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop
> Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop
> Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop
> End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Unloads an image.
> 
> +
> 
> +  @param[in] ImageHandle        Handle that identifies the image to be
> unloaded.
> 
> +
> 
> +  @retval EFI_SUCCESS           The image has been unloaded.
> 
> +  @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image
> handle.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverUnload (
> 
> +  IN EFI_HANDLE ImageHandle
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                 Status;
> 
> +  EFI_HANDLE                 *HandleBuffer;
> 
> +  UINTN                      HandleCount;
> 
> +  UINTN                      Index;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverUnload Start\n"));
> 
> +
> 
> +  //
> 
> +  // Retrieve array of all handles in the handle database
> 
> +  //
> 
> +  Status = gBS->LocateHandleBuffer (
> 
> +                  AllHandles,
> 
> +                  NULL,
> 
> +                  NULL,
> 
> +                  &HandleCount,
> 
> +                  &HandleBuffer
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to locate
> handle buffer, Status: %r\n", Status));
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Disconnect the current driver from handles in the handle database
> 
> +  //
> 
> +  for (Index = 0; Index < HandleCount; Index++) {
> 
> +    gBS->DisconnectController (HandleBuffer[Index], ImageHandle, NULL);
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Free the array of handles
> 
> +  //
> 
> +  if (HandleBuffer != NULL) {
> 
> +    FreePool (HandleBuffer);
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Uninstall protocols installed in the driver entry point
> 
> +  //
> 
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> 
> +                  ImageHandle,
> 
> +                  &gEfiDriverBindingProtocolGuid,
> 
> +                  &gVirtualKeyboardDriverBinding,
> 
> +                  &gEfiComponentNameProtocolGuid,
> 
> +                  &gVirtualKeyboardComponentName,
> 
> +                  &gEfiComponentName2ProtocolGuid,
> 
> +                  &gVirtualKeyboardComponentName2,
> 
> +                  NULL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  HiiRemovePackages (mHiiHandle);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverUnload Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverUnload Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT,
> "VirtualKeyboardDriverUnload End\n"));
> 
> +  return Status;
> 
> +}
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboardDxe.inf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboardDxe.inf
> new file mode 100644
> index 0000000000..9ecc99d5a7
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dDxe/VirtualKeyboardDxe.inf
> @@ -0,0 +1,77 @@
> +## @file
> 
> +# Instance of virtual keyboard driver binding protocol.
> 
> +#
> 
> +# Compliant with efi driver model, 1. VirtualKeyboardDriverSupported
> 
> +# determines if the pointer and GOP are available. 2.
> 
> +# VirtualKeyboardDriverStart initializes an instance of the virtual
> 
> +# keyboard driver for a particular controller. 3.
> 
> +# VirtualKeyboardDriverStop is called by DriverUnload when the I2C bus
> 
> +# driver is being unload.
> 
> +#
> 
> +# Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +  INF_VERSION                    = 0x00010017
> 
> +  BASE_NAME                      = VirtualKeyboardDxe
> 
> +  FILE_GUID                      = E4735AAC-9C27-493f-86EA-9EFF43D7ADCD
> 
> +  VERSION_STRING                 = 1.0
> 
> +  MODULE_TYPE                    = UEFI_DRIVER
> 
> +  ENTRY_POINT                    = VirtualKeyboardDriverEntryPoint
> 
> +  UNLOAD_IMAGE                   = VirtualKeyboardDriverUnload
> 
> +
> 
> +#
> 
> +#  VALID_ARCHITECTURES           = IA32 X64
> 
> +#  DRIVER_BINDING                = gVirtualKeyboardDriverBinding;
> 
> +#  COMPONENT_NAME                = gVirtualKeyboardComponentName;
> 
> +#  COMPONENT_NAME2               = gVirtualKeyboardComponentName2;
> 
> +#
> 
> +
> 
> +[LibraryClasses]
> 
> +  BaseMemoryLib
> 
> +  DebugLib
> 
> +  MemoryAllocationLib
> 
> +  UefiBootServicesTableLib
> 
> +  UefiDriverEntryPoint
> 
> +  UefiLib
> 
> +  PcdLib
> 
> +  HiiLib
> 
> +
> 
> +[Packages]
> 
> +  MdePkg/MdePkg.dec
> 
> +  MdeModulePkg/MdeModulePkg.dec
> 
> +
> UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
> 
> +
> 
> +[Pcd]
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow
> 
> +
> 
> +[Sources]
> 
> +  CapitalLetterKeyboard.bmp
> 
> +  DigitKeyboard.bmp
> 
> +  FullIcon.bmp
> 
> +  SimpleIcon.bmp
> 
> +  SimpleKeyboard.bmp
> 
> +  KeyboardLayout.idf
> 
> +  KeyboardLayout.c
> 
> +  ComponentName.c
> 
> +  Keyboard.c
> 
> +  VirtualKeyboard.h
> 
> +  VirtualKeyboardDriver.c
> 
> +
> 
> +[Protocols]
> 
> +  gEfiAbsolutePointerProtocolGuid               ## TO_START
> 
> +  gEfiDriverBindingProtocolGuid                 ## PRODUCES
> 
> +  gEfiGraphicsOutputProtocolGuid                ## TO_START
> 
> +  gEfiSimpleTextInProtocolGuid                  ## BY_START
> 
> +  gEfiSimpleTextInputExProtocolGuid             ## BY_START
> 
> +  gEfiHiiImageExProtocolGuid                    ## TO_START
> 
> +
> 
> +[Guids]
> 
> +  gEfiConsoleInDeviceGuid                       ## SOMETIMES_PRODUCES
> 
> +  gEfiTouchPanelGuid                            ## TO_START
> 
> +
> 
> +[Depex]
> 
> +  gEfiHiiDatabaseProtocolGuid
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dFeaturePkg.dec
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dFeaturePkg.dec
> new file mode 100644
> index 0000000000..2742a04a8f
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dFeaturePkg.dec
> @@ -0,0 +1,26 @@
> +## @file
> 
> +# This package provides advanced feature functionality for User
> Authentication support.
> 
> +# This package should only depend on EDK II Core packages, IntelSiliconPkg,
> and MinPlatformPkg.
> 
> +#
> 
> +# The DEC files are used by the utilities that parse DSC and
> 
> +# INF files to generate AutoGen.c and AutoGen.h files
> 
> +# for the build infrastructure.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +  DEC_SPECIFICATION = 0x00010017
> 
> +  PACKAGE_NAME      = VirtualKeyboardFeaturePkg
> 
> +  PACKAGE_GUID      = A40DFD69-3552-40E8-8D3D-89741B03B9E1
> 
> +  PACKAGE_VERSION   = 0.1
> 
> +
> 
> +[Includes]
> 
> +  Include
> 
> +
> 
> +[Guids]
> 
> +  ## GUID used for VirtualKeyboardDriver to open TouchPanel protocol.
> 
> +  gEfiTouchPanelGuid                               = { 0x91b1d27b, 0xe126, 0x48d1, { 0x82,
> 0x34, 0xd2, 0x8b, 0x81, 0xc8, 0x83, 0x62 }}
> 
> diff --git
> a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dFeaturePkg.dsc
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dFeaturePkg.dsc
> new file mode 100644
> index 0000000000..ab3605fa15
> --- /dev/null
> +++
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboar
> dFeaturePkg.dsc
> @@ -0,0 +1,30 @@
> +## @file
> 
> +# This is a build description file for the User Authentication advanced
> feature.
> 
> +# This package should only depend on EDK II Core packages, IntelSiliconPkg,
> and MinPlatformPkg.
> 
> +#
> 
> +# The DEC files are used by the utilities that parse DSC and
> 
> +# INF files to generate AutoGen.c and AutoGen.h files
> 
> +# for the build infrastructure.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +  PLATFORM_NAME                  = VirtualKeyboardFeaturePkg
> 
> +  PLATFORM_GUID                  = 6D396683-C82B-41D5-84E7-BB6E13B7C2BF
> 
> +  PLATFORM_VERSION               = 0.1
> 
> +  DSC_SPECIFICATION              = 0x00010005
> 
> +  OUTPUT_DIRECTORY               = Build/$(PLATFORM_NAME)
> 
> +  SUPPORTED_ARCHITECTURES        = IA32|X64
> 
> +  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
> 
> +  SKUID_IDENTIFIER               = DEFAULT
> 
> +  PEI_ARCH                       = IA32
> 
> +  DXE_ARCH                       = X64
> 
> +
> 
> +#
> 
> +# This package always builds the feature.
> 
> +#
> 
> +!include Include/VirtualKeyboardFeature.dsc
> 
> --
> 2.24.0.windows.2
> 
> 
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this group.
> 
> View/Reply Online (#56348): https://edk2.groups.io/g/devel/message/56348
> Mute This Topic: https://groups.io/mt/72555278/1768733
> Group Owner: devel+owner@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub  [eric.dong@intel.com]
> -=-=-=-=-=-=


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [edk2-devel] [PATCH] Features/Intel/UserInterface: Add VirtualKeyboardFeaturePkg
  2020-03-26  0:43 [PATCH] Features/Intel/UserInterface: Add VirtualKeyboardFeaturePkg Tan, Ming
  2020-04-01  5:40 ` [edk2-devel] " Dong, Eric
@ 2020-04-01  8:58 ` Ni, Ray
  1 sibling, 0 replies; 3+ messages in thread
From: Ni, Ray @ 2020-04-01  8:58 UTC (permalink / raw)
  To: devel@edk2.groups.io, Tan, Ming; +Cc: Dong, Eric

Ming,
1. Can you update all the "TODO" in Readme.md to fill with detailed information?
2. gEfiTouchPanelGuid contains the 'Efi' prefix but isn't defined in UEFI or PI spec. Can you please rename it to "gEdkiiTouchPanelGuid"?
    Because there is no header file associated with this GUID, the rename without changing the GUID value may have no impact to other code.
3. Can you please evaluate all the debug messages controlled by DEBUG_VK_* macro? Can some debug messages be removed? Can the proper
    debug error level (ERROR, WARN, INFO, VERBOSE) be assigned to the remaining debug messages?
    I would like to remove all the DEBUG_VK_* macros.

4. Can you please check whether the code can pass ECC check?

Thanks,
Ray

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Tan, Ming
> Sent: Thursday, March 26, 2020 8:44 AM
> To: devel@edk2.groups.io
> Subject: [edk2-devel] [PATCH] Features/Intel/UserInterface: Add VirtualKeyboardFeaturePkg
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2603
> 
> It add a VirtualKeyboardDxe driver.
> It is used with a touch panel, simulate a keyboard in the screen.
> 
> Signed-off-by: Ming Tan <ming.tan@intel.com>
> ---
>  .../Include/PostMemory.fdf                    |   10 +
>  .../Include/PreMemory.fdf                     |    8 +
>  .../Include/VirtualKeyboardFeature.dsc        |   96 ++
>  .../VirtualKeyboardFeaturePkg/Readme.md       |   95 ++
>  .../CapitalLetterKeyboard.bmp                 |  Bin 0 -> 330454 bytes
>  .../VirtualKeyboardDxe/ComponentName.c        |  159 ++
>  .../VirtualKeyboardDxe/ComponentName.h        |   95 ++
>  .../VirtualKeyboardDxe/DigitKeyboard.bmp      |  Bin 0 -> 330454 bytes
>  .../VirtualKeyboardDxe/FullIcon.bmp           |  Bin 0 -> 5454 bytes
>  .../VirtualKeyboardDxe/Keyboard.c             | 1400 +++++++++++++++++
>  .../VirtualKeyboardDxe/KeyboardLayout.c       | 1364 ++++++++++++++++
>  .../VirtualKeyboardDxe/KeyboardLayout.idf     |   12 +
>  .../VirtualKeyboardDxe/SimpleIcon.bmp         |  Bin 0 -> 2814 bytes
>  .../VirtualKeyboardDxe/SimpleKeyboard.bmp     |  Bin 0 -> 30054 bytes
>  .../VirtualKeyboardDxe/VirtualKeyboard.h      |  777 +++++++++
>  .../VirtualKeyboardDriver.c                   |  541 +++++++
>  .../VirtualKeyboardDxe/VirtualKeyboardDxe.inf |   77 +
>  .../VirtualKeyboardFeaturePkg.dec             |   26 +
>  .../VirtualKeyboardFeaturePkg.dsc             |   30 +
>  19 files changed, 4690 insertions(+)
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/CapitalLetterKeyboard.bmp
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/DigitKeyboard.bmp
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/FullIcon.bmp
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleIcon.bmp
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleKeyboard.bmp
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h
>  create mode 100644
> Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
>  create mode 100644 Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf
> new file mode 100644
> index 0000000000..bf4a4d5078
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PostMemory.fdf
> @@ -0,0 +1,10 @@
> +## @file
> 
> +#  FDF file for post-memory modules that enable Virtual Keyboard.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +  INF UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf
> new file mode 100644
> index 0000000000..c39a057f94
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/PreMemory.fdf
> @@ -0,0 +1,8 @@
> +## @file
> 
> +#  FDF file for pre-memory modules that enable Virtual Keyboard.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc
> new file mode 100644
> index 0000000000..c10fb2d567
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Include/VirtualKeyboardFeature.dsc
> @@ -0,0 +1,96 @@
> +## @file
> 
> +# This is a build description file for the Virtual Keyboard feature.
> 
> +# This file should be included into another package DSC file to build this feature.
> 
> +#
> 
> +# The DEC files are used by the utilities that parse DSC and
> 
> +# INF files to generate AutoGen.c and AutoGen.h files
> 
> +# for the build infrastructure.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +################################################################################
> 
> +#
> 
> +# Defines Section - statements that will be processed to create a Makefile.
> 
> +#
> 
> +################################################################################
> 
> +[Defines]
> 
> +!ifndef $(PEI_ARCH)
> 
> +  !error "PEI_ARCH must be specified to build this feature!"
> 
> +!endif
> 
> +!ifndef $(DXE_ARCH)
> 
> +  !error "DXE_ARCH must be specified to build this feature!"
> 
> +!endif
> 
> +
> 
> +################################################################################
> 
> +#
> 
> +# Library Class section - list of all Library Classes needed by this feature.
> 
> +#
> 
> +################################################################################
> 
> +[LibraryClasses]
> 
> +  #######################################
> 
> +  # Edk2 Packages
> 
> +  #######################################
> 
> +  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> 
> +  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> 
> +  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
> 
> +  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
> 
> +  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
> 
> +  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> 
> +  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> 
> +  HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
> 
> +  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> 
> +  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> 
> +  UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
> 
> +  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
> 
> +
> 
> +[LibraryClasses.common.UEFI_DRIVER]
> 
> +  #######################################
> 
> +  # Edk2 Packages
> 
> +  #######################################
> 
> +  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> 
> +
> 
> +###################################################################################################
> 
> +#
> 
> +# Components Section - list of the modules and components that will be processed by compilation
> 
> +#                      tools and the EDK II tools to generate PE32/PE32+/Coff image files.
> 
> +#
> 
> +# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
> 
> +#       into firmware volume images. This section is just a list of modules to compile from
> 
> +#       source into UEFI-compliant binaries.
> 
> +#       It is the FDF file that contains information on combining binary files into firmware
> 
> +#       volume images, whose concept is beyond UEFI and is described in PI specification.
> 
> +#       Binary modules do not need to be listed in this section, as they should be
> 
> +#       specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
> 
> +#       Logo (Logo.bmp), and etc.
> 
> +#       There may also be modules listed in this section that are not required in the FDF file,
> 
> +#       When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
> 
> +#       generated for it, but the binary will not be put into any firmware volume.
> 
> +#
> 
> +###################################################################################################
> 
> +#
> 
> +# Feature DXE Components
> 
> +#
> 
> +[Components.X64]
> 
> +  #####################################
> 
> +  # Virtual Keyboard Feature Package
> 
> +  #####################################
> 
> +  UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
> 
> +
> 
> +###################################################################################################
> 
> +#
> 
> +# BuildOptions Section - Define the module specific tool chain flags that should be used as
> 
> +#                        the default flags for a module. These flags are appended to any
> 
> +#                        standard flags that are defined by the build process. They can be
> 
> +#                        applied for any modules or only those modules with the specific
> 
> +#                        module style (EDK or EDKII) specified in [Components] section.
> 
> +#
> 
> +#                        For advanced features, it is recommended to enable [BuildOptions] in
> 
> +#                        the applicable INF file so it does not affect the whole board package
> 
> +#                        build when this DSC file is active.
> 
> +#
> 
> +###################################################################################################
> 
> +[BuildOptions]
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
> new file mode 100644
> index 0000000000..17a3a00215
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/Readme.md
> @@ -0,0 +1,95 @@
> +# Overview
> 
> +* **Feature Name:** Virtual Keyboard
> 
> +* **PI Phase(s) Supported:** DXE
> 
> +* **SMM Required?** No
> 
> +
> 
> +## Purpose
> 
> +This feature provides a DXE virtual keyboard driver, used with a touch panel.
> 
> +
> 
> +# High-Level Theory of Operation
> 
> +This driver will use the following protocol:
> 
> +  gEfiAbsolutePointerProtocolGuid
> 
> +  gEfiTouchPanelGuid
> 
> +  gEfiGraphicsOutputProtocolGuid
> 
> +
> 
> +It will show a picture like a keyboard in the graphic output, then detect
> 
> +position when user touch the touch panel, then calculate the key which the
> 
> +user want to type.
> 
> +
> 
> +## Firmware Volumes
> 
> +*_TODO_*
> 
> +A bulleted list of the firmware volumes that feature module(s) are placed in.
> 
> +
> 
> +## Modules
> 
> +VirtualKeyboardDxe: The main driver of virtual keyboard
> 
> +
> 
> +## <Module Name>
> 
> +*_TODO_*
> 
> +Each module in the feature should have a section that describes the module in a level of detail that is useful
> 
> +to better understand the module source code.
> 
> +
> 
> +## <Library Name>
> 
> +*_TODO_*
> 
> +Each library in the feature should have a section that describes the library in a level of detail that is useful
> 
> +to better understand the library source code.
> 
> +
> 
> +## Key Functions
> 
> +*_TODO_*
> 
> +A bulleted list of key functions for interacting with the feature.
> 
> +
> 
> +Not all features need to be listed. Only functions exposed through external interfaces that are important for feature
> 
> +users to be aware of.
> 
> +
> 
> +## Configuration
> 
> +*_TODO_*
> 
> +Information that is useful for configuring the feature.
> 
> +
> 
> +Not all configuration options need to be listed. This section is used to provide more background on configuration
> 
> +options than possible elsewhere.
> 
> +
> 
> +## Data Flows
> 
> +*_TODO_*
> 
> +Architecturally defined data structures and flows for the feature.
> 
> +
> 
> +## Control Flows
> 
> +*_TODO_*
> 
> +Key control flows for the feature.
> 
> +
> 
> +## Build Flows
> 
> +*_TODO_*
> 
> +Any special build flows should be described in this section.
> 
> +
> 
> +This is particularly useful for features that use custom build tools or require non-standard tool configuration. If the
> 
> +standard flow in the feature package template is used, this section may be empty.
> 
> +
> 
> +## Test Point Results
> 
> +*_TODO_*
> 
> +The test(s) that can verify porting is complete for the feature.
> 
> +
> 
> +Each feature must describe at least one test point to verify the feature is successful. If the test point is not
> 
> +implemented, this should be stated.
> 
> +
> 
> +## Functional Exit Criteria
> 
> +*_TODO_*
> 
> +The testable functionality for the feature.
> 
> +
> 
> +This section should provide an ordered list of criteria that a board integrator can reference to ensure the feature is
> 
> +functional on their board.
> 
> +
> 
> +## Feature Enabling Checklist
> 
> +*_TODO_*
> 
> +An ordered list of required activities to achieve desired functionality for the feature.
> 
> +
> 
> +## Performance Impact
> 
> +A general expectation for the impact on overall boot performance due to using this feature.
> 
> +
> 
> +This section is expected to provide guidance on:
> 
> +* How to estimate performance impact due to the feature
> 
> +* How to measure performance impact of the feature
> 
> +* How to manage performance impact of the feature
> 
> +
> 
> +## Common Optimizations
> 
> +*_TODO_*
> 
> +Common size or performance tuning options for this feature.
> 
> +
> 
> +This section is recommended but not required. If not used, the contents should be left empty.
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/CapitalLetterKeyboard.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/CapitalLetterKeyboard.bmp
> new file mode 100644
> index 0000000000000000000000000000000000000000..759c3d46a9f0cf6a69fa98563cd04f7a082d3b4d
> GIT binary patch
> literal 330454
> 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
> Ka0)zo_WuC{9xg=y
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c
> new file mode 100644
> index 0000000000..6ac28ab90b
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.c
> @@ -0,0 +1,159 @@
> +/** @file
> 
> +  Virtual Keyboard driver name.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +//
> 
> +// EFI Component Name Protocol
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName = {
> 
> +  VirtualKeyboardComponentNameGetDriverName,
> 
> +  VirtualKeyboardComponentNameGetControllerName,
> 
> +  "eng"
> 
> +};
> 
> +
> 
> +//
> 
> +// EFI Component Name 2 Protocol
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2 = {
> 
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     VirtualKeyboardComponentNameGetDriverName,
> 
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) VirtualKeyboardComponentNameGetControllerName,
> 
> +  "en"
> 
> +};
> 
> +
> 
> +//
> 
> +// Table of driver names
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVirtualKeyboardDriverNameTable[] = {
> 
> +  {
> 
> +    "eng;en",
> 
> +    L"UEFI Virtual Keyboard Driver"
> 
> +  },
> 
> +  {
> 
> +    NULL,
> 
> +    NULL
> 
> +  }
> 
> +};
> 
> +
> 
> +//
> 
> +// Controller name string table
> 
> +//
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVirtualKeyboardControllerNameStringTable[] = {
> 
> +  {
> 
> +    "eng",
> 
> +    L"UEFI Virtual Keyboard Driver"
> 
> +  },
> 
> +  {
> 
> +    NULL,
> 
> +    NULL
> 
> +  }
> 
> +};
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  Language          A pointer to a three-character ISO 639-2 language identifier.
> 
> +                                This is the language of the driver name that that the caller
> 
> +                                is requesting, and it must match one of the languages specified
> 
> +                                in SupportedLanguages.  The number of languages supported by a
> 
> +                                driver is up to the driver writer.
> 
> +  @param[out] DriverName        A pointer to the Unicode string to return.  This Unicode string
> 
> +                                is the name of the driver specified by This in the language
> 
> +                                specified by Language.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
> 
> +                                and the language specified by Language was returned
> 
> +                                in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetDriverName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **DriverName
> 
> +  )
> 
> +{
> 
> +  return LookupUnicodeString2 (
> 
> +           Language,
> 
> +           This->SupportedLanguages,
> 
> +           mVirtualKeyboardDriverNameTable,
> 
> +           DriverName,
> 
> +           (BOOLEAN)(This == &gVirtualKeyboardComponentName)
> 
> +           );
> 
> +}
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user readable name of the controller
> 
> +  that is being managed by an EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  ControllerHandle  The handle of a controller that the driver specified by
> 
> +                                This is managing.  This handle specifies the controller
> 
> +                                whose name is to be returned.
> 
> +  @param[in]  ChildHandle       The handle of the child controller to retrieve the name
> 
> +                                of.  This is an optional parameter that may be NULL.  It
> 
> +                                will be NULL for device drivers.  It will also be NULL
> 
> +                                for a bus drivers that wish to retrieve the name of the
> 
> +                                bus controller.  It will not be NULL for a bus driver
> 
> +                                that wishes to retrieve the name of a child controller.
> 
> +  @param[in]  Language          A pointer to a three character ISO 639-2 language
> 
> +                                identifier.  This is the language of the controller name
> 
> +                                that the caller is requesting, and it must match one
> 
> +                                of the languages specified in SupportedLanguages.  The
> 
> +                                number of languages supported by a driver is up to the
> 
> +                                driver writer.
> 
> +  @param[out] ControllerName    A pointer to the Unicode string to return.  This Unicode
> 
> +                                string is the name of the controller specified by
> 
> +                                ControllerHandle and ChildHandle in the language specified
> 
> +                                by Language, from the point of view of the driver specified
> 
> +                                by This.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
> 
> +                                language specified by Language for the driver
> 
> +                                specified by This was returned in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
> 
> +                                the controller specified by ControllerHandle and
> 
> +                                ChildHandle.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetControllerName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  ControllerHandle,
> 
> +  IN  EFI_HANDLE                  ChildHandle, OPTIONAL
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **ControllerName
> 
> +  )
> 
> +{
> 
> +  //
> 
> +  // ChildHandle must be NULL for a Device Driver
> 
> +  //
> 
> +  if (ChildHandle != NULL) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +  return LookupUnicodeString2 (
> 
> +           Language,
> 
> +           This->SupportedLanguages,
> 
> +           mVirtualKeyboardControllerNameStringTable,
> 
> +           ControllerName,
> 
> +           (BOOLEAN)(This == &gVirtualKeyboardComponentName)
> 
> +           );
> 
> +}
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h
> new file mode 100644
> index 0000000000..327ce9f9cb
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/ComponentName.h
> @@ -0,0 +1,95 @@
> +/** @file
> 
> +  Header file for Virtual Keyboard driver name.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#ifndef _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
> 
> +#define _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
> 
> +
> 
> +#include <Uefi.h>
> 
> +#include <Protocol/ComponentName.h>
> 
> +#include <Protocol/ComponentName2.h>
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user-readable name of the EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  Language          A pointer to a three-character ISO 639-2 language identifier.
> 
> +                                This is the language of the driver name that that the caller
> 
> +                                is requesting, and it must match one of the languages specified
> 
> +                                in SupportedLanguages.  The number of languages supported by a
> 
> +                                driver is up to the driver writer.
> 
> +  @param[out] DriverName        A pointer to the Unicode string to return.  This Unicode string
> 
> +                                is the name of the driver specified by This in the language
> 
> +                                specified by Language.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
> 
> +                                and the language specified by Language was returned
> 
> +                                in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetDriverName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **DriverName
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Retrieves a Unicode string that is the user readable name of the controller
> 
> +  that is being managed by an EFI Driver.
> 
> +
> 
> +  @param[in]  This              A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
> 
> +  @param[in]  ControllerHandle  The handle of a controller that the driver specified by
> 
> +                                This is managing.  This handle specifies the controller
> 
> +                                whose name is to be returned.
> 
> +  @param[in]  ChildHandle       The handle of the child controller to retrieve the name
> 
> +                                of.  This is an optional parameter that may be NULL.  It
> 
> +                                will be NULL for device drivers.  It will also be NULL
> 
> +                                for a bus drivers that wish to retrieve the name of the
> 
> +                                bus controller.  It will not be NULL for a bus driver
> 
> +                                that wishes to retrieve the name of a child controller.
> 
> +  @param[in]  Language          A pointer to a three character ISO 639-2 language
> 
> +                                identifier.  This is the language of the controller name
> 
> +                                that the caller is requesting, and it must match one
> 
> +                                of the languages specified in SupportedLanguages.  The
> 
> +                                number of languages supported by a driver is up to the
> 
> +                                driver writer.
> 
> +  @param[out] ControllerName    A pointer to the Unicode string to return.  This Unicode
> 
> +                                string is the name of the controller specified by
> 
> +                                ControllerHandle and ChildHandle in the language specified
> 
> +                                by Language, from the point of view of the driver specified
> 
> +                                by This.
> 
> +
> 
> +  @retval EFI_SUCCESS           The Unicode string for the user-readable name in the
> 
> +                                language specified by Language for the driver
> 
> +                                specified by This was returned in DriverName.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
> 
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> 
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently managing
> 
> +                                the controller specified by ControllerHandle and
> 
> +                                ChildHandle.
> 
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
> 
> +                                language specified by Language.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardComponentNameGetControllerName (
> 
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  ControllerHandle,
> 
> +  IN  EFI_HANDLE                  ChildHandle, OPTIONAL
> 
> +  IN  CHAR8                       *Language,
> 
> +  OUT CHAR16                      **ControllerName
> 
> +  );
> 
> +#endif
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/DigitKeyboard.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/DigitKeyboard.bmp
> new file mode 100644
> index 0000000000000000000000000000000000000000..b64d62034817e7407120ee2181c935e07bef5a8c
> GIT binary patch
> literal 330454
> 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
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/FullIcon.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/FullIcon.bmp
> new file mode 100644
> index 0000000000000000000000000000000000000000..b940505c8bc74ad6550bc322629d7975c1e1c1fc
> GIT binary patch
> literal 5454
> zcmdUyTS!(}6o56!L@l#1k<1H~<*msK=EYIGfJHUFgo!=$AR-O~g3Ln$_Tv5C7@{FW
> zuaziT6L~3b87f|a5!5uTbW}2D5<@ff*ZKTcvp6&*5#z(Z`TxV--&uR@b@o|%t#u-Q
> zirH&rZa;AK<^LmpPyW_cZd|Rb+&<nn4?bRUiz^!H>wdS8R##V7QBl$K<d1cWYA;{D
> ztZVAFD3jL*2L~Hl`%J6LZf@c|8xF%GjEsyJ{RdKAU2P;=(N9lLXQANWU{&7M)&|ib
> zoyp0`=g*%vw)L&AuN^pWKyM*7F)?9hXD7tQ#s+ft?p+nwqR!Q;S6L`LJY4m6b#+0u
> zZ{MzDW@ct|bX06Ubm)+BvDx0<UI<el_wL<Ofi3EY%@Gk1s$XojwY3#uZEbDoHhXz_
> z>C>^R<KyGTHv*}xtyO_7>J%0hvQTJfsOs<N=zy@jN?yNyjc+ux_O7p)LPA3J?c3++
> z>FMO;BsL#Bc+kVc!`<E8$Hxa!UtjO&=*XjOQDfb*vN9GrckZ04t1GKGI5_n5^gz75
> zz4!0mk1<@|ym`YJtZUwgb&HFO@87>)T3UMd?j1wg!omWC#w~`ctE&(Mwy2?ed3l+I
> z(9eooA!}=E5V1`y85$b0#P}@x{Fk}?ZEkdDXJ>gplgWhtz!<)L`xf%y!v{{T5P2hW
> zb93B<z*kmQkfDzTuFPdf69FJ^mLXzvM9KX8JOoujm?BD8PG%vdO{TNY4Xu4^rqvTC
> zPVC;jd#|}UJ39vk2J&_W1_pNR+U4Tnf+xqv$D_QmvU10c9Y_%gFI~C>NlHq>@sNRc
> zcW<~^OiawqojboXH;fq@8{?$x*|P_=etv!kG&D5G6vWP+JqzLViCT`^qeqV*iHV8G
> zh&^&eA4+&A%_;b~o=rNWMV^-|sqoaPQ>eOg=Z+Grg~Y|hDe3L)g%}S$PWa-*i*4Js
> zi40~VK%Jvg$RLo+%uFR>vr(<yqVuKr%q>nRhmN<P@@LMRK{@-ZBsn=5a^b=SC4GIQ
> z)OBN0;AK(Lu!kbUjv+t@(kW3<QIPEHY$Z)iO`oXMTbtw*WGupFBC|dY9X15tz@HUH
> zM@RGcw{PE8g3Cc-V`G(wZxHI0;2Zd}4kh?Mc<?|;SXdZJGBPrhJbd^Na{l~zCB_c^
> ztU2ZM>C+sL@6FBM-=9}Th`={|eSMD}J$m@?VL5SB9aK{g>XWpzG?ZVye3?E3{`Bcn
> zNJ2uwkt0Vq#Wcdgt5>f$-~j;vsKsp%XlZF7Pca3tix)3K%FD}{&f+AF_V#v2YHBJn
> zVvk(Wh7v*tHK#?!XA7+P>zg-nI@L&PYb!N2hngXN$Qy*v=s<WW#8m`{MMOvlbrik_
> zflIXS?CeAsLNr5wCQ2ZUjg1V+&N%bq$BzjP{r&wA5{IZo6%hu)p=fSy7PXRb5XKA$
> zoHY0B*)!^AlWB#7qOQ(FtkNMJh%w5gq@+M{b8}UOyAX1R5<(?JhoWR^YD&q;lP3|V
> zsi{#S-zoUH5={L>3EwH-R`XxEas^eTrKPI;{{8!qpr9ZnQr?h2l^{Sy(4iz&W2}~%
> zKQb~>Wu)fU@V-fWMmgVBn|!By$>w9nj_Gn@Gx=A^SK4e$N&n+_%GcZc4g36Gn?JkH
> z)JPOL#tkth0ytY#RaK<|1W!moL4gwPLX1VrXZ?A4dRnJQF<|^OCWE8o`0?W^Be7bC
> zbT|?CbA8K3+_-V$2JTc+Qj(LC!;lK|w}0EUYu6y0N^a55&(G)JL->fu%gckXmPC@9
> zH*Xdf7emNv;v1p^wPFv|JGT&^kmF+wC2USsRu+U4EuL`e)~%wVA_yD{kzt4)l+dAo
> p86F<C#GKOBxe+HVs7?Mk@$)bFIfd8L^U5+T;g?l#J@wbDe*hRVpnL!T
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c
> new file mode 100644
> index 0000000000..a2c9a3bfc4
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/Keyboard.c
> @@ -0,0 +1,1400 @@
> +/** @file
> 
> +  Virtural Keyboard Control Engine
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +/**
> 
> +  Notify all keyboards pressed specific key need to hidden Virtual
> 
> +  Keyboard.
> 
> +
> 
> +  @param[in] KeyData          Keyboard pressed specific key data
> 
> +
> 
> +  @retval EFI_SUCCESS         Success for the function.
> 
> +  @retval EFI_NOT_FOUND       Not found Virtual Keyboard protocol.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkNotifyKeyCallback (
> 
> +  IN EFI_KEY_DATA *KeyData
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +  UINTN      MaxColumn;
> 
> +  UINTN      MaxRow;
> 
> +  UINT32     HorizontalPixel;
> 
> +  UINT32     VerticalPixel;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkNotifyKeyCallback Start\n"));
> 
> +
> 
> +  Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, (VOID **) &VkContext);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    return Status;
> 
> +  }
> 
> +
> 
> +  gST->ConOut->QueryMode (
> 
> +                 gST->ConOut,
> 
> +                 gST->ConOut->Mode->Mode,
> 
> +                 &MaxColumn,
> 
> +                 &MaxRow
> 
> +                 );
> 
> +  HorizontalPixel = VkContext->GraphicsOutput->Mode->Info->HorizontalResolution;
> 
> +  VerticalPixel   = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +
> 
> +  //
> 
> +  // CursorRow and CursorColumn are started from 0, so need to add 2 not 1.
> 
> +  //
> 
> +  if (((UINTN)(gST->ConOut->Mode->CursorColumn * EFI_GLYPH_WIDTH) < VkContext->SimIconBackWidth) &&
> 
> +      ((UINTN)((gST->ConOut->Mode->CursorRow + 2) * EFI_GLYPH_HEIGHT) > (VerticalPixel - VkContext-
> >SimIconBackHeight))) {
> 
> +    SaveVkIconBackgroundBltBuffer (VkContext, VkDisplayAttributeSimpleBottom);
> 
> +  } else if (((UINTN)((gST->ConOut->Mode->CursorColumn + 2) * EFI_GLYPH_WIDTH) > (HorizontalPixel - VkContext-
> >FullIconBackWidth)) &&
> 
> +             ((UINTN)((gST->ConOut->Mode->CursorRow + 2) * EFI_GLYPH_HEIGHT) > (VerticalPixel - VkContext-
> >FullIconBackHeight))){
> 
> +    SaveVkIconBackgroundBltBuffer (VkContext, VkDisplayAttributeFullBottom);
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Hide icon/keyboard to prevent screen scroll up.
> 
> +  //
> 
> +  if ((KeyData->Key.UnicodeChar         == CHAR_CARRIAGE_RETURN)    ||
> 
> +      (KeyData->Key.ScanCode            == SCAN_ESC)                ||
> 
> +      ((gST->ConOut->Mode->CursorColumn >= (INT32) (MaxColumn - 2)) &&
> 
> +       (gST->ConOut->Mode->CursorRow    == (INT32) (MaxRow - 1)))) {
> 
> +    HideVkBody (VkContext);
> 
> +    HideVkIcon (VkContext);
> 
> +    VkContext->IconReDrawCheck = 0;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkNotifyKeyCallback End\n"));
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Judge whether is a registed key.
> 
> +
> 
> +  @param[in] RegsiteredData   A pointer to a buffer that is filled in with the keystroke
> 
> +                              state data for the key that was registered.
> 
> +  @param[in] InputData        A pointer to a buffer that is filled in with the keystroke
> 
> +                              state data for the key that was pressed.
> 
> +
> 
> +  @retval TRUE                Key be pressed matches a registered key.
> 
> +  @retval FLASE               Match failed.
> 
> +
> 
> +**/
> 
> +BOOLEAN
> 
> +IsKeyRegistered (
> 
> +  IN EFI_KEY_DATA  *RegsiteredData,
> 
> +  IN EFI_KEY_DATA  *InputData
> 
> +  )
> 
> +{
> 
> +  ASSERT (RegsiteredData != NULL && InputData != NULL);
> 
> +
> 
> +  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
> 
> +      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
> 
> +    return FALSE;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
> 
> +  //
> 
> +  if (RegsiteredData->KeyState.KeyShiftState != 0 &&
> 
> +      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
> 
> +    return FALSE;
> 
> +  }
> 
> +  if (RegsiteredData->KeyState.KeyToggleState != 0 &&
> 
> +      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
> 
> +    return FALSE;
> 
> +  }
> 
> +
> 
> +  return TRUE;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Pop the key from the keybuffer.
> 
> +
> 
> +  @param[in, out] VkContext    Address of an VK_CONTEXT structure.
> 
> +  @param[out]     KeyData      The EFI stand key infomation when code get the key will put
> 
> +                               correct mapping key.
> 
> +
> 
> +  @retval EFI_SUCCESS          The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY        The keystroke data is empty.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkPopTheKey (
> 
> +  IN OUT VK_CONTEXT   *VkContext,
> 
> +     OUT EFI_KEY_DATA *KeyData OPTIONAL
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  UINT8      IndexSt;
> 
> +  UINT8      IndexEd;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Start\n"));
> 
> +  //
> 
> +  // KeyBuffer
> 
> +  // [         0          ]
> 
> +  // [         1          ]<-*IndexSt/IndexEd
> 
> +  // [         2          ]
> 
> +  // [        ...         ]
> 
> +  // [MAX_KEY_BUF_SIZE - 1]
> 
> +  //
> 
> +  Status  = EFI_SUCCESS;
> 
> +  IndexSt = VkContext->KeyStartIndex;
> 
> +  IndexEd = VkContext->KeyEndIndex;
> 
> +
> 
> +  if (IndexEd == IndexSt) {
> 
> +    DEBUG ((DEBUG_VK_KEYS, "ERROR - Keyboard buffer is empty.\n"));
> 
> +    Status = EFI_NOT_READY;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey Unicode:    %08x\n", VkContext-
> >Keybuffer[IndexSt].Key.UnicodeChar));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey ScanCode:   %08x\n", VkContext-
> >Keybuffer[IndexSt].Key.ScanCode));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey ShiftState: %08x\n", VkContext-
> >Keybuffer[IndexSt].KeyState.KeyShiftState));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkPopTheKey ToggleState:%08x\n", VkContext-
> >Keybuffer[IndexSt].KeyState.KeyToggleState));
> 
> +
> 
> +  if (KeyData != NULL) {
> 
> +    *KeyData = VkContext->Keybuffer[IndexSt];
> 
> +  }
> 
> +  VkContext->KeyStartIndex = ++IndexSt % MAX_KEY_BUF_SIZE;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPopTheKey End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Push the event mapping key index to the input key buffer.
> 
> +
> 
> +  @param[in, out] VkContext    Address of an VK_CONTEXT structure.
> 
> +  @param[in]      Unicode      The font's unicode number.
> 
> +
> 
> +  @retval EFI_SUCCESS          The maping key index did put the key buffer.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkPushTheKey (
> 
> +  IN OUT VK_CONTEXT *VkContext,
> 
> +  IN     UINT16     Unicode
> 
> +  )
> 
> +{
> 
> +  UINT8        IndexSt;
> 
> +  UINT8        IndexEd;
> 
> +  EFI_KEY_DATA KeyData;
> 
> +  EFI_STATUS   Status;
> 
> +  LIST_ENTRY   *Link;
> 
> +  VK_NOTIFY    *CurrentNotify;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkPushTheKey Start\n"));
> 
> +  //
> 
> +  // KeyBuffer
> 
> +  // [         0          ]
> 
> +  // [         1          ]<-IndexSt/*IndexEd
> 
> +  // [         2          ]
> 
> +  // [        ...         ]
> 
> +  // [MAX_KEY_BUF_SIZE - 1]
> 
> +  //
> 
> +  IndexSt = VkContext->KeyStartIndex;
> 
> +  IndexEd = VkContext->KeyEndIndex;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +
> 
> +  //
> 
> +  // Check Keyboard Buffer if is full that will pop the first key
> 
> +  //
> 
> +  if (VkContext->IsSupportPartialKey &&
> 
> +    ((VkContext->KeyEndIndex + 2) % MAX_KEY_BUF_SIZE) == IndexSt) {
> 
> +    VkPopTheKey (VkContext, NULL);
> 
> +  }
> 
> +
> 
> +  if (((VkContext->KeyEndIndex + 1) % MAX_KEY_BUF_SIZE) == IndexSt) {
> 
> +    VkPopTheKey (VkContext, NULL);
> 
> +  }
> 
> +
> 
> +  KeyData.Key.ScanCode             = SCAN_NULL;
> 
> +  KeyData.Key.UnicodeChar          = CHAR_NULL;
> 
> +  KeyData.KeyState.KeyShiftState   = EFI_SHIFT_STATE_VALID;
> 
> +  KeyData.KeyState.KeyToggleState  = VkContext->KeyToggleState;
> 
> +  KeyData.KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
> 
> +  KeyData.KeyState.KeyToggleState |= VkContext->IsCapsLockFlag ? EFI_CAPS_LOCK_ACTIVE : 0;
> 
> +
> 
> +  switch (Unicode) {
> 
> +  case VkKeyShift:
> 
> +    VkContext->IsShiftKeyFlag = !VkContext->IsShiftKeyFlag;
> 
> +    if (VkContext->PageNumber >= VkPage2 && VkContext->PageNumber <= VkPage3) {
> 
> +      VkContext->IsShiftKeyFlag ? VkContext->PageNumber++ : VkContext->PageNumber--;
> 
> +    }
> 
> +    VkContext->IsRedrawUpdateUI = TRUE;
> 
> +    break;
> 
> +
> 
> +  case VkKeyTwoPage:
> 
> +    switch (VkContext->PageNumber) {
> 
> +    case VkPage0:
> 
> +    case VkPage1:
> 
> +      VkContext->IsShiftKeyFlag = FALSE;
> 
> +      VkContext->PageNumber     = VkContext->IsShiftKeyFlag ? VkPage3 : VkPage2;
> 
> +      break;
> 
> +
> 
> +    case VkPage2:
> 
> +    case VkPage3:
> 
> +      VkContext->IsShiftKeyFlag = FALSE;
> 
> +      VkContext->PageNumber     = VkContext->IsCapsLockFlag ? VkPage1 : VkPage0;
> 
> +      break;
> 
> +
> 
> +    default:
> 
> +      break;
> 
> +    }
> 
> +    VkContext->IsRedrawUpdateUI = TRUE;
> 
> +    break;
> 
> +
> 
> +  case VkKeyCapslock:
> 
> +    VkContext->IsCapsLockFlag = !VkContext->IsCapsLockFlag;
> 
> +    if (VkContext->PageNumber >= VkPage0 && VkContext->PageNumber <= VkPage1) {
> 
> +      VkContext->IsCapsLockFlag ? VkContext->PageNumber++ : VkContext->PageNumber--;
> 
> +    }
> 
> +    KeyData.KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE;
> 
> +    KeyData.KeyState.KeyToggleState |= VkContext->IsCapsLockFlag ? EFI_CAPS_LOCK_ACTIVE : 0;
> 
> +    VkContext->IsRedrawUpdateUI      = TRUE;
> 
> +    break;
> 
> +
> 
> +  default:
> 
> +    if ((Unicode & VkKeyScanMask) != 0) {
> 
> +      KeyData.Key.ScanCode    = Unicode & ~VkKeyScanMask;
> 
> +    } else {
> 
> +      KeyData.Key.UnicodeChar = Unicode;
> 
> +    }
> 
> +    break;
> 
> +  }
> 
> +
> 
> +  if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
> 
> +    if (!VkContext->IsSupportPartialKey) {
> 
> +      goto End;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  for (Link = GetFirstNode (&VkContext->NotifyList); !IsNull (&VkContext->NotifyList, Link); Link = GetNextNode
> (&VkContext->NotifyList, Link)) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
> 
> +    //
> 
> +    // The key notification function needs to run at TPL_CALLBACK
> 
> +    // while current TPL is TPL_NOTIFY. It will be invoked in
> 
> +    // VkKeyNotifyProcessHandler() which runs at TPL_CALLBACK.
> 
> +    //
> 
> +    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
> 
> +      VkContext->Keybuffer[IndexEd] = KeyData;
> 
> +      VkContext->KeyEndIndex        = ++IndexEd % MAX_KEY_BUF_SIZE;
> 
> +      gBS->SignalEvent (VkContext->KeyNotifyProcessEvent);
> 
> +    }
> 
> +  }
> 
> +  VkContext->Keybuffer[IndexEd] = KeyData;
> 
> +  VkContext->KeyEndIndex        = ++IndexEd % MAX_KEY_BUF_SIZE;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkPushTheKey Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkPushTheKey End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Process key notify.
> 
> +
> 
> +  @param[in] Event                 Indicates the event that invoke this function.
> 
> +  @param[in] Context               Indicates the calling context.
> 
> +
> 
> +**/
> 
> +VOID
> 
> +EFIAPI
> 
> +VkKeyNotifyProcessHandler (
> 
> +  IN  EFI_EVENT Event,
> 
> +  IN  VOID      *Context
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS   Status;
> 
> +  VK_CONTEXT   *VkContext;
> 
> +  EFI_KEY_DATA KeyData;
> 
> +  LIST_ENTRY   *Link;
> 
> +  LIST_ENTRY   *NotifyList;
> 
> +  VK_NOTIFY    *CurrentNotify;
> 
> +  EFI_TPL      OldTpl;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler Start\n"));
> 
> +  VkContext = (VK_CONTEXT *) Context;
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +
> 
> +  //
> 
> +  // Invoke notification functions.
> 
> +  //
> 
> +  NotifyList = &VkContext->NotifyList;
> 
> +  Status = VkPopTheKey (VkContext, &KeyData);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
> 
> +    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
> 
> +      CurrentNotify->KeyNotificationFn (&KeyData);
> 
> +    }
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyNotifyProcessHandler End\n"));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Push the event mapping key index to the input key buffer.
> 
> +
> 
> +  @param[in]  VkContext        Address of an VK_CONTEXT structure.
> 
> +  @param[out] KeyItem          Key Item.
> 
> +  @param[out] Index            Index of Key Item.
> 
> +  @param[in]  TouchX           X position of finger touch.
> 
> +  @param[in]  TouchY           Y position of finger touch.
> 
> +
> 
> +  @retval TRUE                 Touch on Virtual Keyboard.
> 
> +  @retval FALSE                Not touch on Virtual Keyboard.
> 
> +
> 
> +**/
> 
> +BOOLEAN
> 
> +IsTouchVk (
> 
> +  IN  VK_CONTEXT *VkContext,
> 
> +  OUT VK_STRUCT  *KeyItem,
> 
> +  OUT UINT32     *Index,
> 
> +  IN  UINT32     TouchX,
> 
> +  IN  UINT32     TouchY
> 
> +  )
> 
> +{
> 
> +  for (*Index = 0; *Index < VkContext->NumOfKeysInfo; (*Index)++) {
> 
> +    if (VkContext->KeyboardBodyPtr[*Index].DisStartX < TouchX &&
> 
> +        VkContext->KeyboardBodyPtr[*Index].DisEndX   > TouchX &&
> 
> +        VkContext->KeyboardBodyPtr[*Index].DisStartY < TouchY &&
> 
> +        VkContext->KeyboardBodyPtr[*Index].DisEndY   > TouchY) {
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +  if (*Index != VkContext->NumOfKeysInfo) {
> 
> +    *KeyItem = VkContext->KeyboardBodyPtr[*Index];
> 
> +  }
> 
> +
> 
> +  return *Index != VkContext->NumOfKeysInfo;
> 
> +}
> 
> +
> 
> +VOID
> 
> +EFIAPI
> 
> +VkReadyToBootCallBack (
> 
> +  IN EFI_EVENT Event,
> 
> +  IN VOID      *Context
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT                    *VkContext;
> 
> +  VkContext = (VK_CONTEXT *)Context;
> 
> +
> 
> +  HideVkBody (VkContext);
> 
> +  VkContext->TargetKeyboardDisplay  = VkDisplayAttributeNone;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Timer event
> 
> +
> 
> +  This routine is called at TPL_VK_SYNC.
> 
> +
> 
> +  This routine polls for touch panel input.
> 
> +
> 
> +  @param[in] Event    Event whose notification function is being invoked.
> 
> +  @param[in] Context  Pointer to the notification function's context,
> 
> +                      which is implementation-dependent. Context corresponds
> 
> +                      to NotifyContext in CreateEventEx().
> 
> +
> 
> +**/
> 
> +VOID
> 
> +EFIAPI
> 
> +VkTimer (
> 
> +  IN EFI_EVENT Event,
> 
> +  IN VOID      *Context
> 
> +  )
> 
> +{
> 
> +  EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer;
> 
> +  EFI_ABSOLUTE_POINTER_STATE    Point;
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        TouchX;
> 
> +  UINT32                        TouchY;
> 
> +  VK_CONTEXT                    *VkContext;
> 
> +  UINT32                        Index;
> 
> +  VK_STRUCT                     KeyItem;
> 
> +  UINT32                        Font;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Start\n"));
> 
> +  VkContext = (VK_CONTEXT *)Context;
> 
> +
> 
> +  //
> 
> +  // Update keyboard UI layout
> 
> +  //
> 
> +  CheckIconCleared (VkContext);
> 
> +  CheckScreenCleared (VkContext);
> 
> +  CheckBackgroundChanged (VkContext);
> 
> +  if (VkContext->IsRedrawUpdateUI) {
> 
> +    HideVkBody (VkContext);
> 
> +    DrawKeyboardLayout (VkContext);
> 
> +    VkContext->IsRedrawUpdateUI = FALSE;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Error handle for invalid information
> 
> +  //
> 
> +  AbsolutePointer = VkContext->AbsolutePointer;
> 
> +  Status = gBS->CheckEvent (AbsolutePointer->WaitForInput);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS, "ERROR - VkContext->AbsolutePointer->WaitForInput-
> >CheckEvent failed! Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = AbsolutePointer->GetState (AbsolutePointer, &Point);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS, "ERROR - GetState failed, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxX <= Point.CurrentX) {
> 
> +    DEBUG ((
> 
> +      DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +      "ERROR - X value exceeds maximum: X: 0x%016Lx, MaxX: 0x%016Lx\n",
> 
> +      Point.CurrentX,
> 
> +      VkContext->AbsolutePointer->Mode->AbsoluteMaxX
> 
> +      ));
> 
> +    Status = EFI_PROTOCOL_ERROR;
> 
> +    goto Error;
> 
> +  }
> 
> +  if (VkContext->AbsolutePointer->Mode->AbsoluteMaxY <= Point.CurrentY) {
> 
> +    DEBUG ((
> 
> +      DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +      "ERROR - Y value exceeds maximum: Y: 0x%016Lx, MaxY: 0x%016Lx\n",
> 
> +      Point.CurrentY,
> 
> +      VkContext->AbsolutePointer->Mode->AbsoluteMaxY
> 
> +      ));
> 
> +    Status = EFI_PROTOCOL_ERROR;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Update the touch active status
> 
> +  //
> 
> +  VkContext->TouchActive = ((Point.ActiveButtons & EFI_ABSP_TouchActive) != 0) ? TRUE : FALSE;
> 
> +  if (!VkContext->TouchActive) {
> 
> +    VkContext->KeyPressed = FALSE;
> 
> +  }
> 
> +  ConvertCoordinate (VkContext, Point, &TouchX, &TouchY);
> 
> +
> 
> +  if (!VkContext->KeyPressed &&
> 
> +      VkContext->TouchActive &&
> 
> +      IsTouchVk (VkContext, &KeyItem, &Index, TouchX, TouchY)) {
> 
> +    VkGetMappingFont (VkContext, KeyItem, &Font);
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO,                   "VK Touch event is trigger!\n" ));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "TouchActive:            0x%04x  \n",
> VkContext->TouchActive));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "CurrentKeyboardDisplay: 0x%04x  \n",
> VkContext->CurrentKeyboardDisplay));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "X:                      0x%016Lx\n",
> Point.CurrentX));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Y:                      0x%016Lx\n",
> Point.CurrentY));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Z:                      0x%016Lx\n",
> Point.CurrentZ));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Buttons:                0x%08x  \n",
> Point.ActiveButtons));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "MapKey Index:           0x%04x  \n",
> Index));
> 
> +    DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT | DEBUG_INFO | DEBUG_VK_POINTS, "Key Unicode:            0x%08x  \n", Font));
> 
> +
> 
> +    switch (Font) {
> 
> +    //
> 
> +    // Touch the small keyboard icon, show/hide the keyboard.
> 
> +    //
> 
> +    case VkKeyTypeMaximum:
> 
> +      KeyboardLayoutHandler (VkContext, Index);
> 
> +      break;
> 
> +
> 
> +    //
> 
> +    // Touch the key raw.
> 
> +    //
> 
> +    default:
> 
> +      if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeNone) {
> 
> +        break;
> 
> +      }
> 
> +      VkPushTheKey (VkContext, (UINT16) Font);
> 
> +    }
> 
> +    VkContext->KeyPressed = TRUE;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_TIMER_ENTRY_EXIT, "VkTimer End\n"));
> 
> +  return;
> 
> +}
> 
> +
> 
> +/**
> 
> +  VkTouchWaitForKey - SignalEvent when the keybuffer has keys.
> 
> +
> 
> +  @param[in] Event    Event whose notification function is being invoked.
> 
> +  @param[in] Context  Pointer to the notification function's context,
> 
> +                      which is implementation-dependent.  Context corresponds
> 
> +                      to NotifyContext in CreateEventEx().
> 
> +
> 
> +**/
> 
> +VOID
> 
> +EFIAPI
> 
> +VkTouchWaitForKey (
> 
> +  IN EFI_EVENT Event,
> 
> +  IN VOID      *Context
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT *VkContext;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkTouchWaitForKey Start\n"));
> 
> +  VkContext = (VK_CONTEXT*) Context;
> 
> +
> 
> +  if (VkContext->KeyStartIndex != VkContext->KeyEndIndex) {
> 
> +    DEBUG ((DEBUG_VK_KEYS, "Signal VkTouchWaitForKey\n"));
> 
> +    gBS->SignalEvent (Event);
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkTouchWaitForKey End\n"));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get image file data from BIOS image through specific ImageId.
> 
> +
> 
> +  @param[in] VkContext      Address of an VK_CONTEXT structure.
> 
> +  @param[in] ImageId        Guid to get specific image file used.
> 
> +
> 
> +  @retval EFI_IMAGE_INPUT   Image data on BIOS image.
> 
> +
> 
> +**/
> 
> +EFI_IMAGE_INPUT*
> 
> +VkGetImage (
> 
> +  IN VK_CONTEXT   *VkContext,
> 
> +  IN EFI_IMAGE_ID ImageId
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS      Status;
> 
> +  EFI_IMAGE_INPUT Image;
> 
> +  EFI_IMAGE_INPUT *VkImage;
> 
> +
> 
> +
> 
> +  Status = VkContext->HiiImageEx->GetImageEx (
> 
> +                                    VkContext->HiiImageEx,
> 
> +                                    VkContext->HiiHandle,
> 
> +                                    ImageId,
> 
> +                                    &Image
> 
> +                                    );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +  }
> 
> +
> 
> +  VkImage = AllocateCopyPool (sizeof (EFI_IMAGE_INPUT), &Image);
> 
> +  if (VkImage == NULL) {
> 
> +    ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
> 
> +    return NULL;
> 
> +  }
> 
> +
> 
> +  return VkImage;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Dump partial debug message on VkContext.
> 
> +
> 
> +  @param[in] VkContext        Address of an VK_CONTEXT structure.
> 
> +
> 
> +**/
> 
> +VOID
> 
> +VkDumpContext (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT,
> 
> +    "VkContext->Signature: 0x%016x\n",
> 
> +    VkContext->Signature
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT,
> 
> +    "VkContext->Controller: 0x%016x\n",
> 
> +    VkContext->Controller
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->MaxMode: 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->MaxMode
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->Mode: 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->Mode
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->Info->HorizontalResolution: 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->Info->HorizontalResolution
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_GRAPHICS_INFO,
> 
> +    "VkContext->GraphicsOutput->Mode->Info->VerticalResolution: 0x%08x\n",
> 
> +    VkContext->GraphicsOutput->Mode->Info->VerticalResolution
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode X: 0x%016Lx - 0x%016Lx\n",
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMinX,
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMaxX
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode Y: 0x%016Lx - 0x%016Lx\n",
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMinY,
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMaxY
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode Z: 0x%016Lx - 0x%016Lx\n",
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMinZ,
> 
> +    VkContext->AbsolutePointer->Mode->AbsoluteMaxZ
> 
> +    ));
> 
> +  DEBUG ((
> 
> +    DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_VK_POINTS,
> 
> +    "VkContext->AbsolutePointer->Mode->Attributes: 0x%08x\n",
> 
> +    VkContext->AbsolutePointer->Mode->Attributes
> 
> +    ));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Start the virtual keyboard driver
> 
> +
> 
> +  This routine allocates the necessary resources for the driver.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStart to complete the driver
> 
> +  initialization.
> 
> +
> 
> +  @param[in, out] VkContext        Address of an VK_CONTEXT structure
> 
> +  @param[in]      Controller       Handle of device to work with.
> 
> +
> 
> +  @retval EFI_SUCCESS              Driver API properly initialized
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkApiStart (
> 
> +  IN OUT VK_CONTEXT *VkContext,
> 
> +  IN EFI_HANDLE     Controller
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                        Status;
> 
> +  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
> 
> +  EFI_KEY_DATA                      KeyData;
> 
> +  EFI_HANDLE                        NotifyHandle;
> 
> +  EFI_EVENT                         ReadyToBootEvent;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Start\n"));
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_NOTIFY_SIGNAL,
> 
> +                  TPL_CALLBACK,
> 
> +                  VkKeyNotifyProcessHandler,
> 
> +                  VkContext,
> 
> +                  &VkContext->KeyNotifyProcessEvent
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create VkContext-
> >KeyNotifyProcessEvent, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_NOTIFY_WAIT,
> 
> +                  TPL_NOTIFY,
> 
> +                  VkTouchWaitForKey,
> 
> +                  VkContext,
> 
> +                  &(VkContext->SimpleTextIn.WaitForKey)
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create VkContext-
> >SimpleTextIn.WaitForKey, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_NOTIFY_WAIT,
> 
> +                  TPL_NOTIFY,
> 
> +                  VkTouchWaitForKey,
> 
> +                  VkContext,
> 
> +                  &(VkContext->SimpleTextInEx.WaitForKeyEx)
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create VkContext-
> >SimpleTextInEx.WaitForKeyEx, Status %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->CreateEvent (
> 
> +                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
> 
> +                  TPL_VK_SYNC,
> 
> +                  VkTimer,
> 
> +                  (VOID *)VkContext,
> 
> +                  &(VkContext->TimerEvent)
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create the timer event, Status: %r\n",
> Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->SetTimer (
> 
> +                  VkContext->TimerEvent,
> 
> +                  TimerPeriodic,
> 
> +                  (UINT64) VK_POLL_INTERVAL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to set the timer event, Status: %r\n",
> Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Create event to clear keyboard before boot into OS.
> 
> +  //
> 
> +  Status = EfiCreateEventReadyToBootEx (
> 
> +             TPL_CALLBACK,
> 
> +             VkReadyToBootCallBack,
> 
> +             (VOID *)VkContext,
> 
> +             &ReadyToBootEvent
> 
> +             );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to create ReadyToBootEvent,
> Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->LocateProtocol (
> 
> +                  &gEfiHiiImageExProtocolGuid,
> 
> +                  NULL,
> 
> +                  (VOID **) &VkContext->HiiImageEx
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to open HiiImageEx protocol,
> Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Initialize VkContext
> 
> +  //
> 
> +  VkContext->Signature                          = VK_SIGNATURE;
> 
> +  VkContext->Controller                         = Controller;
> 
> +  VkContext->SimpleTextIn.Reset                 = VkKeyboardReset;
> 
> +  VkContext->SimpleTextIn.ReadKeyStroke         = VkKeyboardReadKeyStroke;
> 
> +  VkContext->SimpleTextInEx.Reset               = VkKeyboardResetEx;
> 
> +  VkContext->SimpleTextInEx.ReadKeyStrokeEx     = VkKeyboardReadKeyStrokeEx;
> 
> +  VkContext->SimpleTextInEx.SetState            = VkKeyboardSetState;
> 
> +  VkContext->SimpleTextInEx.RegisterKeyNotify   = VkKeyboardRegisterKeyNotify;
> 
> +  VkContext->SimpleTextInEx.UnregisterKeyNotify = VkKeyboardUnregisterKeyNotify;
> 
> +  VkContext->IsIconShowed                       = FALSE;
> 
> +  VkContext->IsBackgroundChanged                = FALSE;
> 
> +  VkContext->PageNumber                         = 0;
> 
> +  VkContext->CurrentKeyboardDisplay             = VkDisplayAttributeNone;
> 
> +  VkContext->TargetKeyboardDisplay              = VkDisplayAttributeNone;
> 
> +  VkContext->VkBodyBackgroundBltBuffer          = NULL;
> 
> +  VkContext->VkBodyCompoundBltBuffer            = NULL;
> 
> +  VkContext->VkBodyBltSize                      = 0;
> 
> +  VkContext->VkBodyBltStartX                    = 0;
> 
> +  VkContext->VkBodyBltStartY                    = 0;
> 
> +  VkContext->VkBodyBltHeight                    = 0;
> 
> +  VkContext->VkBodyBltWidth                     = 0;
> 
> +  VkContext->IconBltBuffer                      = NULL;
> 
> +  VkContext->IconBltSize                        = 0;
> 
> +  VkContext->IconReDrawCheck                    = 0;
> 
> +  VkContext->FullIconUpdatedFlag                = FALSE;
> 
> +  VkContext->SimIconUpdatedFlag                 = FALSE;
> 
> +  VkContext->KeyStartIndex                      = 0;
> 
> +  VkContext->KeyEndIndex                        = 0;
> 
> +  VkContext->KeyToggleState                     = EFI_TOGGLE_STATE_VALID;
> 
> +  VkContext->SmallIcon                          = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_SIMPLEICON));
> 
> +  VkContext->FullIcon                           = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_FULLICON));
> 
> +  VkContext->SimKeyBody                         = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_SIMPLEKEYBOARD));
> 
> +  VkContext->DigKeyBody                         = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_DIGITKEYBOARD));
> 
> +  VkContext->CapLeKeyBody                       = VkGetImage (VkContext, IMAGE_TOKEN (IMG_VK_CAPITALLETTERKEYBOARD));
> 
> +
> 
> +  InitializeListHead (&VkContext->NotifyList);
> 
> +
> 
> +  Status = SetCharacterPosition (VkContext, 800, 600);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  Status = DrawKeyboardLayout (VkContext);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  Status = HideVkBody (VkContext);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  Status = HideVkIcon (VkContext);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  DEBUG_CODE (
> 
> +    VkDumpContext (VkContext);
> 
> +  );
> 
> +
> 
> +  Status = gBS->HandleProtocol (
> 
> +                  gST->ConsoleInHandle,
> 
> +                  &gEfiSimpleTextInputExProtocolGuid,
> 
> +                  (VOID **)&SimpleEx
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to found ConIn Protocol, Status: %r\n",
> Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  KeyData.KeyState.KeyToggleState = 0;
> 
> +  KeyData.KeyState.KeyShiftState  = 0;
> 
> +  KeyData.Key.ScanCode            = SCAN_ESC;
> 
> +  KeyData.Key.UnicodeChar         = CHAR_NULL;
> 
> +  NotifyHandle                    = NULL;
> 
> +  Status = SimpleEx->RegisterKeyNotify (
> 
> +                       SimpleEx,
> 
> +                       &KeyData,
> 
> +                       VkNotifyKeyCallback,
> 
> +                       &NotifyHandle
> 
> +                       );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to register 'Esc', Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  KeyData.KeyState.KeyToggleState = 0;
> 
> +  KeyData.KeyState.KeyShiftState  = 0;
> 
> +  KeyData.Key.ScanCode            = SCAN_NULL;
> 
> +  KeyData.Key.UnicodeChar         = CHAR_CARRIAGE_RETURN;
> 
> +  Status = SimpleEx->RegisterKeyNotify (
> 
> +                       SimpleEx,
> 
> +                       &KeyData,
> 
> +                       VkNotifyKeyCallback,
> 
> +                       &NotifyHandle
> 
> +                       );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to register 'Enter', Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  for (KeyData.Key.UnicodeChar = L' '; KeyData.Key.UnicodeChar <= L'~'; KeyData.Key.UnicodeChar++) {
> 
> +    Status = SimpleEx->RegisterKeyNotify (
> 
> +                         SimpleEx,
> 
> +                         &KeyData,
> 
> +                         VkNotifyKeyCallback,
> 
> +                         &NotifyHandle
> 
> +                         );
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      DEBUG ((
> 
> +        DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR,
> 
> +        "ERROR - Failed to register '%c', Status: %r\n",
> 
> +        KeyData.Key.UnicodeChar,
> 
> +        Status
> 
> +        ));
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +  if (EFI_ERROR(Status)) {
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  VkApiStop (VkContext);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStart End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Stop the virtual keyboard driver
> 
> +
> 
> +  This routine releases the resources allocated by VKApiStart.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStop to initiate the driver
> 
> +  shutdown.
> 
> +
> 
> +  @param[in] VkContext        Address of an VK_CONTEXT structure
> 
> +
> 
> +**/
> 
> +VOID
> 
> +VkApiStop (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_NOTIFY  *NotifyNode;
> 
> +  LIST_ENTRY *NotifyList;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop Start\n"));
> 
> +
> 
> +  Status = gBS->SetTimer (VkContext->TimerEvent, TimerCancel, 0);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  if (VkContext->KeyNotifyProcessEvent != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->KeyNotifyProcessEvent);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->KeyNotifyProcessEvent = NULL;
> 
> +  }
> 
> +
> 
> +  if (VkContext->TimerEvent != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->TimerEvent);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->TimerEvent = NULL;
> 
> +  }
> 
> +
> 
> +  if (VkContext->SimpleTextIn.WaitForKey != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->SimpleTextIn.WaitForKey);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->SimpleTextIn.WaitForKey = NULL;
> 
> +  }
> 
> +
> 
> +  if (VkContext->SimpleTextInEx.WaitForKeyEx != NULL) {
> 
> +    Status = gBS->CloseEvent (VkContext->SimpleTextInEx.WaitForKeyEx);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->SimpleTextInEx.WaitForKeyEx = NULL;
> 
> +  }
> 
> +
> 
> +  NotifyList = &VkContext->NotifyList;
> 
> +  if (NotifyList != NULL) {
> 
> +    while (!IsListEmpty (NotifyList)) {
> 
> +      NotifyNode = CR (NotifyList->ForwardLink, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
> 
> +      RemoveEntryList (NotifyList->ForwardLink);
> 
> +      gBS->FreePool (NotifyNode);
> 
> +    }
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkApiStop End\n"));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Reset the input device and optionally run diagnostics
> 
> +
> 
> +  @param[in] This                 Protocol instance pointer.
> 
> +  @param[in] ExtendedVerification Driver may perform diagnostics on reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning properly and could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReset (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  IN BOOLEAN                        ExtendedVerification
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReset Start\n"));
> 
> +  Status = EFI_SUCCESS;
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReset End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Resets the input device hardware.
> 
> +
> 
> +  The Reset() function resets the input device hardware. As part
> 
> +  of initialization process, the firmware/device will make a quick
> 
> +  but reasonable attempt to verify that the device is functioning.
> 
> +  If the ExtendedVerification flag is TRUE the firmware may take
> 
> +  an extended amount of time to verify the device is operating on
> 
> +  reset. Otherwise the reset operation is to occur as quickly as
> 
> +  possible. The hardware verification process is not defined by
> 
> +  this specification and is left up to the platform firmware or
> 
> +  driver to implement.
> 
> +
> 
> +  @param[in] This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
> 
> +
> 
> +  @param[in] ExtendedVerification Indicates that the driver may perform a more exhaustive
> 
> +                                  verification operation of the device during reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardResetEx (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN BOOLEAN                           ExtendedVerification
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx Start\n"));
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  Status = VkContext->SimpleTextIn.Reset (&VkContext->SimpleTextIn, ExtendedVerification);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_KEYS, "ERROR - Failed to VK reset, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardResetEx End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device. The WaitForKey Event can
> 
> +  be used to test for existence of a keystroke via WaitForEvent () call.
> 
> +
> 
> +  @param[in]  This         Protocol instance pointer.
> 
> +  @param[out] Key          Driver may perform diagnostics on reset.
> 
> +
> 
> +  @retval EFI_SUCCESS      The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY    There was no keystroke data available.
> 
> +  @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
> 
> +                           hardware errors.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStroke (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  OUT EFI_INPUT_KEY                  *Key
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS    Status;
> 
> +  VK_CONTEXT    *VkContext;
> 
> +  EFI_KEY_DATA  TmpKeyData;
> 
> +  EFI_TPL       OldTpl;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke Start\n"));
> 
> +
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  if (This == NULL || Key == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_PROTOCOL (This);
> 
> +
> 
> +  Status = VkKeyboardReadKeyStrokeEx (&VkContext->SimpleTextInEx, &TmpKeyData);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    goto Error;
> 
> +  }
> 
> +  *Key = TmpKeyData.Key;
> 
> +
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStroke End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device.
> 
> +
> 
> +  @param[in]  This               Protocol instance pointer.
> 
> +  @param[out] KeyData            A pointer to a buffer that is filled in with the keystroke
> 
> +                                 state data for the key that was pressed.
> 
> +
> 
> +  @retval EFI_SUCCESS            The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY          There was no keystroke data available.
> 
> +  @retval EFI_INVALID_PARAMETER  This or KeyData is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStrokeEx (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  OUT EFI_KEY_DATA                      *KeyData
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT        *VkContext;
> 
> +  EFI_STATUS        Status;
> 
> +  EFI_TPL           OldTpl;
> 
> +  EFI_KEY_DATA      TmpKeyData;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx Start\n"));
> 
> +
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  if (This == NULL || KeyData == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  while (TRUE) {
> 
> +    Status = VkPopTheKey (VkContext, &TmpKeyData);
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      DEBUG ((DEBUG_VK_KEYS, "ERROR - Failed to VkPopTheKey check whether keybuffer is empty, Status: %r\n", Status));
> 
> +      goto Error;
> 
> +    }
> 
> +    if (TmpKeyData.Key.ScanCode != SCAN_NULL || TmpKeyData.Key.UnicodeChar != CHAR_NULL) {
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +  *KeyData = TmpKeyData;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardReadKeyStrokeEx End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Set certain state for the input device.
> 
> +
> 
> +  @param[in] This                 Protocol instance pointer.
> 
> +  @param[in] KeyToggleState       A pointer to the EFI_KEY_TOGGLE_STATE to set the
> 
> +                                  state for the input device.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device state was set appropriately.
> 
> +  @retval EFI_INVALID_PARAMETER   This or KeyToggleState is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardSetState (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_KEY_TOGGLE_STATE              *KeyToggleState
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState Start\n"));
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL || KeyToggleState == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  VkContext->KeyToggleState      = *KeyToggleState;
> 
> +  VkContext->IsCapsLockFlag      = (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE;
> 
> +  VkContext->IsSupportPartialKey = (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED;
> 
> +
> 
> +  if (VkContext->PageNumber >= VkPage0 && VkContext->PageNumber <= VkPage1) {
> 
> +    VkContext->PageNumber = VkContext->IsCapsLockFlag ? VkPage1 : VkPage0;
> 
> +  }
> 
> +
> 
> +  HideVkBody (VkContext);
> 
> +  DrawKeyboardLayout (VkContext);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext->KeyToggleState:      %02x\n", VkContext->KeyToggleState));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext->IsCapsLockFlag:      %02x\n", VkContext->IsCapsLockFlag));
> 
> +  DEBUG ((DEBUG_VK_KEYS | DEBUG_INFO, "VkContext->IsSupportPartialKey: %02x\n", VkContext->IsSupportPartialKey));
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardSetState End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Register a notification function for a particular keystroke for the input device.
> 
> +
> 
> +  @param[in]  This                        Protocol instance pointer.
> 
> +  @param[in]  KeyData                     A pointer to a buffer that is filled in with the keystroke
> 
> +                                          information data for the key that was pressed.
> 
> +  @param[in]  KeyNotificationFunction     Points to the function to be called when the key
> 
> +                                          sequence is typed specified by KeyData.
> 
> +  @param[out] NotifyHandle                Points to the unique handle assigned to the registered notification.
> 
> +
> 
> +  @retval EFI_SUCCESS                     The notification function was registered successfully.
> 
> +  @retval EFI_OUT_OF_RESOURCES            Unable to allocate resources for necessary data structures.
> 
> +  @retval EFI_INVALID_PARAMETER           KeyData or NotifyHandle or KeyNotificationFunction is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardRegisterKeyNotify (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN  EFI_KEY_DATA                      *KeyData,
> 
> +  IN  EFI_KEY_NOTIFY_FUNCTION           KeyNotificationFunction,
> 
> +  OUT EFI_HANDLE                        *NotifyHandle
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  EFI_TPL    OldTpl;
> 
> +  VK_CONTEXT *VkContext;
> 
> +  LIST_ENTRY *Link;
> 
> +  VK_NOTIFY  *CurrentNotify;
> 
> +  VK_NOTIFY  *NewNotify;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify Start\n"));
> 
> +
> 
> +  //
> 
> +  // Enter critical section
> 
> +  //
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL || KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +
> 
> +  //
> 
> +  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
> 
> +  //
> 
> +  for (Link = VkContext->NotifyList.ForwardLink; Link != &VkContext->NotifyList; Link = Link->ForwardLink) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
> 
> +    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
> 
> +      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
> 
> +        *NotifyHandle = CurrentNotify;
> 
> +        Status = EFI_SUCCESS;
> 
> +        goto End;
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Allocate resource to save the notification function
> 
> +  //
> 
> +  NewNotify = (VK_NOTIFY *) AllocateZeroPool (sizeof (VK_NOTIFY));
> 
> +  if (NewNotify == NULL) {
> 
> +    Status = EFI_OUT_OF_RESOURCES;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  NewNotify->Signature         = VK_NOTIFY_SIGNATURE;
> 
> +  NewNotify->KeyNotificationFn = KeyNotificationFunction;
> 
> +  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
> 
> +  InsertTailList (&VkContext->NotifyList, &NewNotify->NotifyEntry);
> 
> +
> 
> +  *NotifyHandle = NewNotify;
> 
> +  Status        = EFI_SUCCESS;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  //
> 
> +  // Leave critical section and return
> 
> +  //
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardRegisterKeyNotify End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Remove a registered notification function from a particular keystroke.
> 
> +
> 
> +  @param[in] This                Protocol instance pointer.
> 
> +  @param[in] NotificationHandle  The handle of the notification function being unregistered.
> 
> +
> 
> +  @retval EFI_SUCCESS            The notification function was unregistered successfully.
> 
> +  @retval EFI_INVALID_PARAMETER  The NotificationHandle is invalid
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardUnregisterKeyNotify (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                        NotificationHandle
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  VK_CONTEXT *VkContext;
> 
> +  EFI_TPL    OldTpl;
> 
> +  LIST_ENTRY *Link;
> 
> +  VK_NOTIFY  *CurrentNotify;
> 
> +  BOOLEAN    IsFindNotifyHandle;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify Start\n"));
> 
> +
> 
> +  //
> 
> +  // Enter critical section
> 
> +  //
> 
> +  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> 
> +  Status = EFI_SUCCESS;
> 
> +  if (This == NULL || NotificationHandle == NULL) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +  VkContext = VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL (This);
> 
> +
> 
> +  IsFindNotifyHandle = FALSE;
> 
> +  for (Link = VkContext->NotifyList.ForwardLink; Link != &VkContext->NotifyList; Link = Link->ForwardLink) {
> 
> +    CurrentNotify = CR (Link, VK_NOTIFY, NotifyEntry, VK_NOTIFY_SIGNATURE);
> 
> +    if (CurrentNotify == NotificationHandle) {
> 
> +      //
> 
> +      // Remove the notification function from NotifyList and free resources
> 
> +      //
> 
> +      RemoveEntryList (&CurrentNotify->NotifyEntry);
> 
> +
> 
> +      gBS->FreePool (CurrentNotify);
> 
> +      IsFindNotifyHandle = TRUE;
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (!IsFindNotifyHandle) {
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  //
> 
> +  // Leave critical section and return
> 
> +  //
> 
> +  gBS->RestoreTPL (OldTpl);
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VkKeyboardUnregisterKeyNotify End\n"));
> 
> +  return Status;
> 
> +}
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c
> new file mode 100644
> index 0000000000..dcf78985ee
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.c
> @@ -0,0 +1,1364 @@
> +/** @file
> 
> +  Virtural Keyboard Layout Engine
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +//
> 
> +// 1.FullKeyboardBody
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\CapitalLetterKeyboard.bmp
> 
> +//   (2).\KeyboardLayout\DigitKeyboard.bmp
> 
> +// Based on keyboard's (startX, startY)
> 
> +//
> 
> +// Page0Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | q | w | e | r | t | y | u | i | o | p |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | | a | s | d | f | g | h | j | k | l | F2| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Caps | z | x | c | v | b | n | m |aU |Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// Page1Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | Q | W | E | R | T | Y | U | I | O | P |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | | A | S | D | F | G | H | J | K | L | F2| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Caps | Z | X | C | V | B | N | M |aU |Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// Page2Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Shift| . | ; | ' | , | . | / |F11|F12|Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       | \ | - | = | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// Page3Font
> 
> +// +---+---+---+---+---+---+---+---+---+---+---+
> 
> +// | ! | @ | # | $ | % | ^ | & | * | ( | ) |<X|| Line 0
> 
> +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +// | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +// +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +// |Shift| ~ | : | " | < | > | ? |F11|F12|Enter| Line 2
> 
> +// +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +// | Esc |12#|       Space       | | | _ | + | | Line 3
> 
> +// +-----+---+-------------------+---+---+---+-+
> 
> +//
> 
> +// 2.Screen Corner
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\SimpleIcon.bmp # Screen Corner A/B
> 
> +//   (2).\KeyboardLayout\FullIcon.bmp   # Screen Corner C/D
> 
> +// +-+------------------------------------+-+
> 
> +// |A|                                    |C|
> 
> +// +-+                                    +-+
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// +-+                                    +-+
> 
> +// |B|                                    |D|
> 
> +// +-+------------------------------------+-+
> 
> +//
> 
> +VK_STRUCT mFullKeyboardBody[] = {
> 
> +  // StartX  StartY  EndX    EndY     Page0Font            Page1Font            Page2Font            Page3Font
> 
> +  // Line 0
> 
> +  {  0x0000, 0x0000, 0x0032, 0x0032, {L'q',                L'Q',                L'1',                L'!'            }},
> 
> +  {  0x0032, 0x0000, 0x0064, 0x0032, {L'w',                L'W',                L'2',                L'@'            }},
> 
> +  {  0x0064, 0x0000, 0x0096, 0x0032, {L'e',                L'E',                L'3',                L'#'            }},
> 
> +  {  0x0096, 0x0000, 0x00C8, 0x0032, {L'r',                L'R',                L'4',                L'$'            }},
> 
> +  {  0x00C8, 0x0000, 0x00FA, 0x0032, {L't',                L'T',                L'5',                L'%'            }},
> 
> +  {  0x00FA, 0x0000, 0x012C, 0x0032, {L'y',                L'Y',                L'6',                L'^'            }},
> 
> +  {  0x012C, 0x0000, 0x015E, 0x0032, {L'u',                L'U',                L'7',                L'&'            }},
> 
> +  {  0x015E, 0x0000, 0x0190, 0x0032, {L'i',                L'I',                L'8',                L'*'            }},
> 
> +  {  0x0190, 0x0000, 0x01C2, 0x0032, {L'o',                L'O',                L'9',                L'('            }},
> 
> +  {  0x01C2, 0x0000, 0x01F4, 0x0032, {L'p',                L'P',                L'0',                L')'            }},
> 
> +  {  0x01F4, 0x0000, 0x0226, 0x0032, {VkKeyBackspace,      VkKeyBackspace,      VkKeyBackspace,      VkKeyBackspace  }},
> 
> +  // Line 1
> 
> +  {  0x0000, 0x0032, 0x0019, 0x0064, {VkKeyNull,           VkKeyNull,           VkKeyNull,           VkKeyNull       }},
> 
> +  {  0x0019, 0x0032, 0x004B, 0x0064, {L'a',                L'A',                VkKeyF1,             VkKeyF1         }},
> 
> +  {  0x004B, 0x0032, 0x007D, 0x0064, {L's',                L'S',                VkKeyF2,             VkKeyF2         }},
> 
> +  {  0x007D, 0x0032, 0x00AF, 0x0064, {L'd',                L'D',                VkKeyF3,             VkKeyF3         }},
> 
> +  {  0x00AF, 0x0032, 0x00E1, 0x0064, {L'f',                L'F',                VkKeyF4,             VkKeyF4         }},
> 
> +  {  0x00E1, 0x0032, 0x0113, 0x0064, {L'g',                L'G',                VkKeyF5,             VkKeyF5         }},
> 
> +  {  0x0113, 0x0032, 0x0145, 0x0064, {L'h',                L'H',                VkKeyF6,             VkKeyF6         }},
> 
> +  {  0x0145, 0x0032, 0x0177, 0x0064, {L'j',                L'J',                VkKeyF7,             VkKeyF7         }},
> 
> +  {  0x0177, 0x0032, 0x01A9, 0x0064, {L'k',                L'K',                VkKeyF8,             VkKeyF8         }},
> 
> +  {  0x01A9, 0x0032, 0x01DB, 0x0064, {L'l',                L'L',                VkKeyF9,             VkKeyF9         }},
> 
> +  {  0x01DB, 0x0032, 0x020D, 0x0064, {VkKeyF2,             VkKeyF2,             VkKeyF10,            VkKeyF10        }},
> 
> +  // Line 2
> 
> +  {  0x0000, 0x0064, 0x004B, 0x0096, {VkKeyCapslock,       VkKeyCapslock,       VkKeyShift,          VkKeyShift      }},
> 
> +  {  0x004B, 0x0064, 0x007D, 0x0096, {L'z',                L'Z',                L'`',                L'~'            }},
> 
> +  {  0x007D, 0x0064, 0x00AF, 0x0096, {L'x',                L'X',                L';',                L':'            }},
> 
> +  {  0x00AF, 0x0064, 0x00E1, 0x0096, {L'c',                L'C',                L'\'',               L'"'            }},
> 
> +  {  0x00E1, 0x0064, 0x0113, 0x0096, {L'v',                L'V',                L',',                L'<'            }},
> 
> +  {  0x0113, 0x0064, 0x0145, 0x0096, {L'b',                L'B',                L'.',                L'>'            }},
> 
> +  {  0x0145, 0x0064, 0x0177, 0x0096, {L'n',                L'N',                L'/',                L'?'            }},
> 
> +  {  0x0177, 0x0064, 0x01A9, 0x0096, {L'm',                L'M',                VkKeyF11,            VkKeyF11        }},
> 
> +  {  0x01A9, 0x0064, 0x01DB, 0x0096, {VkKeyUp,             VkKeyUp,             VkKeyF12,            VkKeyF12        }},
> 
> +  {  0x01DB, 0x0064, 0x0226, 0x0096, {VkKeyEnter,          VkKeyEnter,          VkKeyEnter,          VkKeyEnter      }},
> 
> +  // Line 3
> 
> +  {  0x0000, 0x0096, 0x004B, 0x00C8, {VkKeyEsc,            VkKeyEsc,            VkKeyEsc,            VkKeyEsc        }},
> 
> +  {  0x004B, 0x0096, 0x007D, 0x00C8, {VkKeyTwoPage,        VkKeyTwoPage,        VkKeyTwoPage,        VkKeyTwoPage    }},
> 
> +  {  0x007D, 0x0096, 0x0177, 0x00C8, {L' ',                L' ',                L' ',                L' '            }},
> 
> +  {  0x0177, 0x0096, 0x01A9, 0x00C8, {VkKeyLeft,           VkKeyLeft,           L'\\',               L'|'            }},
> 
> +  {  0x01A9, 0x0096, 0x01DB, 0x00C8, {VkKeyDown,           VkKeyDown,           L'-',                L'_'            }},
> 
> +  {  0x01DB, 0x0096, 0x020D, 0x00C8, {VkKeyRight,          VkKeyRight,          L'=',                L'+'            }},
> 
> +  // Screen Corner A
> 
> +  {  0x0000, 0x0000, 0x001E, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}},
> 
> +  // Screen Corner B
> 
> +  {  0x0000, 0x023A, 0x001E, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}},
> 
> +  // Screen Corner C
> 
> +  {  0x02E4, 0x0000, 0x0320, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}},
> 
> +  // Screen Corner D
> 
> +  {  0x02E4, 0x023A, 0x0320, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}}
> 
> +};
> 
> +
> 
> +//
> 
> +// 1.SimpleKeyboardBody
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\SimpleKeyboard.bmp
> 
> +// Based on keyboard's (startX, startY)
> 
> +// +-----+-----+
> 
> +// | Esc |Enter| Line 0
> 
> +// +-----+-----+
> 
> +// | Up  | Down| Line 1
> 
> +// +-----+-----+
> 
> +//
> 
> +// 2.Screen Corner
> 
> +// Follow below design
> 
> +//   (1).\KeyboardLayout\SimpleIcon.bmp # Screen Corner A/B
> 
> +//   (2).\KeyboardLayout\FullIcon.bmp   # Screen Corner C/D
> 
> +// +-+------------------------------------+-+
> 
> +// |A|                                    |C|
> 
> +// +-+                                    +-+
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// |                                        |
> 
> +// +-+                                    +-+
> 
> +// |B|                                    |D|
> 
> +// +-+------------------------------------+-+
> 
> +//
> 
> +VK_STRUCT mSimpleKeyboardBody[] = {
> 
> +  // StartX  StartY  EndX    EndY     Page0Font            Page1Font            Page2Font            Page3Font
> 
> +  // Line 0
> 
> +  {  0x0000, 0x0000, 0x0032, 0x0032, {VkKeyEsc,            VkKeyEsc,            VkKeyEsc,            VkKeyEsc        }},
> 
> +  {  0x0032, 0x0000, 0x0064, 0x0032, {VkKeyEnter,          VkKeyEnter,          VkKeyEnter,          VkKeyEnter      }},
> 
> +  // Line 1
> 
> +  {  0x0000, 0x0032, 0x0032, 0x0064, {VkKeyUp,             VkKeyUp,             VkKeyUp,             VkKeyUp         }},
> 
> +  {  0x0032, 0x0032, 0x0064, 0x0064, {VkKeyDown,           VkKeyDown,           VkKeyDown,           VkKeyDown       }},
> 
> +  // Screen Corner A
> 
> +  {  0x0000, 0x0000, 0x001E, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}},
> 
> +  // Screen Corner B
> 
> +  {  0x0000, 0x023A, 0x001E, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}},
> 
> +  // Screen Corner C
> 
> +  {  0x02E4, 0x0000, 0x0320, 0x001E, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}},
> 
> +  // Screen Corner D
> 
> +  {  0x02E4, 0x023A, 0x0320, 0x0258, {VkKeyTypeMaximum,    VkKeyTypeMaximum,    VkKeyTypeMaximum,
> VkKeyTypeMaximum}}
> 
> +};
> 
> +
> 
> +EFI_STATUS
> 
> +ModifyShiftKeyColor (
> 
> +  IN     VK_CONTEXT                    *VkContext,
> 
> +  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltBuffer
> 
> +  )
> 
> +{
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *TempBltBuffer;
> 
> +  UINTN                         BltSize;
> 
> +  BOOLEAN                       IsPressed;
> 
> +
> 
> +  TempBltBuffer = *BltBuffer;
> 
> +  BltSize       = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
> 
> +  IsPressed     = VkContext->PageNumber <= VkPage1 ?
> 
> +                  VkContext->IsCapsLockFlag :
> 
> +                  VkContext->IsShiftKeyFlag;
> 
> +
> 
> +  while (BltSize-- != 0) {
> 
> +    //
> 
> +    // Color gradient issue
> 
> +    //
> 
> +    if (((TempBltBuffer->Red - TempBltBuffer->Green) > 0x20) &&
> 
> +        ((TempBltBuffer->Red - TempBltBuffer->Blue)  > 0x20)) {
> 
> +      if (IsPressed) {
> 
> +        TempBltBuffer->Red   = 0;
> 
> +        TempBltBuffer->Green = 255;
> 
> +        TempBltBuffer->Blue  = 255;
> 
> +      } else {
> 
> +        TempBltBuffer->Red   = 255;
> 
> +        TempBltBuffer->Green = 255;
> 
> +        TempBltBuffer->Blue  = 255;
> 
> +      }
> 
> +    }
> 
> +    TempBltBuffer++;
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +MakeKeyboardTransparent (
> 
> +  IN     VK_CONTEXT                    *VkContext,
> 
> +  IN     BOOLEAN                       IsTransparent,
> 
> +  IN     EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltIn,
> 
> +  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **BltOut
> 
> +  )
> 
> +{
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Keyboard;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background;
> 
> +  UINTN                         BltSize;
> 
> +
> 
> +  if (*BltOut == NULL) {
> 
> +    *BltOut = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +    if (*BltOut == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +  }
> 
> +  Compound   = *BltOut;
> 
> +  Keyboard   = BltIn;
> 
> +  Background = VkContext->VkBodyBackgroundBltBuffer;
> 
> +  BltSize    = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
> 
> +  while (BltSize-- != 0) {
> 
> +    if (IsTransparent) {
> 
> +      Compound->Red   = (Keyboard->Red * TRANSPARENCY_WEIGHT) / 100 + (Background->Red * (100 -
> TRANSPARENCY_WEIGHT)) / 100;
> 
> +      Compound->Green = (Keyboard->Green * TRANSPARENCY_WEIGHT) / 100 + (Background->Green * (100 -
> TRANSPARENCY_WEIGHT)) / 100;
> 
> +      Compound->Blue  = (Keyboard->Blue * TRANSPARENCY_WEIGHT) / 100 + (Background->Blue * (100 -
> TRANSPARENCY_WEIGHT)) / 100;
> 
> +    } else {
> 
> +      *Compound = *Keyboard;
> 
> +    }
> 
> +    Compound++;
> 
> +    Keyboard++;
> 
> +    Background++;
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINTN      BltSize
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *CurrentBltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *CurrentBltBufferSave;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *OldBltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *OldBltBufferSave;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background;
> 
> +  UINTN                         Size;
> 
> +
> 
> +  CurrentBltBufferSave = NULL;
> 
> +  OldBltBufferSave     = NULL;
> 
> +
> 
> +  //
> 
> +  // Save original blt buffer first.
> 
> +  //
> 
> +  OldBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +  if (OldBltBuffer == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  if (VkContext->VkBodyBackgroundBltBuffer != NULL) {
> 
> +    CopyMem (OldBltBuffer, VkContext->VkBodyBackgroundBltBuffer, VkContext->VkBodyBltSize);
> 
> +  }
> 
> +
> 
> +  if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +    VkContext->VkBodyBltSize = BltSize;
> 
> +    VkContext->VkBodyBackgroundBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +    ASSERT (VkContext->VkBodyBackgroundBltBuffer != NULL);
> 
> +    if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +  } else if (BltSize > VkContext->VkBodyBltSize) {
> 
> +    VkContext->VkBodyBltSize = BltSize;
> 
> +    FreePool (VkContext->VkBodyBackgroundBltBuffer);
> 
> +    VkContext->VkBodyBackgroundBltBuffer = NULL;
> 
> +    VkContext->VkBodyBackgroundBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +    ASSERT (VkContext->VkBodyBackgroundBltBuffer != NULL);
> 
> +    if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +  } else {
> 
> +    ZeroMem (VkContext->VkBodyBackgroundBltBuffer, VkContext->VkBodyBltSize);
> 
> +  }
> 
> +
> 
> +  CurrentBltBuffer = NULL;
> 
> +  if (VkContext->IsBackgroundChanged == TRUE) {
> 
> +    //
> 
> +    // Background changed, merge current visioning blt buffer with old background blt buffer.
> 
> +    //
> 
> +    Compound   = VkContext->VkBodyCompoundBltBuffer;
> 
> +    Background = VkContext->VkBodyBackgroundBltBuffer;
> 
> +    CurrentBltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +    ASSERT (CurrentBltBuffer != NULL);
> 
> +    if (CurrentBltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +    Status = VkContext->GraphicsOutput->Blt (
> 
> +                                          VkContext->GraphicsOutput,
> 
> +                                          CurrentBltBuffer,
> 
> +                                          EfiBltVideoToBltBuffer,
> 
> +                                          VkContext->VkBodyBltStartX,
> 
> +                                          VkContext->VkBodyBltStartY,
> 
> +                                          0,
> 
> +                                          0,
> 
> +                                          VkContext->VkBodyBltWidth,
> 
> +                                          VkContext->VkBodyBltHeight,
> 
> +                                          VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                          );
> 
> +    CurrentBltBufferSave = CurrentBltBuffer;
> 
> +    OldBltBufferSave = OldBltBuffer;
> 
> +    Size = VkContext->VkBodyBltHeight * VkContext->VkBodyBltWidth;
> 
> +    while (Size-- != 0) {
> 
> +      if ((Compound->Red   != CurrentBltBuffer->Red) ||
> 
> +          (Compound->Green != CurrentBltBuffer->Green) ||
> 
> +          (Compound->Blue  != CurrentBltBuffer->Blue)) {
> 
> +        *Background = *CurrentBltBuffer;
> 
> +      } else {
> 
> +        *Background = *OldBltBuffer;
> 
> +      }
> 
> +      Compound++;
> 
> +      Background++;
> 
> +      CurrentBltBuffer++;
> 
> +      OldBltBuffer++;
> 
> +    }
> 
> +  } else {
> 
> +    //
> 
> +    // Background NOT changed, save it to VkBodyBackgroundBltBuffer directly.
> 
> +    //
> 
> +    Status = VkContext->GraphicsOutput->Blt (
> 
> +                                          VkContext->GraphicsOutput,
> 
> +                                          VkContext->VkBodyBackgroundBltBuffer,
> 
> +                                          EfiBltVideoToBltBuffer,
> 
> +                                          VkContext->VkBodyBltStartX,
> 
> +                                          VkContext->VkBodyBltStartY,
> 
> +                                          0,
> 
> +                                          0,
> 
> +                                          VkContext->VkBodyBltWidth,
> 
> +                                          VkContext->VkBodyBltHeight,
> 
> +                                          VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                          );
> 
> +  }
> 
> +
> 
> +  if (CurrentBltBufferSave != NULL) {
> 
> +    FreePool (CurrentBltBufferSave);
> 
> +  }
> 
> +  if (OldBltBufferSave != NULL) {
> 
> +    FreePool (OldBltBufferSave);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +RestoreVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  if (VkContext->VkBodyBackgroundBltBuffer == NULL) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        VkContext->VkBodyBackgroundBltBuffer,
> 
> +                                        EfiBltBufferToVideo,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->VkBodyBltStartX,
> 
> +                                        VkContext->VkBodyBltStartY,
> 
> +                                        VkContext->VkBodyBltWidth,
> 
> +                                        VkContext->VkBodyBltHeight,
> 
> +                                        VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +
> 
> +  FreePool (VkContext->VkBodyBackgroundBltBuffer);
> 
> +  VkContext->VkBodyBackgroundBltBuffer = NULL;
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +SetCharacterPosition (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     DestX,
> 
> +  IN UINT32     DestY
> 
> +  )
> 
> +{
> 
> +  UINTN     Index;
> 
> +  VK_STRUCT *KeyArryPtr;
> 
> +  UINT32    KeyArrySize;
> 
> +
> 
> +  switch (VkContext->TargetKeyboardDisplay) {
> 
> +  case VkDisplayAttributeSimpleTop:
> 
> +  case VkDisplayAttributeSimpleBottom:
> 
> +    KeyArryPtr  = mSimpleKeyboardBody;
> 
> +    KeyArrySize = DIM (mSimpleKeyboardBody);
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullBottom:
> 
> +  case VkDisplayAttributeFullTop:
> 
> +    KeyArryPtr = mFullKeyboardBody;
> 
> +    KeyArrySize = DIM (mFullKeyboardBody);
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeNone:
> 
> +    KeyArryPtr = mFullKeyboardBody;
> 
> +    KeyArrySize = DIM (mFullKeyboardBody);
> 
> +    break;
> 
> +
> 
> +  default:
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  for (Index = 0; Index < KeyArrySize; Index++) {
> 
> +    VkContext->KeyboardBodyPtr[Index] = KeyArryPtr[Index];
> 
> +  }
> 
> +  VkContext->NumOfKeysInfo = KeyArrySize;
> 
> +
> 
> +  for (Index = 0; Index < (VkContext->NumOfKeysInfo - 4); Index++) {
> 
> +    VkContext->KeyboardBodyPtr[Index].DisStartX += (UINT16)DestX;
> 
> +    VkContext->KeyboardBodyPtr[Index].DisStartY += (UINT16)DestY;
> 
> +    VkContext->KeyboardBodyPtr[Index].DisEndX   += (UINT16)DestX;
> 
> +    VkContext->KeyboardBodyPtr[Index].DisEndY   += (UINT16)DestY;
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkIconBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT           *VkContext,
> 
> +  IN VK_DISPLAY_ATTRIBUTE IconType
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GraphicBlt;
> 
> +  UINTN                         BltSize;
> 
> +  UINTN                         Height;
> 
> +  UINTN                         Width;
> 
> +  INTN                          StartX;
> 
> +  INTN                          StartY;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *TempIconBackBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *IconBackBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Compound;
> 
> +  UINTN                         Size;
> 
> +  BOOLEAN                       SaveCursor;
> 
> +
> 
> +  Status             = EFI_SUCCESS;
> 
> +  StartX             = 0;
> 
> +  StartY             = 0;
> 
> +  TempIconBackBuffer = NULL;
> 
> +  IconBackBuffer     = NULL;
> 
> +  Compound           = NULL;
> 
> +
> 
> +  if ((IconType == VkDisplayAttributeFullTop) ||
> 
> +      (IconType == VkDisplayAttributeSimpleTop)) {
> 
> +    return EFI_SUCCESS;
> 
> +  }
> 
> +
> 
> +  SaveCursor = gST->ConOut->Mode->CursorVisible;
> 
> +  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
> 
> +
> 
> +  if (IconType == VkDisplayAttributeFullBottom) {
> 
> +    GraphicBlt = VkContext->FullIcon->Bitmap;
> 
> +    BltSize    = VkContext->FullIcon->Height * VkContext->FullIcon->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
> 
> +    Height     = VkContext->FullIcon->Height;
> 
> +    Width      = VkContext->FullIcon->Width;
> 
> +    StartX     = VkContext->FullIconBackStartX;
> 
> +    StartY     = VkContext->FullIconBackStartY;
> 
> +  } else if (IconType == VkDisplayAttributeSimpleBottom) {
> 
> +    GraphicBlt = VkContext->SmallIcon->Bitmap;
> 
> +    BltSize    = VkContext->SmallIcon->Height * VkContext->SmallIcon->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
> 
> +    Height     = VkContext->SmallIcon->Height;
> 
> +    Width      = VkContext->SmallIcon->Width;
> 
> +    StartX     = VkContext->SimIconBackStartX;
> 
> +    StartY     = VkContext->SimIconBackStartY;
> 
> +  } else {
> 
> +    gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  IconBackBuffer = AllocateZeroPool (BltSize);
> 
> +  if (IconBackBuffer == NULL) {
> 
> +    gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  TempIconBackBuffer = IconBackBuffer;
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        IconBackBuffer,
> 
> +                                        EfiBltVideoToBltBuffer,
> 
> +                                        StartX,
> 
> +                                        StartY,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        Width,
> 
> +                                        Height,
> 
> +                                        Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +
> 
> +  if (IconType == VkDisplayAttributeFullBottom) {
> 
> +    //
> 
> +    // Store full icon background framebuffer
> 
> +    //
> 
> +    VkContext->FullIconBackHeight = Height;
> 
> +    VkContext->FullIconBackWidth  = Width;
> 
> +    if (VkContext->FullIconUpdatedFlag == FALSE) {
> 
> +      //
> 
> +      // No icon draw, save the buffer directly.
> 
> +      //
> 
> +      if (VkContext->FullIconBackBuffer == NULL) {
> 
> +        VkContext->FullIconBackBuffer = AllocateZeroPool (BltSize);
> 
> +        VkContext->FullIconBackSize = BltSize;
> 
> +      }
> 
> +      CopyMem (VkContext->FullIconBackBuffer, IconBackBuffer, BltSize);
> 
> +      VkContext->FullIconUpdatedFlag = TRUE;
> 
> +    } else {
> 
> +      if (CompareMem (VkContext->FullIconBackBuffer, IconBackBuffer, BltSize) != 0) {
> 
> +        Compound = VkContext->FullIconBackBuffer;
> 
> +        Size = Height * Width;
> 
> +        while (Size-- != 0) {
> 
> +          if ((GraphicBlt->Red   != IconBackBuffer->Red) ||
> 
> +              (GraphicBlt->Green != IconBackBuffer->Green) ||
> 
> +              (GraphicBlt->Blue  != IconBackBuffer->Blue)) {
> 
> +            *Compound = *IconBackBuffer;
> 
> +          }
> 
> +          Compound++;
> 
> +          GraphicBlt++;
> 
> +          IconBackBuffer++;
> 
> +        }
> 
> +      }
> 
> +    }
> 
> +  } else if (IconType == VkDisplayAttributeSimpleBottom) {
> 
> +    //
> 
> +    // Store simple icon background framebuffer
> 
> +    //
> 
> +    VkContext->SimIconBackHeight = Height;
> 
> +    VkContext->SimIconBackWidth  = Width;
> 
> +    if (VkContext->SimIconUpdatedFlag == FALSE) {
> 
> +      //
> 
> +      // No icon draw, save the buffer directly.
> 
> +      //
> 
> +      if (VkContext->SimIconBackBuffer == NULL) {
> 
> +        VkContext->SimIconBackBuffer = AllocateZeroPool (BltSize);
> 
> +        VkContext->SimIconBackSize = BltSize;
> 
> +      }
> 
> +      CopyMem (VkContext->SimIconBackBuffer, IconBackBuffer, BltSize);
> 
> +      VkContext->SimIconUpdatedFlag = TRUE;
> 
> +    } else {
> 
> +      if (CompareMem (VkContext->SimIconBackBuffer, IconBackBuffer, BltSize) != 0) {
> 
> +        Compound = VkContext->SimIconBackBuffer;
> 
> +        Size = Height * Width;
> 
> +        while (Size-- != 0) {
> 
> +          if ((GraphicBlt->Red   != IconBackBuffer->Red) ||
> 
> +              (GraphicBlt->Green != IconBackBuffer->Green) ||
> 
> +              (GraphicBlt->Blue  != IconBackBuffer->Blue)) {
> 
> +            *Compound = *IconBackBuffer;
> 
> +          }
> 
> +          Compound++;
> 
> +          GraphicBlt++;
> 
> +          IconBackBuffer++;
> 
> +        }
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (TempIconBackBuffer != NULL)  FreePool (TempIconBackBuffer);
> 
> +
> 
> +  gST->ConOut->EnableCursor (gST->ConOut, SaveCursor);
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard icon.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard icon displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkIcon (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        SizeOfX;
> 
> +  UINT32                        SizeOfY;
> 
> +  INTN                          DestX;
> 
> +  INTN                          DestY;
> 
> +  UINTN                         CoordinateX;
> 
> +  UINTN                         CoordinateY;
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
> 
> +  UINTN                         BltSize;
> 
> +  UINTN                         Height;
> 
> +  UINTN                         Width;
> 
> +
> 
> +  Status         = EFI_SUCCESS;
> 
> +  GraphicsOutput = VkContext->GraphicsOutput;
> 
> +  SizeOfX        = GraphicsOutput->Mode->Info->HorizontalResolution;
> 
> +  SizeOfY        = GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +  CoordinateX    = 0;
> 
> +  CoordinateY    = 0;
> 
> +  Height         = VkImage->Height;
> 
> +  Width          = VkImage->Width;
> 
> +  Blt            = VkImage->Bitmap;
> 
> +  BltSize        = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * (UINT32)(Width * Height);
> 
> +
> 
> +  //
> 
> +  // Calculate the display position according to Attribute.
> 
> +  //
> 
> +  switch (Attribute) {
> 
> +  case VkDisplayAttributeSimpleTop:
> 
> +    DestX = CoordinateX;
> 
> +    DestY = CoordinateY;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullTop:
> 
> +    DestX = (SizeOfX - Width - CoordinateX);
> 
> +    DestY = CoordinateY;;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullBottom:
> 
> +    DestX                         = (SizeOfX - Width - CoordinateX);
> 
> +    DestY                         = (SizeOfY - Height - CoordinateY);
> 
> +    VkContext->FullIconBackStartX = DestX;
> 
> +    VkContext->FullIconBackStartY = DestY;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeSimpleBottom:
> 
> +    DestX = CoordinateX;
> 
> +    DestY = (SizeOfY - Height - CoordinateY);
> 
> +
> 
> +    //
> 
> +    // Save to check icon/screen cleared
> 
> +    //
> 
> +    if (VkContext->IconBltBuffer == NULL) {
> 
> +      VkContext->IconBltSize   = BltSize;
> 
> +      VkContext->IconBltWidth  = Width;
> 
> +      VkContext->IconBltHeight = Height;
> 
> +      VkContext->IconBltBuffer = AllocateZeroPool (BltSize);
> 
> +    }
> 
> +    CopyMem (VkContext->IconBltBuffer, Blt, VkContext->IconBltSize);
> 
> +
> 
> +    VkContext->SimIconBackStartX = DestX;
> 
> +    VkContext->SimIconBackStartY = DestY;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeNone:
> 
> +    return EFI_SUCCESS;
> 
> +
> 
> +  default:
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  if ((DestX >= 0) && (DestY >= 0)) {
> 
> +    //
> 
> +    // Store icon background framebuffer
> 
> +    //
> 
> +    SaveVkIconBackgroundBltBuffer (VkContext, Attribute);
> 
> +    Status = GraphicsOutput->Blt (
> 
> +                               GraphicsOutput,
> 
> +                               Blt,
> 
> +                               EfiBltBufferToVideo,
> 
> +                               0,
> 
> +                               0,
> 
> +                               (UINTN) DestX,
> 
> +                               (UINTN) DestY,
> 
> +                               Width,
> 
> +                               Height,
> 
> +                               Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                               );
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkBody (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        SizeOfX;
> 
> +  UINT32                        SizeOfY;
> 
> +  INTN                          DestX;
> 
> +  INTN                          DestY;
> 
> +  UINTN                         BltSize;
> 
> +  UINTN                         Height;
> 
> +  UINTN                         Width;
> 
> +  UINTN                         CoordinateY;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltIn;
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
> 
> +
> 
> +  Status         = EFI_SUCCESS;
> 
> +  GraphicsOutput = VkContext->GraphicsOutput;
> 
> +  SizeOfX        = GraphicsOutput->Mode->Info->HorizontalResolution;
> 
> +  SizeOfY        = GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +  CoordinateY    = 0;
> 
> +  Height         = VkImage->Height;
> 
> +  Width          = VkImage->Width;
> 
> +  BltSize        = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * (UINT32)(Width * Height);
> 
> +  BltIn          = AllocateCopyPool (BltSize, VkImage->Bitmap);
> 
> +
> 
> +  if (BltIn == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Calculate the display position according to Attribute.
> 
> +  //
> 
> +  switch (Attribute) {
> 
> +  case VkDisplayAttributeSimpleTop:
> 
> +    DestX = ((SizeOfX / 2) - Width) / 4;
> 
> +    DestY = CoordinateY;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeSimpleTop;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeSimpleBottom:
> 
> +    DestX = ((SizeOfX / 2) - Width) / 4;
> 
> +    DestY = (SizeOfY - Height - CoordinateY);
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeSimpleBottom;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullTop:
> 
> +    DestX = (SizeOfX - Width) / 2;
> 
> +    DestY = CoordinateY;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeFullTop;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeFullBottom:
> 
> +    DestX = (SizeOfX - Width) / 2;
> 
> +    DestY = (SizeOfY - Height - CoordinateY);
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeFullBottom;
> 
> +    break;
> 
> +
> 
> +  case VkDisplayAttributeNone:
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    goto DVKBODY_Exit;
> 
> +
> 
> +  default:
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    Status = EFI_INVALID_PARAMETER;
> 
> +    goto DVKBODY_Exit;
> 
> +  }
> 
> +  if ((DestX >= 0) && (DestY >= 0)) {
> 
> +    SetCharacterPosition (VkContext, (UINT32)DestX, (UINT32)DestY);
> 
> +
> 
> +    //
> 
> +    // Store current framebuffer
> 
> +    //
> 
> +    VkContext->VkBodyBltStartX = DestX;
> 
> +    VkContext->VkBodyBltStartY = DestY;
> 
> +    VkContext->VkBodyBltHeight = Height;
> 
> +    VkContext->VkBodyBltWidth  = Width;
> 
> +    SaveVkBodyBackgroundBltBuffer (VkContext, BltSize);
> 
> +
> 
> +    //
> 
> +    // Free compound buffer first.
> 
> +    //
> 
> +    if (VkContext->VkBodyCompoundBltBuffer != NULL) {
> 
> +      FreePool (VkContext->VkBodyCompoundBltBuffer);
> 
> +    }
> 
> +    VkContext->VkBodyCompoundBltBuffer = NULL;
> 
> +    ModifyShiftKeyColor (VkContext, &BltIn);
> 
> +    MakeKeyboardTransparent (VkContext, TRUE, BltIn, &(VkContext->VkBodyCompoundBltBuffer));
> 
> +
> 
> +    //
> 
> +    // Draw keyboard body
> 
> +    //
> 
> +    Status = GraphicsOutput->Blt (
> 
> +                               GraphicsOutput,
> 
> +                               VkContext->VkBodyCompoundBltBuffer,
> 
> +                               EfiBltBufferToVideo,
> 
> +                               0,
> 
> +                               0,
> 
> +                               (UINTN) DestX,
> 
> +                               (UINTN) DestY,
> 
> +                               Width,
> 
> +                               Height,
> 
> +                               Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                               );
> 
> +  }
> 
> +
> 
> +
> 
> +DVKBODY_Exit:
> 
> +  if (BltIn != NULL) {
> 
> +    FreePool (BltIn);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Clear the keyboard body
> 
> +
> 
> +  @param  VkContext             Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkBody (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  RestoreVkBodyBackgroundBltBuffer (VkContext);
> 
> +  VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  Clear the keyboard icon
> 
> +
> 
> +  @param  VkContext             Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkIcon (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +
> 
> +  if ((VkContext->FullIconBackBuffer == NULL) || (VkContext->SimIconBackBuffer == NULL)) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +
> 
> +  if ((VkContext->FullIconUpdatedFlag == FALSE) || (VkContext->SimIconUpdatedFlag == FALSE)) {
> 
> +    return EFI_UNSUPPORTED;
> 
> +  }
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        VkContext->FullIconBackBuffer,
> 
> +                                        EfiBltBufferToVideo,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->FullIconBackStartX,
> 
> +                                        VkContext->FullIconBackStartY,
> 
> +                                        VkContext->FullIconBackWidth,
> 
> +                                        VkContext->FullIconBackHeight,
> 
> +                                        VkContext->FullIconBackWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +
> 
> +  ZeroMem (VkContext->FullIconBackBuffer, VkContext->FullIconBackSize);
> 
> +  VkContext->FullIconUpdatedFlag = FALSE;
> 
> +
> 
> +
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        VkContext->SimIconBackBuffer,
> 
> +                                        EfiBltBufferToVideo,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->SimIconBackStartX,
> 
> +                                        VkContext->SimIconBackStartY,
> 
> +                                        VkContext->SimIconBackWidth,
> 
> +                                        VkContext->SimIconBackHeight,
> 
> +                                        VkContext->SimIconBackWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +  if (!EFI_ERROR (Status)) {
> 
> +    if (VkContext->ScreenCheckBuffer == NULL) {
> 
> +      VkContext->ScreenCheckBufferSize = VkContext->SimIconBackHeight *
> 
> +                                         VkContext->SimIconBackWidth *
> 
> +                                         sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
> 
> +      VkContext->ScreenCheckBuffer = AllocateZeroPool (VkContext->ScreenCheckBufferSize);
> 
> +    }
> 
> +
> 
> +    CopyMem (
> 
> +      VkContext->ScreenCheckBuffer,
> 
> +      VkContext->SimIconBackBuffer,
> 
> +      (VkContext->SimIconBackHeight * VkContext->SimIconBackWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))
> 
> +      );
> 
> +  }
> 
> +  ZeroMem (VkContext->SimIconBackBuffer, VkContext->SimIconBackSize);
> 
> +  VkContext->SimIconUpdatedFlag = FALSE;
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Draw key board on the display
> 
> +
> 
> +  @param[in] VkContext          Graphic Protocol for draw the alphabet.
> 
> +
> 
> +  @retval EFI_SUCCESS           Draw keyboard was done.
> 
> +  @retval EFI_UNSUPPORTED       Did not get key mapping table.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +DrawKeyboardLayout (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +  if (!VkContext->IsIconShowed) {
> 
> +    Status = DrawVkIcon (VkContext, VkContext->SmallIcon, VkDisplayAttributeSimpleTop);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +    Status = DrawVkIcon (VkContext, VkContext->SmallIcon, VkDisplayAttributeSimpleBottom);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +    Status = DrawVkIcon (VkContext, VkContext->FullIcon,  VkDisplayAttributeFullTop);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +    Status = DrawVkIcon (VkContext, VkContext->FullIcon,  VkDisplayAttributeFullBottom);
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    VkContext->IsIconShowed = TRUE;
> 
> +  }
> 
> +
> 
> +  if (VkContext->TargetKeyboardDisplay != VkContext->CurrentKeyboardDisplay) {
> 
> +    switch (VkContext->TargetKeyboardDisplay) {
> 
> +    case VkDisplayAttributeSimpleTop:
> 
> +    case VkDisplayAttributeSimpleBottom:
> 
> +      DrawVkBody (VkContext, VkContext->SimKeyBody, VkContext->TargetKeyboardDisplay);
> 
> +      break;
> 
> +
> 
> +    case VkDisplayAttributeFullTop:
> 
> +    case VkDisplayAttributeFullBottom:
> 
> +      if (VkContext->PageNumber <= VkPage1) {
> 
> +        DrawVkBody (VkContext, VkContext->CapLeKeyBody, VkContext->TargetKeyboardDisplay);
> 
> +      } else {
> 
> +        DrawVkBody (VkContext, VkContext->DigKeyBody, VkContext->TargetKeyboardDisplay);
> 
> +      }
> 
> +
> 
> +    case VkDisplayAttributeNone:
> 
> +      break;
> 
> +
> 
> +    default:
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +EFI_STATUS
> 
> +KeyboardLayoutHandler (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     Index
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +
> 
> +  if (Index == (VkContext->NumOfKeysInfo - 4)) {
> 
> +    //
> 
> +    // Touch the LeftTop icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeSimpleTop) {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeSimpleTop;
> 
> +    }
> 
> +  } else if (Index == (VkContext->NumOfKeysInfo - 3)) {
> 
> +    //
> 
> +    // Touch the LeftBottom icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeSimpleBottom) {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeSimpleBottom;
> 
> +    }
> 
> +  } else if (Index == (VkContext->NumOfKeysInfo - 2)) {
> 
> +    //
> 
> +    // Touch the RightTop icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeFullTop) {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeFullTop;
> 
> +    }
> 
> +  } else {
> 
> +    //
> 
> +    // Touch the RightBottom icon
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay == VkDisplayAttributeFullBottom) {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    } else {
> 
> +      VkContext->TargetKeyboardDisplay = VkDisplayAttributeFullBottom;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (VkContext->TargetKeyboardDisplay == VkDisplayAttributeNone) {
> 
> +    //
> 
> +    // Just hide the current keyboard
> 
> +    //
> 
> +    HideVkBody (VkContext);
> 
> +    VkContext->KeyTouchedTimeOut = VK_REPEAT_TIMEOUT;
> 
> +
> 
> +  } else {
> 
> +    //
> 
> +    // If current keyboard status is NOT none,
> 
> +    // hide current keyboard first and then draw the target keyboard
> 
> +    //
> 
> +    if (VkContext->CurrentKeyboardDisplay != VkDisplayAttributeNone) {
> 
> +      HideVkBody (VkContext);
> 
> +    }
> 
> +    Status = DrawKeyboardLayout (VkContext);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This routine is used to check if icon has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckIconCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        VerticalResolution;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +  BltBuffer = NULL;
> 
> +  VkContext->IconReDrawCheck++;
> 
> +  if (VkContext->IconReDrawCheck <= 10) {
> 
> +    //
> 
> +    // Check it every 10 * 100ms.
> 
> +    //
> 
> +    return Status;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Check if right-bottomed region is black, if yes, clean screen happened, need to re-draw keyboard.
> 
> +  //
> 
> +  VerticalResolution    = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +  BltBuffer             = AllocateZeroPool (VkContext->IconBltSize);
> 
> +  if (BltBuffer == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        BltBuffer,
> 
> +                                        EfiBltVideoToBltBuffer,
> 
> +                                        0,
> 
> +                                        (VerticalResolution - VkContext->IconBltHeight),
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->IconBltWidth,
> 
> +                                        VkContext->IconBltHeight,
> 
> +                                        VkContext->IconBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    FreePool (BltBuffer);
> 
> +    return Status;
> 
> +  }
> 
> +  VkContext->IsIconShowed = TRUE;
> 
> +  if (VkContext->IconBltBuffer == NULL) {
> 
> +    //
> 
> +    // No icon has been drawn.
> 
> +    //
> 
> +    VkContext->IsIconShowed = FALSE;
> 
> +  } else {
> 
> +    if (CompareMem (BltBuffer, VkContext->IconBltBuffer, VkContext->IconBltSize) != 0) {
> 
> +      //
> 
> +      // Icon has been overridden, need to re-draw.
> 
> +      //
> 
> +      VkContext->IsIconShowed = FALSE;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (VkContext->IsIconShowed == FALSE) {
> 
> +    if (VkContext->ScreenCheckBuffer != NULL) {
> 
> +      if (CompareMem (BltBuffer, VkContext->ScreenCheckBuffer, VkContext->IconBltSize) == 0) {
> 
> +        //
> 
> +        // Icon has been overridden, force to re-draw the keyboard.
> 
> +        //
> 
> +        Status = DrawKeyboardLayout (VkContext);
> 
> +      } else {
> 
> +        //
> 
> +        // Save blt buffer of icon position and use it to check if icon is overridden.
> 
> +        //
> 
> +        CopyMem (VkContext->ScreenCheckBuffer, BltBuffer, VkContext->IconBltSize);
> 
> +      }
> 
> +    } else {
> 
> +      //
> 
> +      // Draw the keyboard.
> 
> +      //
> 
> +      Status = DrawKeyboardLayout (VkContext);
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (BltBuffer != NULL) {
> 
> +    FreePool (BltBuffer);
> 
> +  }
> 
> +
> 
> +  VkContext->IconReDrawCheck = 0;
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  ConvertCoordinate - Convert the touch panel's coordinate to display's coordinate.
> 
> +
> 
> +  @param[in]  VkContext             Virtual Keyboard context.
> 
> +  @param[in]  Point                 The coordinate reported from touch panel.
> 
> +  @param[out] TouchX                The coordinate X converted to display panel.
> 
> +  @param[out] TouchY                The coordinate Y converted to display panel..
> 
> +
> 
> +  @retval EFI_SUCCESS               Convert success.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +ConvertCoordinate (
> 
> +  IN  VK_CONTEXT                 *VkContext,
> 
> +  IN  EFI_ABSOLUTE_POINTER_STATE Point,
> 
> +  OUT UINT32                     *TouchX,
> 
> +  OUT UINT32                     *TouchY
> 
> +  )
> 
> +{
> 
> +  UINT64 AbsoluteMaxX;
> 
> +  UINT64 AbsoluteMaxY;
> 
> +  UINT32 HorizontalResolution;
> 
> +  UINT32 VerticalResolution;
> 
> +
> 
> +  AbsoluteMaxX         = VkContext->AbsolutePointer->Mode->AbsoluteMaxX;
> 
> +  AbsoluteMaxY         = VkContext->AbsolutePointer->Mode->AbsoluteMaxY;
> 
> +  HorizontalResolution = VkContext->GraphicsOutput->Mode->Info->HorizontalResolution;
> 
> +  VerticalResolution   = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +  *TouchX              = (UINT32) MultU64x32 (Point.CurrentX, HorizontalResolution) / (UINT32) AbsoluteMaxX;
> 
> +  *TouchY              = (UINT32) MultU64x32 (Point.CurrentY, VerticalResolution) / (UINT32) AbsoluteMaxY;
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This routine is used to check if screen has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckScreenCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  UINT32                        HorizontalResolution;
> 
> +  UINT32                        VerticalResolution;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBufferIndex;
> 
> +  UINTN                         BltSize;
> 
> +  BOOLEAN                       IsScreenCleared;
> 
> +
> 
> +  //
> 
> +  // Check left-bottom side.
> 
> +  // If IconBltBuffer is null, checking is meaningless.
> 
> +  //
> 
> +  if (VkContext->IconBltBuffer == NULL) {
> 
> +    return EFI_SUCCESS;
> 
> +  }
> 
> +
> 
> +  IsScreenCleared = FALSE;
> 
> +  Status          = EFI_SUCCESS;
> 
> +  if ((gST->ConOut->Mode->CursorColumn == 0) && (gST->ConOut->Mode->CursorRow == 0)) {
> 
> +    //
> 
> +    // System may call gST->ConOut->ClearScreen
> 
> +    //
> 
> +    HorizontalResolution  = VkContext->GraphicsOutput->Mode->Info->HorizontalResolution;
> 
> +    VerticalResolution    = VkContext->GraphicsOutput->Mode->Info->VerticalResolution;
> 
> +    BltBuffer             = AllocateZeroPool (VkContext->IconBltSize);
> 
> +    if (BltBuffer == NULL) {
> 
> +      return EFI_OUT_OF_RESOURCES;
> 
> +    }
> 
> +
> 
> +    BltBufferIndex = BltBuffer;
> 
> +    Status = VkContext->GraphicsOutput->Blt (
> 
> +                                          VkContext->GraphicsOutput,
> 
> +                                          BltBuffer,
> 
> +                                          EfiBltVideoToBltBuffer,
> 
> +                                          (HorizontalResolution - VkContext->IconBltWidth),
> 
> +                                          (VerticalResolution - VkContext->IconBltHeight),
> 
> +                                          0,
> 
> +                                          0,
> 
> +                                          VkContext->IconBltWidth,
> 
> +                                          VkContext->IconBltHeight,
> 
> +                                          VkContext->IconBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                          );
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      FreePool (BltBuffer);
> 
> +      return Status;
> 
> +    }
> 
> +    BltSize = VkContext->IconBltHeight * VkContext->IconBltWidth;
> 
> +    IsScreenCleared = TRUE;
> 
> +    while (BltSize-- != 0) {
> 
> +      if ((BltBufferIndex->Red != 0) || (BltBufferIndex->Green != 0) || (BltBufferIndex->Blue != 0)) {
> 
> +        IsScreenCleared = FALSE;
> 
> +        break;
> 
> +      }
> 
> +      BltBufferIndex++;
> 
> +    }
> 
> +    FreePool (BltBuffer);
> 
> +  }
> 
> +
> 
> +  if (IsScreenCleared == TRUE) {
> 
> +    VkContext->IsIconShowed   = FALSE;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +
> 
> +    if (VkContext->VkBodyBackgroundBltBuffer != NULL) {
> 
> +      FreePool (VkContext->VkBodyBackgroundBltBuffer);
> 
> +      VkContext->VkBodyBackgroundBltBuffer = NULL;
> 
> +    }
> 
> +
> 
> +    if (VkContext->VkBodyCompoundBltBuffer != NULL) {
> 
> +      FreePool (VkContext->VkBodyCompoundBltBuffer);
> 
> +      VkContext->VkBodyCompoundBltBuffer = NULL;
> 
> +    }
> 
> +
> 
> +    if (VkContext->IconBltBuffer != NULL) {
> 
> +      FreePool (VkContext->IconBltBuffer);
> 
> +      VkContext->IconBltBuffer = NULL;
> 
> +    }
> 
> +
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This routine is used to check if background beneath virtual keyboard has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckBackgroundChanged (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
> 
> +
> 
> +  Status                         = EFI_SUCCESS;
> 
> +  VkContext->IsBackgroundChanged = FALSE;
> 
> +
> 
> +  if ((VkContext->CurrentKeyboardDisplay == VkDisplayAttributeNone) || (VkContext->VkBodyCompoundBltBuffer ==
> NULL)) {
> 
> +    return EFI_SUCCESS;
> 
> +  }
> 
> +
> 
> +  BltBuffer = AllocateZeroPool (VkContext->VkBodyBltSize);
> 
> +  if (BltBuffer == NULL) {
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +  Status = VkContext->GraphicsOutput->Blt (
> 
> +                                        VkContext->GraphicsOutput,
> 
> +                                        BltBuffer,
> 
> +                                        EfiBltVideoToBltBuffer,
> 
> +                                        VkContext->VkBodyBltStartX,
> 
> +                                        VkContext->VkBodyBltStartY,
> 
> +                                        0,
> 
> +                                        0,
> 
> +                                        VkContext->VkBodyBltWidth,
> 
> +                                        VkContext->VkBodyBltHeight,
> 
> +                                        VkContext->VkBodyBltWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
> 
> +                                        );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    FreePool (BltBuffer);
> 
> +    return Status;
> 
> +  }
> 
> +  if (CompareMem (BltBuffer, VkContext->VkBodyCompoundBltBuffer, VkContext->VkBodyBltSize) != 0) {
> 
> +    VkContext->IsBackgroundChanged = TRUE;
> 
> +    VkContext->CurrentKeyboardDisplay = VkDisplayAttributeNone;
> 
> +    DrawKeyboardLayout (VkContext);
> 
> +  }
> 
> +
> 
> +  if (BltBuffer != NULL) {
> 
> +    FreePool (BltBuffer);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get unicode by VkContext->PageNumber and VkContext->KeyboardBodyPtr.
> 
> +
> 
> +  @param[in]  VkContext            Address of an VK_CONTEXT structure.
> 
> +  @param[in]  KeyItem              Key Item.
> 
> +  @param[out] FontPtr              Follow VkContext->PageNumber to translate
> 
> +                                   font unicode.
> 
> +
> 
> +  @retval EFI_SUCCESS              Finish translating FontPtr.
> 
> +  @retval EFI_INVALID_PARAMETER    VkContext or FontPtr is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkGetMappingFont (
> 
> +  IN  VK_CONTEXT *VkContext,
> 
> +  IN  VK_STRUCT  KeyItem,
> 
> +  OUT UINT32     *FontPtr
> 
> +  )
> 
> +{
> 
> +  if ((VkContext == NULL) || (FontPtr == NULL) || (VkContext->PageNumber>=VkPageMaximum)) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +  *FontPtr = (UINT32) KeyItem.PageFont[VkContext->PageNumber];
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf
> new file mode 100644
> index 0000000000..995bd0d859
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/KeyboardLayout.idf
> @@ -0,0 +1,12 @@
> +// /** @file
> 
> +// Virtual Keyboard Layout
> 
> +//
> 
> +// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +//
> 
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +//
> 
> +#image IMG_VK_CAPITALLETTERKEYBOARD TRANSPARENT CapitalLetterKeyboard.bmp
> 
> +#image IMG_VK_DIGITKEYBOARD         TRANSPARENT DigitKeyboard.bmp
> 
> +#image IMG_VK_FULLICON              TRANSPARENT FullIcon.bmp
> 
> +#image IMG_VK_SIMPLEICON            TRANSPARENT SimpleIcon.bmp
> 
> +#image IMG_VK_SIMPLEKEYBOARD        TRANSPARENT SimpleKeyboard.bmp
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleIcon.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleIcon.bmp
> new file mode 100644
> index 0000000000000000000000000000000000000000..16816f031eb98bf8169c7119b95ea3ed1371f41d
> GIT binary patch
> literal 2814
> zcmeHDu?>JQ41<*mn3%bM1K9bStAMDgEvtknP%#v#jj<EA^|~EHm%hdJ+18X--;Igi
> zvz~tHZ083bZvKJwS=AedIaS~0$e`HvNI;OvAp=5}kZlld1O%z<Y2HkwWx^;3ew~S4
> zE{O5qpp83T)f<O7RWIkrpxE|EK#<BI145UOZ4hn*1gY$4-b|%s!YByBnW#Y!<5EEz
> Lcf5u-&Un3EdmJn}
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleKeyboard.bmp
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/SimpleKeyboard.bmp
> new file mode 100644
> index 0000000000000000000000000000000000000000..3004a534f026fe4906e64480f2239b7b7923640b
> GIT binary patch
> literal 30054
> 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
> D{aYn_
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h
> new file mode 100644
> index 0000000000..debd4346c7
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboard.h
> @@ -0,0 +1,777 @@
> +/** @file
> 
> +  Header file for Virtual Keyboard driver.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#ifndef _VIRTUAL_KEYBOARD_H_
> 
> +#define _VIRTUAL_KEYBOARD_H_
> 
> +
> 
> +#include <Uefi.h>
> 
> +#include <Library/BaseMemoryLib.h>
> 
> +#include <Library/DebugLib.h>
> 
> +#include <Library/MemoryAllocationLib.h>
> 
> +#include <Library/UefiBootServicesTableLib.h>
> 
> +#include <Library/UefiDriverEntryPoint.h>
> 
> +#include <Library/UefiLib.h>
> 
> +#include <Library/BaseLib.h>
> 
> +#include <Library/PcdLib.h>
> 
> +#include <Library/HiiLib.h>
> 
> +#include <Protocol/AbsolutePointer.h>
> 
> +#include <Protocol/GraphicsOutput.h>
> 
> +#include <Protocol/SimpleTextIn.h>
> 
> +#include <Protocol/SimpleTextInEx.h>
> 
> +#include <Protocol/SimpleTextOut.h>
> 
> +#include <Protocol/HiiDatabase.h>
> 
> +#include <Protocol/HiiImageEx.h>
> 
> +#include <Protocol/HiiPackageList.h>
> 
> +#include <Guid/ConsoleInDevice.h>
> 
> +#include "ComponentName.h"
> 
> +
> 
> +//
> 
> +// Global Variables
> 
> +//
> 
> +extern EFI_DRIVER_BINDING_PROTOCOL   gVirtualKeyboardDriverBinding;
> 
> +extern EFI_COMPONENT_NAME_PROTOCOL   gVirtualKeyboardComponentName;
> 
> +extern EFI_COMPONENT_NAME2_PROTOCOL  gVirtualKeyboardComponentName2;
> 
> +
> 
> +///
> 
> +/// Debug raw data points
> 
> +///
> 
> +#define DEBUG_VK_POINTS               0x40000000
> 
> +
> 
> +///
> 
> +/// Debug data point scaling
> 
> +///
> 
> +#define DEBUG_VK_POINT_SCALING        0x20000000
> 
> +
> 
> +///
> 
> +/// Debug key press
> 
> +///
> 
> +#define DEBUG_VK_KEYS                 0x10000000
> 
> +
> 
> +///
> 
> +/// Debug routine entry and exit
> 
> +///
> 
> +#define DEBUG_VK_ROUTINE_ENTRY_EXIT   0x08000000
> 
> +
> 
> +///
> 
> +/// Display the graphics info
> 
> +///
> 
> +#define DEBUG_VK_GRAPHICS_INFO        0x04000000
> 
> +
> 
> +///
> 
> +/// Display the timer entry and exit
> 
> +///
> 
> +#define DEBUG_VK_TIMER_ENTRY_EXIT     0x00100000
> 
> +
> 
> +///
> 
> +/// Signature
> 
> +///
> 
> +#define VK_SIGNATURE                  SIGNATURE_32 ('V', 'K', 'e', 'y')
> 
> +#define VK_NOTIFY_SIGNATURE           SIGNATURE_32 ('V', 'K', 'n', 's')
> 
> +
> 
> +///
> 
> +/// Poll interval
> 
> +///
> 
> +#define VK_POLL_INTERVAL              (1000 * 1000)
> 
> +
> 
> +///
> 
> +/// Define the touch timeout in poll intervals
> 
> +///
> 
> +#define VK_REPEAT_TIMEOUT             5
> 
> +
> 
> +///
> 
> +/// TPL used to synchronize add/remove from list
> 
> +///
> 
> +#define TPL_VK_SYNC                   TPL_NOTIFY
> 
> +
> 
> +///
> 
> +/// Dimension of an array ( number of elements )
> 
> +///
> 
> +#define DIM(x)      ( sizeof ( x ) / sizeof ( x [ 0 ]))
> 
> +
> 
> +///
> 
> +/// Define Key buffer
> 
> +///
> 
> +#define MAX_KEY_BUF_SIZE 64
> 
> +
> 
> +///
> 
> +/// Define Transparent Weight
> 
> +///
> 
> +#define TRANSPARENCY_WEIGHT 50
> 
> +
> 
> +typedef struct _VK_CONTEXT VK_CONTEXT;
> 
> +
> 
> +typedef enum _VK_KEY_TYPE {
> 
> +  VkKeyNull         = 0x0000 | CHAR_NULL,
> 
> +  VkKeyBackspace    = 0x0000 | CHAR_BACKSPACE,
> 
> +  VkKeyTab          = 0x0000 | CHAR_TAB,
> 
> +  VkKeyEnter        = 0x0000 | CHAR_CARRIAGE_RETURN,
> 
> +  VkKeyScanMask     = 0x1000,
> 
> +  VkKeyEsc          = 0x1000 | SCAN_ESC,
> 
> +  VkKeyLeft         = 0x1000 | SCAN_LEFT,
> 
> +  VkKeyRight        = 0x1000 | SCAN_RIGHT,
> 
> +  VkKeyUp           = 0x1000 | SCAN_UP,
> 
> +  VkKeyDown         = 0x1000 | SCAN_DOWN,
> 
> +  VkKeyF1           = 0x1000 | SCAN_F1,
> 
> +  VkKeyF2           = 0x1000 | SCAN_F2,
> 
> +  VkKeyF3           = 0x1000 | SCAN_F3,
> 
> +  VkKeyF4           = 0x1000 | SCAN_F4,
> 
> +  VkKeyF5           = 0x1000 | SCAN_F5,
> 
> +  VkKeyF6           = 0x1000 | SCAN_F6,
> 
> +  VkKeyF7           = 0x1000 | SCAN_F7,
> 
> +  VkKeyF8           = 0x1000 | SCAN_F8,
> 
> +  VkKeyF9           = 0x1000 | SCAN_F9,
> 
> +  VkKeyF10          = 0x1000 | SCAN_F10,
> 
> +  VkKeyF11          = 0x1000 | SCAN_F11,
> 
> +  VkKeyF12          = 0x1000 | SCAN_F12,
> 
> +  VkKeySpecificMask = 0x2000,
> 
> +  VkKeyShift        = 0x2000 | 0x0000,
> 
> +  VkKeyCapslock     = 0x2000 | 0x0001,
> 
> +  VkKeyTwoPage      = 0x2000 | 0x0002,
> 
> +  VkKeyTypeMaximum  = 0xFFFF
> 
> +} VK_KEY_TYPE;
> 
> +
> 
> +typedef enum _VK_PAGE_TYPE {
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | q | w | e | r | t | y | u | i | o | p |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | | a | s | d | f | g | h | j | k | l | F2| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Caps | z | x | c | v | b | n | m |aU |Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage0,
> 
> +
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | Q | W | E | R | T | Y | U | I | O | P |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | | A | S | D | F | G | H | J | K | L | F2| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Caps | Z | X | C | V | B | N | M |aU |Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       |aL |aD |aR | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage1,
> 
> +
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Shift| . | ; | ' | , | . | / |F11|F12|Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       | \ | - | = | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage2,
> 
> +
> 
> +  //
> 
> +  // +---+---+---+---+---+---+---+---+---+---+---+
> 
> +  // | ! | @ | # | $ | % | ^ | & | * | ( | ) |<X|| Line 0
> 
> +  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> 
> +  // | |F1 |F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10| | Line 1
> 
> +  // +-+---+---+---+---+---+---+---+---+---+---+-+
> 
> +  // |Shift| ~ | : | " | < | > | ? |F11|F12|Enter| Line 2
> 
> +  // +-----+---+---+---+---+---+---+---+---+---+-+
> 
> +  // | Esc |12#|       Space       | | | _ | + | | Line 3
> 
> +  // +-----+---+-------------------+---+---+---+-+
> 
> +  //
> 
> +  VkPage3,
> 
> +  VkPageMaximum
> 
> +} VK_PAGE_TYPE;
> 
> +
> 
> +typedef enum VK_DISPLAY_ATTRIBUTE {
> 
> +  VkDisplayAttributeNone,         /// No keyboard displayed
> 
> +  VkDisplayAttributeFullTop,      /// Full keyboard display at top
> 
> +  VkDisplayAttributeFullBottom,   /// Full keyboard display at bottom
> 
> +  VkDisplayAttributeSimpleTop,    /// Simple keyboard display at top
> 
> +  VkDisplayAttributeSimpleBottom, /// Simple keyboard display at bottom
> 
> +  VkDisplayAttributeMaximum
> 
> +} VK_DISPLAY_ATTRIBUTE;
> 
> +
> 
> +typedef struct _VK_STRUCT {
> 
> +  UINT16      DisStartX;
> 
> +  UINT16      DisStartY;
> 
> +  UINT16      DisEndX;
> 
> +  UINT16      DisEndY;
> 
> +  VK_KEY_TYPE PageFont[VkPageMaximum];
> 
> +} VK_STRUCT;
> 
> +
> 
> +typedef struct _VK_NOTIFY {
> 
> +  UINTN                               Signature;
> 
> +  EFI_KEY_DATA                        KeyData;
> 
> +  EFI_KEY_NOTIFY_FUNCTION             KeyNotificationFn;
> 
> +  LIST_ENTRY                          NotifyEntry;
> 
> +} VK_NOTIFY;
> 
> +
> 
> +///
> 
> +/// Virtual Keyboard context
> 
> +///
> 
> +struct _VK_CONTEXT {
> 
> +  ///
> 
> +  /// Structure identification
> 
> +  ///
> 
> +  UINTN                             Signature;
> 
> +
> 
> +  ///
> 
> +  /// Controller Handle
> 
> +  ///
> 
> +  EFI_HANDLE                        Controller;
> 
> +
> 
> +  ///
> 
> +  /// Upper level API
> 
> +  ///
> 
> +  EFI_SIMPLE_TEXT_INPUT_PROTOCOL    SimpleTextIn;
> 
> +
> 
> +  ///
> 
> +  /// Simple Text In EX
> 
> +  ///
> 
> +  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleTextInEx;
> 
> +
> 
> +  ///
> 
> +  /// Lower level APIs
> 
> +  ///
> 
> +  EFI_ABSOLUTE_POINTER_PROTOCOL     *AbsolutePointer;
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL      *GraphicsOutput;
> 
> +
> 
> +  ///
> 
> +  /// Flag when the last poll indicated a touch event
> 
> +  ///
> 
> +  BOOLEAN                           TouchActive;
> 
> +
> 
> +  ///
> 
> +  /// Time to poll for touch input
> 
> +  ///
> 
> +  EFI_EVENT                         TimerEvent;
> 
> +
> 
> +  ///
> 
> +  /// HII handle to get image data used
> 
> +  ///
> 
> +  EFI_HII_HANDLE                    HiiHandle;
> 
> +  EFI_HII_IMAGE_EX_PROTOCOL         *HiiImageEx;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard body background buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *VkBodyBackgroundBltBuffer;
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *VkBodyCompoundBltBuffer;
> 
> +  UINTN                             VkBodyBltSize;
> 
> +  UINTN                             VkBodyBltStartX;
> 
> +  UINTN                             VkBodyBltStartY;
> 
> +  UINTN                             VkBodyBltHeight;
> 
> +  UINTN                             VkBodyBltWidth;
> 
> +  BOOLEAN                           IsBackgroundChanged;
> 
> +
> 
> +  ///
> 
> +  /// Icon buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *IconBltBuffer;
> 
> +  UINTN                             IconBltSize;
> 
> +  UINTN                             IconBltHeight;
> 
> +  UINTN                             IconBltWidth;
> 
> +
> 
> +  ///
> 
> +  /// Full icon background buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *FullIconBackBuffer;
> 
> +  UINTN                             FullIconBackStartX;
> 
> +  UINTN                             FullIconBackStartY;
> 
> +  UINTN                             FullIconBackHeight;
> 
> +  UINTN                             FullIconBackWidth;
> 
> +  UINTN                             FullIconBackSize;
> 
> +  BOOLEAN                           FullIconUpdatedFlag;
> 
> +
> 
> +  ///
> 
> +  /// Simple icon background buffer information
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *SimIconBackBuffer;
> 
> +  UINTN                             SimIconBackStartX;
> 
> +  UINTN                             SimIconBackStartY;
> 
> +  UINTN                             SimIconBackHeight;
> 
> +  UINTN                             SimIconBackWidth;
> 
> +  UINTN                             SimIconBackSize;
> 
> +  BOOLEAN                           SimIconUpdatedFlag;
> 
> +
> 
> +  ///
> 
> +  /// Small Icon
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *SmallIcon;
> 
> +
> 
> +  ///
> 
> +  /// Full Icon
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *FullIcon;
> 
> +
> 
> +  ///
> 
> +  /// Simple Key body
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *SimKeyBody;
> 
> +
> 
> +  ///
> 
> +  /// Digital key body
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *DigKeyBody;
> 
> +
> 
> +  ///
> 
> +  /// Capital Letter Key board
> 
> +  ///
> 
> +  EFI_IMAGE_INPUT                   *CapLeKeyBody;
> 
> +
> 
> +  ///
> 
> +  /// Screen check buffer.
> 
> +  /// This is used to check if screen is kept scrolling up.
> 
> +  ///
> 
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *ScreenCheckBuffer;
> 
> +  UINTN                             ScreenCheckBufferSize;
> 
> +
> 
> +  ///
> 
> +  /// Key state
> 
> +  ///
> 
> +  BOOLEAN                           KeyPressed;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard display status
> 
> +  ///
> 
> +  VK_DISPLAY_ATTRIBUTE              CurrentKeyboardDisplay;
> 
> +  VK_DISPLAY_ATTRIBUTE              TargetKeyboardDisplay;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard icon display status
> 
> +  ///
> 
> +  BOOLEAN                           IsIconShowed;
> 
> +  UINT8                             IconReDrawCheck;
> 
> +
> 
> +  ///
> 
> +  /// Keyboard body Image address
> 
> +  /// Size of KeyboardBodyPtr must larger than mFullKeyboardBody
> 
> +  ///
> 
> +  UINT32                            NumOfKeysInfo;
> 
> +  VK_STRUCT                         KeyboardBodyPtr[50];
> 
> +
> 
> +  ///
> 
> +  /// KeyBuffer
> 
> +  ///
> 
> +  EFI_EVENT                         KeyNotifyProcessEvent;
> 
> +  EFI_KEY_TOGGLE_STATE              KeyToggleState;
> 
> +  EFI_KEY_DATA                      Keybuffer[MAX_KEY_BUF_SIZE];
> 
> +  UINT8                             KeyStartIndex;
> 
> +  UINT8                             KeyEndIndex;
> 
> +  UINT16                            KeyTouchedTimeOut;
> 
> +  BOOLEAN                           IsShiftKeyFlag;
> 
> +  BOOLEAN                           IsCapsLockFlag;
> 
> +  BOOLEAN                           IsSupportPartialKey;
> 
> +  BOOLEAN                           IsRedrawUpdateUI;
> 
> +  VK_PAGE_TYPE                      PageNumber;
> 
> +  LIST_ENTRY                        NotifyList;
> 
> +};
> 
> +
> 
> +///
> 
> +/// Locate VK_CONTEXT from protocol
> 
> +///
> 
> +#define VK_CONTEXT_FROM_PROTOCOL(a)                CR (a, VK_CONTEXT, SimpleTextIn, VK_SIGNATURE)
> 
> +#define VK_CONTEXT_FROM_SIMPLETEXTINEX_PROTOCOL(a) CR (a, VK_CONTEXT, SimpleTextInEx, VK_SIGNATURE)
> 
> +#define VK_CONTEXT_FROM_VKBD_PROTOCOL(a)           CR (a, VK_CONTEXT, VkbdProtocol, VK_SIGNATURE)
> 
> +
> 
> +/**
> 
> +  Start the virtual keyboard driver
> 
> +
> 
> +  This routine allocates the necessary resources for the driver.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStart to complete the driver
> 
> +  initialization.
> 
> +
> 
> +  @param[in, out] VkContext        Address of an VK_CONTEXT structure
> 
> +  @param[in] Controller            Handle of device to work with.
> 
> +
> 
> +  @retval EFI_SUCCESS              Driver API properly initialized
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkApiStart (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN EFI_HANDLE Controller
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Stop the virtual keyboard driver
> 
> +
> 
> +  This routine releases the resources allocated by VKApiStart.
> 
> +
> 
> +  This routine is called by VirtualKeyboardDriverStop to initiate the driver
> 
> +  shutdown.
> 
> +
> 
> +  @param[in] VkContext        Address of an VK_CONTEXT structure
> 
> +
> 
> +**/
> 
> +VOID
> 
> +VkApiStop (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Resets the input device hardware.
> 
> +
> 
> +  The Reset() function resets the input device hardware. As part
> 
> +  of initialization process, the firmware/device will make a quick
> 
> +  but reasonable attempt to verify that the device is functioning.
> 
> +  If the ExtendedVerification flag is TRUE the firmware may take
> 
> +  an extended amount of time to verify the device is operating on
> 
> +  reset. Otherwise the reset operation is to occur as quickly as
> 
> +  possible. The hardware verification process is not defined by
> 
> +  this specification and is left up to the platform firmware or
> 
> +  driver to implement.
> 
> +
> 
> +  @param[in] This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
> 
> +
> 
> +  @param[in] ExtendedVerification Indicates that the driver may perform a more exhaustive
> 
> +                                  verification operation of the device during reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReset (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  IN BOOLEAN                        ExtendedVerification
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device. The WaitForKey Event can
> 
> +  be used to test for existence of a keystroke via WaitForEvent () call.
> 
> +
> 
> +  @param[in]  This         Protocol instance pointer.
> 
> +  @param[out] Key          Driver may perform diagnostics on reset.
> 
> +
> 
> +  @retval EFI_SUCCESS      The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY    There was no keystroke data available.
> 
> +  @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
> 
> +                           hardware errors.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStroke (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
> 
> +  OUT EFI_INPUT_KEY                  *Key
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Resets the input device hardware.
> 
> +
> 
> +  The Reset() function resets the input device hardware. As part
> 
> +  of initialization process, the firmware/device will make a quick
> 
> +  but reasonable attempt to verify that the device is functioning.
> 
> +  If the ExtendedVerification flag is TRUE the firmware may take
> 
> +  an extended amount of time to verify the device is operating on
> 
> +  reset. Otherwise the reset operation is to occur as quickly as
> 
> +  possible. The hardware verification process is not defined by
> 
> +  this specification and is left up to the platform firmware or
> 
> +  driver to implement.
> 
> +
> 
> +  @param[in] This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
> 
> +
> 
> +  @param[in] ExtendedVerification Indicates that the driver may perform a more exhaustive
> 
> +                                  verification operation of the device during reset.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device was reset.
> 
> +  @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could not be reset.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardResetEx (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN BOOLEAN                           ExtendedVerification
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Reads the next keystroke from the input device.
> 
> +
> 
> +  @param[in]  This               Protocol instance pointer.
> 
> +  @param[out] KeyData            A pointer to a buffer that is filled in with the keystroke
> 
> +                                 state data for the key that was pressed.
> 
> +
> 
> +  @retval EFI_SUCCESS            The keystroke information was returned.
> 
> +  @retval EFI_NOT_READY          There was no keystroke data available.
> 
> +  @retval EFI_INVALID_PARAMETER  This or KeyData is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardReadKeyStrokeEx (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  OUT EFI_KEY_DATA                      *KeyData
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Set certain state for the input device.
> 
> +
> 
> +  @param[in] This                 Protocol instance pointer.
> 
> +  @param[in] KeyToggleState       A pointer to the EFI_KEY_TOGGLE_STATE to set the
> 
> +                                  state for the input device.
> 
> +
> 
> +  @retval EFI_SUCCESS             The device state was set appropriately.
> 
> +  @retval EFI_INVALID_PARAMETER   This or KeyToggleState is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardSetState (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_KEY_TOGGLE_STATE              *KeyToggleState
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Register a notification function for a particular keystroke for the input device.
> 
> +
> 
> +  @param[in]  This                        Protocol instance pointer.
> 
> +  @param[in]  KeyData                     A pointer to a buffer that is filled in with the keystroke
> 
> +                                          information data for the key that was pressed.
> 
> +  @param[in]  KeyNotificationFunction     Points to the function to be called when the key
> 
> +                                          sequence is typed specified by KeyData.
> 
> +  @param[out] NotifyHandle                Points to the unique handle assigned to the registered notification.
> 
> +
> 
> +  @retval EFI_SUCCESS                     The notification function was registered successfully.
> 
> +  @retval EFI_OUT_OF_RESOURCES            Unable to allocate resources for necessary data structures.
> 
> +  @retval EFI_INVALID_PARAMETER           KeyData or NotifyHandle or KeyNotificationFunction is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardRegisterKeyNotify (
> 
> +  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN  EFI_KEY_DATA                      *KeyData,
> 
> +  IN  EFI_KEY_NOTIFY_FUNCTION           KeyNotificationFunction,
> 
> +  OUT EFI_HANDLE                        *NotifyHandle
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Remove a registered notification function from a particular keystroke.
> 
> +
> 
> +  @param[in] This                Protocol instance pointer.
> 
> +  @param[in] NotificationHandle  The handle of the notification function being unregistered.
> 
> +
> 
> +  @retval EFI_SUCCESS            The notification function was unregistered successfully.
> 
> +  @retval EFI_INVALID_PARAMETER  The NotificationHandle is invalid
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VkKeyboardUnregisterKeyNotify (
> 
> +  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                        NotificationHandle
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Draw key board on the display
> 
> +
> 
> +  @param[in] VkContext          Graphic Protocol for draw the alphabet.
> 
> +
> 
> +  @retval EFI_SUCCESS           Draw keyboard was done.
> 
> +  @retval EFI_UNSUPPORTED       Did not get key mapping table.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +DrawKeyboardLayout (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Clear the keyboard body
> 
> +
> 
> +  @param[in] VkContext          Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkBody (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Clear the keyboard icon
> 
> +
> 
> +  @param[in] VkContext          Code context.
> 
> +
> 
> +  @retval EFI_SUCCESS           Clear rectangle is done.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +HideVkIcon (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard icon.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard icon displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkIcon (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Use to draw the keyboard.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +  @param[in] VkImage    Image of keyboard to display on the screen.
> 
> +  @param[in] Attribute  Attribute of keyboard to display on the screen.
> 
> +
> 
> +  @retval EFI_SUCCESS           ConsoleControl has been flipped to graphics and keyboard displayed.
> 
> +  @retval EFI_UNSUPPORTED       KeyboardFile not found
> 
> +  @retval EFI_INVALID_PARAMETER Attribute is unknown.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +DrawVkBody (
> 
> +  IN VK_CONTEXT                    *VkContext,
> 
> +  IN EFI_IMAGE_INPUT               *VkImage,
> 
> +  IN VK_DISPLAY_ATTRIBUTE          Attribute
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Get unicode by VkContext->PageNumber and VkContext->KeyboardBodyPtr.
> 
> +
> 
> +  @param[in]  VkContext            Address of an VK_CONTEXT structure.
> 
> +  @param[in]  KeyItem              Key Item.
> 
> +  @param[out] FontPtr              Follow VkContext->PageNumber to translate
> 
> +                                   font unicode.
> 
> +
> 
> +  @retval EFI_SUCCESS              Finish translating FontPtr.
> 
> +  @retval EFI_INVALID_PARAMETER    VkContext or FontPtr is NULL.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +VkGetMappingFont (
> 
> +  IN  VK_CONTEXT *VkContext,
> 
> +  IN  VK_STRUCT  KeyItem,
> 
> +  OUT UINT32     *FontPtr
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This routine is used to check if icon has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckIconCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  ConvertCoordinate - Convert the touch panel's coordinate to display's coordinate.
> 
> +
> 
> +  @param[in]  VkContext             Virtual Keyboard context.
> 
> +  @param[in]  Point                 The coordinate reported from touch panel.
> 
> +  @param[out] TouchX                The coordinate X converted to display panel.
> 
> +  @param[out] TouchY                The coordinate Y converted to display panel..
> 
> +
> 
> +  @retval EFI_SUCCESS               Convert success.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +ConvertCoordinate (
> 
> +  IN  VK_CONTEXT                 *VkContext,
> 
> +  IN  EFI_ABSOLUTE_POINTER_STATE Point,
> 
> +  OUT UINT32                     *TouchX,
> 
> +  OUT UINT32                     *TouchY
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This routine is used to check if screen has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckScreenCleared (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This routine is used to check if background beneath virtual keyboard has been cleared.
> 
> +
> 
> +  @param[in] VkContext  Pointer to virtual keyboard's context
> 
> +
> 
> +  @retval EFI_SUCCESS   Function completed.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +CheckBackgroundChanged (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +/**
> 
> +  To prevent screen keyboard layout occur scroll up
> 
> +
> 
> +  @param[in]  VkContext            Address of an VK_CONTEXT structure.
> 
> +
> 
> +**/
> 
> +VOID
> 
> +PreventScreenScrollUp (
> 
> +  IN OUT VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +SetCharacterPosition (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     DestX,
> 
> +  IN UINT32     DestY
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +KeyboardLayoutHandler (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINT32     Index
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext,
> 
> +  IN UINTN      BltSize
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +RestoreVkBodyBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT *VkContext
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +SaveVkIconBackgroundBltBuffer (
> 
> +  IN VK_CONTEXT           *VkContext,
> 
> +  IN VK_DISPLAY_ATTRIBUTE IconType
> 
> +  );
> 
> +#endif
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c
> new file mode 100644
> index 0000000000..42ad493a9f
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDriver.c
> @@ -0,0 +1,541 @@
> +/** @file
> 
> +  Virtual Keyboard driver.
> 
> +
> 
> +  Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include "VirtualKeyboard.h"
> 
> +
> 
> +UINT32         mOrigConOutRow      = 0;
> 
> +UINT32         mOrigSetupConOutRow = 0;
> 
> +EFI_HII_HANDLE mHiiHandle          = NULL;
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverSupported (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStart (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  );
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStop (
> 
> +  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  Controller,
> 
> +  IN  UINTN                       NumberOfChildren,
> 
> +  IN  EFI_HANDLE                  *ChildHandleBuffer
> 
> +  );
> 
> +
> 
> +EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = {
> 
> +  VirtualKeyboardDriverSupported,
> 
> +  VirtualKeyboardDriverStart,
> 
> +  VirtualKeyboardDriverStop,
> 
> +  0x10,
> 
> +  NULL,
> 
> +  NULL
> 
> +};
> 
> +
> 
> +/**
> 
> +  This is the declaration of an EFI image entry point. This entry point is
> 
> +  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
> 
> +  both device drivers and bus drivers.
> 
> +
> 
> +  @param  ImageHandle           The firmware allocated handle for the UEFI image.
> 
> +  @param  SystemTable           A pointer to the EFI System Table.
> 
> +
> 
> +  @retval EFI_SUCCESS           The operation completed successfully.
> 
> +  @retval Others                An unexpected error occurred.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverEntryPoint (
> 
> +  IN EFI_HANDLE       ImageHandle,
> 
> +  IN EFI_SYSTEM_TABLE *SystemTable
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                     Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverEntryPoint Start\n"));
> 
> +  //
> 
> +  // Install UEFI Driver Model protocol(s).
> 
> +  //
> 
> +  Status = EfiLibInstallDriverBindingComponentName2 (
> 
> +             ImageHandle,
> 
> +             SystemTable,
> 
> +             &gVirtualKeyboardDriverBinding,
> 
> +             ImageHandle,
> 
> +             &gVirtualKeyboardComponentName,
> 
> +             &gVirtualKeyboardComponentName2
> 
> +             );
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  mHiiHandle = HiiAddPackages (
> 
> +                 &gEfiCallerIdGuid,
> 
> +                 NULL,
> 
> +                 VirtualKeyboardDxeImages,
> 
> +                 NULL
> 
> +                 );
> 
> +  ASSERT (mHiiHandle != NULL);
> 
> +
> 
> +  mOrigConOutRow      = PcdGet32 (PcdConOutRow);
> 
> +  mOrigSetupConOutRow = PcdGet32 (PcdSetupConOutRow);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverEntryPoint End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Verify the controller type
> 
> +
> 
> +  This routine determines if the pointer and GOP are available.
> 
> +
> 
> +  This routine is called by the UEFI driver framework during connect
> 
> +  processing.
> 
> +
> 
> +  @param[in] DriverBinding        Protocol instance pointer.
> 
> +  @param[in] Controller           Handle of device to test.
> 
> +  @param[in] RemainingDevicePath  Not used.
> 
> +
> 
> +  @retval EFI_SUCCESS             This driver supports this device.
> 
> +  @retval other                   This driver does not support this device.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverSupported (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  )
> 
> +{
> 
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
> 
> +  EFI_STATUS                    Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverSupported Start\n"));
> 
> +
> 
> +  //
> 
> +  // Verify that the driver is not already started
> 
> +  //
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (!EFI_ERROR (Status)) {
> 
> +    Status = EFI_ALREADY_STARTED;
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK has already initialized\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Determine if the pointer protocol is available.
> 
> +  // This should be installed in touch driver.
> 
> +  //
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiAbsolutePointerProtocolGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Absolute pointer protocol not found\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiTouchPanelGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Touch Panel Guid not found\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Determine if the graphics output protocol is available
> 
> +  //
> 
> +  Status = gBS->HandleProtocol (
> 
> +                  gST->ConsoleOutHandle,
> 
> +                  &gEfiGraphicsOutputProtocolGuid,
> 
> +                  (VOID **)&GraphicsOutput
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - VK Graphics output protocol not found\n"));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO, "VirtualKeyboardDriverSupported Success, Status: %r\n",
> Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverSupported Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverSupported End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Connect to the controller
> 
> +
> 
> +  This routine initializes an instance of the virutal keyboard driver for this
> 
> +  controller.
> 
> +
> 
> +  This routine is called by the UEFI driver framework during connect
> 
> +  processing if the controller passes the tests in I2cBusDriverSupported.
> 
> +
> 
> +  @param[in] DriverBinding        Protocol instance pointer.
> 
> +  @param[in] Controller           Handle of device to work with.
> 
> +  @param[in] RemainingDevicePath  Not used, always produce all possible children.
> 
> +
> 
> +  @retval EFI_SUCCESS             This driver is added to Controller.
> 
> +  @retval other                   This driver does not support this device.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStart (
> 
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN EFI_HANDLE                  Controller,
> 
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT *VkContext;
> 
> +  EFI_STATUS Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO, "VirtualKeyboardDriverStart Start\n"));
> 
> +
> 
> +  VkContext = AllocateZeroPool (sizeof (VK_CONTEXT));
> 
> +  if (VkContext == NULL) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - No memory for virtual keyboard driver\n"));
> 
> +    Status = EFI_OUT_OF_RESOURCES;
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiAbsolutePointerProtocolGuid,
> 
> +                  (VOID**) &VkContext->AbsolutePointer,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to open absolute pointer protocol,
> Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiTouchPanelGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - TouchPanel GUID not found, Status: %r\n",
> Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->HandleProtocol (
> 
> +                  gST->ConsoleOutHandle,
> 
> +                  &gEfiGraphicsOutputProtocolGuid,
> 
> +                  (VOID**) &VkContext->GraphicsOutput
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Graphics output protocol not available,
> Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  VkContext->HiiHandle = mHiiHandle;
> 
> +  Status = VkApiStart (VkContext, Controller);
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to VkApiStart, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> 
> +                  &Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  VkContext,
> 
> +                  &gEfiSimpleTextInProtocolGuid,
> 
> +                  &VkContext->SimpleTextIn,
> 
> +                  &gEfiSimpleTextInputExProtocolGuid,
> 
> +                  &VkContext->SimpleTextInEx,
> 
> +                  &gEfiConsoleInDeviceGuid,
> 
> +                  NULL,
> 
> +                  NULL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_ERROR, "ERROR - Failed to install VK protocols, Status: %r\n",
> Status));
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT | DEBUG_INFO, "VirtualKeyboardDriverStart Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  if (VkContext != NULL) {
> 
> +    FreePool (VkContext);
> 
> +  }
> 
> +
> 
> +  gBS->CloseProtocol (
> 
> +         Controller,
> 
> +         &gEfiAbsolutePointerProtocolGuid,
> 
> +         This->DriverBindingHandle,
> 
> +         Controller
> 
> +         );
> 
> +
> 
> +  //
> 
> +  // Restore setting if connect device fail.
> 
> +  //
> 
> +  PcdSet32S (PcdConOutRow, mOrigConOutRow);
> 
> +  PcdSet32S (PcdSetupConOutRow, mOrigSetupConOutRow);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStart Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStart End\n"));
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Disconnect from the controller.
> 
> +
> 
> +  This routine disconnects from the controller.
> 
> +
> 
> +  This routine is called by DriverUnload when the I2C bus driver
> 
> +  is being unloaded.
> 
> +
> 
> +  @param[in] DriverBinding        Protocol instance pointer.
> 
> +  @param[in] Controller           Handle of device to stop driver on.
> 
> +  @param[in] NumberOfChildren     How many children need to be stopped.
> 
> +  @param[in] ChildHandleBuffer    Not used.
> 
> +
> 
> +  @retval EFI_SUCCESS             This driver is removed Controller.
> 
> +  @retval EFI_DEVICE_ERROR        The device could not be stopped due to a device error.
> 
> +  @retval other                   This driver was not removed from this device.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverStop (
> 
> +  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
> 
> +  IN  EFI_HANDLE                  Controller,
> 
> +  IN  UINTN                       NumberOfChildren,
> 
> +  IN  EFI_HANDLE                  *ChildHandleBuffer
> 
> +  )
> 
> +{
> 
> +  VK_CONTEXT                          *VkContext;
> 
> +  EFI_STATUS                          Status;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop Start\n"));
> 
> +
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  (VOID**)&VkContext,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    Status = EFI_SUCCESS;
> 
> +    goto Success;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Done with the driver protocol
> 
> +  //
> 
> +  Status = gBS->CloseProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to close the VK protocol, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Remove ConsoleIn protocols first to close the link in ConSplitter
> 
> +  //
> 
> +  Status = gBS->OpenProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiConsoleInDeviceGuid,
> 
> +                  NULL,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller,
> 
> +                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to uninstall the protocols, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Remove the remaining protocols
> 
> +  //
> 
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> 
> +                  Controller,
> 
> +                  &gEfiCallerIdGuid,
> 
> +                  VkContext,
> 
> +                  &gEfiSimpleTextInProtocolGuid,
> 
> +                  &VkContext->SimpleTextIn,
> 
> +                  &gEfiSimpleTextInputExProtocolGuid,
> 
> +                  &VkContext->SimpleTextInEx,
> 
> +                  &gEfiConsoleInDeviceGuid,
> 
> +                  NULL,
> 
> +                  NULL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to uninstall the protocols, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Stop the driver
> 
> +  //
> 
> +  VkApiStop (VkContext);
> 
> +
> 
> +  //
> 
> +  // Release the pointer protocol upon failure
> 
> +  //
> 
> +  Status = gBS->CloseProtocol (
> 
> +                  Controller,
> 
> +                  &gEfiAbsolutePointerProtocolGuid,
> 
> +                  This->DriverBindingHandle,
> 
> +                  Controller
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to close absolute pointer protocol, Status: %r\n", Status));
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Release VkContext
> 
> +  //
> 
> +  if (VkContext != NULL) {
> 
> +    FreePool (VkContext);
> 
> +  }
> 
> +
> 
> +Success:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverStop End\n"));
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Unloads an image.
> 
> +
> 
> +  @param[in] ImageHandle        Handle that identifies the image to be unloaded.
> 
> +
> 
> +  @retval EFI_SUCCESS           The image has been unloaded.
> 
> +  @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VirtualKeyboardDriverUnload (
> 
> +  IN EFI_HANDLE ImageHandle
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                 Status;
> 
> +  EFI_HANDLE                 *HandleBuffer;
> 
> +  UINTN                      HandleCount;
> 
> +  UINTN                      Index;
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload Start\n"));
> 
> +
> 
> +  //
> 
> +  // Retrieve array of all handles in the handle database
> 
> +  //
> 
> +  Status = gBS->LocateHandleBuffer (
> 
> +                  AllHandles,
> 
> +                  NULL,
> 
> +                  NULL,
> 
> +                  &HandleCount,
> 
> +                  &HandleBuffer
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "ERROR - Failed to locate handle buffer, Status: %r\n", Status));
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Disconnect the current driver from handles in the handle database
> 
> +  //
> 
> +  for (Index = 0; Index < HandleCount; Index++) {
> 
> +    gBS->DisconnectController (HandleBuffer[Index], ImageHandle, NULL);
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Free the array of handles
> 
> +  //
> 
> +  if (HandleBuffer != NULL) {
> 
> +    FreePool (HandleBuffer);
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Uninstall protocols installed in the driver entry point
> 
> +  //
> 
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> 
> +                  ImageHandle,
> 
> +                  &gEfiDriverBindingProtocolGuid,
> 
> +                  &gVirtualKeyboardDriverBinding,
> 
> +                  &gEfiComponentNameProtocolGuid,
> 
> +                  &gVirtualKeyboardComponentName,
> 
> +                  &gEfiComponentName2ProtocolGuid,
> 
> +                  &gVirtualKeyboardComponentName2,
> 
> +                  NULL
> 
> +                  );
> 
> +  if (EFI_ERROR (Status)) {
> 
> +    ASSERT_EFI_ERROR (Status);
> 
> +    goto Error;
> 
> +  }
> 
> +
> 
> +  HiiRemovePackages (mHiiHandle);
> 
> +
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload Success, Status: %r\n", Status));
> 
> +  goto End;
> 
> +
> 
> +Error:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload Failed, Status: %r\n", Status));
> 
> +
> 
> +End:
> 
> +  DEBUG ((DEBUG_VK_ROUTINE_ENTRY_EXIT, "VirtualKeyboardDriverUnload End\n"));
> 
> +  return Status;
> 
> +}
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
> new file mode 100644
> index 0000000000..9ecc99d5a7
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
> @@ -0,0 +1,77 @@
> +## @file
> 
> +# Instance of virtual keyboard driver binding protocol.
> 
> +#
> 
> +# Compliant with efi driver model, 1. VirtualKeyboardDriverSupported
> 
> +# determines if the pointer and GOP are available. 2.
> 
> +# VirtualKeyboardDriverStart initializes an instance of the virtual
> 
> +# keyboard driver for a particular controller. 3.
> 
> +# VirtualKeyboardDriverStop is called by DriverUnload when the I2C bus
> 
> +# driver is being unload.
> 
> +#
> 
> +# Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +  INF_VERSION                    = 0x00010017
> 
> +  BASE_NAME                      = VirtualKeyboardDxe
> 
> +  FILE_GUID                      = E4735AAC-9C27-493f-86EA-9EFF43D7ADCD
> 
> +  VERSION_STRING                 = 1.0
> 
> +  MODULE_TYPE                    = UEFI_DRIVER
> 
> +  ENTRY_POINT                    = VirtualKeyboardDriverEntryPoint
> 
> +  UNLOAD_IMAGE                   = VirtualKeyboardDriverUnload
> 
> +
> 
> +#
> 
> +#  VALID_ARCHITECTURES           = IA32 X64
> 
> +#  DRIVER_BINDING                = gVirtualKeyboardDriverBinding;
> 
> +#  COMPONENT_NAME                = gVirtualKeyboardComponentName;
> 
> +#  COMPONENT_NAME2               = gVirtualKeyboardComponentName2;
> 
> +#
> 
> +
> 
> +[LibraryClasses]
> 
> +  BaseMemoryLib
> 
> +  DebugLib
> 
> +  MemoryAllocationLib
> 
> +  UefiBootServicesTableLib
> 
> +  UefiDriverEntryPoint
> 
> +  UefiLib
> 
> +  PcdLib
> 
> +  HiiLib
> 
> +
> 
> +[Packages]
> 
> +  MdePkg/MdePkg.dec
> 
> +  MdeModulePkg/MdeModulePkg.dec
> 
> +  UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
> 
> +
> 
> +[Pcd]
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow
> 
> +
> 
> +[Sources]
> 
> +  CapitalLetterKeyboard.bmp
> 
> +  DigitKeyboard.bmp
> 
> +  FullIcon.bmp
> 
> +  SimpleIcon.bmp
> 
> +  SimpleKeyboard.bmp
> 
> +  KeyboardLayout.idf
> 
> +  KeyboardLayout.c
> 
> +  ComponentName.c
> 
> +  Keyboard.c
> 
> +  VirtualKeyboard.h
> 
> +  VirtualKeyboardDriver.c
> 
> +
> 
> +[Protocols]
> 
> +  gEfiAbsolutePointerProtocolGuid               ## TO_START
> 
> +  gEfiDriverBindingProtocolGuid                 ## PRODUCES
> 
> +  gEfiGraphicsOutputProtocolGuid                ## TO_START
> 
> +  gEfiSimpleTextInProtocolGuid                  ## BY_START
> 
> +  gEfiSimpleTextInputExProtocolGuid             ## BY_START
> 
> +  gEfiHiiImageExProtocolGuid                    ## TO_START
> 
> +
> 
> +[Guids]
> 
> +  gEfiConsoleInDeviceGuid                       ## SOMETIMES_PRODUCES
> 
> +  gEfiTouchPanelGuid                            ## TO_START
> 
> +
> 
> +[Depex]
> 
> +  gEfiHiiDatabaseProtocolGuid
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
> new file mode 100644
> index 0000000000..2742a04a8f
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dec
> @@ -0,0 +1,26 @@
> +## @file
> 
> +# This package provides advanced feature functionality for User Authentication support.
> 
> +# This package should only depend on EDK II Core packages, IntelSiliconPkg, and MinPlatformPkg.
> 
> +#
> 
> +# The DEC files are used by the utilities that parse DSC and
> 
> +# INF files to generate AutoGen.c and AutoGen.h files
> 
> +# for the build infrastructure.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +  DEC_SPECIFICATION = 0x00010017
> 
> +  PACKAGE_NAME      = VirtualKeyboardFeaturePkg
> 
> +  PACKAGE_GUID      = A40DFD69-3552-40E8-8D3D-89741B03B9E1
> 
> +  PACKAGE_VERSION   = 0.1
> 
> +
> 
> +[Includes]
> 
> +  Include
> 
> +
> 
> +[Guids]
> 
> +  ## GUID used for VirtualKeyboardDriver to open TouchPanel protocol.
> 
> +  gEfiTouchPanelGuid                               = { 0x91b1d27b, 0xe126, 0x48d1, { 0x82, 0x34, 0xd2, 0x8b, 0x81, 0xc8, 0x83, 0x62 }}
> 
> diff --git a/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc
> b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc
> new file mode 100644
> index 0000000000..ab3605fa15
> --- /dev/null
> +++ b/Features/Intel/UserInterface/VirtualKeyboardFeaturePkg/VirtualKeyboardFeaturePkg.dsc
> @@ -0,0 +1,30 @@
> +## @file
> 
> +# This is a build description file for the User Authentication advanced feature.
> 
> +# This package should only depend on EDK II Core packages, IntelSiliconPkg, and MinPlatformPkg.
> 
> +#
> 
> +# The DEC files are used by the utilities that parse DSC and
> 
> +# INF files to generate AutoGen.c and AutoGen.h files
> 
> +# for the build infrastructure.
> 
> +#
> 
> +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +  PLATFORM_NAME                  = VirtualKeyboardFeaturePkg
> 
> +  PLATFORM_GUID                  = 6D396683-C82B-41D5-84E7-BB6E13B7C2BF
> 
> +  PLATFORM_VERSION               = 0.1
> 
> +  DSC_SPECIFICATION              = 0x00010005
> 
> +  OUTPUT_DIRECTORY               = Build/$(PLATFORM_NAME)
> 
> +  SUPPORTED_ARCHITECTURES        = IA32|X64
> 
> +  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
> 
> +  SKUID_IDENTIFIER               = DEFAULT
> 
> +  PEI_ARCH                       = IA32
> 
> +  DXE_ARCH                       = X64
> 
> +
> 
> +#
> 
> +# This package always builds the feature.
> 
> +#
> 
> +!include Include/VirtualKeyboardFeature.dsc
> 
> --
> 2.24.0.windows.2
> 
> 
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this group.
> 
> View/Reply Online (#56348): https://edk2.groups.io/g/devel/message/56348
> Mute This Topic: https://groups.io/mt/72555278/1712937
> Group Owner: devel+owner@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub  [ray.ni@intel.com]
> -=-=-=-=-=-=


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-04-01  8:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-26  0:43 [PATCH] Features/Intel/UserInterface: Add VirtualKeyboardFeaturePkg Tan, Ming
2020-04-01  5:40 ` [edk2-devel] " Dong, Eric
2020-04-01  8:58 ` Ni, Ray

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox