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