mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
289 lines
9.6 KiB
C
289 lines
9.6 KiB
C
/** @file
|
|
AppleKeyMapAggregator edge detection
|
|
|
|
Copyright (c) 2021, Mike Beaton. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-3-Clause
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
#include <Protocol/AppleKeyMapAggregator.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/OcAppleKeyMapLib.h>
|
|
#include <Library/OcDebugLogLib.h>
|
|
#include <Library/OcMiscLib.h>
|
|
#include <Library/OcTimerLib.h>
|
|
#include <Library/TimerLib.h>
|
|
|
|
VOID
|
|
OcFreeKeyRepeatContext (
|
|
OC_KEY_REPEAT_CONTEXT **Context
|
|
)
|
|
{
|
|
ASSERT (Context != NULL);
|
|
|
|
if (*Context == NULL) {
|
|
return;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "OCKM: Freeing key repeat context %p %p %p\n", *Context, (*Context)->KeysHeld, (*Context)->KeyHeldTimes));
|
|
|
|
FreePool ((*Context)->KeyHeldTimes);
|
|
FreePool ((*Context)->KeysHeld);
|
|
FreePool (*Context);
|
|
|
|
*Context = NULL;
|
|
}
|
|
|
|
EFI_STATUS
|
|
OcInitKeyRepeatContext (
|
|
OUT OC_KEY_REPEAT_CONTEXT **Context,
|
|
IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap,
|
|
IN UINTN MaxKeysHeld,
|
|
IN UINT64 InitialDelay,
|
|
IN UINT64 SubsequentDelay,
|
|
IN BOOLEAN PreventInitialRepeat
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
APPLE_MODIFIER_MAP Modifiers;
|
|
UINTN NumKeysUp;
|
|
UINTN NumKeysDown;
|
|
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: Allocating %d for repeat context\n", sizeof (OC_KEY_REPEAT_CONTEXT)));
|
|
*Context = AllocatePool (sizeof (OC_KEY_REPEAT_CONTEXT));
|
|
if (*Context == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: Cannot allocate repeat context\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (MaxKeysHeld == 0) {
|
|
(*Context)->KeysHeld = NULL;
|
|
} else {
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: Allocating %d for keys held\n", MaxKeysHeld * sizeof ((*Context)->KeysHeld[0])));
|
|
(*Context)->KeysHeld = AllocatePool (MaxKeysHeld * sizeof ((*Context)->KeysHeld[0]));
|
|
if ((*Context)->KeysHeld == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: Cannot allocate keys held\n"));
|
|
FreePool (*Context);
|
|
*Context = NULL;
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: Allocating %d for key held times\n", MaxKeysHeld * sizeof ((*Context)->KeyHeldTimes[0])));
|
|
(*Context)->KeyHeldTimes = AllocatePool (MaxKeysHeld * sizeof ((*Context)->KeyHeldTimes[0]));
|
|
if ((*Context)->KeyHeldTimes == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: Cannot allocate key held times\n"));
|
|
FreePool ((*Context)->KeysHeld);
|
|
FreePool (*Context);
|
|
*Context = NULL;
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
|
|
(*Context)->KeyMap = KeyMap;
|
|
|
|
(*Context)->NumKeysHeld = 0;
|
|
(*Context)->MaxKeysHeld = MaxKeysHeld;
|
|
|
|
(*Context)->InitialDelay = InitialDelay;
|
|
(*Context)->SubsequentDelay = SubsequentDelay;
|
|
(*Context)->PreviousTime = 0;
|
|
|
|
if ((MaxKeysHeld == 0) || (PreventInitialRepeat == FALSE)) {
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
//
|
|
// Prevent any keys which are down at init from appearring as immediate down key strokes or even repeating until released and then pressed again
|
|
//
|
|
NumKeysDown = MaxKeysHeld;
|
|
|
|
Status = OcGetUpDownKeys (
|
|
*Context,
|
|
&Modifiers,
|
|
&NumKeysUp,
|
|
NULL,
|
|
&NumKeysDown,
|
|
NULL,
|
|
MAX_INT64 >> 1 // == far future, creates massive but manageable negative delta on next call
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: InitKeyRepeatContext initial GetUpDownKeys call - %r\n", Status));
|
|
OcFreeKeyRepeatContext (Context);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "OCKM: Allocated key repeat context %p %p %p\n", *Context, (*Context)->KeysHeld, (*Context)->KeyHeldTimes));
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
OcGetUpDownKeys (
|
|
IN OUT OC_KEY_REPEAT_CONTEXT *RepeatContext,
|
|
OUT APPLE_MODIFIER_MAP *Modifiers,
|
|
IN OUT UINTN *NumKeysUp,
|
|
OUT APPLE_KEY_CODE *KeysUp OPTIONAL,
|
|
IN OUT UINTN *NumKeysDown,
|
|
OUT APPLE_KEY_CODE *KeysDown OPTIONAL,
|
|
IN UINT64 CurrentTime
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN NumRawKeys;
|
|
APPLE_KEY_CODE RawKeys[OC_KEY_MAP_DEFAULT_SIZE];
|
|
UINTN NumKeysHeldInCopy;
|
|
UINTN MaxKeysHeldInCopy;
|
|
APPLE_KEY_CODE KeysHeldCopy[OC_HELD_KEYS_DEFAULT_SIZE];
|
|
INT64 KeyHeldTimesCopy[OC_HELD_KEYS_DEFAULT_SIZE];
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
APPLE_KEY_CODE Key;
|
|
INT64 KeyTime;
|
|
UINT64 DeltaTime;
|
|
BOOLEAN FoundHeldKey;
|
|
|
|
ASSERT (Modifiers != NULL);
|
|
ASSERT (NumKeysUp != NULL);
|
|
ASSERT (NumKeysDown != NULL);
|
|
ASSERT (RepeatContext != NULL);
|
|
ASSERT (RepeatContext->KeyMap != NULL);
|
|
ASSERT (RepeatContext->NumKeysHeld <= RepeatContext->MaxKeysHeld);
|
|
|
|
ASSERT_EQUALS (RepeatContext->KeysHeld == NULL, RepeatContext->KeyHeldTimes == NULL);
|
|
|
|
DeltaTime = CurrentTime - RepeatContext->PreviousTime;
|
|
RepeatContext->PreviousTime = CurrentTime;
|
|
|
|
if (RepeatContext->KeysHeld != NULL) {
|
|
//
|
|
// All held keys could potentially go into keys up
|
|
//
|
|
if ((KeysUp != NULL) && (RepeatContext->MaxKeysHeld > *NumKeysUp)) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: MaxKeysHeld %d exceeds NumKeysUp %d\n", RepeatContext->MaxKeysHeld, *NumKeysUp));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// All requested keys could potentially go into held keys
|
|
// (NumKeysDown is always used as the requested number of keys to scan, even if there is no KeysDown buffer to return down keycodes)
|
|
//
|
|
if ((KeysDown != NULL) && (*NumKeysDown > RepeatContext->MaxKeysHeld)) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: Number of keys requested %d exceeds MaxKeysHeld %d\n", *NumKeysDown, RepeatContext->MaxKeysHeld));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Clone live entries of KeysHeld buffer
|
|
//
|
|
MaxKeysHeldInCopy = ARRAY_SIZE (KeysHeldCopy);
|
|
if (RepeatContext->MaxKeysHeld > MaxKeysHeldInCopy) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: MaxKeysHeld %d exceeds supported copy space %d\n", RepeatContext->MaxKeysHeld, MaxKeysHeldInCopy));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
CopyMem (KeysHeldCopy, RepeatContext->KeysHeld, RepeatContext->NumKeysHeld * sizeof (RepeatContext->KeysHeld[0]));
|
|
CopyMem (KeyHeldTimesCopy, RepeatContext->KeyHeldTimes, RepeatContext->NumKeysHeld * sizeof (RepeatContext->KeyHeldTimes[0]));
|
|
NumKeysHeldInCopy = RepeatContext->NumKeysHeld;
|
|
} else {
|
|
NumKeysHeldInCopy = 0;
|
|
}
|
|
|
|
NumRawKeys = ARRAY_SIZE (RawKeys);
|
|
if (*NumKeysDown > NumRawKeys) {
|
|
DEBUG ((DEBUG_ERROR, "OCKM: Number of keys requested %d exceeds supported raw key bufsize %d\n", *NumKeysDown, NumRawKeys));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = RepeatContext->KeyMap->GetKeyStrokes (
|
|
RepeatContext->KeyMap,
|
|
Modifiers,
|
|
&NumRawKeys,
|
|
RawKeys
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if ((KeysDown != NULL) && (NumRawKeys > *NumKeysDown)) {
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: [%p] %ld %ld %ld\n", RepeatContext, RepeatContext->InitialDelay, RepeatContext->SubsequentDelay, DeltaTime));
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: [%p] I u:%d d:%d n:%d h:%d r:%d m:%d\n", RepeatContext, *NumKeysUp, *NumKeysDown, RepeatContext->MaxKeysHeld, RepeatContext->NumKeysHeld, NumRawKeys, *Modifiers));
|
|
|
|
*NumKeysUp = 0;
|
|
*NumKeysDown = 0;
|
|
RepeatContext->NumKeysHeld = 0;
|
|
|
|
//
|
|
// Loop through all keys which are currently down
|
|
//
|
|
for (Index = 0; Index < NumRawKeys; ++Index) {
|
|
Key = RawKeys[Index];
|
|
if (RepeatContext->KeysHeld != NULL) {
|
|
RepeatContext->KeysHeld[RepeatContext->NumKeysHeld] = Key;
|
|
}
|
|
|
|
FoundHeldKey = FALSE;
|
|
for (Index2 = 0; Index2 < NumKeysHeldInCopy; Index2++) {
|
|
if (KeysHeldCopy[Index2] == Key) {
|
|
FoundHeldKey = TRUE;
|
|
KeyTime = KeyHeldTimesCopy[Index2] + DeltaTime;
|
|
KeysHeldCopy[Index2] = 0; // Mark held key as still down
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: [%p] Still down 0x%X %ld\n", RepeatContext, Key, KeyTime));
|
|
if ((RepeatContext->InitialDelay != 0) && (KeyTime >= 0)) {
|
|
if (KeysDown != NULL) {
|
|
KeysDown[*NumKeysDown] = Key;
|
|
}
|
|
|
|
(*NumKeysDown)++;
|
|
KeyTime -= RepeatContext->SubsequentDelay;
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: [%p] Repeating 0x%X %ld\n", RepeatContext, Key, KeyTime));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!FoundHeldKey) {
|
|
if (KeysDown != NULL) {
|
|
KeysDown[*NumKeysDown] = Key;
|
|
}
|
|
|
|
(*NumKeysDown)++;
|
|
KeyTime = -(INT64)RepeatContext->InitialDelay;
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: [%p] New down 0x%X %ld\n", RepeatContext, Key, KeyTime));
|
|
}
|
|
|
|
if (RepeatContext->KeysHeld != NULL) {
|
|
RepeatContext->KeyHeldTimes[RepeatContext->NumKeysHeld] = KeyTime;
|
|
RepeatContext->NumKeysHeld++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Process remaining held keys
|
|
//
|
|
for (Index = 0; Index < NumKeysHeldInCopy; Index++) {
|
|
Key = KeysHeldCopy[Index];
|
|
if (Key != 0) {
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: [%p] Gone up 0x%X %ld\n", RepeatContext, Key, KeyHeldTimesCopy[Index]));
|
|
if (KeysUp != NULL) {
|
|
KeysUp[*NumKeysUp] = Key;
|
|
}
|
|
|
|
(*NumKeysUp)++;
|
|
}
|
|
}
|
|
|
|
DEBUG ((OC_TRACE_UPDOWNKEYS, "OCKM: [%p] O u:%d d:%d n:%d h:%d r:%d\n", RepeatContext, *NumKeysUp, *NumKeysDown, RepeatContext->MaxKeysHeld, RepeatContext->NumKeysHeld, NumRawKeys));
|
|
|
|
return Status;
|
|
}
|