]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Win/Host/WinGopScreen.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinGopScreen.c
CommitLineData
7a465451
RN
1/** @file\r
2\r
d773459e 3Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
e3ba31da 4SPDX-License-Identifier: BSD-2-Clause-Patent\r
7a465451
RN
5\r
6Module Name:\r
7\r
8 WinGopScreen.c\r
9\r
10Abstract:\r
11\r
12 This file produces the graphics abstration of GOP. It is called by\r
13 WinNtGopDriver.c file which deals with the UEFI 2.0 driver model.\r
14 This file just does graphics.\r
15\r
16\r
17**/\r
18\r
19#include "WinGop.h"\r
20\r
a550d468
MK
21DWORD mTlsIndex = TLS_OUT_OF_INDEXES;\r
22DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex.\r
7a465451
RN
23\r
24BOOLEAN\r
25WinNtGopConvertParamToEfiKeyShiftState (\r
26 IN GRAPHICS_PRIVATE_DATA *Private,\r
27 IN WPARAM *wParam,\r
28 IN LPARAM *lParam,\r
29 IN BOOLEAN Flag\r
30 )\r
31{\r
32 switch (*wParam) {\r
a550d468
MK
33 //\r
34 // BUGBUG: Only GetAsyncKeyState() and GetKeyState() can distinguish\r
35 // left and right Ctrl, and Shift key.\r
36 // Neither of the two is defined in EFI_WIN_NT_THUNK_PROTOCOL.\r
37 // Therefor, we can not set the correct Shift state here.\r
38 //\r
39 case VK_SHIFT:\r
40 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {\r
7a465451
RN
41 Private->RightShift = Flag;\r
42 } else {\r
43 Private->LeftShift = Flag;\r
44 }\r
7a465451 45\r
a550d468 46 return TRUE;\r
7a465451 47\r
a550d468
MK
48 case VK_LSHIFT:\r
49 Private->LeftShift = Flag;\r
50 return TRUE;\r
7a465451 51\r
a550d468
MK
52 case VK_RSHIFT:\r
53 Private->RightShift = Flag;\r
54 return TRUE;\r
55\r
56 case VK_CONTROL:\r
57 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {\r
58 Private->RightCtrl = Flag;\r
7a465451
RN
59 } else {\r
60 Private->LeftCtrl = Flag;\r
61 }\r
7a465451 62\r
a550d468 63 return TRUE;\r
7a465451 64\r
a550d468
MK
65 case VK_LCONTROL:\r
66 Private->LeftCtrl = Flag;\r
67 return TRUE;\r
7a465451 68\r
a550d468
MK
69 case VK_RCONTROL:\r
70 Private->RightCtrl = Flag;\r
71 return TRUE;\r
7a465451 72\r
a550d468
MK
73 case VK_LWIN:\r
74 Private->LeftLogo = Flag;\r
75 return TRUE;\r
7a465451 76\r
a550d468
MK
77 case VK_RWIN:\r
78 Private->RightLogo = Flag;\r
79 return TRUE;\r
80\r
81 case VK_APPS:\r
82 Private->Menu = Flag;\r
83 return TRUE;\r
84 //\r
85 // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message,\r
86 // so SySReq shift state is not supported here.\r
87 //\r
88 case VK_PRINT:\r
89 Private->SysReq = Flag;\r
90 return TRUE;\r
91 //\r
92 // For Alt Keystroke.\r
93 //\r
94 case VK_MENU:\r
95 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {\r
7a465451
RN
96 Private->RightAlt = Flag;\r
97 } else {\r
98 Private->LeftAlt = Flag;\r
99 }\r
7a465451 100\r
a550d468
MK
101 return TRUE;\r
102\r
103 default:\r
104 return FALSE;\r
7a465451
RN
105 }\r
106}\r
107\r
108BOOLEAN\r
109WinNtGopConvertParamToEfiKey (\r
110 IN GRAPHICS_PRIVATE_DATA *Private,\r
111 IN WPARAM *wParam,\r
112 IN LPARAM *lParam,\r
113 IN EFI_INPUT_KEY *Key\r
114 )\r
115{\r
a550d468
MK
116 BOOLEAN Flag;\r
117\r
7a465451
RN
118 Flag = FALSE;\r
119 switch (*wParam) {\r
a550d468
MK
120 case VK_HOME: Key->ScanCode = SCAN_HOME;\r
121 Flag = TRUE;\r
122 break;\r
123 case VK_END: Key->ScanCode = SCAN_END;\r
124 Flag = TRUE;\r
125 break;\r
126 case VK_LEFT: Key->ScanCode = SCAN_LEFT;\r
127 Flag = TRUE;\r
128 break;\r
129 case VK_RIGHT: Key->ScanCode = SCAN_RIGHT;\r
130 Flag = TRUE;\r
131 break;\r
132 case VK_UP: Key->ScanCode = SCAN_UP;\r
133 Flag = TRUE;\r
134 break;\r
135 case VK_DOWN: Key->ScanCode = SCAN_DOWN;\r
136 Flag = TRUE;\r
137 break;\r
138 case VK_DELETE: Key->ScanCode = SCAN_DELETE;\r
139 Flag = TRUE;\r
140 break;\r
141 case VK_INSERT: Key->ScanCode = SCAN_INSERT;\r
142 Flag = TRUE;\r
143 break;\r
144 case VK_PRIOR: Key->ScanCode = SCAN_PAGE_UP;\r
145 Flag = TRUE;\r
146 break;\r
147 case VK_NEXT: Key->ScanCode = SCAN_PAGE_DOWN;\r
148 Flag = TRUE;\r
149 break;\r
150 case VK_ESCAPE: Key->ScanCode = SCAN_ESC;\r
151 Flag = TRUE;\r
152 break;\r
153\r
154 case VK_F1: Key->ScanCode = SCAN_F1;\r
155 Flag = TRUE;\r
156 break;\r
157 case VK_F2: Key->ScanCode = SCAN_F2;\r
158 Flag = TRUE;\r
159 break;\r
160 case VK_F3: Key->ScanCode = SCAN_F3;\r
161 Flag = TRUE;\r
162 break;\r
163 case VK_F4: Key->ScanCode = SCAN_F4;\r
164 Flag = TRUE;\r
165 break;\r
166 case VK_F5: Key->ScanCode = SCAN_F5;\r
167 Flag = TRUE;\r
168 break;\r
169 case VK_F6: Key->ScanCode = SCAN_F6;\r
170 Flag = TRUE;\r
171 break;\r
172 case VK_F7: Key->ScanCode = SCAN_F7;\r
173 Flag = TRUE;\r
174 break;\r
175 case VK_F8: Key->ScanCode = SCAN_F8;\r
176 Flag = TRUE;\r
177 break;\r
178 case VK_F9: Key->ScanCode = SCAN_F9;\r
179 Flag = TRUE;\r
180 break;\r
181 case VK_F11: Key->ScanCode = SCAN_F11;\r
182 Flag = TRUE;\r
183 break;\r
184 case VK_F12: Key->ScanCode = SCAN_F12;\r
185 Flag = TRUE;\r
186 break;\r
187\r
188 case VK_F13: Key->ScanCode = SCAN_F13;\r
189 Flag = TRUE;\r
190 break;\r
191 case VK_F14: Key->ScanCode = SCAN_F14;\r
192 Flag = TRUE;\r
193 break;\r
194 case VK_F15: Key->ScanCode = SCAN_F15;\r
195 Flag = TRUE;\r
196 break;\r
197 case VK_F16: Key->ScanCode = SCAN_F16;\r
198 Flag = TRUE;\r
199 break;\r
200 case VK_F17: Key->ScanCode = SCAN_F17;\r
201 Flag = TRUE;\r
202 break;\r
203 case VK_F18: Key->ScanCode = SCAN_F18;\r
204 Flag = TRUE;\r
205 break;\r
206 case VK_F19: Key->ScanCode = SCAN_F19;\r
207 Flag = TRUE;\r
208 break;\r
209 case VK_F20: Key->ScanCode = SCAN_F20;\r
210 Flag = TRUE;\r
211 break;\r
212 case VK_F21: Key->ScanCode = SCAN_F21;\r
213 Flag = TRUE;\r
214 break;\r
215 case VK_F22: Key->ScanCode = SCAN_F22;\r
216 Flag = TRUE;\r
217 break;\r
218 case VK_F23: Key->ScanCode = SCAN_F23;\r
219 Flag = TRUE;\r
220 break;\r
221 case VK_F24: Key->ScanCode = SCAN_F24;\r
222 Flag = TRUE;\r
223 break;\r
224 case VK_PAUSE: Key->ScanCode = SCAN_PAUSE;\r
225 Flag = TRUE;\r
226 break;\r
227\r
228 //\r
229 // Set toggle state\r
230 //\r
231 case VK_NUMLOCK:\r
232 Private->NumLock = (BOOLEAN)(!Private->NumLock);\r
233 Flag = TRUE;\r
234 break;\r
235 case VK_SCROLL:\r
236 Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock);\r
237 Flag = TRUE;\r
238 break;\r
239 case VK_CAPITAL:\r
240 Private->CapsLock = (BOOLEAN)(!Private->CapsLock);\r
241 Flag = TRUE;\r
242 break;\r
7a465451
RN
243 }\r
244\r
245 return (WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, lParam, TRUE)) == TRUE ? TRUE : Flag;\r
246}\r
247\r
7a465451
RN
248//\r
249// GOP Protocol Member Functions\r
250//\r
251\r
252/**\r
253 Change the resolution and resize of the window\r
254**/\r
255EFI_STATUS\r
256EFIAPI\r
257WinNtWndSize (\r
258 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
259 IN UINT32 Width,\r
260 IN UINT32 Height\r
a550d468 261 )\r
7a465451 262{\r
a550d468
MK
263 RETURN_STATUS RStatus;\r
264 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION Info;\r
265 GRAPHICS_PRIVATE_DATA *Private;\r
266 RECT Rect;\r
267 BITMAPV4HEADER *VirtualScreenInfo;\r
268 FRAME_BUFFER_CONFIGURE *FrameBufferConfigure;\r
269 UINTN FrameBufferConfigureSize;\r
7a465451
RN
270\r
271 Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
7a465451
RN
272\r
273 //\r
274 // Allocate DIB frame buffer directly from NT for performance enhancement\r
d773459e 275 // This buffer is the virtual screen/frame buffer.\r
7a465451 276 //\r
d773459e 277 VirtualScreenInfo = HeapAlloc (\r
a550d468
MK
278 GetProcessHeap (),\r
279 HEAP_ZERO_MEMORY,\r
280 Width * Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER)\r
281 );\r
d773459e
RN
282 if (VirtualScreenInfo == NULL) {\r
283 return EFI_OUT_OF_RESOURCES;\r
284 }\r
7a465451
RN
285\r
286 //\r
287 // Update the virtual screen info data structure\r
d773459e 288 // Use negative Height to make sure screen/buffer are using the same coordinate.\r
7a465451 289 //\r
a550d468
MK
290 VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);\r
291 VirtualScreenInfo->bV4Width = Width;\r
292 VirtualScreenInfo->bV4Height = -(LONG)Height;\r
293 VirtualScreenInfo->bV4Planes = 1;\r
d773459e 294 VirtualScreenInfo->bV4BitCount = 32;\r
7a465451
RN
295 //\r
296 // uncompressed\r
297 //\r
d773459e
RN
298 VirtualScreenInfo->bV4V4Compression = BI_RGB;\r
299\r
300 Info.HorizontalResolution = Width;\r
301 Info.VerticalResolution = Height;\r
302 Info.PixelFormat = PixelBlueGreenRedReserved8BitPerColor;\r
303 Info.PixelsPerScanLine = Width;\r
304 FrameBufferConfigureSize = 0;\r
a550d468 305 RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, NULL, &FrameBufferConfigureSize);\r
d773459e
RN
306 ASSERT (RStatus == EFI_BUFFER_TOO_SMALL);\r
307 FrameBufferConfigure = AllocatePool (FrameBufferConfigureSize);\r
308 if (FrameBufferConfigure == NULL) {\r
309 HeapFree (GetProcessHeap (), 0, VirtualScreenInfo);\r
310 return EFI_OUT_OF_RESOURCES;\r
311 }\r
a550d468 312\r
d773459e
RN
313 RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, FrameBufferConfigure, &FrameBufferConfigureSize);\r
314 ASSERT_RETURN_ERROR (RStatus);\r
315\r
d773459e
RN
316 if (Private->FrameBufferConfigure != NULL) {\r
317 FreePool (Private->FrameBufferConfigure);\r
318 }\r
a550d468 319\r
d773459e 320 Private->FrameBufferConfigure = FrameBufferConfigure;\r
7a465451
RN
321\r
322 //\r
d773459e
RN
323 // Free the old buffer. We do not save the content of the old buffer since the\r
324 // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.\r
325 // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()\r
7a465451 326 //\r
d773459e
RN
327 if (Private->VirtualScreenInfo != NULL) {\r
328 HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);\r
329 }\r
a550d468 330\r
d773459e
RN
331 Private->VirtualScreenInfo = VirtualScreenInfo;\r
332\r
333 Private->Width = Width;\r
334 Private->Height = Height;\r
7a465451
RN
335\r
336 //\r
337 // Use the AdjuctWindowRect fuction to calculate the real width and height\r
338 // of the new window including the border and caption\r
339 //\r
d773459e
RN
340 Rect.left = 0;\r
341 Rect.top = 0;\r
342 Rect.right = Width;\r
343 Rect.bottom = Height;\r
7a465451
RN
344\r
345 AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);\r
346\r
347 Width = Rect.right - Rect.left;\r
348 Height = Rect.bottom - Rect.top;\r
349\r
350 //\r
351 // Retrieve the original window position information\r
352 //\r
353 GetWindowRect (Private->WindowHandle, &Rect);\r
354\r
355 //\r
356 // Adjust the window size\r
357 //\r
358 MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE);\r
359\r
7a465451
RN
360 return EFI_SUCCESS;\r
361}\r
362\r
363/**\r
364 Blt pixels from the rectangle (Width X Height) formed by the BltBuffer\r
365 onto the graphics screen starting a location (X, Y). (0, 0) is defined as\r
366 the upper left hand side of the screen. (X, Y) can be outside of the\r
367 current screen geometry and the BltBuffer will be cliped when it is\r
368 displayed. X and Y can be negative or positive. If Width or Height is\r
369 bigger than the current video screen the image will be clipped.\r
370\r
371 @param This Protocol instance pointer.\r
372 @param X X location on graphics screen.\r
373 @param Y Y location on the graphics screen.\r
374 @param Width Width of BltBuffer.\r
3d6b7fd3 375 @param Height Height of BltBuffer\r
7a465451
RN
376 @param BltOperation Operation to perform on BltBuffer and video memory\r
377 @param BltBuffer Buffer containing data to blt into video buffer.\r
378 This buffer has a size of\r
379 Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
380 @param SourceX If the BltOperation is a EfiCopyBlt this is the\r
381 source of the copy. For other BLT operations this\r
382 argument is not used.\r
383 @param SourceX If the BltOperation is a EfiCopyBlt this is the\r
384 source of the copy. For other BLT operations this\r
385 argument is not used.\r
386\r
387 @retval EFI_SUCCESS The palette is updated with PaletteArray.\r
388 @retval EFI_INVALID_PARAMETER BltOperation is not valid.\r
3d6b7fd3 389 @retval EFI_DEVICE_ERROR A hardware error occurred writing to the video\r
7a465451
RN
390 buffer.\r
391\r
392**/\r
393// TODO: SourceY - add argument and description to function comment\r
394// TODO: DestinationX - add argument and description to function comment\r
395// TODO: DestinationY - add argument and description to function comment\r
396// TODO: Delta - add argument and description to function comment\r
397EFI_STATUS\r
398WinNtWndBlt (\r
a550d468
MK
399 IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,\r
400 IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,\r
401 IN EFI_UGA_BLT_OPERATION BltOperation,\r
402 IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args\r
403 )\r
7a465451 404{\r
a550d468
MK
405 RETURN_STATUS RStatus;\r
406 GRAPHICS_PRIVATE_DATA *Private;\r
407 RECT Rect;\r
7a465451
RN
408\r
409 Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);\r
d773459e
RN
410 RStatus = FrameBufferBlt (\r
411 Private->FrameBufferConfigure,\r
412 BltBuffer,\r
413 BltOperation,\r
a550d468
MK
414 Args->SourceX,\r
415 Args->SourceY,\r
416 Args->DestinationX,\r
417 Args->DestinationY,\r
418 Args->Width,\r
419 Args->Height,\r
d773459e
RN
420 Args->Delta\r
421 );\r
422 if (RETURN_ERROR (RStatus)) {\r
423 return (EFI_STATUS)RStatus;\r
7a465451
RN
424 }\r
425\r
426 if (BltOperation != EfiBltVideoToBltBuffer) {\r
427 //\r
428 // Mark the area we just blted as Invalid so WM_PAINT will update.\r
429 //\r
430 Rect.left = (LONG)Args->DestinationX;\r
431 Rect.top = (LONG)Args->DestinationY;\r
432 Rect.right = (LONG)(Args->DestinationX + Args->Width);\r
433 Rect.bottom = (LONG)(Args->DestinationY + Args->Height);\r
434 InvalidateRect (Private->WindowHandle, &Rect, FALSE);\r
435\r
436 //\r
437 // Send the WM_PAINT message to the thread that is drawing the window. We\r
438 // are in the main thread and the window drawing is in a child thread.\r
439 // There is a child thread per window. We have no CriticalSection or Mutex\r
440 // since we write the data and the other thread displays the data. While\r
441 // we may miss some data for a short period of time this is no different than\r
442 // a write combining on writes to a frame buffer.\r
443 //\r
444\r
445 UpdateWindow (Private->WindowHandle);\r
446 }\r
447\r
448 return EFI_SUCCESS;\r
449}\r
450\r
7a465451
RN
451/**\r
452 Win32 Windows event handler.\r
453\r
454 See Win32 Book\r
455\r
456 @return See Win32 Book\r
457\r
458**/\r
459// TODO: hwnd - add argument and description to function comment\r
460// TODO: iMsg - add argument and description to function comment\r
461// TODO: wParam - add argument and description to function comment\r
462// TODO: lParam - add argument and description to function comment\r
463LRESULT\r
464CALLBACK\r
465WinNtGopThreadWindowProc (\r
466 IN HWND hwnd,\r
467 IN UINT iMsg,\r
468 IN WPARAM wParam,\r
469 IN LPARAM lParam\r
470 )\r
471{\r
a550d468
MK
472 GRAPHICS_PRIVATE_DATA *Private;\r
473 HDC Handle;\r
474 PAINTSTRUCT PaintStruct;\r
475 LPARAM Index;\r
476 EFI_INPUT_KEY Key;\r
477 BOOLEAN AltIsPress;\r
478 INT32 PosX;\r
479 INT32 PosY;\r
7a465451 480\r
7a465451
RN
481 //\r
482 // Use mTlsIndex global to get a Thread Local Storage version of Private.\r
483 // This works since each Gop protocol has a unique Private data instance and\r
484 // a unique thread.\r
485 //\r
486 AltIsPress = FALSE;\r
a550d468 487 Private = TlsGetValue (mTlsIndex);\r
7a465451
RN
488 ASSERT (NULL != Private);\r
489\r
490 switch (iMsg) {\r
a550d468
MK
491 case WM_PAINT:\r
492 Handle = BeginPaint (hwnd, &PaintStruct);\r
493\r
494 SetDIBitsToDevice (\r
495 Handle, // Destination Device Context\r
496 0, // Destination X - 0\r
497 0, // Destination Y - 0\r
498 Private->Width, // Width\r
499 Private->Height, // Height\r
500 0, // Source X\r
501 0, // Source Y\r
502 0, // DIB Start Scan Line\r
503 Private->Height, // Number of scan lines\r
504 Private->VirtualScreenInfo + 1, // Address of array of DIB bits\r
505 (BITMAPINFO *)Private->VirtualScreenInfo, // Address of structure with bitmap info\r
506 DIB_RGB_COLORS // RGB or palette indexes\r
507 );\r
508\r
509 EndPaint (hwnd, &PaintStruct);\r
7a465451 510 return 0;\r
7a465451
RN
511\r
512 //\r
a550d468
MK
513 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case\r
514 // WM_SYSKEYDOWN is posted when F10 is pressed or\r
515 // holds down ALT key and then presses another key.\r
7a465451 516 //\r
a550d468
MK
517 case WM_SYSKEYDOWN:\r
518\r
519 Key.ScanCode = 0;\r
520 Key.UnicodeChar = CHAR_NULL;\r
521 switch (wParam) {\r
522 case VK_F10:\r
523 Key.ScanCode = SCAN_F10;\r
524 Key.UnicodeChar = CHAR_NULL;\r
525 GopPrivateAddKey (Private, Key);\r
526 return 0;\r
527 }\r
528\r
529 //\r
530 // If ALT or ALT + modifier key is pressed.\r
531 //\r
532 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {\r
533 if (Key.ScanCode != 0) {\r
534 //\r
535 // If ALT is pressed with other ScanCode.\r
536 // Always revers the left Alt for simple.\r
537 //\r
538 Private->LeftAlt = TRUE;\r
539 }\r
540\r
541 GopPrivateAddKey (Private, Key);\r
7a465451 542 //\r
a550d468
MK
543 // When Alt is released there is no windoes message, so\r
544 // clean it after using it.\r
7a465451 545 //\r
a550d468
MK
546 Private->RightAlt = FALSE;\r
547 Private->LeftAlt = FALSE;\r
548 return 0;\r
7a465451 549 }\r
a550d468
MK
550\r
551 AltIsPress = TRUE;\r
552\r
553 case WM_CHAR:\r
7a465451 554 //\r
a550d468 555 // The ESC key also generate WM_CHAR.\r
7a465451 556 //\r
a550d468
MK
557 if (wParam == 0x1B) {\r
558 return 0;\r
559 }\r
560\r
561 if (AltIsPress == TRUE) {\r
562 //\r
563 // If AltIsPress is true that means the Alt key is pressed.\r
564 //\r
565 Private->LeftAlt = TRUE;\r
566 }\r
567\r
568 for (Index = 0; Index < (lParam & 0xffff); Index++) {\r
569 if (wParam != 0) {\r
570 Key.UnicodeChar = (CHAR16)wParam;\r
571 Key.ScanCode = SCAN_NULL;\r
572 GopPrivateAddKey (Private, Key);\r
573 }\r
574 }\r
575\r
576 if (AltIsPress == TRUE) {\r
577 //\r
578 // When Alt is released there is no windoes message, so\r
579 // clean it after using it.\r
580 //\r
581 Private->LeftAlt = FALSE;\r
582 Private->RightAlt = FALSE;\r
583 }\r
584\r
7a465451 585 return 0;\r
7a465451 586\r
a550d468
MK
587 case WM_SYSKEYUP:\r
588 //\r
589 // ALT is pressed with another key released\r
590 //\r
591 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);\r
7a465451 592 return 0;\r
7a465451 593\r
a550d468
MK
594 case WM_KEYDOWN:\r
595 Key.ScanCode = SCAN_NULL;\r
596 Key.UnicodeChar = CHAR_NULL;\r
7a465451 597 //\r
a550d468
MK
598 // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR\r
599 // So if there is no modifier key updated, skip the WM_KEYDOWN even.\r
7a465451 600 //\r
a550d468
MK
601 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {\r
602 //\r
603 // Support the partial keystroke, add all keydown event into the queue.\r
604 //\r
7a465451
RN
605 GopPrivateAddKey (Private, Key);\r
606 }\r
7a465451 607\r
a550d468 608 return 0;\r
7a465451 609\r
a550d468
MK
610 case WM_KEYUP:\r
611 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);\r
612 return 0;\r
613\r
614 case WM_MOUSEMOVE:\r
615 PosX = GET_X_LPARAM (lParam);\r
616 PosY = GET_Y_LPARAM (lParam);\r
617\r
618 if (Private->PointerPreviousX != PosX) {\r
619 Private->PointerState.RelativeMovementX += (PosX - Private->PointerPreviousX);\r
620 Private->PointerPreviousX = PosX;\r
621 Private->PointerStateChanged = TRUE;\r
622 }\r
623\r
624 if (Private->PointerPreviousY != PosY) {\r
625 Private->PointerState.RelativeMovementY += (PosY - Private->PointerPreviousY);\r
626 Private->PointerPreviousY = PosY;\r
627 Private->PointerStateChanged = TRUE;\r
628 }\r
629\r
630 Private->PointerState.RelativeMovementZ = 0;\r
631 return 0;\r
632\r
633 case WM_LBUTTONDOWN:\r
634 Private->PointerState.LeftButton = TRUE;\r
635 Private->PointerStateChanged = TRUE;\r
636 return 0;\r
637\r
638 case WM_LBUTTONUP:\r
639 Private->PointerState.LeftButton = FALSE;\r
640 Private->PointerStateChanged = TRUE;\r
641 return 0;\r
642\r
643 case WM_RBUTTONDOWN:\r
644 Private->PointerState.RightButton = TRUE;\r
645 Private->PointerStateChanged = TRUE;\r
646 return 0;\r
647\r
648 case WM_RBUTTONUP:\r
649 Private->PointerState.RightButton = FALSE;\r
650 Private->PointerStateChanged = TRUE;\r
651 return 0;\r
652\r
653 case WM_CLOSE:\r
7a465451 654 //\r
a550d468
MK
655 // This close message is issued by user, core is not aware of this,\r
656 // so don't release the window display resource, just hide the window.\r
7a465451 657 //\r
a550d468
MK
658 ShowWindow (Private->WindowHandle, SW_HIDE);\r
659 return 0;\r
7a465451 660\r
a550d468
MK
661 case WM_DESTROY:\r
662 DestroyWindow (hwnd);\r
663 PostQuitMessage (0);\r
7a465451 664\r
a550d468 665 HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);\r
7a465451 666\r
a550d468 667 ExitThread (0);\r
7a465451 668\r
a550d468
MK
669 default:\r
670 break;\r
671 }\r
7a465451
RN
672\r
673 return DefWindowProc (hwnd, iMsg, wParam, lParam);\r
674}\r
675\r
7a465451 676/**\r
3d6b7fd3
AC
677 This thread simulates the end of WinMain () application. Each Window needs\r
678 to process its events. The messages are dispatched to\r
7a465451 679 WinNtGopThreadWindowProc ().\r
3d6b7fd3
AC
680 Be very careful since WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()\r
681 are running in a separate thread. We have to do this to process the events.\r
7a465451
RN
682\r
683 @param lpParameter Handle of window to manage.\r
684\r
685 @return if a WM_QUIT message is returned exit.\r
686\r
687**/\r
688DWORD\r
689WINAPI\r
690WinNtGopThreadWinMain (\r
a550d468 691 LPVOID lpParameter\r
7a465451
RN
692 )\r
693{\r
694 MSG Message;\r
695 GRAPHICS_PRIVATE_DATA *Private;\r
696 RECT Rect;\r
697\r
a550d468 698 Private = (GRAPHICS_PRIVATE_DATA *)lpParameter;\r
7a465451
RN
699 ASSERT (NULL != Private);\r
700\r
701 //\r
702 // Since each thread has unique private data, save the private data in Thread\r
703 // Local Storage slot. Then the shared global mTlsIndex can be used to get\r
704 // thread specific context.\r
705 //\r
706 TlsSetValue (mTlsIndex, Private);\r
707\r
a550d468 708 Private->ThreadId = GetCurrentThreadId ();\r
7a465451
RN
709\r
710 Private->WindowsClass.cbSize = sizeof (WNDCLASSEX);\r
711 Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;\r
712 Private->WindowsClass.lpfnWndProc = WinNtGopThreadWindowProc;\r
713 Private->WindowsClass.cbClsExtra = 0;\r
714 Private->WindowsClass.cbWndExtra = 0;\r
715 Private->WindowsClass.hInstance = NULL;\r
716 Private->WindowsClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);\r
717 Private->WindowsClass.hCursor = LoadCursor (NULL, IDC_ARROW);\r
718 Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW;\r
719 Private->WindowsClass.lpszMenuName = NULL;\r
720 Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME;\r
721 Private->WindowsClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);\r
722\r
723 //\r
724 // Use 100 x 100 as initial Window size.\r
725 //\r
726 Private->Width = 100;\r
727 Private->Height = 100;\r
728\r
7a465451
RN
729 //\r
730 // This call will fail after the first time, but thats O.K. since we only need\r
731 // WIN_NT_GOP_CLASS_NAME to exist to create the window.\r
732 //\r
7a465451
RN
733 RegisterClassEx (&Private->WindowsClass);\r
734\r
735 //\r
736 // Setting Rect values to allow for the AdjustWindowRect to provide\r
737 // us the correct sizes for the client area when doing the CreateWindowEx\r
738 //\r
739 Rect.top = 0;\r
740 Rect.bottom = Private->Height;\r
741 Rect.left = 0;\r
742 Rect.right = Private->Width;\r
743\r
744 AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);\r
745\r
746 Private->WindowHandle = CreateWindowEx (\r
747 0,\r
748 WIN_NT_GOP_CLASS_NAME,\r
749 Private->WindowName,\r
750 WS_OVERLAPPEDWINDOW,\r
751 CW_USEDEFAULT,\r
752 CW_USEDEFAULT,\r
753 Rect.right - Rect.left,\r
754 Rect.bottom - Rect.top,\r
755 NULL,\r
756 NULL,\r
757 NULL,\r
758 (VOID **)&Private\r
759 );\r
760\r
761 //\r
3d6b7fd3 762 // The reset of this thread is the standard windows program. We need a separate\r
7a465451
RN
763 // thread since we must process the message loop to make windows act like\r
764 // windows.\r
765 //\r
766\r
767 ShowWindow (Private->WindowHandle, SW_SHOW);\r
768 UpdateWindow (Private->WindowHandle);\r
769\r
770 //\r
771 // Let the main thread get some work done\r
772 //\r
773 ReleaseSemaphore (Private->ThreadInited, 1, NULL);\r
774\r
775 //\r
776 // This is the message loop that all Windows programs need.\r
777 //\r
778 while (GetMessage (&Message, Private->WindowHandle, 0, 0)) {\r
779 TranslateMessage (&Message);\r
780 DispatchMessage (&Message);\r
781 }\r
782\r
783 return (DWORD)Message.wParam;\r
784}\r
785\r
7a465451
RN
786/**\r
787 TODO: Add function description\r
788\r
789 @param Private TODO: add argument description\r
790 @param HorizontalResolution TODO: add argument description\r
791 @param VerticalResolution TODO: add argument description\r
792 @param ColorDepth TODO: add argument description\r
793 @param RefreshRate TODO: add argument description\r
794\r
795 @return TODO: add return values\r
796\r
797**/\r
798EFI_STATUS\r
799EFIAPI\r
800WinNtGraphicsWindowOpen (\r
a550d468 801 IN EMU_IO_THUNK_PROTOCOL *This\r
7a465451
RN
802 )\r
803{\r
a550d468
MK
804 DWORD NewThreadId;\r
805 GRAPHICS_PRIVATE_DATA *Private;\r
7a465451
RN
806\r
807 Private = AllocateZeroPool (sizeof (*Private));\r
808\r
809 GopPrivateCreateQ (Private, &Private->QueueForRead);\r
810\r
811 Private->GraphicsWindowIo.Size = WinNtWndSize;\r
812 Private->GraphicsWindowIo.CheckKey = WinNtWndCheckKey;\r
813 Private->GraphicsWindowIo.GetKey = WinNtWndGetKey;\r
814 Private->GraphicsWindowIo.KeySetState = WinNtWndKeySetState;\r
815 Private->GraphicsWindowIo.RegisterKeyNotify = WinNtWndRegisterKeyNotify;\r
816 Private->GraphicsWindowIo.Blt = WinNtWndBlt;\r
817 Private->GraphicsWindowIo.CheckPointer = WinNtWndCheckPointer;\r
818 Private->GraphicsWindowIo.GetPointerState = WinNtWndGetPointerState;\r
819\r
820 Private->WindowName = This->ConfigString;\r
821 //\r
822 // Initialize a Thread Local Storge variable slot. We use TLS to get the\r
823 // correct Private data instance into the windows thread.\r
824 //\r
825 if (mTlsIndex == TLS_OUT_OF_INDEXES) {\r
826 ASSERT (0 == mTlsIndexUseCount);\r
827 mTlsIndex = TlsAlloc ();\r
828 }\r
829\r
830 //\r
831 // always increase the use count!\r
832 //\r
833 mTlsIndexUseCount++;\r
834\r
835 Private->ThreadInited = CreateSemaphore (NULL, 0, 1, NULL);\r
836 Private->ThreadHandle = CreateThread (\r
837 NULL,\r
838 0,\r
839 WinNtGopThreadWinMain,\r
a550d468 840 (VOID *)Private,\r
7a465451
RN
841 0,\r
842 &NewThreadId\r
843 );\r
844\r
845 //\r
846 // The other thread has entered the windows message loop so we can\r
847 // continue our initialization.\r
848 //\r
849 WaitForSingleObject (Private->ThreadInited, INFINITE);\r
850 CloseHandle (Private->ThreadInited);\r
851\r
a550d468 852 This->Private = Private;\r
7a465451
RN
853 This->Interface = &Private->GraphicsWindowIo;\r
854\r
855 return EFI_SUCCESS;\r
856}\r
857\r
858EFI_STATUS\r
859EFIAPI\r
860WinNtGraphicsWindowClose (\r
a550d468
MK
861 IN EMU_IO_THUNK_PROTOCOL *This\r
862 )\r
7a465451 863{\r
a550d468 864 GRAPHICS_PRIVATE_DATA *Private;\r
7a465451
RN
865\r
866 Private = (GRAPHICS_PRIVATE_DATA *)This->Private;\r
867\r
868 //\r
869 // BugBug: Shutdown GOP Hardware and any child devices.\r
870 //\r
871 SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);\r
872 CloseHandle (Private->ThreadHandle);\r
873\r
874 mTlsIndexUseCount--;\r
875\r
876 //\r
877 // The callback function for another window could still be called,\r
878 // so we need to make sure there are no more users of mTlsIndex.\r
879 //\r
880 if (0 == mTlsIndexUseCount) {\r
881 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);\r
882\r
883 TlsFree (mTlsIndex);\r
884 mTlsIndex = TLS_OUT_OF_INDEXES;\r
885\r
886 UnregisterClass (\r
887 Private->WindowsClass.lpszClassName,\r
888 Private->WindowsClass.hInstance\r
a550d468 889 );\r
7a465451
RN
890 }\r
891\r
7a465451
RN
892 GopPrivateDestroyQ (Private, &Private->QueueForRead);\r
893 return EFI_SUCCESS;\r
894}\r
895\r
a550d468 896EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo = {\r
7a465451
RN
897 &gEmuGraphicsWindowProtocolGuid,\r
898 NULL,\r
899 NULL,\r
900 0,\r
901 WinNtGraphicsWindowOpen,\r
902 WinNtGraphicsWindowClose,\r
903 NULL\r
904};\r