diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index b4d6a5a3a25..69e86f143f1 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -25,6 +25,7 @@ #include "libc/errno.h" #include "libc/fmt/itoa.h" #include "libc/intrin/atomic.h" +#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/dll.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/nomultics.internal.h" @@ -160,24 +161,57 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) { return 0; } +#if 0 + kprintf("bKeyDown=%hhhd wVirtualKeyCode=%s wVirtualScanCode=%s " + "UnicodeChar=%#x[%#lc] dwControlKeyState=%s\n", + r->Event.KeyEvent.bKeyDown, + DescribeVirtualKeyCode(r->Event.KeyEvent.wVirtualKeyCode), + DescribeVirtualKeyCode(r->Event.KeyEvent.wVirtualScanCode), + r->Event.KeyEvent.uChar.UnicodeChar, + r->Event.KeyEvent.uChar.UnicodeChar, + DescribeControlKeyState(r->Event.KeyEvent.dwControlKeyState)); +#endif + // process arrow keys, function keys, etc. int n = 0; - if (!c) { - int w; - w = GetVirtualKey(vk, !!(cks & kNtShiftPressed), - !!(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))); - if (!w) return 0; + int v = GetVirtualKey(vk, !!(cks & kNtShiftPressed), + !!(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))); + if (v) { p[n++] = 033; if (cks & (kNtLeftAltPressed | kNtRightAltPressed)) { p[n++] = 033; } - if (w > 0) { + if (v > 0) { p[n++] = '['; } else { - w = -w; + v = -v; } - do p[n++] = w; - while ((w >>= 8)); + do p[n++] = v; + while ((v >>= 8)); + return n; + } + + // ^/ should be interpreted as ^_ + if (vk == kNtVkOem_2 && (cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))) { + p[n++] = 037; + return n; + } + + // everything needs a unicode mapping from here on out + // handle some stuff microsoft doesn't encode, e.g. ctrl+alt+b + if (!c) { + if (isgraph(vk) && (cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed))) { + c = CTRL(vk); + } else { + return 0; + } + } + + // shift-tab is backtab or ^[Z + if (vk == kNtVkTab && (cks & (kNtShiftPressed))) { + p[n++] = 033; + p[n++] = '['; + p[n++] = 'Z'; return n; } @@ -230,7 +264,6 @@ static textwindows int ProcessKeyEvent(const struct NtInputRecord *r, char *p) { // insert esc prefix when alt is held if ((cks & (kNtLeftAltPressed | kNtRightAltPressed)) && - !(cks & (kNtLeftCtrlPressed | kNtRightCtrlPressed)) && r->Event.KeyEvent.bKeyDown) { p[n++] = 033; } diff --git a/libc/intrin/describecontrolkeystate.c b/libc/intrin/describecontrolkeystate.c new file mode 100644 index 00000000000..468cd1bf503 --- /dev/null +++ b/libc/intrin/describecontrolkeystate.c @@ -0,0 +1,38 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/struct/inputrecord.h" + +static const struct DescribeFlags kControlKeyState[] = { + {kNtRightAltPressed, "RightAltPressed"}, // + {kNtLeftAltPressed, "LeftAltPressed"}, // + {kNtRightCtrlPressed, "RightCtrlPressed"}, // + {kNtLeftCtrlPressed, "LeftCtrlPressed"}, // + {kNtShiftPressed, "ShiftPressed"}, // + {kNtNumlockOn, "NumlockOn"}, // + {kNtScrolllockOn, "ScrolllockOn"}, // + {kNtCapslockOn, "CapslockOn"}, // + {kNtEnhancedKey, "EnhancedKey"}, // +}; + +const char *(DescribeControlKeyState)(char buf[64], uint32_t x) { + return DescribeFlags(buf, 64, kControlKeyState, ARRAYLEN(kControlKeyState), + "kNt", x); +} diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h index 7b8e3fd2efb..be5819072b8 100644 --- a/libc/intrin/describeflags.internal.h +++ b/libc/intrin/describeflags.internal.h @@ -16,6 +16,7 @@ const char *DescribeArchPrctlCode(char[12], int); const char *DescribeCancelState(char[12], int, int *); const char *DescribeCapability(char[32], int); const char *DescribeClockName(char[32], int); +const char *DescribeControlKeyState(char[64], uint32_t); const char *DescribeDirfd(char[12], int); const char *DescribeDnotifyFlags(char[80], int); const char *DescribeErrno(char[20], int); @@ -44,7 +45,6 @@ const char *DescribeNtPipeOpenFlags(char[64], uint32_t); const char *DescribeNtProcAccessFlags(char[256], uint32_t); const char *DescribeNtStartFlags(char[128], uint32_t); const char *DescribeNtSymlinkFlags(char[64], uint32_t); -const char *DescribeThreadCreateFlags(char[64], uint32_t); const char *DescribeOpenFlags(char[128], int); const char *DescribeOpenMode(char[15], int, int); const char *DescribePersonalityFlags(char[128], int); @@ -66,6 +66,8 @@ const char *DescribeSocketProtocol(char[12], int); const char *DescribeSocketType(char[64], int); const char *DescribeStdioState(char[12], int); const char *DescribeStringList(char[300], char *const[]); +const char *DescribeThreadCreateFlags(char[64], uint32_t); +const char *DescribeVirtualKeyCode(char[32], uint32_t); const char *DescribeWhence(char[12], int); const char *DescribeWhichPrio(char[12], int); @@ -73,6 +75,7 @@ const char *DescribeWhichPrio(char[12], int); #define DescribeCancelState(x, y) DescribeCancelState(alloca(12), x, y) #define DescribeCapability(x) DescribeCapability(alloca(32), x) #define DescribeClockName(x) DescribeClockName(alloca(32), x) +#define DescribeControlKeyState(x) DescribeControlKeyState(alloca(64), x) #define DescribeDirfd(x) DescribeDirfd(alloca(12), x) #define DescribeDnotifyFlags(x) DescribeDnotifyFlags(alloca(80), x) #define DescribeErrno(x) DescribeErrno(alloca(20), x) @@ -120,6 +123,7 @@ const char *DescribeWhichPrio(char[12], int); #define DescribeStdioState(x) DescribeStdioState(alloca(12), x) #define DescribeStringList(x) DescribeStringList(alloca(300), x) #define DescribeThreadCreateFlags(x) DescribeThreadCreateFlags(alloca(64), x) +#define DescribeVirtualKeyCode(x) DescribeVirtualKeyCode(alloca(32), x) #define DescribeWhence(x) DescribeWhence(alloca(12), x) #define DescribeWhichPrio(x) DescribeWhichPrio(alloca(12), x) diff --git a/libc/intrin/describevirtualkeycode.c b/libc/intrin/describevirtualkeycode.c new file mode 100644 index 00000000000..8b910e5f03b --- /dev/null +++ b/libc/intrin/describevirtualkeycode.c @@ -0,0 +1,216 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/kprintf.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/vk.h" + +// clang-format off +static const struct VirtualKeyCodeName { + uint32_t code; + const char *name; +} kVirtualKeyCodeNames[] = { + {kNtVkLbutton, "kNtVkLbutton"}, + {kNtVkRbutton, "kNtVkRbutton"}, + {kNtVkCancel, "kNtVkCancel"}, + {kNtVkMbutton, "kNtVkMbutton"}, + {kNtVkXbutton1, "kNtVkXbutton1"}, + {kNtVkXbutton2, "kNtVkXbutton2"}, + {kNtVkBack, "kNtVkBack"}, + {kNtVkTab, "kNtVkTab"}, + {kNtVkClear, "kNtVkClear"}, + {kNtVkReturn, "kNtVkReturn"}, + {kNtVkShift, "kNtVkShift"}, + {kNtVkControl, "kNtVkControl"}, + {kNtVkMenu, "kNtVkMenu"}, + {kNtVkPause, "kNtVkPause"}, + {kNtVkCapital, "kNtVkCapital"}, + {kNtVkKana, "kNtVkKana"}, + {kNtVkHangul, "kNtVkHangul"}, + {kNtVkJunja, "kNtVkJunja"}, + {kNtVkFinal, "kNtVkFinal"}, + {kNtVkHanja, "kNtVkHanja"}, + {kNtVkKanji, "kNtVkKanji"}, + {kNtVkEscape, "kNtVkEscape"}, + {kNtVkConvert, "kNtVkConvert"}, + {kNtVkNonconvert, "kNtVkNonconvert"}, + {kNtVkAccept, "kNtVkAccept"}, + {kNtVkModechange, "kNtVkModechange"}, + {kNtVkSpace, "kNtVkSpace"}, + {kNtVkPrior, "kNtVkPrior"}, + {kNtVkNext, "kNtVkNext"}, + {kNtVkEnd, "kNtVkEnd"}, + {kNtVkHome, "kNtVkHome"}, + {kNtVkLeft, "kNtVkLeft"}, + {kNtVkUp, "kNtVkUp"}, + {kNtVkRight, "kNtVkRight"}, + {kNtVkDown, "kNtVkDown"}, + {kNtVkSelect, "kNtVkSelect"}, + {kNtVkPrint, "kNtVkPrint"}, + {kNtVkExecute, "kNtVkExecute"}, + {kNtVkSnapshot, "kNtVkSnapshot"}, + {kNtVkInsert, "kNtVkInsert"}, + {kNtVkDelete, "kNtVkDelete"}, + {kNtVkHelp, "kNtVkHelp"}, + {kNtVkLwin, "kNtVkLwin"}, + {kNtVkRwin, "kNtVkRwin"}, + {kNtVkApps, "kNtVkApps"}, + {kNtVkSleep, "kNtVkSleep"}, + {kNtVkNumpad0, "kNtVkNumpad0"}, + {kNtVkNumpad1, "kNtVkNumpad1"}, + {kNtVkNumpad2, "kNtVkNumpad2"}, + {kNtVkNumpad3, "kNtVkNumpad3"}, + {kNtVkNumpad4, "kNtVkNumpad4"}, + {kNtVkNumpad5, "kNtVkNumpad5"}, + {kNtVkNumpad6, "kNtVkNumpad6"}, + {kNtVkNumpad7, "kNtVkNumpad7"}, + {kNtVkNumpad8, "kNtVkNumpad8"}, + {kNtVkNumpad9, "kNtVkNumpad9"}, + {kNtVkMultiply, "kNtVkMultiply"}, + {kNtVkAdd, "kNtVkAdd"}, + {kNtVkSeparator, "kNtVkSeparator"}, + {kNtVkSubtract, "kNtVkSubtract"}, + {kNtVkDecimal, "kNtVkDecimal"}, + {kNtVkDivide, "kNtVkDivide"}, + {kNtVkF1, "kNtVkF1"}, + {kNtVkF2, "kNtVkF2"}, + {kNtVkF3, "kNtVkF3"}, + {kNtVkF4, "kNtVkF4"}, + {kNtVkF5, "kNtVkF5"}, + {kNtVkF6, "kNtVkF6"}, + {kNtVkF7, "kNtVkF7"}, + {kNtVkF8, "kNtVkF8"}, + {kNtVkF9, "kNtVkF9"}, + {kNtVkF10, "kNtVkF10"}, + {kNtVkF11, "kNtVkF11"}, + {kNtVkF12, "kNtVkF12"}, + {kNtVkF13, "kNtVkF13"}, + {kNtVkF14, "kNtVkF14"}, + {kNtVkF15, "kNtVkF15"}, + {kNtVkF16, "kNtVkF16"}, + {kNtVkF17, "kNtVkF17"}, + {kNtVkF18, "kNtVkF18"}, + {kNtVkF19, "kNtVkF19"}, + {kNtVkF20, "kNtVkF20"}, + {kNtVkF21, "kNtVkF21"}, + {kNtVkF22, "kNtVkF22"}, + {kNtVkF23, "kNtVkF23"}, + {kNtVkF24, "kNtVkF24"}, + {kNtVkNumlock, "kNtVkNumlock"}, + {kNtVkScroll, "kNtVkScroll"}, + {kNtVkLshift, "kNtVkLshift"}, + {kNtVkRshift, "kNtVkRshift"}, + {kNtVkLcontrol, "kNtVkLcontrol"}, + {kNtVkRcontrol, "kNtVkRcontrol"}, + {kNtVkLmenu, "kNtVkLmenu"}, + {kNtVkRmenu, "kNtVkRmenu"}, + {kNtVkBrowserBack, "kNtVkBrowserBack"}, + {kNtVkBrowserForward, "kNtVkBrowserForward"}, + {kNtVkBrowserRefresh, "kNtVkBrowserRefresh"}, + {kNtVkBrowserStop, "kNtVkBrowserStop"}, + {kNtVkBrowserSearch, "kNtVkBrowserSearch"}, + {kNtVkBrowserFavorites, "kNtVkBrowserFavorites"}, + {kNtVkBrowserHome, "kNtVkBrowserHome"}, + {kNtVkVolumeMute, "kNtVkVolumeMute"}, + {kNtVkVolumeDown, "kNtVkVolumeDown"}, + {kNtVkVolumeUp, "kNtVkVolumeUp"}, + {kNtVkMediaNextTrack, "kNtVkMediaNextTrack"}, + {kNtVkMediaPrevTrack, "kNtVkMediaPrevTrack"}, + {kNtVkMediaStop, "kNtVkMediaStop"}, + {kNtVkMediaPlayPause, "kNtVkMediaPlayPause"}, + {kNtVkLaunchMail, "kNtVkLaunchMail"}, + {kNtVkLaunchMediaSelect, "kNtVkLaunchMediaSelect"}, + {kNtVkLaunchApp1, "kNtVkLaunchApp1"}, + {kNtVkLaunchApp2, "kNtVkLaunchApp2"}, + {kNtVkOem_1, "kNtVkOem_1"}, + {kNtVkOemPlus, "kNtVkOemPlus"}, + {kNtVkOemComma, "kNtVkOemComma"}, + {kNtVkOemMinus, "kNtVkOemMinus"}, + {kNtVkOemPeriod, "kNtVkOemPeriod"}, + {kNtVkOem_2, "kNtVkOem_2"}, + {kNtVkOem_3, "kNtVkOem_3"}, + {kNtVkGamepadA, "kNtVkGamepadA"}, + {kNtVkGamepadB, "kNtVkGamepadB"}, + {kNtVkGamepadX, "kNtVkGamepadX"}, + {kNtVkGamepadY, "kNtVkGamepadY"}, + {kNtVkGamepadRightShoulder, "kNtVkGamepadRightShoulder"}, + {kNtVkGamepadLeftShoulder, "kNtVkGamepadLeftShoulder"}, + {kNtVkGamepadLeftTrigger, "kNtVkGamepadLeftTrigger"}, + {kNtVkGamepadRightTrigger, "kNtVkGamepadRightTrigger"}, + {kNtVkGamepadDpadUp, "kNtVkGamepadDpadUp"}, + {kNtVkGamepadDpadDown, "kNtVkGamepadDpadDown"}, + {kNtVkGamepadDpadLeft, "kNtVkGamepadDpadLeft"}, + {kNtVkGamepadDpadRight, "kNtVkGamepadDpadRight"}, + {kNtVkGamepadMenu, "kNtVkGamepadMenu"}, + {kNtVkGamepadView, "kNtVkGamepadView"}, + {kNtVkGamepadLeftThumbstickButton, "kNtVkGamepadLeftThumbstickButton"}, + {kNtVkGamepadRightThumbstickButton, "kNtVkGamepadRightThumbstickButton"}, + {kNtVkGamepadLeftThumbstickUp, "kNtVkGamepadLeftThumbstickUp"}, + {kNtVkGamepadLeftThumbstickDown, "kNtVkGamepadLeftThumbstickDown"}, + {kNtVkGamepadLeftThumbstickRight, "kNtVkGamepadLeftThumbstickRight"}, + {kNtVkGamepadLeftThumbstickLeft, "kNtVkGamepadLeftThumbstickLeft"}, + {kNtVkGamepadRightThumbstickUp, "kNtVkGamepadRightThumbstickUp"}, + {kNtVkGamepadRightThumbstickDown, "kNtVkGamepadRightThumbstickDown"}, + {kNtVkGamepadRightThumbstickRight, "kNtVkGamepadRightThumbstickRight"}, + {kNtVkGamepadRightThumbstickLeft, "kNtVkGamepadRightThumbstickLeft"}, + {kNtVkOem_4, "kNtVkOem_4"}, + {kNtVkOem_5, "kNtVkOem_5"}, + {kNtVkOem_6, "kNtVkOem_6"}, + {kNtVkOem_7, "kNtVkOem_7"}, + {kNtVkOem_8, "kNtVkOem_8"}, + {kNtVkOemAx, "kNtVkOemAx"}, + {kNtVkOem_102, "kNtVkOem_102"}, + {kNtVkIcoHelp, "kNtVkIcoHelp"}, + {kNtVkIco_00, "kNtVkIco_00"}, + {kNtVkProcesskey, "kNtVkProcesskey"}, + {kNtVkIcoClear, "kNtVkIcoClear"}, + {kNtVkPacket, "kNtVkPacket"}, + {kNtVkOemReset, "kNtVkOemReset"}, + {kNtVkOemJump, "kNtVkOemJump"}, + {kNtVkOemPa1, "kNtVkOemPa1"}, + {kNtVkOemPa2, "kNtVkOemPa2"}, + {kNtVkOemPa3, "kNtVkOemPa3"}, + {kNtVkOemWsctrl, "kNtVkOemWsctrl"}, + {kNtVkOemCusel, "kNtVkOemCusel"}, + {kNtVkOemAttn, "kNtVkOemAttn"}, + {kNtVkOemFinish, "kNtVkOemFinish"}, + {kNtVkOemCopy, "kNtVkOemCopy"}, + {kNtVkOemAuto, "kNtVkOemAuto"}, + {kNtVkOemEnlw, "kNtVkOemEnlw"}, + {kNtVkOemBacktab, "kNtVkOemBacktab"}, + {kNtVkAttn, "kNtVkAttn"}, + {kNtVkCrsel, "kNtVkCrsel"}, + {kNtVkExsel, "kNtVkExsel"}, + {kNtVkEreof, "kNtVkEreof"}, + {kNtVkPlay, "kNtVkPlay"}, + {kNtVkZoom, "kNtVkZoom"}, + {kNtVkNoname, "kNtVkNoname"}, + {kNtVkPa1, "kNtVkPa1"}, + {kNtVkOemClear, "kNtVkOemClear"}, +}; +// clang-format on + +const char *(DescribeVirtualKeyCode)(char buf[32], uint32_t x) { + for (int i = 0; i < ARRAYLEN(kVirtualKeyCodeNames); ++i) { + if (x == kVirtualKeyCodeNames[i].code) { + return kVirtualKeyCodeNames[i].name; + } + } + ksnprintf(buf, 32, "%#x[%#lc]", x, x); + return buf; +}