OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
InputSimAbsPtr.c
Go to the documentation of this file.
1
8#include <Uefi.h>
9
10#include <Protocol/AppleEvent.h>
11#include <Protocol/AbsolutePointer.h>
12
13#include <Library/BaseLib.h>
14#include <Library/BaseMemoryLib.h>
15#include <Library/BaseOverflowLib.h>
16#include <Library/DebugLib.h>
18#include <Library/OcCpuLib.h>
19#include <Library/OcMiscLib.h>
20#include <Library/UefiBootServicesTableLib.h>
21#include <Library/UefiLib.h>
22
23#include "../OpenCanopy.h"
24#include "../GuiIo.h"
25
26#define ABS_DOUBLE_CLICK_RADIUS 25U
27#define IS_POWER_2(x) (((x) & ((x) - 1)) == 0 && (x) != 0)
28
29#define POINTER_SCALE 1U
30
49
50enum {
54};
55
56STATIC
57VOID
59 IN OUT GUI_POINTER_CONTEXT *Context,
60 IN UINT8 Type,
61 IN UINT32 X,
62 IN UINT32 Y
63 )
64{
65 UINT32 Tail;
66
67 //
68 // Due to the modulus, wraparounds do not matter. The size of the queue must
69 // be a power of two for this to hold.
70 //
72 IS_POWER_2 (ARRAY_SIZE (Context->EventQueue)),
73 "The pointer event queue must have a power of two length."
74 );
75
76 Tail = Context->EventQueueTail % ARRAY_SIZE (Context->EventQueue);
77 Context->EventQueue[Tail].Type = Type;
78 Context->EventQueue[Tail].Pos.Pos.X = X;
79 Context->EventQueue[Tail].Pos.Pos.Y = Y;
80 ++Context->EventQueueTail;
81}
82
83BOOLEAN
85 IN OUT GUI_POINTER_CONTEXT *Context,
86 OUT GUI_PTR_EVENT *Event
87 )
88{
89 UINT32 Head;
90
91 if (Context->EventQueueHead == Context->EventQueueTail) {
92 return FALSE;
93 }
94
95 //
96 // Due to the modulus, wraparounds do not matter. The size of the queue must
97 // be a power of two for this to hold.
98 //
100 IS_POWER_2 (ARRAY_SIZE (Context->EventQueue)),
101 "The pointer event queue must have a power of two length."
102 );
103
104 Head = Context->EventQueueHead % ARRAY_SIZE (Context->EventQueue);
105 Event->Type = Context->EventQueue[Head].Type;
106 Event->Pos.Pos.X = Context->EventQueue[Head].Pos.Pos.X;
107 Event->Pos.Pos.Y = Context->EventQueue[Head].Pos.Pos.Y;
108 ++Context->EventQueueHead;
109
110 return TRUE;
111}
112
113STATIC
114VOID
115EFIAPI
117 IN APPLE_EVENT_INFORMATION *Information,
118 IN VOID *NotifyContext
119 )
120{
121 APPLE_POINTER_EVENT_TYPE EventType;
122 GUI_POINTER_CONTEXT *Context;
123
124 Context = NotifyContext;
125
126 ASSERT ((Information->EventType & APPLE_ALL_MOUSE_EVENTS) != 0);
127 //
128 // Discard simple pointer updates when absolute pointer locked.
129 //
130 if (Context->LockedBy == PointerLockedAbsolute) {
131 return;
132 }
133
134 EventType = Information->EventData.PointerEventType;
135
136 if ((EventType & APPLE_EVENT_TYPE_MOUSE_MOVED) != 0) {
137 Context->CurPos.Pos.X = (UINT32)Information->PointerPosition.Horizontal;
138 Context->CurPos.Pos.Y = (UINT32)Information->PointerPosition.Vertical;
139 }
140
141 if ((EventType & APPLE_EVENT_TYPE_LEFT_BUTTON) != 0) {
142 if ((EventType & APPLE_EVENT_TYPE_MOUSE_DOWN) != 0) {
143 ASSERT (Context->LockedBy == PointerUnlocked);
145 Context,
147 (UINT32)Information->PointerPosition.Horizontal,
148 (UINT32)Information->PointerPosition.Vertical
149 );
150 Context->LockedBy = PointerLockedSimple;
151 } else if ((EventType & APPLE_EVENT_TYPE_MOUSE_UP) != 0) {
152 ASSERT (Context->LockedBy == PointerLockedSimple);
154 Context,
156 (UINT32)Information->PointerPosition.Horizontal,
157 (UINT32)Information->PointerPosition.Vertical
158 );
159 Context->LockedBy = PointerUnlocked;
160 } else if ((EventType & APPLE_EVENT_TYPE_MOUSE_DOUBLE_CLICK) != 0) {
162 Context,
164 (UINT32)Information->PointerPosition.Horizontal,
165 (UINT32)Information->PointerPosition.Vertical
166 );
167 }
168 }
169}
170
171STATIC
172VOID
173EFIAPI
175 IN EFI_EVENT Event,
176 IN OUT VOID *NotifyContext
177 )
178{
179 GUI_POINTER_CONTEXT *Context;
180 EFI_STATUS Status;
181 EFI_ABSOLUTE_POINTER_STATE PointerState;
182 UINT64 NewX;
183 UINT64 NewY;
184 GUI_PTR_POSITION NewPos;
185
186 ASSERT (NotifyContext != NULL);
187
188 Context = NotifyContext;
189 ASSERT (Context->AbsPointer != NULL);
190 //
191 // Discard absolute pointer updates when simple pointer locked.
192 //
193 if (Context->LockedBy == PointerLockedSimple) {
194 return;
195 }
196
197 Status = Context->AbsPointer->GetState (Context->AbsPointer, &PointerState);
198 if (EFI_ERROR (Status)) {
199 return;
200 }
201
202 NewX = PointerState.CurrentX - Context->AbsPointer->Mode->AbsoluteMinX;
203 NewX *= Context->MaxXPlus1;
204 NewPos.Pos.X = (UINT32)DivU64x32 (
205 NewX,
206 (UINT32)(Context->AbsPointer->Mode->AbsoluteMaxX - Context->AbsPointer->Mode->AbsoluteMinX)
207 );
208
209 NewY = PointerState.CurrentY - Context->AbsPointer->Mode->AbsoluteMinY;
210 NewY *= Context->MaxYPlus1;
211 NewPos.Pos.Y = (UINT32)DivU64x32 (
212 NewY,
213 (UINT32)(Context->AbsPointer->Mode->AbsoluteMaxY - Context->AbsPointer->Mode->AbsoluteMinY)
214 );
215
216 Context->CurPos.Uint64 = NewPos.Uint64;
217 //
218 // Cancel double click when the finger is moved too far away.
219 //
220 ASSERT (Context->UiScale > 0);
221
222 if (Context->AbsDoubleClick) {
223 if ( (ABS ((INT64)NewPos.Pos.X - Context->AbsLastDownPos.Pos.X) > ABS_DOUBLE_CLICK_RADIUS * Context->UiScale)
224 || (ABS ((INT64)NewPos.Pos.Y - Context->AbsLastDownPos.Pos.Y) > ABS_DOUBLE_CLICK_RADIUS * Context->UiScale))
225 {
226 Context->AbsDoubleClick = FALSE;
227 }
228 }
229
230 if (Context->AbsPrimaryDown != ((PointerState.ActiveButtons & EFI_ABSP_TouchActive) != 0)) {
231 Context->AbsPrimaryDown = ((PointerState.ActiveButtons & EFI_ABSP_TouchActive) != 0);
232 if (Context->AbsPrimaryDown) {
233 ASSERT (Context->LockedBy == PointerUnlocked);
235 Context,
237 NewPos.Pos.X,
238 NewPos.Pos.Y
239 );
241
242 Context->AbsLastDownPos.Uint64 = NewPos.Uint64;
243 Context->AbsDoubleClick = TRUE;
244 } else {
247 Context,
249 NewPos.Pos.X,
250 NewPos.Pos.Y
251 );
252 Context->LockedBy = PointerUnlocked;
253
254 if (Context->AbsDoubleClick) {
256 Context,
258 NewPos.Pos.X,
259 NewPos.Pos.Y
260 );
261 Context->AbsDoubleClick = FALSE;
262 }
263 }
264 }
265}
266
267VOID
269 IN OUT GUI_POINTER_CONTEXT *Context
270 )
271{
272 ASSERT (Context != NULL);
273
274 Context->EventQueueHead = 0;
275 Context->EventQueueTail = 0;
276
277 Context->LockedBy = PointerUnlocked;
278}
279
280VOID
282 IN OUT GUI_POINTER_CONTEXT *Context,
283 OUT GUI_PTR_POSITION *Position
284 )
285{
286 EFI_TPL OldTpl;
287
288 ASSERT (Context != NULL);
289 ASSERT (Position != NULL);
290 //
291 // Prevent pointer updates during state retrieval.
292 // On 64+-bit systems, the operation is atomic.
293 //
294 if (sizeof (UINTN) < sizeof (UINT64)) {
295 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
296 }
297
298 //
299 // Return the current pointer position.
300 //
301 Position->Uint64 = Context->CurPos.Uint64;
302
303 if (sizeof (UINTN) < sizeof (UINT64)) {
304 gBS->RestoreTPL (OldTpl);
305 }
306}
307
308VOID
310 IN OUT GUI_POINTER_CONTEXT *Context,
311 IN CONST GUI_PTR_POSITION *Position
312 )
313{
314 EFI_TPL OldTpl;
315 DIMENSION ApplePosition;
316
317 ASSERT (Context != NULL);
318 ASSERT (Position != NULL);
319
320 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
321
322 ApplePosition.Horizontal = (INT32)Position->Pos.X;
323 ApplePosition.Vertical = (INT32)Position->Pos.Y;
324 Context->AppleEvent->SetCursorPosition (
325 &ApplePosition
326 );
327
328 //
329 // Return the current pointer position.
330 //
331 Context->CurPos.Uint64 = Position->Uint64;
332
333 gBS->RestoreTPL (OldTpl);
334}
335
338 IN UINT32 DefaultX,
339 IN UINT32 DefaultY,
340 IN UINT32 Width,
341 IN UINT32 Height,
342 IN UINT8 UiScale
343 )
344{
345 // TODO: alloc on the fly?
346 STATIC GUI_POINTER_CONTEXT Context;
347
348 EFI_STATUS Status;
349 EFI_STATUS Status2;
350 DIMENSION Dimension;
351
352 ASSERT (DefaultX <= MAX_INT32);
353 ASSERT (DefaultY <= MAX_INT32);
354
355 Context.MaxXPlus1 = Width;
356 Context.MaxYPlus1 = Height;
357 Context.CurPos.Pos.X = DefaultX;
358 Context.CurPos.Pos.Y = DefaultY;
359 Context.UiScale = UiScale;
360
361 Context.AppleEvent = OcGetProtocol (
363 DEBUG_WARN,
364 "GuiPointerConstruct",
365 "AppleEvent"
366 );
367
368 Status = EFI_UNSUPPORTED;
369 if (Context.AppleEvent != NULL) {
370 if (Context.AppleEvent->Revision >= APPLE_EVENT_PROTOCOL_REVISION) {
371 Dimension.Horizontal = (INT32)DefaultX;
372 Dimension.Vertical = (INT32)DefaultY;
373 Context.AppleEvent->SetCursorPosition (
374 &Dimension
375 );
376
377 //
378 // Do not register 'Click' as its behaviour does not follow OS behaviour.
379 //
380 Status = Context.AppleEvent->RegisterHandler (
383 &Context.AppleEventHandle,
384 &Context
385 );
386 }
387
388 if (EFI_ERROR (Status)) {
389 DEBUG ((
390 DEBUG_WARN,
391 "OCUI: AppleEvent %u is unsupported - %r\n",
392 Context.AppleEvent->Revision,
393 Status
394 ));
395 return NULL;
396 }
397 }
398
399 Status2 = OcHandleProtocolFallback (
400 gST->ConsoleInHandle,
402 (VOID **)&Context.AbsPointer
403 );
404 if (!EFI_ERROR (Status2)) {
405 Context.AbsPollEvent = EventLibCreateNotifyTimerEvent (
407 &Context,
408 EFI_TIMER_PERIOD_MILLISECONDS (10),
409 TRUE
410 );
411 if (Context.AbsPollEvent == NULL) {
412 Status2 = EFI_UNSUPPORTED;
413 }
414 }
415
416 if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {
417 return NULL;
418 }
419
420 return &Context;
421}
422
423VOID
425 IN GUI_POINTER_CONTEXT *Context
426 )
427{
428 ASSERT (Context != NULL);
429 ASSERT (Context->AppleEvent != NULL);
430
431 Context->AppleEvent->UnregisterHandler (Context->AppleEventHandle);
432
433 if (Context->AbsPollEvent != NULL) {
434 EventLibCancelEvent (Context->AbsPollEvent);
435 }
436
437 ZeroMem (Context, sizeof (*Context));
438}
UINTN APPLE_POINTER_EVENT_TYPE
Definition AppleEvent.h:48
#define APPLE_EVENT_TYPE_MOUSE_MOVED
Definition AppleEvent.h:21
VOID * APPLE_EVENT_HANDLE
Definition AppleEvent.h:95
#define APPLE_EVENT_TYPE_MOUSE_CLICK
Definition AppleEvent.h:24
#define APPLE_EVENT_TYPE_LEFT_BUTTON
Definition AppleEvent.h:26
#define APPLE_EVENT_TYPE_MOUSE_DOUBLE_CLICK
Definition AppleEvent.h:25
#define APPLE_ALL_MOUSE_EVENTS
Definition AppleEvent.h:41
#define APPLE_EVENT_TYPE_MOUSE_DOWN
Definition AppleEvent.h:22
EFI_GUID gAppleEventProtocolGuid
#define APPLE_EVENT_TYPE_MOUSE_UP
Definition AppleEvent.h:23
#define APPLE_EVENT_PROTOCOL_REVISION
Definition AppleEvent.h:100
EFI_EVENT EventLibCreateNotifyTimerEvent(IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *NotifyContext, IN UINT64 TriggerTime, IN BOOLEAN SignalPeriodic)
VOID EventLibCancelEvent(IN EFI_EVENT Event)
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
STATIC VOID InternalQueuePointerEvent(IN OUT GUI_POINTER_CONTEXT *Context, IN UINT8 Type, IN UINT32 X, IN UINT32 Y)
VOID GuiPointerReset(IN OUT GUI_POINTER_CONTEXT *Context)
@ PointerLockedSimple
@ PointerUnlocked
@ PointerLockedAbsolute
STATIC VOID EFIAPI InternalUpdateContextAbsolute(IN EFI_EVENT Event, IN OUT VOID *NotifyContext)
VOID GuiPointerGetPosition(IN OUT GUI_POINTER_CONTEXT *Context, OUT GUI_PTR_POSITION *Position)
VOID GuiPointerSetPosition(IN OUT GUI_POINTER_CONTEXT *Context, IN CONST GUI_PTR_POSITION *Position)
STATIC VOID EFIAPI InternalAppleEventNotification(IN APPLE_EVENT_INFORMATION *Information, IN VOID *NotifyContext)
#define ABS_DOUBLE_CLICK_RADIUS
GUI_POINTER_CONTEXT * GuiPointerConstruct(IN UINT32 DefaultX, IN UINT32 DefaultY, IN UINT32 Width, IN UINT32 Height, IN UINT8 UiScale)
VOID GuiPointerDestruct(IN GUI_POINTER_CONTEXT *Context)
BOOLEAN GuiPointerGetEvent(IN OUT GUI_POINTER_CONTEXT *Context, OUT GUI_PTR_EVENT *Event)
#define IS_POWER_2(x)
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
EFI_SYSTEM_TABLE * gST
EFI_BOOT_SERVICES * gBS
VOID * OcGetProtocol(IN EFI_GUID *Protocol, IN UINTN ErrorLevel, IN CONST CHAR8 *CallerName OPTIONAL, IN CONST CHAR8 *ProtocolName OPTIONAL)
EFI_STATUS OcHandleProtocolFallback(IN EFI_HANDLE Handle, IN EFI_GUID *Protocol, OUT VOID **Interface)
UINTN Head
Definition OcTypingLib.h:46
UINTN Tail
Definition OcTypingLib.h:47
@ GuiPointerPrimaryUp
Definition OpenCanopy.h:23
@ GuiPointerPrimaryDown
Definition OpenCanopy.h:22
@ GuiPointerPrimaryDoubleClick
Definition OpenCanopy.h:24
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_GUID gEfiAbsolutePointerProtocolGuid
#define ASSERT(x)
Definition coder.h:55
#define DivU64x32(x, y, z)
INT32 Horizontal
Definition AppleEvent.h:65
INT32 Vertical
Definition AppleEvent.h:66
GUI_PTR_POSITION CurPos
GUI_PTR_EVENT EventQueue[16]
EFI_ABSOLUTE_POINTER_PROTOCOL * AbsPointer
APPLE_EVENT_HANDLE AppleEventHandle
GUI_PTR_POSITION AbsLastDownPos
APPLE_EVENT_PROTOCOL * AppleEvent
struct GUI_PTR_POSITION::@111 Pos