diff --git a/Changelog.md b/Changelog.md index f1906a527c87cc9ebbf498e396156b5a781e82c3..02f3d173854164bee4e99f5bfdd2ccf73871b87e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,7 @@ OpenCore Changelog - Updated emulated NVRAM save script for compatibilty with earlier macOS (Snow Leopard+ tested) - Updated emulated NVRAM save script to automatically install as launch daemon (Yosemite+) or logout hook - Fixed maximum click duration and double click speed for non-standard poll frequencies +- Added support for pointer dwell-clicking #### v0.8.5 - Updated builtin firmware versions for SMBIOS and the rest diff --git a/Docs/Configuration.pdf b/Docs/Configuration.pdf index 57f4898ad359b4ecf3060fe6e7a3cf868fceae4b..1a376e04db01aab7e727e4e87ccbd13f20f890a1 100644 Binary files a/Docs/Configuration.pdf and b/Docs/Configuration.pdf differ diff --git a/Docs/Configuration.tex b/Docs/Configuration.tex index 936e40487528c89c6260962c22c5473d927e55a3..391f126d91ea64204b3037b5741ba2f223b69ecb 100755 --- a/Docs/Configuration.tex +++ b/Docs/Configuration.tex @@ -7604,6 +7604,40 @@ for additional options. optionally be modified in combination with \texttt{PointerSpeedDiv}, according to user preference, to achieve customised mouse movement scaling. +\item + \texttt{PointerDwellClickTimeout}\\ + \textbf{Type}: \texttt{plist\ integer}\\ + \textbf{Failsafe}: \texttt{0}\\ + \textbf{Description}: Configure pointer dwell-clicking single left click timeout in + milliseconds in the OpenCore re-implementation of the Apple Event protocol. + Has no effect when using the OEM Apple implementation (see \texttt{AppleEvent} setting). + + When the timeout expires, a single left click is issued at the current position. + \texttt{0} indicates the timeout is disabled. + +\item + \texttt{PointerDwellDoubleClickTimeout}\\ + \textbf{Type}: \texttt{plist\ integer}\\ + \textbf{Failsafe}: \texttt{0}\\ + \textbf{Description}: Configure pointer dwell-clicking single left double click timeout in + milliseconds in the OpenCore re-implementation of the Apple Event protocol. + Has no effect when using the OEM Apple implementation (see \texttt{AppleEvent} setting). + + When the timeout expires, a single left double click is issued at the current position. + \texttt{0} indicates the timeout is disabled. + +\item + \texttt{PointerDwellRadius}\\ + \textbf{Type}: \texttt{plist\ integer}\\ + \textbf{Failsafe}: \texttt{0}\\ + \textbf{Description}: Configure pointer dwell-clicking tolerance radius in pixels in the + OpenCore re-implementation of the Apple Event protocol. + Has no effect when using the OEM Apple implementation (see \texttt{AppleEvent} setting). + + The radius is scaled by \texttt{UIScale}. When the pointer leaves this radius, the timeouts for \texttt{PointerDwellClickTimeout} + and \texttt{PointerDwellDoubleClickTimeout} are reset and the new position is the centre + for the new dwell-clicking tolerance radius. + \end{enumerate} \subsection{Audio Properties}\label{uefiaudioprops} diff --git a/Docs/Sample.plist b/Docs/Sample.plist index ced5e3f7a1e3c0e65578b951d572d5ca3afec750..bc0c1f88a172be1a292fd29ea7a3905e41f8e3f2 100644 --- a/Docs/Sample.plist +++ b/Docs/Sample.plist @@ -1379,6 +1379,12 @@ 50 KeySubsequentDelay 5 + PointerDwellClickTimeout + 0 + PointerDwellDoubleClickTimeout + 0 + PointerDwellRadius + 0 PointerPollMask -1 PointerPollMax diff --git a/Docs/SampleCustom.plist b/Docs/SampleCustom.plist index 08c48c17dc6b3db5ace52985e80085fba219aa30..0b33b00584683dd434b598102c7cb59a89f8d26d 100644 --- a/Docs/SampleCustom.plist +++ b/Docs/SampleCustom.plist @@ -1747,6 +1747,12 @@ 50 KeySubsequentDelay 5 + PointerDwellClickTimeout + 0 + PointerDwellDoubleClickTimeout + 0 + PointerDwellRadius + 0 PointerPollMask -1 PointerPollMax diff --git a/Include/Acidanthera/Library/OcAppleEventLib.h b/Include/Acidanthera/Library/OcAppleEventLib.h index 6f688d8b8263dfa8e2dac48a02b539e10e4f4bfc..00460b606db110d4bdf56cbd7321b389bcb018fd 100644 --- a/Include/Acidanthera/Library/OcAppleEventLib.h +++ b/Include/Acidanthera/Library/OcAppleEventLib.h @@ -24,23 +24,26 @@ /** Install and initialise Apple Event protocol. - @param[in] Install If false, do not install even when no suitable OEM version found. - @param[in] Reinstall If true, force overwrite installed protocol. - If false, use Apple OEM protocol where possible. - @param[in] CustomDelays If true, use key delays specified. - If false, use Apple OEM default key delay values. - OC builtin AppleEvent only. - @param[in] KeyInitialDelay Key repeat initial delay in 10ms units. - @param[in] KeySubsequentDelay Key repeat subsequent delay in 10ms units. - If zero, warn and use 1. - @param[in] GraphicsInputMirroring If true, disable Apple default behaviour which can - prevent keyboard input reaching non-Apple GUI UEFI apps. - OC builtin AppleEvent only. - @param[in] PointerPollMin Pointer polling minimal period in ms. - @param[in] PointerPollMax Pointer polling maximum period in ms. - @param[in] PointerPollMask Pointer polling mask to choose polled handles. - @param[in] PointerSpeedDiv Pointer speed divisor. If zero, warn and use 1. - @param[in] PointerSpeedMul Pointer speed multiplier. + @param[in] Install If false, do not install even when no suitable OEM version found. + @param[in] Reinstall If true, force overwrite installed protocol. + If false, use Apple OEM protocol where possible. + @param[in] CustomDelays If true, use key delays specified. + If false, use Apple OEM default key delay values. + OC builtin AppleEvent only. + @param[in] KeyInitialDelay Key repeat initial delay in 10ms units. + @param[in] KeySubsequentDelay Key repeat subsequent delay in 10ms units. + If zero, warn and use 1. + @param[in] GraphicsInputMirroring If true, disable Apple default behaviour which can + prevent keyboard input reaching non-Apple GUI UEFI apps. + OC builtin AppleEvent only. + @param[in] PointerPollMin Pointer polling minimal period in ms. + @param[in] PointerPollMax Pointer polling maximum period in ms. + @param[in] PointerPollMask Pointer polling mask to choose polled handles. + @param[in] PointerSpeedDiv Pointer speed divisor. If zero, warn and use 1. + @param[in] PointerSpeedMul Pointer speed multiplier. + @param[in] PointerDwellClickTimeout Pointer dwell-clicking single left click timeout. + @param[in] PointerDwellDoubleClickTimeout Pointer dwell-clicking single left double click timeout. + @param[in] PointerDwellRadius Pointer dwell-clicking tolerance radius in pixels. @retval installed or located protocol or NULL. **/ @@ -56,7 +59,10 @@ OcAppleEventInstallProtocol ( IN UINT32 PointerPollMax, IN UINT32 PointerPollMask, IN UINT16 PointerSpeedDiv, - IN UINT16 PointerSpeedMul + IN UINT16 PointerSpeedMul, + IN UINT16 PointerDwellClickTimeout, + IN UINT16 PointerDwellDoubleClickTimeout, + IN UINT16 PointerDwellRadius ); #endif // OC_APPLE_EVENT_LIB_H diff --git a/Include/Acidanthera/Library/OcConfigurationLib.h b/Include/Acidanthera/Library/OcConfigurationLib.h index e381e50011edbe756f1213bb06f8262e3800facb..3b2060857fa455ac8053fb16eb6fc7527322a3d5 100644 --- a/Include/Acidanthera/Library/OcConfigurationLib.h +++ b/Include/Acidanthera/Library/OcConfigurationLib.h @@ -633,16 +633,19 @@ OC_DECLARE (OC_UEFI_APFS) /// AppleInput is a set of options to configure OpenCore's reverse engingeered then customised implementation of the AppleEvent protocol. /// #define OC_UEFI_APPLEINPUT_FIELDS(_, __) \ - _(OC_STRING , AppleEvent , , OC_STRING_CONSTR ("Auto", _, __) , OC_DESTR (OC_STRING) ) \ - _(BOOLEAN , CustomDelays , , FALSE , ()) \ - _(UINT16 , KeyInitialDelay , , 50 , ()) \ - _(UINT16 , KeySubsequentDelay , , 5 , ()) \ - _(BOOLEAN , GraphicsInputMirroring, , FALSE , ()) \ - _(UINT32 , PointerPollMin , , 0 , ()) \ - _(UINT32 , PointerPollMax , , 0 , ()) \ - _(UINT32 , PointerPollMask , , ((UINT32) (-1)) , ()) \ - _(UINT16 , PointerSpeedDiv , , 1 , ()) \ - _(UINT16 , PointerSpeedMul , , 1 , ()) + _(OC_STRING , AppleEvent , , OC_STRING_CONSTR ("Auto", _, __) , OC_DESTR (OC_STRING) ) \ + _(BOOLEAN , CustomDelays , , FALSE , ()) \ + _(UINT16 , KeyInitialDelay , , 50 , ()) \ + _(UINT16 , KeySubsequentDelay , , 5 , ()) \ + _(BOOLEAN , GraphicsInputMirroring , , FALSE , ()) \ + _(UINT32 , PointerPollMin , , 0 , ()) \ + _(UINT32 , PointerPollMax , , 0 , ()) \ + _(UINT32 , PointerPollMask , , ((UINT32) (-1)) , ()) \ + _(UINT16 , PointerSpeedDiv , , 1 , ()) \ + _(UINT16 , PointerSpeedMul , , 1 , ()) \ + _(UINT16 , PointerDwellClickTimeout , , 0 , ()) \ + _(UINT16 , PointerDwellDoubleClickTimeout, , 0 , ()) \ + _(UINT16 , PointerDwellRadius , , 0 , ()) OC_DECLARE (OC_UEFI_APPLEINPUT) /// diff --git a/Library/OcAppleEventLib/AppleEventInternal.h b/Library/OcAppleEventLib/AppleEventInternal.h index 4c3d8708c731e056f4ba0aee9bda4f4366773e69..e4a3d7184ee3331a8e3ee3204cb41c8de3d9415b 100644 --- a/Library/OcAppleEventLib/AppleEventInternal.h +++ b/Library/OcAppleEventLib/AppleEventInternal.h @@ -164,6 +164,11 @@ InternalSetKeyBehaviour ( IN BOOLEAN GraphicsInputMirroring ); +VOID +InternalInitializePointerUiScale ( + VOID + ); + VOID InternalSetPointerPolling ( IN UINT32 PointerPollMin, @@ -177,6 +182,13 @@ InternalSetPointerSpeed ( IN UINT16 PointerSpeedMul ); +VOID +InternalSetDwellClicking ( + IN UINT16 ClickTimeout, + IN UINT16 DoubleClickTimeout, + IN UINT16 Radius + ); + extern UINT32 mPointerSpeedMul; extern UINT32 mPointerSpeedDiv; diff --git a/Library/OcAppleEventLib/OcAppleEventLib.c b/Library/OcAppleEventLib/OcAppleEventLib.c index 16d0b345133a365538499d8691662ee6840c87aa..a9d40a3179f8bc9d2a7c919be434fde2ca69da9c 100644 --- a/Library/OcAppleEventLib/OcAppleEventLib.c +++ b/Library/OcAppleEventLib/OcAppleEventLib.c @@ -564,7 +564,10 @@ OcAppleEventInstallProtocol ( IN UINT32 PointerPollMax, IN UINT32 PointerPollMask, IN UINT16 PointerSpeedDiv, - IN UINT16 PointerSpeedMul + IN UINT16 PointerSpeedMul, + IN UINT16 PointerDwellClickTimeout, + IN UINT16 PointerDwellDoubleClickTimeout, + IN UINT16 PointerDwellRadius ) { EFI_STATUS Status; @@ -618,8 +621,14 @@ OcAppleEventInstallProtocol ( GraphicsInputMirroring ); + InternalInitializePointerUiScale (); InternalSetPointerPolling (PointerPollMin, PointerPollMax, PointerPollMask); InternalSetPointerSpeed (PointerSpeedDiv, PointerSpeedMul); + InternalSetDwellClicking ( + PointerDwellClickTimeout, + PointerDwellDoubleClickTimeout, + PointerDwellRadius + ); Status = gBS->InstallMultipleProtocolInterfaces ( &gImageHandle, diff --git a/Library/OcAppleEventLib/PointerHandler.c b/Library/OcAppleEventLib/PointerHandler.c index 52afe37af048dd8b246e3536763f2f176fc0e6a8..4ebb19e6578ccb3e1f2c4ac383f86c74b94a776d 100644 --- a/Library/OcAppleEventLib/PointerHandler.c +++ b/Library/OcAppleEventLib/PointerHandler.c @@ -144,6 +144,33 @@ STATIC UINT64 mMaxPointerResolutionY = 1; STATIC UINT64 mPointerRawX; STATIC UINT64 mPointerRawY; +STATIC UINT32 mDwellClickTimeout; +STATIC UINT32 mDwellDoubleClickTimeout; +STATIC UINT32 mDwellClickRadiusSqr; +STATIC DIMENSION mDwellPosition; +STATIC UINT32 mDwellClickTime; + +VOID +InternalInitializePointerUiScale ( + VOID + ) +{ + EFI_STATUS Status; + UINTN DataSize; + + DataSize = sizeof (mUiScale); + Status = gRT->GetVariable ( + APPLE_UI_SCALE_VARIABLE_NAME, + &gAppleVendorVariableGuid, + NULL, + &DataSize, + (VOID *)&mUiScale + ); + if (EFI_ERROR (Status) || (mUiScale != 2)) { + mUiScale = 1; + } +} + VOID InternalSetPointerPolling ( IN UINT32 PointerPollMin, @@ -193,6 +220,18 @@ InternalSetPointerSpeed ( mPointerSpeedMul = PointerSpeedMul; } +VOID +InternalSetDwellClicking ( + IN UINT16 ClickTimeout, + IN UINT16 DoubleClickTimeout, + IN UINT16 Radius + ) +{ + mDwellClickTimeout = (UINT32)ClickTimeout * 10000; + mDwellDoubleClickTimeout = (UINT32)DoubleClickTimeout * 10000; + mDwellClickRadiusSqr = ((UINT32)Radius * Radius) * (mUiScale * mUiScale); +} + // InternalRegisterSimplePointerInterface STATIC VOID @@ -720,6 +759,90 @@ InternalHandleButtonInteraction ( ++Pointer->ButtonTicksSinceClick; } +STATIC +VOID +InternalResetDwellClicking ( + VOID + ) +{ + mDwellClickTime = 0; + CopyMem ( + &mDwellPosition, + &mCursorPosition, + sizeof (mDwellPosition) + ); +} + +STATIC +VOID +InternalQueueDwellClick ( + IN APPLE_EVENT_TYPE EventType, + IN APPLE_MODIFIER_MAP Modifiers + ) +{ + APPLE_EVENT_INFORMATION *Information; + + Information = InternalCreatePointerEventQueueInformation ( + APPLE_EVENT_TYPE_LEFT_BUTTON | APPLE_EVENT_TYPE_MOUSE_DOWN, + Modifiers + ); + if (Information != NULL) { + EventAddEventToQueue (Information); + } + + Information = InternalCreatePointerEventQueueInformation ( + APPLE_EVENT_TYPE_LEFT_BUTTON | APPLE_EVENT_TYPE_MOUSE_UP, + Modifiers + ); + if (Information != NULL) { + EventAddEventToQueue (Information); + } + + Information = InternalCreatePointerEventQueueInformation ( + APPLE_EVENT_TYPE_LEFT_BUTTON | EventType, + Modifiers + ); + if (Information != NULL) { + EventAddEventToQueue (Information); + } +} + +STATIC +VOID +InternalHandleDwellClicking ( + IN APPLE_MODIFIER_MAP Modifiers + ) +{ + BOOLEAN ClickDisabled; + BOOLEAN DoubleClickDisabled; + INT32 DistX; + INT32 DistY; + + ClickDisabled = mDwellClickTimeout == 0; + DoubleClickDisabled = mDwellDoubleClickTimeout == 0; + if (ClickDisabled && DoubleClickDisabled) { + return; + } + + DistX = mCursorPosition.Horizontal - mDwellPosition.Horizontal; + DistY = mCursorPosition.Vertical - mDwellPosition.Vertical; + if ((UINT32)(DistX * DistX + DistY * DistY) <= mDwellClickRadiusSqr) { + mDwellClickTime += mSimplePointerPollTime; + + if (!DoubleClickDisabled && (mDwellClickTime >= mDwellDoubleClickTimeout)) { + InternalQueueDwellClick (APPLE_EVENT_TYPE_MOUSE_DOUBLE_CLICK, Modifiers); + InternalResetDwellClicking (); + } else if (!ClickDisabled && (mDwellClickTime >= mDwellClickTimeout)) { + InternalQueueDwellClick (APPLE_EVENT_TYPE_MOUSE_CLICK, Modifiers); + if (DoubleClickDisabled) { + InternalResetDwellClicking (); + } + } + } else { + InternalResetDwellClicking (); + } +} + // InternalSimplePointerPollNotifyFunction STATIC VOID @@ -879,6 +1002,8 @@ InternalSimplePointerPollNotifyFunction ( InternalHandleButtonInteraction (CommonStatus, &mLeftButtonInfo, Modifiers); InternalHandleButtonInteraction (CommonStatus, &mRightButtonInfo, Modifiers); + + InternalHandleDwellClicking (Modifiers); } if (EFI_ERROR (CommonStatus)) { @@ -944,25 +1069,10 @@ EventCreateSimplePointerPollEvent ( ) { EFI_STATUS Status; - UINTN DataSize; UINTN Index; DEBUG ((DEBUG_VERBOSE, "EventCreateSimplePointerPollEvent\n")); - DataSize = sizeof (mUiScale); - - Status = gRT->GetVariable ( - APPLE_UI_SCALE_VARIABLE_NAME, - &gAppleVendorVariableGuid, - NULL, - &DataSize, - (VOID *)&mUiScale - ); - - if (EFI_ERROR (Status) || (mUiScale != 2)) { - mUiScale = 1; - } - InternalRemoveUninstalledInstances ( &mPointerProtocols, &mNumberOfPointerProtocols, diff --git a/Library/OcConfigurationLib/OcConfigurationLib.c b/Library/OcConfigurationLib/OcConfigurationLib.c index 442bc385d7a504110b58cd7072b3745eb706b850..07a17b3efcf25266107260bf327d7806cac0d8e1 100644 --- a/Library/OcConfigurationLib/OcConfigurationLib.c +++ b/Library/OcConfigurationLib/OcConfigurationLib.c @@ -764,16 +764,19 @@ OC_SCHEMA STATIC OC_SCHEMA mUefiAppleInputSchema[] = { - OC_SCHEMA_STRING_IN ("AppleEvent", OC_GLOBAL_CONFIG, Uefi.AppleInput.AppleEvent), - OC_SCHEMA_BOOLEAN_IN ("CustomDelays", OC_GLOBAL_CONFIG, Uefi.AppleInput.CustomDelays), - OC_SCHEMA_BOOLEAN_IN ("GraphicsInputMirroring", OC_GLOBAL_CONFIG, Uefi.AppleInput.GraphicsInputMirroring), - OC_SCHEMA_INTEGER_IN ("KeyInitialDelay", OC_GLOBAL_CONFIG, Uefi.AppleInput.KeyInitialDelay), - OC_SCHEMA_INTEGER_IN ("KeySubsequentDelay", OC_GLOBAL_CONFIG, Uefi.AppleInput.KeySubsequentDelay), - OC_SCHEMA_INTEGER_IN ("PointerPollMask", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMask), - OC_SCHEMA_INTEGER_IN ("PointerPollMax", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMax), - OC_SCHEMA_INTEGER_IN ("PointerPollMin", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMin), - OC_SCHEMA_INTEGER_IN ("PointerSpeedDiv", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerSpeedDiv), - OC_SCHEMA_INTEGER_IN ("PointerSpeedMul", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerSpeedMul), + OC_SCHEMA_STRING_IN ("AppleEvent", OC_GLOBAL_CONFIG, Uefi.AppleInput.AppleEvent), + OC_SCHEMA_BOOLEAN_IN ("CustomDelays", OC_GLOBAL_CONFIG, Uefi.AppleInput.CustomDelays), + OC_SCHEMA_BOOLEAN_IN ("GraphicsInputMirroring", OC_GLOBAL_CONFIG, Uefi.AppleInput.GraphicsInputMirroring), + OC_SCHEMA_INTEGER_IN ("KeyInitialDelay", OC_GLOBAL_CONFIG, Uefi.AppleInput.KeyInitialDelay), + OC_SCHEMA_INTEGER_IN ("KeySubsequentDelay", OC_GLOBAL_CONFIG, Uefi.AppleInput.KeySubsequentDelay), + OC_SCHEMA_INTEGER_IN ("PointerDwellClickTimeout", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerDwellClickTimeout), + OC_SCHEMA_INTEGER_IN ("PointerDwellDoubleClickTimeout", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerDwellDoubleClickTimeout), + OC_SCHEMA_INTEGER_IN ("PointerDwellRadius", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerDwellRadius), + OC_SCHEMA_INTEGER_IN ("PointerPollMask", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMask), + OC_SCHEMA_INTEGER_IN ("PointerPollMax", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMax), + OC_SCHEMA_INTEGER_IN ("PointerPollMin", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMin), + OC_SCHEMA_INTEGER_IN ("PointerSpeedDiv", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerSpeedDiv), + OC_SCHEMA_INTEGER_IN ("PointerSpeedMul", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerSpeedMul), }; STATIC diff --git a/Library/OcMainLib/OpenCoreUefi.c b/Library/OcMainLib/OpenCoreUefi.c index 920ee5d7667bfe235bbbd1f822a9c3a1ceec4b34..5f0c503e7f1ea7f7e1787ab4f780371adfbd9414 100644 --- a/Library/OcMainLib/OpenCoreUefi.c +++ b/Library/OcMainLib/OpenCoreUefi.c @@ -451,7 +451,10 @@ OcReinstallProtocols ( Config->Uefi.AppleInput.PointerPollMax, Config->Uefi.AppleInput.PointerPollMask, Config->Uefi.AppleInput.PointerSpeedDiv, - Config->Uefi.AppleInput.PointerSpeedMul + Config->Uefi.AppleInput.PointerSpeedMul, + Config->Uefi.AppleInput.PointerDwellClickTimeout, + Config->Uefi.AppleInput.PointerDwellDoubleClickTimeout, + Config->Uefi.AppleInput.PointerDwellRadius ) == NULL) && InstallAppleEvent) {