public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ruiyu Ni <ruiyu.ni@intel.com>
To: edk2-devel@lists.01.org
Cc: Star Zeng <star.zeng@intel.com>,
	Michael D Kinney <michael.d.kinney@intel.com>
Subject: [PATCH 2/6] MdeModulePkg/ConSplitter: ReadKeyStrokeEx always return key state
Date: Mon, 22 Jan 2018 16:10:20 +0800	[thread overview]
Message-ID: <20180122081024.283496-3-ruiyu.ni@intel.com> (raw)
In-Reply-To: <20180122081024.283496-1-ruiyu.ni@intel.com>

Today's implementation only return key state when there is key.
But when user doesn't press any key, the key state cannot be
returned.

The patch changes the ReadKeyStrokeEx() to always return the
key state even there is no key pressed.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 .../Universal/Console/ConSplitterDxe/ConSplitter.c | 164 ++++++++++++++++++---
 .../Universal/Console/ConSplitterDxe/ConSplitter.h |   4 +-
 2 files changed, 143 insertions(+), 25 deletions(-)

diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
index e70ff6114a..022fca7cbb 100644
--- a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
+++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
@@ -16,7 +16,7 @@
   never removed. Such design ensures sytem function well during none console
   device situation.
 
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
@@ -67,6 +67,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA  mConIn = {
     (LIST_ENTRY *) NULL,
     (LIST_ENTRY *) NULL
   },
+  (EFI_KEY_DATA *) NULL,
+  0,
   0,
   FALSE,
 
@@ -606,6 +608,7 @@ ConSplitterTextInConstructor (
   )
 {
   EFI_STATUS  Status;
+  UINTN       TextInExListCount;
 
   //
   // Allocate buffer for Simple Text Input device
@@ -631,6 +634,19 @@ ConSplitterTextInConstructor (
                   );
   ASSERT_EFI_ERROR (Status);
 
+  //
+  // Allocate buffer for KeyQueue
+  //
+  TextInExListCount = ConInPrivate->TextInExListCount;
+  Status = ConSplitterGrowBuffer (
+             sizeof (EFI_KEY_DATA),
+             &TextInExListCount,
+             (VOID **) &ConInPrivate->KeyQueue
+             );
+  if (EFI_ERROR (Status)) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
   //
   // Allocate buffer for Simple Text Input Ex device
   //
@@ -1968,6 +1984,17 @@ ConSplitterTextInExAddDevice (
         return EFI_OUT_OF_RESOURCES;
       }
     }
+
+    TextInExListCount = Private->TextInExListCount;
+    Status = ConSplitterGrowBuffer (
+               sizeof (EFI_KEY_DATA),
+               &TextInExListCount,
+               (VOID **) &Private->KeyQueue
+               );
+    if (EFI_ERROR (Status)) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
     Status = ConSplitterGrowBuffer (
               sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
               &Private->TextInExListCount,
@@ -3445,11 +3472,46 @@ ConSplitterTextInReset (
 
   if (!EFI_ERROR (ReturnStatus)) {
     ToggleStateSyncReInitialization (Private);
+    //
+    // Empty the key queue.
+    //
+    Private->CurrentNumberOfKeys = 0;
   }
 
   return ReturnStatus;
 }
 
+/**
+  Dequeue the saved key from internal key queue.
+
+  @param  Private                  Protocol instance pointer.
+  @param  KeyData                  A pointer to a buffer that is filled in with the
+                                   keystroke state data for the key that was
+                                   pressed.
+  @retval EFI_NOT_FOUND            Queue is empty.
+  @retval EFI_SUCCESS              First key is dequeued and returned.
+**/
+EFI_STATUS
+ConSplitterTextInExDequeueKey (
+  IN  TEXT_IN_SPLITTER_PRIVATE_DATA   *Private,
+  OUT EFI_KEY_DATA                    *KeyData
+  )
+{
+  if (Private->CurrentNumberOfKeys == 0) {
+    return EFI_NOT_FOUND;
+  }
+  //
+  // Return the first saved key.
+  //
+  CopyMem (KeyData, &Private->KeyQueue[0], sizeof (EFI_KEY_DATA));
+  Private->CurrentNumberOfKeys--;
+  CopyMem (
+    &Private->KeyQueue[0],
+    &Private->KeyQueue[1],
+    Private->CurrentNumberOfKeys * sizeof (EFI_KEY_DATA)
+    );
+  return EFI_SUCCESS;
+}
 
 /**
   Reads the next keystroke from the input device. The WaitForKey Event can
@@ -3473,7 +3535,13 @@ ConSplitterTextInPrivateReadKeyStroke (
 {
   EFI_STATUS    Status;
   UINTN         Index;
-  EFI_INPUT_KEY CurrentKey;
+  EFI_KEY_DATA  KeyData;
+
+  Status = ConSplitterTextInExDequeueKey (Private, &KeyData);
+  if (!EFI_ERROR (Status)) {
+    CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+    return Status;
+  }
 
   Key->UnicodeChar  = 0;
   Key->ScanCode     = SCAN_NULL;
@@ -3486,15 +3554,15 @@ ConSplitterTextInPrivateReadKeyStroke (
   for (Index = 0; Index < Private->CurrentNumberOfConsoles;) {
     Status = Private->TextInList[Index]->ReadKeyStroke (
                                           Private->TextInList[Index],
-                                          &CurrentKey
+                                          &KeyData.Key
                                           );
     if (!EFI_ERROR (Status)) {
       //
       // If it is not partial keystorke, return the key. Otherwise, continue
       // to read key from THIS physical console input device.
       //
-      if ((CurrentKey.ScanCode != CHAR_NULL) || (CurrentKey.UnicodeChar != SCAN_NULL)) {
-        *Key = CurrentKey;
+      if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {
+        CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
         return Status;
       }
     } else {
@@ -3681,6 +3749,10 @@ ConSplitterTextInResetEx (
 
   if (!EFI_ERROR (ReturnStatus)) {
     ToggleStateSyncReInitialization (Private);
+    //
+    // Empty the key queue.
+    //
+    Private->CurrentNumberOfKeys = 0;
   }
 
   return ReturnStatus;
@@ -3714,6 +3786,7 @@ ConSplitterTextInReadKeyStrokeEx (
   TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
   EFI_STATUS                    Status;
   UINTN                         Index;
+  EFI_KEY_STATE                 KeyState;
   EFI_KEY_DATA                  CurrentKeyData;
 
 
@@ -3725,9 +3798,6 @@ ConSplitterTextInReadKeyStrokeEx (
 
   Private->KeyEventSignalState = FALSE;
 
-  KeyData->Key.UnicodeChar  = 0;
-  KeyData->Key.ScanCode     = SCAN_NULL;
-
   //
   // Signal ConnectConIn event on first call in Lazy ConIn mode
   //
@@ -3738,35 +3808,81 @@ ConSplitterTextInReadKeyStrokeEx (
   }
 
   //
-  // if no physical console input device exists, return EFI_NOT_READY;
-  // if any physical console input device has key input,
-  // return the key and EFI_SUCCESS.
+  // Return the first saved key.
+  //
+  Status = ConSplitterTextInExDequeueKey (Private, KeyData);
+  if (!EFI_ERROR (Status)) {
+    return Status;
+  }
+  ASSERT (Private->CurrentNumberOfKeys == 0);
+
+  ZeroMem (&KeyState, sizeof (KeyState));
+
+  //
+  // Iterate through all physical consoles to get key state.
+  // Some physical consoles may return valid key.
+  // Queue the valid keys.
   //
-  for (Index = 0; Index < Private->CurrentNumberOfExConsoles;) {
+  for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+    ZeroMem (&CurrentKeyData, sizeof (EFI_KEY_DATA));
     Status = Private->TextInExList[Index]->ReadKeyStrokeEx (
-                                          Private->TextInExList[Index],
-                                          &CurrentKeyData
-                                          );
+                                             Private->TextInExList[Index],
+                                             &CurrentKeyData
+                                             );
+    if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
+      continue;
+    }
+
+    //
+    // Consolidate the key state from all physical consoles.
+    //
+    if ((CurrentKeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) {
+      KeyState.KeyShiftState |= CurrentKeyData.KeyState.KeyShiftState;
+    }
+    if ((CurrentKeyData.KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != 0) {
+      KeyState.KeyToggleState |= CurrentKeyData.KeyState.KeyToggleState;
+    }
+
     if (!EFI_ERROR (Status)) {
       //
       // If virtual KeyState has been required to be exposed, or it is not
-      // partial keystorke, return the key. Otherwise, continue to read key
-      // from THIS physical console input device.
+      // partial keystorke, queue the key.
+      // It's possible that user presses at multiple keyboards at the same moment,
+      // Private->KeyQueue[] are the storage to save all the keys.
       //
       if ((Private->VirtualKeyStateExported) ||
           (CurrentKeyData.Key.ScanCode != CHAR_NULL) ||
           (CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) {
-        CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData));
-        return Status;
+        CopyMem (
+          &Private->KeyQueue[Private->CurrentNumberOfKeys],
+          &CurrentKeyData,
+          sizeof (EFI_KEY_DATA)
+          );
+        Private->CurrentNumberOfKeys++;
       }
-    } else {
-      //
-      // Continue to read key from NEXT physical console input device.
-      //
-      Index++;
     }
   }
 
+  //
+  // Consolidate the key state for all keys in Private->KeyQueue[]
+  //
+  for (Index = 0; Index < Private->CurrentNumberOfKeys; Index++) {
+    CopyMem (&Private->KeyQueue[Index].KeyState, &KeyState, sizeof (EFI_KEY_STATE));
+  }
+  
+  //
+  // Return the first saved key.
+  //
+  Status = ConSplitterTextInExDequeueKey (Private, KeyData);
+  if (!EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Always return the key state even there is no key pressed.
+  //
+  ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
+  CopyMem (&KeyData->KeyState, &KeyState, sizeof (KeyData->KeyState));
   return EFI_NOT_READY;
 }
 
diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h
index 9469860bf0..5fde6b0cb4 100644
--- a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h
+++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.h
@@ -1,7 +1,7 @@
 /** @file
   Private data structures for the Console Splitter driver
 
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -129,6 +129,8 @@ typedef struct {
   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  **TextInExList;
   UINTN                              TextInExListCount;
   LIST_ENTRY                         NotifyList;
+  EFI_KEY_DATA                       *KeyQueue;
+  UINTN                              CurrentNumberOfKeys;
   //
   // It will be initialized and synced between console input devices
   // for toggle state sync.
-- 
2.15.1.windows.2



  parent reply	other threads:[~2018-01-22  8:05 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-22  8:10 [PATCH 0/6] ReadKeyStrokeEx always return key state Ruiyu Ni
2018-01-22  8:10 ` [PATCH 1/6] MdePkg/SimpleTextInEx.h: Fix comments alignment Ruiyu Ni
2018-01-22  8:10 ` Ruiyu Ni [this message]
2018-02-01  5:35   ` [PATCH 2/6] MdeModulePkg/ConSplitter: ReadKeyStrokeEx always return key state Zeng, Star
2018-01-22  8:10 ` [PATCH 3/6] MdeModulePkg/UsbKb: " Ruiyu Ni
2018-01-22  8:10 ` [PATCH 4/6] MdeModulePkg/Ps2Kb: " Ruiyu Ni
2018-01-22  8:10 ` [PATCH 5/6] IntelFrameworkModule/Ps2Kb: " Ruiyu Ni
2018-01-22  8:10 ` [PATCH 6/6] IntelFrameworkModule/ThunkKb: " Ruiyu Ni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180122081024.283496-3-ruiyu.ni@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox