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

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