audk/EmulatorPkg/Win/Host/WinGopInput.c

460 lines
12 KiB
C

/** @file
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
Module Name:
WinGopInput.c
Abstract:
This file produces the Simple Text In for an Gop window.
This stuff is linked at the hip to the Window, since the window
processing is done in a thread kicked off in WinNtGopImplementation.c
Since the window information is processed in an other thread we need
a keyboard Queue to pass data about. The Simple Text In code just
takes data off the Queue. The WinProc message loop takes keyboard input
and places it in the Queue.
**/
#include "WinGop.h"
/**
TODO: Add function description
@param Private TODO: add argument description
@retval EFI_SUCCESS TODO: Add description for return value
**/
EFI_STATUS
GopPrivateCreateQ (
IN GRAPHICS_PRIVATE_DATA *Private,
IN GOP_QUEUE_FIXED *Queue
)
{
InitializeCriticalSection (&Queue->Cs);
Queue->Front = 0;
Queue->Rear = 0;
return EFI_SUCCESS;
}
/**
TODO: Add function description
@param Private TODO: add argument description
@retval EFI_SUCCESS TODO: Add description for return value
**/
EFI_STATUS
GopPrivateDestroyQ (
IN GRAPHICS_PRIVATE_DATA *Private,
IN GOP_QUEUE_FIXED *Queue
)
{
Queue->Front = 0;
Queue->Rear = 0;
DeleteCriticalSection (&Queue->Cs);
return EFI_SUCCESS;
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Key TODO: add argument description
@retval EFI_NOT_READY TODO: Add description for return value
@retval EFI_SUCCESS TODO: Add description for return value
**/
EFI_STATUS
GopPrivateAddQ (
IN GRAPHICS_PRIVATE_DATA *Private,
IN GOP_QUEUE_FIXED *Queue,
IN EFI_KEY_DATA *KeyData
)
{
EnterCriticalSection (&Queue->Cs);
if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {
LeaveCriticalSection (&Queue->Cs);
return EFI_NOT_READY;
}
CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
Queue->Rear = (Queue->Rear + 1) % MAX_Q;
LeaveCriticalSection (&Queue->Cs);
return EFI_SUCCESS;
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Key TODO: add argument description
@retval EFI_NOT_READY TODO: Add description for return value
@retval EFI_SUCCESS TODO: Add description for return value
**/
EFI_STATUS
GopPrivateDeleteQ (
IN GRAPHICS_PRIVATE_DATA *Private,
IN GOP_QUEUE_FIXED *Queue,
OUT EFI_KEY_DATA *Key
)
{
EnterCriticalSection (&Queue->Cs);
if (Queue->Front == Queue->Rear) {
LeaveCriticalSection (&Queue->Cs);
return EFI_NOT_READY;
}
CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));
Queue->Front = (Queue->Front + 1) % MAX_Q;
if ((Key->Key.ScanCode == SCAN_NULL) && (Key->Key.UnicodeChar == CHAR_NULL)) {
if (!Private->IsPartialKeySupport) {
//
// If partial keystrok is not enabled, don't return the partial keystroke.
//
LeaveCriticalSection (&Queue->Cs);
ZeroMem (Key, sizeof (EFI_KEY_DATA));
return EFI_NOT_READY;
}
}
LeaveCriticalSection (&Queue->Cs);
return EFI_SUCCESS;
}
/**
TODO: Add function description
@param Private TODO: add argument description
@retval EFI_NOT_READY TODO: Add description for return value
@retval EFI_SUCCESS TODO: Add description for return value
**/
EFI_STATUS
GopPrivateCheckQ (
IN GOP_QUEUE_FIXED *Queue
)
{
if (Queue->Front == Queue->Rear) {
return EFI_NOT_READY;
}
return EFI_SUCCESS;
}
/**
Initialize the key state.
@param Private The GOP_PRIVATE_DATA instance.
@param KeyState A pointer to receive the key state information.
**/
VOID
InitializeKeyState (
IN GRAPHICS_PRIVATE_DATA *Private,
IN EFI_KEY_STATE *KeyState
)
{
KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID;
KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;
//
// Record Key shift state and toggle state
//
if (Private->LeftCtrl) {
KeyState->KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
}
if (Private->RightCtrl) {
KeyState->KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
}
if (Private->LeftAlt) {
KeyState->KeyShiftState |= EFI_LEFT_ALT_PRESSED;
}
if (Private->RightAlt) {
KeyState->KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
}
if (Private->LeftShift) {
KeyState->KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
}
if (Private->RightShift) {
KeyState->KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
}
if (Private->LeftLogo) {
KeyState->KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
}
if (Private->RightLogo) {
KeyState->KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
}
if (Private->Menu) {
KeyState->KeyShiftState |= EFI_MENU_KEY_PRESSED;
}
if (Private->SysReq) {
KeyState->KeyShiftState |= EFI_SYS_REQ_PRESSED;
}
if (Private->CapsLock) {
KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
}
if (Private->NumLock) {
KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
}
if (Private->ScrollLock) {
KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
}
if (Private->IsPartialKeySupport) {
KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;
}
}
/**
TODO: Add function description
@param Private TODO: add argument description
@param Key TODO: add argument description
@retval EFI_NOT_READY TODO: Add description for return value
@retval EFI_SUCCESS TODO: Add description for return value
**/
EFI_STATUS
GopPrivateAddKey (
IN GRAPHICS_PRIVATE_DATA *Private,
IN EFI_INPUT_KEY Key
)
{
EFI_KEY_DATA KeyData;
KeyData.Key = Key;
InitializeKeyState (Private, &KeyData.KeyState);
//
// Convert Ctrl+[1-26] to Ctrl+[A-Z]
//
if ((Private->LeftCtrl || Private->RightCtrl) &&
(KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)
)
{
if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {
KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);
} else {
KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);
}
}
//
// Unmask the Shift bit for printable char
//
if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||
((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))
)
{
KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
}
GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);
if (Private->MakeRegisterdKeyCallback != NULL) {
Private->MakeRegisterdKeyCallback (Private->RegisterdKeyCallbackContext, &KeyData);
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
WinNtWndCheckKey (
IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
)
{
GRAPHICS_PRIVATE_DATA *Private;
Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
return GopPrivateCheckQ (&Private->QueueForRead);
}
EFI_STATUS
EFIAPI
WinNtWndGetKey (
IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
IN EFI_KEY_DATA *KeyData
)
/*++
Routine Description:
Reads the next keystroke from the input device. The WaitForKey Event can
be used to test for existence of a keystroke via WaitForEvent () call.
Arguments:
Private - The private structure of WinNt Gop device.
KeyData - A pointer to a buffer that is filled in with the keystroke
state data for the key that was pressed.
Returns:
EFI_SUCCESS - The keystroke information was returned.
EFI_NOT_READY - There was no keystroke data available.
EFI_DEVICE_ERROR - The keystroke information was not returned due to
hardware errors.
EFI_INVALID_PARAMETER - KeyData is NULL.
--*/
{
EFI_STATUS Status;
GRAPHICS_PRIVATE_DATA *Private;
Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
InitializeKeyState (Private, &KeyData->KeyState);
Status = GopPrivateCheckQ (&Private->QueueForRead);
if (!EFI_ERROR (Status)) {
//
// If a Key press exists try and read it.
//
Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);
if (!EFI_ERROR (Status)) {
//
// If partial keystroke is not enabled, check whether it is value key. If not return
// EFI_NOT_READY.
//
if (!Private->IsPartialKeySupport) {
if ((KeyData->Key.ScanCode == SCAN_NULL) && (KeyData->Key.UnicodeChar == CHAR_NULL)) {
Status = EFI_NOT_READY;
}
}
}
}
return Status;
}
EFI_STATUS
EFIAPI
WinNtWndKeySetState (
IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
IN EFI_KEY_TOGGLE_STATE *KeyToggleState
)
{
GRAPHICS_PRIVATE_DATA *Private;
Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
Private->ScrollLock = FALSE;
Private->NumLock = FALSE;
Private->CapsLock = FALSE;
Private->IsPartialKeySupport = FALSE;
if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
Private->ScrollLock = TRUE;
}
if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
Private->NumLock = TRUE;
}
if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
Private->CapsLock = TRUE;
}
if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
Private->IsPartialKeySupport = TRUE;
}
Private->KeyState.KeyToggleState = *KeyToggleState;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
WinNtWndRegisterKeyNotify (
IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
IN VOID *Context
)
{
GRAPHICS_PRIVATE_DATA *Private;
Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
Private->MakeRegisterdKeyCallback = MakeCallBack;
Private->BreakRegisterdKeyCallback = BreakCallBack;
Private->RegisterdKeyCallbackContext = Context;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
WinNtWndCheckPointer (
IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
)
{
GRAPHICS_PRIVATE_DATA *Private;
Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
if (!Private->PointerStateChanged) {
return EFI_NOT_READY;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
WinNtWndGetPointerState (
IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
IN EFI_SIMPLE_POINTER_STATE *State
)
{
GRAPHICS_PRIVATE_DATA *Private;
Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
if (!Private->PointerStateChanged) {
return EFI_NOT_READY;
}
State->RelativeMovementX = Private->PointerState.RelativeMovementX;
State->RelativeMovementY = Private->PointerState.RelativeMovementY;
State->RelativeMovementZ = Private->PointerState.RelativeMovementZ;
State->LeftButton = Private->PointerState.LeftButton;
State->RightButton = Private->PointerState.RightButton;
Private->PointerState.RelativeMovementX = 0;
Private->PointerState.RelativeMovementY = 0;
Private->PointerState.RelativeMovementZ = 0;
Private->PointerStateChanged = FALSE;
return EFI_SUCCESS;
}