|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "DebugShowInput.h" |
|
|
|
#include <windows.h> |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
|
|
#include <string> |
|
|
|
#include "../shared/StringBuilder.h" |
|
#include "InputMap.h" |
|
|
|
namespace { |
|
|
|
struct Flag { |
|
DWORD value; |
|
const char *text; |
|
}; |
|
|
|
static const Flag kButtonStates[] = { |
|
{ FROM_LEFT_1ST_BUTTON_PRESSED, "1" }, |
|
{ FROM_LEFT_2ND_BUTTON_PRESSED, "2" }, |
|
{ FROM_LEFT_3RD_BUTTON_PRESSED, "3" }, |
|
{ FROM_LEFT_4TH_BUTTON_PRESSED, "4" }, |
|
{ RIGHTMOST_BUTTON_PRESSED, "R" }, |
|
}; |
|
|
|
static const Flag kControlKeyStates[] = { |
|
{ CAPSLOCK_ON, "CapsLock" }, |
|
{ ENHANCED_KEY, "Enhanced" }, |
|
{ LEFT_ALT_PRESSED, "LAlt" }, |
|
{ LEFT_CTRL_PRESSED, "LCtrl" }, |
|
{ NUMLOCK_ON, "NumLock" }, |
|
{ RIGHT_ALT_PRESSED, "RAlt" }, |
|
{ RIGHT_CTRL_PRESSED, "RCtrl" }, |
|
{ SCROLLLOCK_ON, "ScrollLock" }, |
|
{ SHIFT_PRESSED, "Shift" }, |
|
}; |
|
|
|
static const Flag kMouseEventFlags[] = { |
|
{ DOUBLE_CLICK, "Double" }, |
|
{ 8, "HWheel" }, |
|
{ MOUSE_MOVED, "Move" }, |
|
{ MOUSE_WHEELED, "Wheel" }, |
|
}; |
|
|
|
static void writeFlags(StringBuilder &out, DWORD flags, |
|
const char *remainderName, |
|
const Flag *table, size_t tableSize, |
|
char pre, char sep, char post) { |
|
DWORD remaining = flags; |
|
bool wroteSomething = false; |
|
for (size_t i = 0; i < tableSize; ++i) { |
|
const Flag &f = table[i]; |
|
if ((f.value & flags) == f.value) { |
|
if (!wroteSomething && pre != '\0') { |
|
out << pre; |
|
} else if (wroteSomething && sep != '\0') { |
|
out << sep; |
|
} |
|
out << f.text; |
|
wroteSomething = true; |
|
remaining &= ~f.value; |
|
} |
|
} |
|
if (remaining != 0) { |
|
if (!wroteSomething && pre != '\0') { |
|
out << pre; |
|
} else if (wroteSomething && sep != '\0') { |
|
out << sep; |
|
} |
|
out << remainderName << "(0x" << hexOfInt(remaining) << ')'; |
|
wroteSomething = true; |
|
} |
|
if (wroteSomething && post != '\0') { |
|
out << post; |
|
} |
|
} |
|
|
|
template <size_t n> |
|
static void writeFlags(StringBuilder &out, DWORD flags, |
|
const char *remainderName, |
|
const Flag (&table)[n], |
|
char pre, char sep, char post) { |
|
writeFlags(out, flags, remainderName, table, n, pre, sep, post); |
|
} |
|
|
|
} |
|
|
|
std::string controlKeyStatePrefix(DWORD controlKeyState) { |
|
StringBuilder sb; |
|
writeFlags(sb, controlKeyState, |
|
"keyState", kControlKeyStates, '\0', '-', '-'); |
|
return sb.str_moved(); |
|
} |
|
|
|
std::string mouseEventToString(const MOUSE_EVENT_RECORD &mer) { |
|
const uint16_t buttons = mer.dwButtonState & 0xFFFF; |
|
const int16_t wheel = mer.dwButtonState >> 16; |
|
StringBuilder sb; |
|
sb << "pos=" << mer.dwMousePosition.X << ',' |
|
<< mer.dwMousePosition.Y; |
|
writeFlags(sb, mer.dwControlKeyState, "keyState", kControlKeyStates, ' ', ' ', '\0'); |
|
writeFlags(sb, mer.dwEventFlags, "flags", kMouseEventFlags, ' ', ' ', '\0'); |
|
writeFlags(sb, buttons, "buttons", kButtonStates, ' ', ' ', '\0'); |
|
if (wheel != 0) { |
|
sb << " wheel=" << wheel; |
|
} |
|
return sb.str_moved(); |
|
} |
|
|
|
void debugShowInput(bool enableMouse, bool escapeInput) { |
|
HANDLE conin = GetStdHandle(STD_INPUT_HANDLE); |
|
DWORD origConsoleMode = 0; |
|
if (!GetConsoleMode(conin, &origConsoleMode)) { |
|
fprintf(stderr, "Error: could not read console mode -- " |
|
"is STDIN a console handle?\n"); |
|
exit(1); |
|
} |
|
DWORD restoreConsoleMode = origConsoleMode; |
|
if (enableMouse && !(restoreConsoleMode & ENABLE_EXTENDED_FLAGS)) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
restoreConsoleMode |= ENABLE_EXTENDED_FLAGS; |
|
restoreConsoleMode |= ENABLE_QUICK_EDIT_MODE; |
|
restoreConsoleMode |= ENABLE_INSERT_MODE; |
|
} |
|
DWORD newConsoleMode = restoreConsoleMode; |
|
newConsoleMode &= ~ENABLE_PROCESSED_INPUT; |
|
newConsoleMode &= ~ENABLE_LINE_INPUT; |
|
newConsoleMode &= ~ENABLE_ECHO_INPUT; |
|
newConsoleMode |= ENABLE_WINDOW_INPUT; |
|
if (enableMouse) { |
|
newConsoleMode |= ENABLE_MOUSE_INPUT; |
|
newConsoleMode &= ~ENABLE_QUICK_EDIT_MODE; |
|
} else { |
|
newConsoleMode &= ~ENABLE_MOUSE_INPUT; |
|
} |
|
if (escapeInput) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newConsoleMode |= 0x200; |
|
} |
|
if (!SetConsoleMode(conin, newConsoleMode)) { |
|
fprintf(stderr, "Error: could not set console mode " |
|
"(0x%x -> 0x%x -> 0x%x)\n", |
|
static_cast<unsigned int>(origConsoleMode), |
|
static_cast<unsigned int>(newConsoleMode), |
|
static_cast<unsigned int>(restoreConsoleMode)); |
|
exit(1); |
|
} |
|
printf("\nPress any keys -- Ctrl-D exits\n\n"); |
|
INPUT_RECORD records[32]; |
|
DWORD actual = 0; |
|
bool finished = false; |
|
while (!finished && |
|
ReadConsoleInputW(conin, records, 32, &actual) && actual >= 1) { |
|
StringBuilder sb; |
|
for (DWORD i = 0; i < actual; ++i) { |
|
const INPUT_RECORD &record = records[i]; |
|
if (record.EventType == KEY_EVENT) { |
|
const KEY_EVENT_RECORD &ker = record.Event.KeyEvent; |
|
InputMap::Key key = { |
|
ker.wVirtualKeyCode, |
|
ker.uChar.UnicodeChar, |
|
static_cast<uint16_t>(ker.dwControlKeyState), |
|
}; |
|
sb << "key: " << (ker.bKeyDown ? "dn" : "up") |
|
<< " rpt=" << ker.wRepeatCount |
|
<< " scn=" << (ker.wVirtualScanCode ? "0x" : "") << hexOfInt(ker.wVirtualScanCode) |
|
<< ' ' << key.toString() << '\n'; |
|
if ((ker.dwControlKeyState & |
|
(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) && |
|
ker.wVirtualKeyCode == 'D') { |
|
finished = true; |
|
break; |
|
} else if (ker.wVirtualKeyCode == 0 && |
|
ker.wVirtualScanCode == 0 && |
|
ker.uChar.UnicodeChar == 4) { |
|
|
|
|
|
finished = true; |
|
break; |
|
} |
|
} else if (record.EventType == MOUSE_EVENT) { |
|
const MOUSE_EVENT_RECORD &mer = record.Event.MouseEvent; |
|
sb << "mouse: " << mouseEventToString(mer) << '\n'; |
|
} else if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) { |
|
const WINDOW_BUFFER_SIZE_RECORD &wbsr = |
|
record.Event.WindowBufferSizeEvent; |
|
sb << "buffer-resized: dwSize=(" |
|
<< wbsr.dwSize.X << ',' |
|
<< wbsr.dwSize.Y << ")\n"; |
|
} else if (record.EventType == MENU_EVENT) { |
|
const MENU_EVENT_RECORD &mer = record.Event.MenuEvent; |
|
sb << "menu-event: commandId=0x" |
|
<< hexOfInt(mer.dwCommandId) << '\n'; |
|
} else if (record.EventType == FOCUS_EVENT) { |
|
const FOCUS_EVENT_RECORD &fer = record.Event.FocusEvent; |
|
sb << "focus: " << (fer.bSetFocus ? "gained" : "lost") << '\n'; |
|
} |
|
} |
|
|
|
const auto str = sb.str_moved(); |
|
fwrite(str.data(), 1, str.size(), stdout); |
|
fflush(stdout); |
|
} |
|
SetConsoleMode(conin, restoreConsoleMode); |
|
} |
|
|