提交 c7b10630 编写于 作者: M Marvin Häuser

OcAppleEventLib: Support dwell-clicking

Fixes https://github.com/acidanthera/bugtracker/issues/2067
上级 b6d62ed5
...@@ -4,6 +4,7 @@ OpenCore Changelog ...@@ -4,6 +4,7 @@ OpenCore Changelog
- Updated emulated NVRAM save script for compatibilty with earlier macOS (Snow Leopard+ tested) - 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 - 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 - Fixed maximum click duration and double click speed for non-standard poll frequencies
- Added support for pointer dwell-clicking
#### v0.8.5 #### v0.8.5
- Updated builtin firmware versions for SMBIOS and the rest - Updated builtin firmware versions for SMBIOS and the rest
......
...@@ -7604,6 +7604,40 @@ for additional options. ...@@ -7604,6 +7604,40 @@ for additional options.
optionally be modified in combination with \texttt{PointerSpeedDiv}, according to user optionally be modified in combination with \texttt{PointerSpeedDiv}, according to user
preference, to achieve customised mouse movement scaling. 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} \end{enumerate}
\subsection{Audio Properties}\label{uefiaudioprops} \subsection{Audio Properties}\label{uefiaudioprops}
......
...@@ -1379,6 +1379,12 @@ ...@@ -1379,6 +1379,12 @@
<integer>50</integer> <integer>50</integer>
<key>KeySubsequentDelay</key> <key>KeySubsequentDelay</key>
<integer>5</integer> <integer>5</integer>
<key>PointerDwellClickTimeout</key>
<integer>0</integer>
<key>PointerDwellDoubleClickTimeout</key>
<integer>0</integer>
<key>PointerDwellRadius</key>
<integer>0</integer>
<key>PointerPollMask</key> <key>PointerPollMask</key>
<integer>-1</integer> <integer>-1</integer>
<key>PointerPollMax</key> <key>PointerPollMax</key>
......
...@@ -1747,6 +1747,12 @@ ...@@ -1747,6 +1747,12 @@
<integer>50</integer> <integer>50</integer>
<key>KeySubsequentDelay</key> <key>KeySubsequentDelay</key>
<integer>5</integer> <integer>5</integer>
<key>PointerDwellClickTimeout</key>
<integer>0</integer>
<key>PointerDwellDoubleClickTimeout</key>
<integer>0</integer>
<key>PointerDwellRadius</key>
<integer>0</integer>
<key>PointerPollMask</key> <key>PointerPollMask</key>
<integer>-1</integer> <integer>-1</integer>
<key>PointerPollMax</key> <key>PointerPollMax</key>
......
...@@ -24,23 +24,26 @@ ...@@ -24,23 +24,26 @@
/** /**
Install and initialise Apple Event protocol. Install and initialise Apple Event protocol.
@param[in] Install If false, do not install even when no suitable OEM version found. @param[in] Install If false, do not install even when no suitable OEM version found.
@param[in] Reinstall If true, force overwrite installed protocol. @param[in] Reinstall If true, force overwrite installed protocol.
If false, use Apple OEM protocol where possible. If false, use Apple OEM protocol where possible.
@param[in] CustomDelays If true, use key delays specified. @param[in] CustomDelays If true, use key delays specified.
If false, use Apple OEM default key delay values. If false, use Apple OEM default key delay values.
OC builtin AppleEvent only. OC builtin AppleEvent only.
@param[in] KeyInitialDelay Key repeat initial delay in 10ms units. @param[in] KeyInitialDelay Key repeat initial delay in 10ms units.
@param[in] KeySubsequentDelay Key repeat subsequent delay in 10ms units. @param[in] KeySubsequentDelay Key repeat subsequent delay in 10ms units.
If zero, warn and use 1. If zero, warn and use 1.
@param[in] GraphicsInputMirroring If true, disable Apple default behaviour which can @param[in] GraphicsInputMirroring If true, disable Apple default behaviour which can
prevent keyboard input reaching non-Apple GUI UEFI apps. prevent keyboard input reaching non-Apple GUI UEFI apps.
OC builtin AppleEvent only. OC builtin AppleEvent only.
@param[in] PointerPollMin Pointer polling minimal period in ms. @param[in] PointerPollMin Pointer polling minimal period in ms.
@param[in] PointerPollMax Pointer polling maximum period in ms. @param[in] PointerPollMax Pointer polling maximum period in ms.
@param[in] PointerPollMask Pointer polling mask to choose polled handles. @param[in] PointerPollMask Pointer polling mask to choose polled handles.
@param[in] PointerSpeedDiv Pointer speed divisor. If zero, warn and use 1. @param[in] PointerSpeedDiv Pointer speed divisor. If zero, warn and use 1.
@param[in] PointerSpeedMul Pointer speed multiplier. @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. @retval installed or located protocol or NULL.
**/ **/
...@@ -56,7 +59,10 @@ OcAppleEventInstallProtocol ( ...@@ -56,7 +59,10 @@ OcAppleEventInstallProtocol (
IN UINT32 PointerPollMax, IN UINT32 PointerPollMax,
IN UINT32 PointerPollMask, IN UINT32 PointerPollMask,
IN UINT16 PointerSpeedDiv, IN UINT16 PointerSpeedDiv,
IN UINT16 PointerSpeedMul IN UINT16 PointerSpeedMul,
IN UINT16 PointerDwellClickTimeout,
IN UINT16 PointerDwellDoubleClickTimeout,
IN UINT16 PointerDwellRadius
); );
#endif // OC_APPLE_EVENT_LIB_H #endif // OC_APPLE_EVENT_LIB_H
...@@ -633,16 +633,19 @@ OC_DECLARE (OC_UEFI_APFS) ...@@ -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. /// AppleInput is a set of options to configure OpenCore's reverse engingeered then customised implementation of the AppleEvent protocol.
/// ///
#define OC_UEFI_APPLEINPUT_FIELDS(_, __) \ #define OC_UEFI_APPLEINPUT_FIELDS(_, __) \
_(OC_STRING , AppleEvent , , OC_STRING_CONSTR ("Auto", _, __) , OC_DESTR (OC_STRING) ) \ _(OC_STRING , AppleEvent , , OC_STRING_CONSTR ("Auto", _, __) , OC_DESTR (OC_STRING) ) \
_(BOOLEAN , CustomDelays , , FALSE , ()) \ _(BOOLEAN , CustomDelays , , FALSE , ()) \
_(UINT16 , KeyInitialDelay , , 50 , ()) \ _(UINT16 , KeyInitialDelay , , 50 , ()) \
_(UINT16 , KeySubsequentDelay , , 5 , ()) \ _(UINT16 , KeySubsequentDelay , , 5 , ()) \
_(BOOLEAN , GraphicsInputMirroring, , FALSE , ()) \ _(BOOLEAN , GraphicsInputMirroring , , FALSE , ()) \
_(UINT32 , PointerPollMin , , 0 , ()) \ _(UINT32 , PointerPollMin , , 0 , ()) \
_(UINT32 , PointerPollMax , , 0 , ()) \ _(UINT32 , PointerPollMax , , 0 , ()) \
_(UINT32 , PointerPollMask , , ((UINT32) (-1)) , ()) \ _(UINT32 , PointerPollMask , , ((UINT32) (-1)) , ()) \
_(UINT16 , PointerSpeedDiv , , 1 , ()) \ _(UINT16 , PointerSpeedDiv , , 1 , ()) \
_(UINT16 , PointerSpeedMul , , 1 , ()) _(UINT16 , PointerSpeedMul , , 1 , ()) \
_(UINT16 , PointerDwellClickTimeout , , 0 , ()) \
_(UINT16 , PointerDwellDoubleClickTimeout, , 0 , ()) \
_(UINT16 , PointerDwellRadius , , 0 , ())
OC_DECLARE (OC_UEFI_APPLEINPUT) OC_DECLARE (OC_UEFI_APPLEINPUT)
/// ///
......
...@@ -164,6 +164,11 @@ InternalSetKeyBehaviour ( ...@@ -164,6 +164,11 @@ InternalSetKeyBehaviour (
IN BOOLEAN GraphicsInputMirroring IN BOOLEAN GraphicsInputMirroring
); );
VOID
InternalInitializePointerUiScale (
VOID
);
VOID VOID
InternalSetPointerPolling ( InternalSetPointerPolling (
IN UINT32 PointerPollMin, IN UINT32 PointerPollMin,
...@@ -177,6 +182,13 @@ InternalSetPointerSpeed ( ...@@ -177,6 +182,13 @@ InternalSetPointerSpeed (
IN UINT16 PointerSpeedMul IN UINT16 PointerSpeedMul
); );
VOID
InternalSetDwellClicking (
IN UINT16 ClickTimeout,
IN UINT16 DoubleClickTimeout,
IN UINT16 Radius
);
extern UINT32 mPointerSpeedMul; extern UINT32 mPointerSpeedMul;
extern UINT32 mPointerSpeedDiv; extern UINT32 mPointerSpeedDiv;
......
...@@ -564,7 +564,10 @@ OcAppleEventInstallProtocol ( ...@@ -564,7 +564,10 @@ OcAppleEventInstallProtocol (
IN UINT32 PointerPollMax, IN UINT32 PointerPollMax,
IN UINT32 PointerPollMask, IN UINT32 PointerPollMask,
IN UINT16 PointerSpeedDiv, IN UINT16 PointerSpeedDiv,
IN UINT16 PointerSpeedMul IN UINT16 PointerSpeedMul,
IN UINT16 PointerDwellClickTimeout,
IN UINT16 PointerDwellDoubleClickTimeout,
IN UINT16 PointerDwellRadius
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
...@@ -618,8 +621,14 @@ OcAppleEventInstallProtocol ( ...@@ -618,8 +621,14 @@ OcAppleEventInstallProtocol (
GraphicsInputMirroring GraphicsInputMirroring
); );
InternalInitializePointerUiScale ();
InternalSetPointerPolling (PointerPollMin, PointerPollMax, PointerPollMask); InternalSetPointerPolling (PointerPollMin, PointerPollMax, PointerPollMask);
InternalSetPointerSpeed (PointerSpeedDiv, PointerSpeedMul); InternalSetPointerSpeed (PointerSpeedDiv, PointerSpeedMul);
InternalSetDwellClicking (
PointerDwellClickTimeout,
PointerDwellDoubleClickTimeout,
PointerDwellRadius
);
Status = gBS->InstallMultipleProtocolInterfaces ( Status = gBS->InstallMultipleProtocolInterfaces (
&gImageHandle, &gImageHandle,
......
...@@ -144,6 +144,33 @@ STATIC UINT64 mMaxPointerResolutionY = 1; ...@@ -144,6 +144,33 @@ STATIC UINT64 mMaxPointerResolutionY = 1;
STATIC UINT64 mPointerRawX; STATIC UINT64 mPointerRawX;
STATIC UINT64 mPointerRawY; 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 VOID
InternalSetPointerPolling ( InternalSetPointerPolling (
IN UINT32 PointerPollMin, IN UINT32 PointerPollMin,
...@@ -193,6 +220,18 @@ InternalSetPointerSpeed ( ...@@ -193,6 +220,18 @@ InternalSetPointerSpeed (
mPointerSpeedMul = PointerSpeedMul; 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 // InternalRegisterSimplePointerInterface
STATIC STATIC
VOID VOID
...@@ -720,6 +759,90 @@ InternalHandleButtonInteraction ( ...@@ -720,6 +759,90 @@ InternalHandleButtonInteraction (
++Pointer->ButtonTicksSinceClick; ++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 // InternalSimplePointerPollNotifyFunction
STATIC STATIC
VOID VOID
...@@ -879,6 +1002,8 @@ InternalSimplePointerPollNotifyFunction ( ...@@ -879,6 +1002,8 @@ InternalSimplePointerPollNotifyFunction (
InternalHandleButtonInteraction (CommonStatus, &mLeftButtonInfo, Modifiers); InternalHandleButtonInteraction (CommonStatus, &mLeftButtonInfo, Modifiers);
InternalHandleButtonInteraction (CommonStatus, &mRightButtonInfo, Modifiers); InternalHandleButtonInteraction (CommonStatus, &mRightButtonInfo, Modifiers);
InternalHandleDwellClicking (Modifiers);
} }
if (EFI_ERROR (CommonStatus)) { if (EFI_ERROR (CommonStatus)) {
...@@ -944,25 +1069,10 @@ EventCreateSimplePointerPollEvent ( ...@@ -944,25 +1069,10 @@ EventCreateSimplePointerPollEvent (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
UINTN DataSize;
UINTN Index; UINTN Index;
DEBUG ((DEBUG_VERBOSE, "EventCreateSimplePointerPollEvent\n")); 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 ( InternalRemoveUninstalledInstances (
&mPointerProtocols, &mPointerProtocols,
&mNumberOfPointerProtocols, &mNumberOfPointerProtocols,
......
...@@ -764,16 +764,19 @@ OC_SCHEMA ...@@ -764,16 +764,19 @@ OC_SCHEMA
STATIC STATIC
OC_SCHEMA OC_SCHEMA
mUefiAppleInputSchema[] = { mUefiAppleInputSchema[] = {
OC_SCHEMA_STRING_IN ("AppleEvent", OC_GLOBAL_CONFIG, Uefi.AppleInput.AppleEvent), 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 ("CustomDelays", OC_GLOBAL_CONFIG, Uefi.AppleInput.CustomDelays),
OC_SCHEMA_BOOLEAN_IN ("GraphicsInputMirroring", OC_GLOBAL_CONFIG, Uefi.AppleInput.GraphicsInputMirroring), 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 ("KeyInitialDelay", OC_GLOBAL_CONFIG, Uefi.AppleInput.KeyInitialDelay),
OC_SCHEMA_INTEGER_IN ("KeySubsequentDelay", OC_GLOBAL_CONFIG, Uefi.AppleInput.KeySubsequentDelay), 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 ("PointerDwellClickTimeout", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerDwellClickTimeout),
OC_SCHEMA_INTEGER_IN ("PointerPollMax", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMax), OC_SCHEMA_INTEGER_IN ("PointerDwellDoubleClickTimeout", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerDwellDoubleClickTimeout),
OC_SCHEMA_INTEGER_IN ("PointerPollMin", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMin), OC_SCHEMA_INTEGER_IN ("PointerDwellRadius", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerDwellRadius),
OC_SCHEMA_INTEGER_IN ("PointerSpeedDiv", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerSpeedDiv), OC_SCHEMA_INTEGER_IN ("PointerPollMask", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerPollMask),
OC_SCHEMA_INTEGER_IN ("PointerSpeedMul", OC_GLOBAL_CONFIG, Uefi.AppleInput.PointerSpeedMul), 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 STATIC
......
...@@ -451,7 +451,10 @@ OcReinstallProtocols ( ...@@ -451,7 +451,10 @@ OcReinstallProtocols (
Config->Uefi.AppleInput.PointerPollMax, Config->Uefi.AppleInput.PointerPollMax,
Config->Uefi.AppleInput.PointerPollMask, Config->Uefi.AppleInput.PointerPollMask,
Config->Uefi.AppleInput.PointerSpeedDiv, 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) ) == NULL)
&& InstallAppleEvent) && InstallAppleEvent)
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册