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