312a549847c5f303f03d0ec3ac73a88cbdaadf1f
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinGopInput.c
1 /** @file\r
2 \r
3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
4 SPDX-License-Identifier: BSD-2-Clause-Patent\r
5 \r
6 Module Name:\r
7 \r
8   WinGopInput.c\r
9 \r
10 Abstract:\r
11 \r
12   This file produces the Simple Text In for an Gop window.\r
13 \r
14   This stuff is linked at the hip to the Window, since the window\r
15   processing is done in a thread kicked off in WinNtGopImplementation.c\r
16 \r
17   Since the window information is processed in an other thread we need\r
18   a keyboard Queue to pass data about. The Simple Text In code just\r
19   takes data off the Queue. The WinProc message loop takes keyboard input\r
20   and places it in the Queue.\r
21 \r
22 \r
23 **/\r
24 \r
25 \r
26 #include "WinGop.h"\r
27 \r
28 \r
29 /**\r
30   TODO: Add function description\r
31 \r
32   @param  Private               TODO: add argument description\r
33 \r
34   @retval EFI_SUCCESS           TODO: Add description for return value\r
35 \r
36 **/\r
37 EFI_STATUS\r
38 GopPrivateCreateQ (\r
39   IN  GRAPHICS_PRIVATE_DATA    *Private,\r
40   IN GOP_QUEUE_FIXED           *Queue\r
41   )\r
42 {\r
43   InitializeCriticalSection (&Queue->Cs);\r
44   Queue->Front = 0;\r
45   Queue->Rear  = 0;\r
46   return EFI_SUCCESS;\r
47 }\r
48 \r
49 \r
50 /**\r
51   TODO: Add function description\r
52 \r
53   @param  Private               TODO: add argument description\r
54 \r
55   @retval EFI_SUCCESS           TODO: Add description for return value\r
56 \r
57 **/\r
58 EFI_STATUS\r
59 GopPrivateDestroyQ (\r
60   IN  GRAPHICS_PRIVATE_DATA    *Private,\r
61   IN GOP_QUEUE_FIXED           *Queue\r
62   )\r
63 {\r
64   Queue->Front = 0;\r
65   Queue->Rear  = 0;\r
66   DeleteCriticalSection (&Queue->Cs);\r
67   return EFI_SUCCESS;\r
68 }\r
69 \r
70 \r
71 /**\r
72   TODO: Add function description\r
73 \r
74   @param  Private               TODO: add argument description\r
75   @param  Key                   TODO: add argument description\r
76 \r
77   @retval EFI_NOT_READY         TODO: Add description for return value\r
78   @retval EFI_SUCCESS           TODO: Add description for return value\r
79 \r
80 **/\r
81 EFI_STATUS\r
82 GopPrivateAddQ (\r
83   IN  GRAPHICS_PRIVATE_DATA    *Private,\r
84   IN GOP_QUEUE_FIXED           *Queue,\r
85   IN EFI_KEY_DATA              *KeyData\r
86   )\r
87 {\r
88   EnterCriticalSection (&Queue->Cs);\r
89 \r
90   if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {\r
91     LeaveCriticalSection (&Queue->Cs);\r
92     return EFI_NOT_READY;\r
93   }\r
94 \r
95   CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));\r
96   Queue->Rear           = (Queue->Rear + 1) % MAX_Q;\r
97 \r
98   LeaveCriticalSection (&Queue->Cs);\r
99   return EFI_SUCCESS;\r
100 }\r
101 \r
102 \r
103 /**\r
104   TODO: Add function description\r
105 \r
106   @param  Private               TODO: add argument description\r
107   @param  Key                   TODO: add argument description\r
108 \r
109   @retval EFI_NOT_READY         TODO: Add description for return value\r
110   @retval EFI_SUCCESS           TODO: Add description for return value\r
111 \r
112 **/\r
113 EFI_STATUS\r
114 GopPrivateDeleteQ (\r
115   IN  GRAPHICS_PRIVATE_DATA    *Private,\r
116   IN  GOP_QUEUE_FIXED          *Queue,\r
117   OUT EFI_KEY_DATA             *Key\r
118   )\r
119 {\r
120   EnterCriticalSection (&Queue->Cs);\r
121 \r
122   if (Queue->Front == Queue->Rear) {\r
123     LeaveCriticalSection (&Queue->Cs);\r
124     return EFI_NOT_READY;\r
125   }\r
126 \r
127   CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));\r
128   Queue->Front  = (Queue->Front + 1) % MAX_Q;\r
129 \r
130   if (Key->Key.ScanCode == SCAN_NULL && Key->Key.UnicodeChar == CHAR_NULL) {\r
131     if (!Private->IsPartialKeySupport) {\r
132       //\r
133       // If partial keystrok is not enabled, don't return the partial keystroke.\r
134       //\r
135       LeaveCriticalSection (&Queue->Cs);\r
136       ZeroMem (Key, sizeof (EFI_KEY_DATA));\r
137       return EFI_NOT_READY;\r
138     }\r
139   }\r
140   LeaveCriticalSection (&Queue->Cs);\r
141   return EFI_SUCCESS;\r
142 }\r
143 \r
144 \r
145 /**\r
146   TODO: Add function description\r
147 \r
148   @param  Private               TODO: add argument description\r
149 \r
150   @retval EFI_NOT_READY         TODO: Add description for return value\r
151   @retval EFI_SUCCESS           TODO: Add description for return value\r
152 \r
153 **/\r
154 EFI_STATUS\r
155 GopPrivateCheckQ (\r
156   IN  GOP_QUEUE_FIXED     *Queue\r
157   )\r
158 {\r
159   if (Queue->Front == Queue->Rear) {\r
160     return EFI_NOT_READY;\r
161   }\r
162 \r
163   return EFI_SUCCESS;\r
164 }\r
165 \r
166 /**\r
167   Initialize the key state.\r
168 \r
169   @param  Private               The GOP_PRIVATE_DATA instance.\r
170   @param  KeyState              A pointer to receive the key state information.\r
171 **/\r
172 VOID\r
173 InitializeKeyState (\r
174   IN  GRAPHICS_PRIVATE_DATA    *Private,\r
175   IN  EFI_KEY_STATE            *KeyState\r
176   )\r
177 {\r
178   KeyState->KeyShiftState  = EFI_SHIFT_STATE_VALID;\r
179   KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
180 \r
181   //\r
182   // Record Key shift state and toggle state\r
183   //\r
184   if (Private->LeftCtrl) {\r
185     KeyState->KeyShiftState  |= EFI_LEFT_CONTROL_PRESSED;\r
186   }\r
187   if (Private->RightCtrl) {\r
188     KeyState->KeyShiftState  |= EFI_RIGHT_CONTROL_PRESSED;\r
189   }\r
190   if (Private->LeftAlt) {\r
191     KeyState->KeyShiftState  |= EFI_LEFT_ALT_PRESSED;\r
192   }\r
193   if (Private->RightAlt) {\r
194     KeyState->KeyShiftState  |= EFI_RIGHT_ALT_PRESSED;\r
195   }\r
196   if (Private->LeftShift) {\r
197     KeyState->KeyShiftState  |= EFI_LEFT_SHIFT_PRESSED;\r
198   }\r
199   if (Private->RightShift) {\r
200     KeyState->KeyShiftState  |= EFI_RIGHT_SHIFT_PRESSED;\r
201   }\r
202   if (Private->LeftLogo) {\r
203     KeyState->KeyShiftState  |= EFI_LEFT_LOGO_PRESSED;\r
204   }\r
205   if (Private->RightLogo) {\r
206     KeyState->KeyShiftState  |= EFI_RIGHT_LOGO_PRESSED;\r
207   }\r
208   if (Private->Menu) {\r
209     KeyState->KeyShiftState  |= EFI_MENU_KEY_PRESSED;\r
210   }\r
211   if (Private->SysReq) {\r
212     KeyState->KeyShiftState  |= EFI_SYS_REQ_PRESSED;\r
213   }\r
214   if (Private->CapsLock) {\r
215     KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
216   }\r
217   if (Private->NumLock) {\r
218     KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;\r
219   }\r
220   if (Private->ScrollLock) {\r
221     KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;\r
222   }\r
223   if (Private->IsPartialKeySupport) {\r
224     KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;\r
225   }\r
226 }\r
227 \r
228 /**\r
229   TODO: Add function description\r
230 \r
231   @param  Private               TODO: add argument description\r
232   @param  Key                   TODO: add argument description\r
233 \r
234   @retval EFI_NOT_READY         TODO: Add description for return value\r
235   @retval EFI_SUCCESS           TODO: Add description for return value\r
236 \r
237 **/\r
238 EFI_STATUS\r
239 GopPrivateAddKey (\r
240   IN  GRAPHICS_PRIVATE_DATA  *Private,\r
241   IN  EFI_INPUT_KEY          Key\r
242   )\r
243 {\r
244   EFI_KEY_DATA            KeyData;\r
245 \r
246   KeyData.Key = Key;\r
247   InitializeKeyState (Private, &KeyData.KeyState);\r
248 \r
249   //\r
250   // Convert Ctrl+[1-26] to Ctrl+[A-Z]\r
251   //\r
252   if ((Private->LeftCtrl || Private->RightCtrl) &&\r
253       (KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)\r
254      ) {\r
255     if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {\r
256       KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);\r
257     } else {\r
258       KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);\r
259     }\r
260   }\r
261 \r
262   //\r
263   // Unmask the Shift bit for printable char\r
264   //\r
265   if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||\r
266       ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))\r
267      ) {\r
268     KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
269   }\r
270 \r
271   GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);\r
272   if (Private->MakeRegisterdKeyCallback != NULL) {\r
273     Private->MakeRegisterdKeyCallback (Private->RegisterdKeyCallbackContext, &KeyData);\r
274   }\r
275 \r
276   return EFI_SUCCESS;\r
277 }\r
278 \r
279 \r
280 EFI_STATUS\r
281 EFIAPI\r
282 WinNtWndCheckKey (\r
283   IN  EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
284   )\r
285 {\r
286   GRAPHICS_PRIVATE_DATA           *Private;\r
287 \r
288   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
289 \r
290   return GopPrivateCheckQ (&Private->QueueForRead);\r
291 \r
292 }\r
293 EFI_STATUS\r
294 EFIAPI\r
295 WinNtWndGetKey (\r
296   IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,\r
297   IN  EFI_KEY_DATA                  *KeyData\r
298   )\r
299 /*++\r
300 \r
301   Routine Description:\r
302     Reads the next keystroke from the input device. The WaitForKey Event can\r
303     be used to test for existance of a keystroke via WaitForEvent () call.\r
304 \r
305   Arguments:\r
306     Private    - The private structure of WinNt Gop device.\r
307     KeyData    - A pointer to a buffer that is filled in with the keystroke\r
308                  state data for the key that was pressed.\r
309 \r
310   Returns:\r
311     EFI_SUCCESS           - The keystroke information was returned.\r
312     EFI_NOT_READY         - There was no keystroke data availiable.\r
313     EFI_DEVICE_ERROR      - The keystroke information was not returned due to\r
314                             hardware errors.\r
315     EFI_INVALID_PARAMETER - KeyData is NULL.\r
316 \r
317 --*/\r
318 {\r
319   EFI_STATUS                      Status;\r
320   GRAPHICS_PRIVATE_DATA           *Private;\r
321 \r
322   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
323 \r
324   ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
325   InitializeKeyState (Private, &KeyData->KeyState);\r
326 \r
327   Status  = GopPrivateCheckQ (&Private->QueueForRead);\r
328   if (!EFI_ERROR (Status)) {\r
329     //\r
330     // If a Key press exists try and read it.\r
331     //\r
332     Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);\r
333     if (!EFI_ERROR (Status)) {\r
334       //\r
335       // If partial keystroke is not enabled, check whether it is value key. If not return\r
336       // EFI_NOT_READY.\r
337       //\r
338       if (!Private->IsPartialKeySupport) {\r
339         if (KeyData->Key.ScanCode == SCAN_NULL && KeyData->Key.UnicodeChar == CHAR_NULL) {\r
340           Status = EFI_NOT_READY;\r
341         }\r
342       }\r
343     }\r
344   }\r
345 \r
346   return Status;\r
347 \r
348 }\r
349 \r
350 EFI_STATUS\r
351 EFIAPI\r
352 WinNtWndKeySetState (\r
353   IN EMU_GRAPHICS_WINDOW_PROTOCOL   *GraphicsIo,\r
354   IN EFI_KEY_TOGGLE_STATE           *KeyToggleState\r
355   )\r
356 {\r
357   GRAPHICS_PRIVATE_DATA           *Private;\r
358 \r
359   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
360   Private->ScrollLock = FALSE;\r
361   Private->NumLock = FALSE;\r
362   Private->CapsLock = FALSE;\r
363   Private->IsPartialKeySupport = FALSE;\r
364 \r
365   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
366     Private->ScrollLock = TRUE;\r
367   }\r
368   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
369     Private->NumLock = TRUE;\r
370   }\r
371   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
372     Private->CapsLock = TRUE;\r
373   }\r
374   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {\r
375     Private->IsPartialKeySupport = TRUE;\r
376   }\r
377   Private->KeyState.KeyToggleState = *KeyToggleState;\r
378   return EFI_SUCCESS;\r
379 }\r
380 \r
381 \r
382 EFI_STATUS\r
383 EFIAPI\r
384 WinNtWndRegisterKeyNotify (\r
385   IN EMU_GRAPHICS_WINDOW_PROTOCOL                        *GraphicsIo,\r
386   IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    MakeCallBack,\r
387   IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK    BreakCallBack,\r
388   IN VOID                                                *Context\r
389   )\r
390 {\r
391   GRAPHICS_PRIVATE_DATA           *Private;\r
392 \r
393   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
394 \r
395   Private->MakeRegisterdKeyCallback    = MakeCallBack;\r
396   Private->BreakRegisterdKeyCallback   = BreakCallBack;\r
397   Private->RegisterdKeyCallbackContext = Context;\r
398 \r
399   return EFI_SUCCESS;\r
400 }\r
401 \r
402 EFI_STATUS\r
403 EFIAPI\r
404 WinNtWndCheckPointer (\r
405   IN  EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo\r
406   )\r
407 {\r
408   GRAPHICS_PRIVATE_DATA           *Private;\r
409 \r
410   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
411 \r
412   if (!Private->PointerStateChanged) {\r
413     return EFI_NOT_READY;\r
414   }\r
415 \r
416   return EFI_SUCCESS;\r
417 }\r
418 \r
419 EFI_STATUS\r
420 EFIAPI\r
421 WinNtWndGetPointerState (\r
422   IN  EMU_GRAPHICS_WINDOW_PROTOCOL  *GraphicsIo,\r
423   IN  EFI_SIMPLE_POINTER_STATE      *State\r
424   )\r
425 {\r
426   GRAPHICS_PRIVATE_DATA           *Private;\r
427 \r
428   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
429 \r
430   if (!Private->PointerStateChanged) {\r
431     return EFI_NOT_READY;\r
432   }\r
433 \r
434   State->RelativeMovementX = Private->PointerState.RelativeMovementX;\r
435   State->RelativeMovementY = Private->PointerState.RelativeMovementY;\r
436   State->RelativeMovementZ = Private->PointerState.RelativeMovementZ;\r
437   State->LeftButton        = Private->PointerState.LeftButton;\r
438   State->RightButton       = Private->PointerState.RightButton;\r
439 \r
440   Private->PointerState.RelativeMovementX = 0;\r
441   Private->PointerState.RelativeMovementY = 0;\r
442   Private->PointerState.RelativeMovementZ = 0;\r
443 \r
444   Private->PointerStateChanged = FALSE;\r
445 \r
446   return EFI_SUCCESS;\r
447 }\r