OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcTypingLib.c
Go to the documentation of this file.
1
8#include <Uefi.h>
9#include <Library/BaseLib.h>
10#include <Library/MemoryAllocationLib.h>
11#include <Library/UefiBootServicesTableLib.h>
14#include <Library/OcMiscLib.h>
15#include <Library/OcTimerLib.h>
16#include <Library/OcTypingLib.h>
17
19
20STATIC
21VOID
22EFIAPI
24 IN APPLE_EVENT_INFORMATION *Information,
25 IN OC_TYPING_CONTEXT *Context
26 )
27{
29 CHAR16 UnicodeChar;
30 UINTN NewHead;
31
32 AppleKeyCode = 0;
33 UnicodeChar = L'\0';
34
35 if (Information->EventData.KeyData != NULL) {
36 AppleKeyCode = Information->EventData.KeyData->AppleKeyCode;
37 UnicodeChar = Information->EventData.KeyData->InputKey.UnicodeChar;
38 }
39
40 DEBUG ((OC_TRACE_TYPING, "OCTY: HandleKeyEvent[%p] %x:%d[%x] %c\n", &HandleKeyEvent, Information->EventType, Information->Modifiers, AppleKeyCode, UnicodeChar));
41
42 //
43 // We now handle modifiers immediately, rather than in the queue. By comparison this reduces
44 // memory footprint, simplifies queue and dequeue code and removes any possibility of
45 // stuck modifiers if queue fills. It also still behaves at least as well from end user pov.
46 // Difference is that modifiers held when action occurs are what apply, not modifiers
47 // held when key which caused action was pressed - but it is not at all clear that
48 // this is incorrect, it may even be more correct.
49 //
50 if ((Information->EventType & APPLE_EVENT_TYPE_MODIFIER_UP) != 0) {
51 Context->CurrentModifiers &= ~Information->Modifiers;
52 return;
53 } else if ((Information->EventType & APPLE_EVENT_TYPE_MODIFIER_DOWN) != 0) {
54 Context->CurrentModifiers |= Information->Modifiers;
55 return;
56 } else if ((Information->EventType & APPLE_EVENT_TYPE_KEY_DOWN) == 0) {
57 return;
58 }
59
60 NewHead = Context->Head + 1;
61 if (NewHead >= OC_TYPING_BUFFER_SIZE) {
62 NewHead = 0;
63 }
64
65 //
66 // Now that we are returning key presses only (not modifiers) in the queue, just drop any over queue length
67 //
68 if (NewHead == Context->Tail) {
69 return;
70 }
71
72 Context->Head = NewHead;
73
74 DEBUG_CODE_BEGIN ();
75 ASSERT (AppleKeyCode != 0);
76 DEBUG_CODE_END ();
77
78 DEBUG ((OC_TRACE_TYPING, "OCTY: Writing to %d\n", Context->Head));
79
80 Context->Buffer[Context->Head].AppleKeyCode = AppleKeyCode;
81 Context->Buffer[Context->Head].UnicodeChar = UnicodeChar;
82
83 #if defined (OC_TRACE_KEY_TIMES)
84 DEBUG_CODE_BEGIN ();
85 Context->KeyTimes[Context->Head] = GetPerformanceCounter ();
86 DEBUG_CODE_END ();
87 #endif
88}
89
90EFI_STATUS
92 OUT OC_TYPING_CONTEXT **Context
93 )
94{
95 EFI_STATUS Status;
96
97 DEBUG ((OC_TRACE_TYPING, "OCTY: OcRegisterTypingHandler\n"));
98
99 *Context = NULL;
100
101 Status = gBS->LocateProtocol (
103 NULL,
104 (VOID **)&mProtocol
105 );
106
107 if (EFI_ERROR (Status)) {
108 DEBUG ((DEBUG_ERROR, "OCTY: Failed to locate apple event protocol - %r\n", Status));
109 return Status;
110 }
111
112 DEBUG ((OC_TRACE_TYPING, "OCTY: About to allocate %d x %d for buffer, plus rest of context = %d\n", OC_TYPING_BUFFER_SIZE, sizeof ((*Context)->Buffer[0]), sizeof (**Context)));
113
114 *Context = AllocatePool (sizeof (**Context));
115
116 if (*Context == NULL) {
117 Status = EFI_OUT_OF_RESOURCES;
118 DEBUG ((DEBUG_ERROR, "OCTY: Failed to allocate context - %r\n", Status));
119 return Status;
120 }
121
122 (*Context)->KeyTimes = NULL;
123
124 #if defined (OC_TRACE_KEY_TIMES)
125 DEBUG_CODE_BEGIN ();
126 DEBUG ((OC_TRACE_TYPING, "OCTY: About to allocate %d x %d for key times buffer\n", OC_TYPING_BUFFER_SIZE, sizeof ((*Context)->KeyTimes[0])));
127
128 (*Context)->KeyTimes = AllocatePool (OC_TYPING_BUFFER_SIZE * sizeof ((*Context)->KeyTimes[0]));
129
130 if ((*Context)->KeyTimes == NULL) {
131 DEBUG ((DEBUG_ERROR, "OCTY: Failed to allocate typing context key times buffer - %r\n", Status));
132 FreePool (*Context);
133 *Context = NULL;
134 Status = EFI_OUT_OF_RESOURCES;
135 return Status;
136 }
137
138 DEBUG_CODE_END ();
139 #endif
140
141 DEBUG ((OC_TRACE_TYPING, "OCTY: RegisterHandler (F, [%p], %p, %p)\n", &HandleKeyEvent, &(*Context)->Handle, *Context));
142 Status = mProtocol->RegisterHandler (
145 &(*Context)->Handle,
146 *Context
147 );
148
149 if (EFI_ERROR (Status)) {
150 DEBUG ((DEBUG_ERROR, "OCTY: Failed to register handler - %r\n", Status));
151 #if defined (OC_TRACE_KEY_TIMES)
152 DEBUG_CODE_BEGIN ();
153 FreePool ((*Context)->KeyTimes);
154 DEBUG_CODE_END ();
155 #endif
156 FreePool (*Context);
157 *Context = NULL;
158 return Status;
159 }
160
161 //
162 // Init
163 //
164 OcFlushTypingBuffer (*Context);
165
166 DEBUG ((OC_TRACE_TYPING, "OCTY: reg c=%p h=%p k=%p\n", *Context, (*Context)->Handle, (*Context)->KeyTimes));
167 DEBUG ((DEBUG_INFO, "OCTY: Registered handler\n"));
168
169 return EFI_SUCCESS;
170}
171
172EFI_STATUS
174 IN OC_TYPING_CONTEXT **Context
175 )
176{
177 EFI_STATUS Status;
178
179 ASSERT (Context != NULL);
180
181 if (*Context == NULL) {
182 return EFI_SUCCESS;
183 }
184
185 DEBUG ((OC_TRACE_TYPING, "OCTY: unreg c=%p h=%p k=%p\n", *Context, (*Context)->Handle, (*Context)->KeyTimes));
186
187 if ((*Context)->Handle == NULL) {
188 Status = EFI_NOT_STARTED;
189 } else {
190 Status = mProtocol->UnregisterHandler ((*Context)->Handle);
191 (*Context)->Handle = NULL;
192
193 if (EFI_ERROR (Status)) {
194 DEBUG ((DEBUG_ERROR, "OCTY: Failed to unregister handler - %r\n", Status));
195 } else {
196 // show this here, before freeing the pools; any stray events in log after this point would be a problem
197 DEBUG ((DEBUG_INFO, "OCTY: Unregistered handler\n"));
198 }
199 }
200
201 #if defined (OC_TRACE_KEY_TIMES)
202 DEBUG_CODE_BEGIN ();
203 if ((*Context)->KeyTimes != NULL) {
204 FreePool ((*Context)->KeyTimes);
205 (*Context)->KeyTimes = NULL;
206 }
207
208 DEBUG_CODE_END ();
209 #endif
210
211 FreePool (*Context);
212 *Context = NULL;
213
214 //
215 // Prevent chars which have queued up in ConIn (which is not used by us) affecting subsequent applications.
216 //
218
219 return Status;
220}
221
222VOID
224 IN OC_TYPING_CONTEXT *Context,
225 OUT APPLE_MODIFIER_MAP *Modifiers,
227 OUT CHAR16 *UnicodeChar
228 )
229{
230 UINTN NewTail;
231 UINT64 CurrentMillis;
232
233 CurrentMillis = 0;
234
235 ASSERT (Context != NULL);
236
237 DEBUG ((OC_TRACE_TYPING, "OCTY: OcGetNextKeystroke(%p, M, K)\n", Context));
238
239 *Modifiers = Context->CurrentModifiers;
240 *AppleKeyCode = 0;
241 *UnicodeChar = L'\0';
242
243 //
244 // Buffer empty.
245 //
246 if (Context->Tail == Context->Head) {
247 return;
248 }
249
250 DEBUG ((OC_TRACE_TYPING, "OCTY: %d != %d\n", Context->Tail, Context->Head));
251
252 //
253 // Write can potentially occur in the middle of read, so don't update
254 // Context->Tail until data is read.
255 //
256 NewTail = Context->Tail + 1;
257
258 if (NewTail >= OC_TYPING_BUFFER_SIZE) {
259 NewTail = 0;
260 }
261
262 DEBUG ((OC_TRACE_TYPING, "OCTY: Reading from %d\n", NewTail));
263
264 *AppleKeyCode = Context->Buffer[NewTail].AppleKeyCode;
265 *UnicodeChar = Context->Buffer[NewTail].UnicodeChar;
266
267 Context->Tail = NewTail;
268
269 #if defined (OC_TRACE_KEY_TIMES)
270 DEBUG_CODE_BEGIN ();
271 CurrentMillis = DivU64x64Remainder (GetTimeInNanoSecond (Context->KeyTimes[Context->Tail]), 1000000ULL, NULL);
272 DEBUG ((DEBUG_INFO, "OCTY: OcGetNextKeystroke @%d %d[%x] %,Lu\n", Context->Tail, *Modifiers, *AppleKeyCode, CurrentMillis));
273 DEBUG_CODE_END ();
274 #else
275 DEBUG ((OC_TRACE_TYPING, "OCTY: OcGetNextKeystroke @%d %d[%x] %,Lu\n", Context->Tail, *Modifiers, *AppleKeyCode, CurrentMillis));
276 #endif
277}
278
279VOID
281 IN OC_TYPING_CONTEXT *Context
282 )
283{
284 Context->Tail = 0;
285 Context->Head = 0;
286 Context->CurrentModifiers = 0;
287 DEBUG ((OC_TRACE_TYPING, "OCTY: OcFlushTypingBuffer %d %d %d\n", Context->Tail, Context->Head, Context->CurrentModifiers));
288}
#define APPLE_EVENT_TYPE_MODIFIER_UP
Definition AppleEvent.h:32
#define APPLE_EVENT_TYPE_KEY_DOWN
Definition AppleEvent.h:29
#define APPLE_ALL_KEYBOARD_EVENTS
Definition AppleEvent.h:42
VOID(EFIAPI * APPLE_EVENT_NOTIFY_FUNCTION)(IN APPLE_EVENT_INFORMATION *Information, IN VOID *NotifyContext)
Definition AppleEvent.h:89
#define APPLE_EVENT_TYPE_MODIFIER_DOWN
Definition AppleEvent.h:31
EFI_GUID gAppleEventProtocolGuid
APPLE_HID_USAGE APPLE_KEY_CODE
Definition AppleHid.h:317
UINT16 APPLE_MODIFIER_MAP
Definition AppleHid.h:102
EFI_BOOT_SERVICES * gBS
VOID OcConsoleFlush(VOID)
STATIC APPLE_EVENT_PROTOCOL * mProtocol
Definition OcTypingLib.c:18
EFI_STATUS OcUnregisterTypingHandler(IN OC_TYPING_CONTEXT **Context)
STATIC VOID EFIAPI HandleKeyEvent(IN APPLE_EVENT_INFORMATION *Information, IN OC_TYPING_CONTEXT *Context)
Definition OcTypingLib.c:23
EFI_STATUS OcRegisterTypingHandler(OUT OC_TYPING_CONTEXT **Context)
Definition OcTypingLib.c:91
VOID OcGetNextKeystroke(IN OC_TYPING_CONTEXT *Context, OUT APPLE_MODIFIER_MAP *Modifiers, OUT APPLE_KEY_CODE *AppleKeyCode, OUT CHAR16 *UnicodeChar)
VOID OcFlushTypingBuffer(IN OC_TYPING_CONTEXT *Context)
CHAR16 UnicodeChar
Definition OcTypingLib.h:38
#define OC_TYPING_BUFFER_SIZE
Definition OcTypingLib.h:32
APPLE_KEY_CODE AppleKeyCode
Definition OcTypingLib.h:37
#define OC_TRACE_TYPING
Definition OcTypingLib.h:14
PACKED struct @7 OC_TYPING_CONTEXT
UINT64 EFIAPI DivU64x64Remainder(IN UINT64 Dividend, IN UINT64 Divisor, OUT UINT64 *Remainder OPTIONAL)
Definition UserMath.c:59
UINT64 EFIAPI GetTimeInNanoSecond(IN UINT64 Ticks)
UINT64 EFIAPI GetPerformanceCounter(VOID)
#define ASSERT(x)
Definition coder.h:55
EVENT_UNREGISTER_HANDLER UnregisterHandler
Definition AppleEvent.h:163
EVENT_REGISTER_HANDLER RegisterHandler
Definition AppleEvent.h:162