AppleEvent: Improve key repeat fine tuning

This commit is contained in:
MikeBeaton 2021-03-29 16:34:10 +01:00
parent dbc9a3de63
commit e646a47885
11 changed files with 112 additions and 42 deletions

View File

@ -6357,18 +6357,56 @@ functioning. Feature highlights:
\emph{Note}: Currently \texttt{V1}, \texttt{V2}, and \texttt{AMI} unlike \texttt{Auto} only do filtering of
the particular specified protocol. This may change in the future versions.
\item
\texttt{KeySkipFirstDelay}\\
\textbf{Type}: \texttt{plist\ boolean}\\
\textbf{Failsafe}: \texttt{false}\\
\textbf{Description}: Suppress initial delay before key repeat in
OpenCore implementation of Apple Event protocol.
\item
\texttt{KeyInitialDelay}\\
\textbf{Type}: \texttt{plist\ integer}\\
\textbf{Failsafe}: \texttt{0} (acts as \texttt{50}, or 500ms)\\
\textbf{Description}: Configure initial keyboard repeat delay in OpenCore implementation
of Apple Event protocol, in units of 10ms.
When combining OpenCore \texttt{KeySupport} with the Apple Event protocol, key repeat behaviour
may show one additional slow key repeat before normal key repeat starts. Enabling this option
works around this problem by suppressing the initial repeat delay in the OpenCore Apple Event
implementation. This option is recommended to be set when using \texttt{KeySupport} mode, in most
cases, and is not recommended to be set on any systems which are not using \texttt{KeySupport} mode.
In order to fine tune keyboard behaviour three values are relavent:
\texttt{KeyForgetThreshold}, \texttt{KeyInitialDelay} and \texttt{KeySubsequentDelay}.
The tuning procedure is as follows:
\begin{itemize}
\tightlist
\item On systems which are not using \texttt{KeySupport}, no tuning
is needed.
\item On systems which are using \texttt{KeySupport}, it is important to tune
\texttt{KeyForgetThreshold} as documented above, in order to get reliable key-held
behaviour - including reliable responses to boot hotkeys - within OC.
\item After this, no further tuning is \emph{required} for reliable operation.
However for fine tuning, proceed as follows:
\end{itemize}
Apple Event protocol is used widely for key input in OpenCore, since we have to
provide it for Apple's own pre-boot systems to use anyway. However, a minor issue
is that when combining OpenCore \texttt{KeySupport} with Apple Event key handling,
key repeat behaviour may show one additional slow key repeat before normal key repeat starts.
This is perfectly usable in practice, but in order to fine tune your key response and avoid
this minor issue, configure the value of \texttt{KeyInitialDelay} to be the same as the value of
\texttt{KeySubsequentDelay}, i.e. by default configure a value of \texttt{5} for
\texttt{KeyInitialDelay}. On many systems this will be sufficient. However on some
pathological - especially PS/2 - systems, you may find that using \texttt{5} and \texttt{5}
for \texttt{KeyInitialDelay} and \texttt{KeySubsequentDelay} causes two key responses for
every key press. In this case, you will need to tune the shared value upwards until you avoid
this new symptom. E.g. values as high as \texttt{9} and \texttt{9} have been observed required
on some systems.
\emph{Note}: When tuning keyboard behaviour, double key responses can make it impossible to
access some boot entries - avoid making your system unbootable. If you do not have easy access to
another boot method, you are recommended to set \texttt{Misc/Boot/Timeout} to \texttt{5} before
trying this procedure, so that your normal OS will boot after a short time anyway.
\item
\texttt{KeySubsequentDelay}\\
\textbf{Type}: \texttt{plist\ integer}\\
\textbf{Failsafe}: \texttt{0} (acts as \texttt{5}, or 50ms)\\
\textbf{Description}: Configure subsequent keyboard repeat delay in OpenCore implementation
of Apple Event protocol, in units of 10ms.
See documentation of \texttt{KeyInitialDelay}.
\item
\texttt{KeySwap}\\

View File

@ -1154,8 +1154,10 @@
<false/>
<key>KeyForgetThreshold</key>
<integer>5</integer>
<key>KeySkipFirstDelay</key>
<true/>
<key>KeyInitialDelay</key>
<integer>0</integer>
<key>KeySubsequentDelay</key>
<integer>0</integer>
<key>KeySupport</key>
<true/>
<key>KeySupportMode</key>

View File

@ -1351,8 +1351,10 @@
<false/>
<key>KeyForgetThreshold</key>
<integer>5</integer>
<key>KeySkipFirstDelay</key>
<true/>
<key>KeyInitialDelay</key>
<integer>0</integer>
<key>KeySubsequentDelay</key>
<integer>0</integer>
<key>KeySupport</key>
<true/>
<key>KeySupportMode</key>

View File

@ -22,14 +22,18 @@
Install and initialise Apple Event protocol.
@param[in] Reinstall Overwrite installed protocol.
@param[in] KeySkipFirstDelay Modify keyboard handling to suppress initial delay.
@param[in] KeyInitialDelay Key repeat initial delay in 10ms units.
If less than or equal to 0 then use 50.
@param[in] KeySubsequentDelay Key repeat subsequent delay in 10ms units.
If less than or equal to 0 then use 5.
@retval installed or located protocol or NULL.
**/
APPLE_EVENT_PROTOCOL *
OcAppleEventInstallProtocol (
IN BOOLEAN Reinstall,
IN BOOLEAN KeySkipFirstDelay
IN UINT16 KeyInitialDelay OPTIONAL,
IN UINT16 KeySubsequentDelay OPTIONAL
);
#endif // OC_APPLE_EVENT_LIB_H

View File

@ -604,9 +604,10 @@ typedef enum {
_(OC_STRING , KeySupportMode , , OC_STRING_CONSTR ("Auto", _, __) , OC_DESTR (OC_STRING)) \
_(OC_STRING , PointerSupportMode , , OC_STRING_CONSTR ("", _, __) , OC_DESTR (OC_STRING)) \
_(UINT32 , TimerResolution , , 0 , ()) \
_(UINT16 , KeyInitialDelay , , 0 , ()) \
_(UINT16 , KeySubsequentDelay , , 0 , ()) \
_(UINT8 , KeyForgetThreshold , , 0 , ()) \
_(BOOLEAN , KeySupport , , FALSE , ()) \
_(BOOLEAN , KeySkipFirstDelay , , FALSE , ()) \
_(BOOLEAN , KeyFiltering , , FALSE , ()) \
_(BOOLEAN , KeySwap , , FALSE , ()) \
_(BOOLEAN , PointerSupport , , FALSE , ())

View File

@ -154,10 +154,11 @@ EventInputKeyFromAppleKeyCode (
IN BOOLEAN Shifted
);
// InternalSkipFirstKeyDelay
// InternalSetKeyDelays
VOID
InternalSkipFirstKeyDelay (
IN BOOLEAN SkipFirstDelay
InternalSetKeyDelays (
IN UINT16 KeyInitialDelay,
IN UINT16 KeySubsequentDelay
);
#endif // APPLE_EVENT_INTERNAL_H_

View File

@ -66,19 +66,29 @@ STATIC KEY_STROKE_INFORMATION mKeyStrokeInfo[10];
// mCLockChanged
STATIC BOOLEAN mCLockChanged = FALSE;
// mSkipFirstDelay
STATIC BOOLEAN mSkipFirstDelay = FALSE;
// mKeyInitialDelay, mKeySubsequentDelay
STATIC UINTN mKeyInitialDelay = 50;
STATIC UINTN mKeySubsequentDelay = 5;
// mAppleKeyMapAggregator
STATIC APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *mKeyMapAggregator = NULL;
// InternalSkipFirstKeyDelay
// InternalSetKeyDelays
VOID
InternalSkipFirstKeyDelay (
IN BOOLEAN SkipFirstDelay
InternalSetKeyDelays (
IN UINT16 KeyInitialDelay,
IN UINT16 KeySubsequentDelay
)
{
mSkipFirstDelay = SkipFirstDelay;
if (KeyInitialDelay != 0) {
mKeyInitialDelay = KeyInitialDelay;
}
if (KeySubsequentDelay != 0) {
mKeySubsequentDelay = KeySubsequentDelay;
}
DEBUG ((DEBUG_INFO, "OCAE: Using %d (%d0ms) and %d (%d0ms)\n", mKeyInitialDelay, mKeyInitialDelay, mKeySubsequentDelay, mKeySubsequentDelay));
}
// InternalGetAppleKeyStrokes
@ -504,9 +514,9 @@ InternalGetCurrentKeyStroke (
if (KeyInfo != NULL) {
AcceptStroke = (BOOLEAN)(
(!mSkipFirstDelay && KeyInfo->NumberOfStrokes < (KEY_STROKE_DELAY * 10))
(KeyInfo->NumberOfStrokes < mKeyInitialDelay)
? (KeyInfo->NumberOfStrokes == 0)
: ((KeyInfo->NumberOfStrokes % KEY_STROKE_DELAY) == 0)
: (((KeyInfo->NumberOfStrokes - mKeyInitialDelay) % mKeySubsequentDelay) == 0)
);
if (AcceptStroke) {

View File

@ -548,15 +548,19 @@ AppleEventUnload (
/**
Install and initialise Apple Event protocol.
@param[in] Reinstall Overwrite installed protocol.
@param[in] KeySkipFirstDelay Modify keyboard handling to suppress initial delay.
@param[in] Reinstall Overwrite installed protocol.
@param[in] KeyInitialDelay Key repeat initial delay in 10ms units.
If less than or equal to 0 then use 50.
@param[in] KeySubsequentDelay Key repeat subsequent delay in 10ms units.
If less than or equal to 0 then use 5.
@retval installed or located protocol or NULL.
**/
APPLE_EVENT_PROTOCOL *
OcAppleEventInstallProtocol (
IN BOOLEAN Reinstall,
IN BOOLEAN KeySkipFirstDelay
IN UINT16 KeyInitialDelay OPTIONAL,
IN UINT16 KeySubsequentDelay OPTIONAL
)
{
EFI_STATUS Status;
@ -584,7 +588,7 @@ OcAppleEventInstallProtocol (
}
}
InternalSkipFirstKeyDelay (KeySkipFirstDelay);
InternalSetKeyDelays (KeyInitialDelay, KeySubsequentDelay);
//
// Apple code supports unloading, ours does not.

View File

@ -728,7 +728,8 @@ OC_SCHEMA
mUefiInputSchema[] = {
OC_SCHEMA_BOOLEAN_IN ("KeyFiltering", OC_GLOBAL_CONFIG, Uefi.Input.KeyFiltering),
OC_SCHEMA_INTEGER_IN ("KeyForgetThreshold", OC_GLOBAL_CONFIG, Uefi.Input.KeyForgetThreshold),
OC_SCHEMA_BOOLEAN_IN ("KeySkipFirstDelay", OC_GLOBAL_CONFIG, Uefi.Input.KeySkipFirstDelay),
OC_SCHEMA_INTEGER_IN ("KeyInitialDelay", OC_GLOBAL_CONFIG, Uefi.Input.KeyInitialDelay),
OC_SCHEMA_INTEGER_IN ("KeySubsequentDelay", OC_GLOBAL_CONFIG, Uefi.Input.KeySubsequentDelay),
OC_SCHEMA_BOOLEAN_IN ("KeySupport", OC_GLOBAL_CONFIG, Uefi.Input.KeySupport),
OC_SCHEMA_STRING_IN ("KeySupportMode", OC_GLOBAL_CONFIG, Uefi.Input.KeySupportMode),
OC_SCHEMA_BOOLEAN_IN ("KeySwap", OC_GLOBAL_CONFIG, Uefi.Input.KeySwap),

View File

@ -36,7 +36,7 @@ AIKProtocolArriveHandler (
Keycode = (AIK_SELF *) Context;
if (Keycode == NULL || Keycode->OurJobIsDone) {
DEBUG ((DEBUG_INFO, "AIKProtocolArriveHandler got null handler or called when done\n"));
DEBUG ((DEBUG_INFO, "AIK: ProtocolArriveHandler got null handler or called when done\n"));
return;
}
@ -47,7 +47,7 @@ AIKProtocolArriveHandler (
//
AIKProtocolArriveUninstall (Keycode);
} else {
DEBUG ((DEBUG_INFO, "AIKProtocolArriveHandler AIKInstall failed - %r\n", Status));
DEBUG ((DEBUG_INFO, "AIK: ProtocolArriveHandler AIKInstall failed - %r\n", Status));
}
}
@ -106,7 +106,7 @@ AIKPollKeyboardHandler (
Keycode = (AIK_SELF *) Context;
if (Keycode == NULL || Keycode->OurJobIsDone) {
DEBUG ((DEBUG_INFO, "AIKPollKeyboardHandler got null handler or called when done\n"));
DEBUG ((DEBUG_INFO, "AIK: PollKeyboardHandler got null handler or called when done\n"));
return;
}
@ -205,12 +205,12 @@ AIKInstall (
if (!EFI_ERROR (Status)) {
Status = gBS->SetTimer (Keycode->PollKeyboardEvent, TimerPeriodic, AIK_KEY_POLL_INTERVAL);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "AIKPollKeyboardHandler timer setting failed - %r\n", Status));
DEBUG ((DEBUG_INFO, "AIK: PollKeyboardHandler timer setting failed - %r\n", Status));
gBS->CloseEvent (Keycode->PollKeyboardEvent);
Keycode->PollKeyboardEvent = NULL;
}
} else {
DEBUG ((DEBUG_INFO, "AIKPollKeyboardHandler event creation failed - %r\n", Status));
DEBUG ((DEBUG_INFO, "AIK: PollKeyboardHandler event creation failed - %r\n", Status));
}
if (EFI_ERROR (Status)) {
@ -259,7 +259,6 @@ OcAppleGenericInputKeycodeInit (
//
// Allow to see whether this is installed, even on success
//
DEBUG ((DEBUG_INFO, "AIKInstall - %r\n", Status));
if (EFI_ERROR (Status)) {
//
// No AppleKeyMapAggregator present, install on its availability.
@ -269,10 +268,14 @@ OcAppleGenericInputKeycodeInit (
//
// TODO: Should there be DEBUG_ERROR here (critical error?)
//
DEBUG ((DEBUG_INFO, "AIK is NOT waiting for protocols - %r\n", Status));
DEBUG ((DEBUG_INFO, "AIK: NOT waiting for protocols - %r\n", Status));
}
}
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "AIK: Using %d (%d0ms)\n", KeyForgotThreshold, KeyForgotThreshold));
}
return Status;
}

View File

@ -341,7 +341,11 @@ OcReinstallProtocols (
DEBUG ((DEBUG_ERROR, "OC: Failed to install key map protocols\n"));
}
if (OcAppleEventInstallProtocol (Config->Uefi.ProtocolOverrides.AppleEvent, Config->Uefi.Input.KeySkipFirstDelay) == NULL) {
if (OcAppleEventInstallProtocol (
Config->Uefi.ProtocolOverrides.AppleEvent,
Config->Uefi.Input.KeyInitialDelay,
Config->Uefi.Input.KeySubsequentDelay
) == NULL) {
DEBUG ((DEBUG_ERROR, "OC: Failed to install key event protocol\n"));
}