2 /* INCLUDES *******************************************************************/
9 // #include "emulator.h"
12 /* VARIABLES ******************************************************************/
14 static HANDLE CurrentConsoleOutput
= INVALID_HANDLE_VALUE
;
16 static HANDLE ConsoleInput
= INVALID_HANDLE_VALUE
;
17 static HANDLE ConsoleOutput
= INVALID_HANDLE_VALUE
;
18 static DWORD OrgConsoleInputMode
, OrgConsoleOutputMode
;
20 HWND hConsoleWnd
= NULL
;
21 static HMENU hConsoleMenu
= NULL
;
22 static INT VdmMenuPos
= -1;
23 static BOOL CaptureMouse
= FALSE
;
26 * Those menu helpers were taken from the GUI frontend in winsrv.dll
28 typedef struct _VDM_MENUITEM
31 const struct _VDM_MENUITEM
*SubMenu
;
33 } VDM_MENUITEM
, *PVDM_MENUITEM
;
35 static const VDM_MENUITEM VdmMenuItems
[] =
37 { IDS_VDM_DUMPMEM_TXT
, NULL
, ID_VDM_DUMPMEM_TXT
},
38 { IDS_VDM_DUMPMEM_BIN
, NULL
, ID_VDM_DUMPMEM_BIN
},
39 { -1, NULL
, 0 }, /* Separator */
40 // { IDS_VDM_MOUNT_FLOPPY, NULL, ID_VDM_DRIVES },
41 // { IDS_VDM_EJECT_FLOPPY, NULL, ID_VDM_DRIVES },
42 { -1, NULL
, 0 }, /* Separator */
43 { IDS_VDM_QUIT
, NULL
, ID_VDM_QUIT
},
45 { 0, NULL
, 0 } /* End of list */
48 static const VDM_MENUITEM VdmMainMenuItems
[] =
50 { -1, NULL
, 0 }, /* Separator */
51 { IDS_CAPTURE_MOUSE
, NULL
, ID_CAPTURE_MOUSE
}, /* "Capture mouse"; can be renamed to "Release mouse" */
52 { IDS_VDM_MENU
, VdmMenuItems
, 0 }, /* ReactOS VDM Menu */
54 { 0, NULL
, 0 } /* End of list */
58 AppendMenuItems(HMENU hMenu
,
59 const VDM_MENUITEM
*Items
)
62 WCHAR szMenuString
[256];
67 if (Items
[i
].uID
!= (UINT
)-1)
69 if (LoadStringW(GetModuleHandle(NULL
),
72 ARRAYSIZE(szMenuString
)) > 0)
74 if (Items
[i
].SubMenu
!= NULL
)
76 hSubMenu
= CreatePopupMenu();
79 AppendMenuItems(hSubMenu
, Items
[i
].SubMenu
);
81 if (!AppendMenuW(hMenu
,
86 DestroyMenu(hSubMenu
);
107 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].uCmdID
== 0));
111 VdmMenuExists(HMENU hConsoleMenu
)
114 MenuPos
= GetMenuItemCount(hConsoleMenu
);
116 /* Check for the presence of one of the VDM menu items */
117 for (i
= 0; i
<= MenuPos
; i
++)
119 if (GetMenuItemID(hConsoleMenu
, i
) == ID_CAPTURE_MOUSE
)
121 /* Set VdmMenuPos to the position of the existing menu */
130 UpdateVdmMenuMouse(VOID
)
132 WCHAR szMenuString
[256];
134 /* Update "Capture/Release mouse" menu item */
135 if (LoadStringW(GetModuleHandle(NULL
),
136 (CaptureMouse
? IDS_RELEASE_MOUSE
: IDS_CAPTURE_MOUSE
),
138 ARRAYSIZE(szMenuString
)) > 0)
140 ModifyMenuW(hConsoleMenu
, ID_CAPTURE_MOUSE
,
141 MF_BYCOMMAND
, ID_CAPTURE_MOUSE
, szMenuString
);
146 UpdateVdmMenuDisks(VOID
)
151 WCHAR szNoMedia
[100];
152 WCHAR szMenuString1
[256], szMenuString2
[256];
154 /* Update the disks menu items */
156 LoadStringW(GetModuleHandle(NULL
),
159 ARRAYSIZE(szNoMedia
));
161 LoadStringW(GetModuleHandle(NULL
),
162 IDS_VDM_MOUNT_FLOPPY
,
164 ARRAYSIZE(szMenuString1
));
166 for (i
= 0; i
< ARRAYSIZE(GlobalSettings
.FloppyDisks
); ++i
)
168 ItemID
= ID_VDM_DRIVES
+ (2 * i
);
170 if (GlobalSettings
.FloppyDisks
[i
].Length
!= 0 &&
171 GlobalSettings
.FloppyDisks
[i
].Buffer
&&
172 GlobalSettings
.FloppyDisks
[i
].Buffer
!= L
'\0')
174 /* Update item text */
175 _snwprintf(szMenuString2
, ARRAYSIZE(szMenuString2
), szMenuString1
, i
, GlobalSettings
.FloppyDisks
[i
].Buffer
);
176 szMenuString2
[ARRAYSIZE(szMenuString2
) - 1] = UNICODE_NULL
;
177 ModifyMenuW(hConsoleMenu
, ItemID
, MF_BYCOMMAND
| MF_STRING
, ItemID
, szMenuString2
);
179 /* Enable the eject item */
180 EnableMenuItem(hConsoleMenu
, ItemID
+ 1, MF_BYCOMMAND
| MF_ENABLED
);
184 /* Update item text */
185 _snwprintf(szMenuString2
, ARRAYSIZE(szMenuString2
), szMenuString1
, i
, szNoMedia
);
186 szMenuString2
[ARRAYSIZE(szMenuString2
) - 1] = UNICODE_NULL
;
187 ModifyMenuW(hConsoleMenu
, ItemID
, MF_BYCOMMAND
| MF_STRING
, ItemID
, szMenuString2
);
189 /* Disable the eject item */
190 EnableMenuItem(hConsoleMenu
, ItemID
+ 1, MF_BYCOMMAND
| MF_GRAYED
);
198 UpdateVdmMenuMouse();
199 UpdateVdmMenuDisks();
203 CreateVdmMenu(HANDLE ConOutHandle
)
209 WCHAR szNoMedia
[100];
210 WCHAR szMenuString1
[256], szMenuString2
[256];
212 hConsoleMenu
= ConsoleMenuControl(ConOutHandle
,
214 ID_VDM_DRIVES
+ (2 * ARRAYSIZE(GlobalSettings
.FloppyDisks
)));
215 if (hConsoleMenu
== NULL
) return;
217 /* Get the position where we are going to insert our menu items */
218 VdmMenuPos
= GetMenuItemCount(hConsoleMenu
);
220 /* Really add the menu if it doesn't already exist (in case eg. NTVDM crashed) */
221 if (!VdmMenuExists(hConsoleMenu
))
223 /* Add all the menu entries */
224 AppendMenuItems(hConsoleMenu
, VdmMainMenuItems
);
226 /* Add the removable drives menu entries */
227 hVdmSubMenu
= GetSubMenu(hConsoleMenu
, VdmMenuPos
+ 2); // VdmMenuItems
228 Pos
= 3; // After the 2 items and the separator in VdmMenuItems
230 LoadStringW(GetModuleHandle(NULL
),
233 ARRAYSIZE(szNoMedia
));
235 LoadStringW(GetModuleHandle(NULL
),
236 IDS_VDM_MOUNT_FLOPPY
,
238 ARRAYSIZE(szMenuString1
));
240 /* Drive 'x' -- Mount */
241 for (i
= 0; i
< ARRAYSIZE(GlobalSettings
.FloppyDisks
); ++i
)
243 ItemID
= ID_VDM_DRIVES
+ (2 * i
);
246 _snwprintf(szMenuString2
, ARRAYSIZE(szMenuString2
), szMenuString1
, i
, szNoMedia
);
247 szMenuString2
[ARRAYSIZE(szMenuString2
) - 1] = UNICODE_NULL
;
248 InsertMenuW(hVdmSubMenu
, Pos
++, MF_STRING
| MF_BYPOSITION
, ItemID
, szMenuString2
);
251 LoadStringW(GetModuleHandle(NULL
),
252 IDS_VDM_EJECT_FLOPPY
,
254 ARRAYSIZE(szMenuString1
));
256 /* Drive 'x' -- Eject */
257 for (i
= 0; i
< ARRAYSIZE(GlobalSettings
.FloppyDisks
); ++i
)
259 ItemID
= ID_VDM_DRIVES
+ (2 * i
);
262 _snwprintf(szMenuString2
, ARRAYSIZE(szMenuString2
), szMenuString1
, i
);
263 szMenuString2
[ARRAYSIZE(szMenuString2
) - 1] = UNICODE_NULL
;
264 InsertMenuW(hVdmSubMenu
, Pos
++, MF_STRING
| MF_BYPOSITION
, ItemID
+ 1, szMenuString2
);
267 /* Refresh the menu state */
269 DrawMenuBar(hConsoleWnd
);
277 const VDM_MENUITEM
*Items
= VdmMainMenuItems
;
281 DeleteMenu(hConsoleMenu
, VdmMenuPos
, MF_BYPOSITION
);
283 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].uCmdID
== 0));
285 DrawMenuBar(hConsoleWnd
);
288 static VOID
CaptureMousePointer(HANDLE ConOutHandle
, BOOLEAN Capture
)
290 static BOOL IsClipped
= FALSE
; // For debugging purposes
291 UNREFERENCED_PARAMETER(IsClipped
);
297 // if (IsClipped) return;
299 /* Be sure the cursor will be hidden */
300 while (ShowConsoleCursor(ConOutHandle
, FALSE
) >= 0) ;
302 GetClientRect(hConsoleWnd
, &rcClip
);
303 MapWindowPoints(hConsoleWnd
, HWND_DESKTOP
/*NULL*/, (LPPOINT
)&rcClip
, 2 /* Magic value when the LPPOINT parameter is a RECT */);
304 IsClipped
= ClipCursor(&rcClip
);
308 // if (!IsClipped) return;
313 /* Be sure the cursor will be shown */
314 while (ShowConsoleCursor(ConOutHandle
, TRUE
) < 0) ;
318 static VOID
EnableExtraHardware(HANDLE ConsoleInput
)
322 if (GetConsoleMode(ConsoleInput
, &ConInMode
))
325 // GetNumberOfConsoleMouseButtons();
326 // GetSystemMetrics(SM_CMOUSEBUTTONS);
327 // GetSystemMetrics(SM_MOUSEPRESENT);
331 /* Support mouse input events if there is a mouse on the system */
332 ConInMode
|= ENABLE_MOUSE_INPUT
;
337 /* Do not support mouse input events if there is no mouse on the system */
338 ConInMode
&= ~ENABLE_MOUSE_INPUT
;
342 SetConsoleMode(ConsoleInput
, ConInMode
);
352 /* PUBLIC FUNCTIONS ***********************************************************/
355 VdmShutdown(BOOLEAN Immediate
);
359 ConsoleCtrlHandler(DWORD ControlType
)
363 case CTRL_LAST_CLOSE_EVENT
:
365 /* Delayed shutdown */
366 DPRINT1("NTVDM delayed killing in the CTRL_LAST_CLOSE_EVENT CtrlHandler!\n");
373 /* Stop the VDM if the user logs out or closes the console */
374 DPRINT1("Killing NTVDM in the 'default' CtrlHandler!\n");
384 hConsoleWnd
= GetConsoleWindow();
385 CreateVdmMenu(ConsoleOutput
);
389 ConsoleCleanupUI(VOID
)
391 /* Display again properly the mouse pointer */
392 if (CaptureMouse
) CaptureMousePointer(ConsoleOutput
, !CaptureMouse
);
400 /* Save the original input and output console modes */
401 if (!GetConsoleMode(ConsoleInput
, &OrgConsoleInputMode
) ||
402 !GetConsoleMode(ConsoleOutput
, &OrgConsoleOutputMode
))
404 CloseHandle(ConsoleOutput
);
405 CloseHandle(ConsoleInput
);
406 wprintf(L
"FATAL: Cannot save console in/out modes\n");
410 /* Set the console input mode */
411 SetConsoleMode(ConsoleInput
, ENABLE_WINDOW_INPUT
);
412 EnableExtraHardware(ConsoleInput
);
414 /* Set the console output mode */
415 // SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
417 /* Initialize the UI */
429 /* Restore the original input and output console modes */
430 SetConsoleMode(ConsoleOutput
, OrgConsoleOutputMode
);
431 SetConsoleMode(ConsoleInput
, OrgConsoleInputMode
);
435 ConsoleReattach(HANDLE ConOutHandle
)
438 CurrentConsoleOutput
= ConOutHandle
;
439 CreateVdmMenu(ConOutHandle
);
441 /* Synchronize mouse cursor display with console screenbuffer switches */
442 CaptureMousePointer(CurrentConsoleOutput
, CaptureMouse
);
448 /* Set the handler routine */
449 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
451 /* Enable the CTRL_LAST_CLOSE_EVENT */
452 SetLastConsoleEventActive();
455 * NOTE: The CONIN$ and CONOUT$ "virtual" files
456 * always point to non-redirected console handles.
459 /* Get the input handle to the real console, and check for success */
460 ConsoleInput
= CreateFileW(L
"CONIN$",
461 GENERIC_READ
| GENERIC_WRITE
,
462 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
467 if (ConsoleInput
== INVALID_HANDLE_VALUE
)
469 wprintf(L
"FATAL: Cannot retrieve a handle to the console input\n");
473 /* Get the output handle to the real console, and check for success */
474 ConsoleOutput
= CreateFileW(L
"CONOUT$",
475 GENERIC_READ
| GENERIC_WRITE
,
476 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
481 if (ConsoleOutput
== INVALID_HANDLE_VALUE
)
483 CloseHandle(ConsoleInput
);
484 wprintf(L
"FATAL: Cannot retrieve a handle to the console output\n");
488 /* Effectively attach to the console */
489 return ConsoleAttach();
495 /* Detach from the console */
498 /* Close the console handles */
499 if (ConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleOutput
);
500 if (ConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleInput
);
503 VOID
MenuEventHandler(PMENU_EVENT_RECORD MenuEvent
)
505 switch (MenuEvent
->dwCommandId
)
508 * System-defined menu commands
515 * If the mouse is captured, release it or recapture it
516 * when the menu opens or closes, respectively.
518 if (!CaptureMouse
) break;
519 CaptureMousePointer(CurrentConsoleOutput
, MenuEvent
->dwCommandId
== WM_INITMENU
? FALSE
: TRUE
);
525 * User-defined menu commands
528 case ID_CAPTURE_MOUSE
:
529 CaptureMouse
= !CaptureMouse
;
530 CaptureMousePointer(CurrentConsoleOutput
, CaptureMouse
);
531 UpdateVdmMenuMouse();
534 case ID_VDM_DUMPMEM_TXT
:
538 case ID_VDM_DUMPMEM_BIN
:
542 /* Drive 0 -- Mount */
543 /* Drive 1 -- Mount */
544 case ID_VDM_DRIVES
+ 0:
545 case ID_VDM_DRIVES
+ 2:
547 ULONG DiskNumber
= (MenuEvent
->dwCommandId
- ID_VDM_DRIVES
) / 2;
548 MountFloppy(DiskNumber
);
552 /* Drive 0 -- Eject */
553 /* Drive 1 -- Eject */
554 case ID_VDM_DRIVES
+ 1:
555 case ID_VDM_DRIVES
+ 3:
557 ULONG DiskNumber
= (MenuEvent
->dwCommandId
- ID_VDM_DRIVES
- 1) / 2;
558 EjectFloppy(DiskNumber
);
564 // EmulatorTerminate();
566 /* Nothing runs, so exit immediately */
567 DPRINT1("Killing NTVDM via console menu!\n");
576 VOID
FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent
)
579 * If the mouse is captured, release it or recapture it
580 * when we lose or regain focus, respectively.
582 if (!CaptureMouse
) return;
583 CaptureMousePointer(CurrentConsoleOutput
, FocusEvent
->bSetFocus
);