Last active
November 20, 2023 15:58
-
-
Save benanil/f66aadcb46390a5479f19c691fbf4034 to your computer and use it in GitHub Desktop.
Windows Keyboard & Mouse Input like glfw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum KeyboardKey_ | |
{ | |
Key_BACK = 0x08, | |
Key_TAB = 0x09, | |
Key_CLEAR = 0x0C, | |
Key_RETURN = 0x0D, | |
Key_SHIFT = 0x10, | |
Key_CONTROL = 0x11, | |
Key_MENU = 0x12, | |
Key_PAUSE = 0x13, | |
Key_CAPITAL = 0x14, | |
Key_ESCAPE = 0x1B, | |
Key_CONVERT = 0x1C, | |
Key_NONCONVERT = 0x1D, | |
Key_ACCEPT = 0x1E, | |
Key_MODECHANGE = 0x1F, | |
Key_SPACE = 0x20, | |
Key_PRIOR = 0x21, | |
Key_NEXT = 0x22, | |
Key_END = 0x23, | |
Key_HOME = 0x24, | |
Key_LEFT = 0x25, | |
Key_UP = 0x26, | |
Key_RIGHT = 0x27, | |
Key_DOWN = 0x28, | |
Key_SELECT = 0x29, | |
Key_PRINT = 0x2A, | |
Key_EXECUTE = 0x2B, | |
Key_SNAPSHOT = 0x2C, | |
Key_INSERT = 0x2D, | |
Key_DELETE = 0x2E, | |
Key_HELP = 0x2F, | |
Key_LWIN = 0x5B, | |
Key_RWIN = 0x5C, | |
Key_APPS = 0x5D, | |
Key_SLEEP = 0x5F, | |
Key_NUMPAD0 = 0x60, | |
Key_NUMPAD1 = 0x61, | |
Key_NUMPAD2 = 0x62, | |
Key_NUMPAD3 = 0x63, | |
Key_NUMPAD4 = 0x64, | |
Key_NUMPAD5 = 0x65, | |
Key_NUMPAD6 = 0x66, | |
Key_NUMPAD7 = 0x67, | |
Key_NUMPAD8 = 0x68, | |
Key_NUMPAD9 = 0x69, | |
Key_MULTIPLY = 0x6A, | |
Key_ADD = 0x6B, | |
Key_SEPARATOR = 0x6C, | |
Key_SUBTRACT = 0x6D, | |
Key_DECIMAL = 0x6E, | |
Key_DIVIDE = 0x6F, | |
Key_F1 = 0x70, | |
Key_F2 = 0x71, | |
Key_F3 = 0x72, | |
Key_F4 = 0x73, | |
Key_F5 = 0x74, | |
Key_F6 = 0x75, | |
Key_F7 = 0x76, | |
Key_F8 = 0x77, | |
Key_F9 = 0x78, | |
Key_F10 = 0x79, | |
Key_F11 = 0x7A, | |
Key_F12 = 0x7B, | |
}; | |
typedef int KeyboardKey; | |
enum MouseButton_ | |
{ | |
MouseButton_Left = 1, | |
MouseButton_Right = 2, | |
MouseButton_Middle = 4 | |
}; | |
typedef int MouseButton; | |
// public functions that are callable from different cpp files, | |
// you might want to write these to header file. | |
// use KeyboardKey enum or asci char 'X' | |
bool GetKeyDown(char c); | |
bool GetKeyPressed(char c); | |
bool GetKeyReleased(char c); | |
bool GetMouseDown(MouseButton button); | |
bool GetMouseReleased(MouseButton button); | |
bool GetMousePressed(MouseButton button); | |
// set these callbacks or leave it as nullptr | |
static void(*WindowMoveCallback)(int, int) = nullptr; | |
static void(*WindowResizeCallback)(int, int) = nullptr; | |
static void(*MouseMoveCallback)(float, float) = nullptr; | |
static void(*KeyPressCallback)(wchar_t) = nullptr; | |
static void(*FocusChangedCallback)(bool) = nullptr; | |
// 128bit bitfield storage for keyboard keys | |
unsigned long g_axDownKeys[2]{}; | |
unsigned long g_axLastKeys[2]{}; | |
unsigned long g_axPressedKeys[2]{}; | |
unsigned long g_axReleasedKeys[2]{}; | |
// mouse | |
int g_axMouseDown = 0, g_axMouseLast = 0, g_axMousePressed = 0, g_axMouseReleased = 0; | |
inline bool GetBit128(unsigned long bits[2], int idx) { return !!(bits[idx > 63] & (1ul << (idx & 63ul))); } | |
inline void SetBit128(unsigned long bits[2], int idx) { bits[idx > 63] |= 1ul << (idx & 63); } | |
inline void ResetBit128(unsigned long bits[2], int idx) { bits[idx > 63] &= ~(1ul << (idx & 63)); } | |
bool GetKeyDown(char c) { return GetBit128(g_axDownKeys, c); } | |
bool GetKeyReleased(char c) { return GetBit128(g_axReleasedKeys, c); } | |
bool GetKeyPressed(char c) { return GetBit128(g_axPressedKeys, c); } | |
static void SetPressedAndReleasedKeys() | |
{ | |
g_axReleasedKeys[0] = g_axLastKeys[0] & ~g_axDownKeys[0]; | |
g_axReleasedKeys[1] = g_axLastKeys[1] & ~g_axDownKeys[1]; | |
g_axPressedKeys[0] = ~g_axLastKeys[0] & g_axDownKeys[0]; | |
g_axPressedKeys[1] = ~g_axLastKeys[1] & g_axDownKeys[1]; | |
// Mouse | |
g_axMouseReleased = g_axMouseLast & ~g_axMouseDown; | |
g_axMousePressed = ~g_axMouseLast & g_axMouseDown; | |
} | |
static void RecordLastKeys() { | |
g_axLastKeys[0] = g_axDownKeys[0]; | |
g_axLastKeys[1] = g_axDownKeys[1]; | |
g_axMouseLast = g_axMouseDown; | |
} | |
bool GetMouseDown(MouseButton button) { return !!(g_axMouseDown & button); } | |
bool GetMouseReleased(MouseButton button) { return !!(g_axMouseReleased & button); } | |
bool GetMousePressed(MouseButton button) { return !!(g_axMousePressed & button); } | |
void GetMousePos(float* x, float* y) | |
{ | |
ASSERT((uint64_t)x & (uint64_t)y); // shouldn't be nullptr | |
POINT point; | |
GetCursorPos(&point); | |
*x = (float)point.x; | |
*y = (float)point.y; | |
} | |
void SetMousePos(float x, float y) | |
{ | |
SetCursorPos((int)x, (int)y); | |
} | |
float g_axMousePosX = 0.0, g_axMousePosY = 0.0f; | |
void GetMouseWindowPos(float* x, float* y) | |
{ | |
*x = g_axMousePosX; *y = g_axMousePosY; | |
} | |
void SetMouseWindowPos(float x, float y) | |
{ | |
SetMousePos(windowPosX_ + x, windowPosY_ + y); | |
} | |
static LRESULT CALLBACK WindowCallback(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) | |
{ | |
LRESULT result = 0; | |
wchar_t wch = 0; | |
switch (msg) | |
{ | |
case WM_MOUSEMOVE: | |
g_axMousePosX = (float)LOWORD(lparam); | |
g_axMousePosY = (float)HIWORD(lparam); | |
if (MouseMoveCallback) MouseMoveCallback(g_axMousePosX, g_axMousePosY); | |
break; | |
case WM_LBUTTONDOWN: g_axMouseDown |= MouseButton_Left; break; | |
case WM_RBUTTONDOWN: g_axMouseDown |= MouseButton_Right; break; | |
case WM_MBUTTONDOWN: g_axMouseDown |= MouseButton_Middle; break; | |
case WM_LBUTTONUP: g_axMouseDown &= ~MouseButton_Left; break; | |
case WM_RBUTTONUP: g_axMouseDown &= ~MouseButton_Right; break; | |
case WM_MBUTTONUP: g_axMouseDown &= ~MouseButton_Middle; break; | |
case WM_XBUTTONUP: g_axMouseDown &= ~MouseButton_Middle; break; | |
case WM_KEYDOWN: | |
case WM_SYSKEYDOWN: | |
{ | |
if (wparam > 127) break; | |
SetBit128(g_axDownKeys, wparam); | |
break; | |
} | |
case WM_SETFOCUS: | |
case WM_KILLFOCUS: | |
if (FocusChangedCallback) FocusChangedCallback(msg == WM_SETFOCUS); | |
break; | |
case WM_KEYUP: | |
case WM_SYSKEYUP: | |
{ | |
if (wparam > 127) break; | |
ResetBit128(g_axDownKeys, wparam); | |
break; | |
} | |
case WM_CHAR: | |
::MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, (char*)&wparam, 1, &wch, 1); | |
if (KeyPressCallback) KeyPressCallback(wch); | |
break; | |
case WM_SIZE: | |
windowWidth_ = LOWORD(lparam); | |
windowHeight_ = HIWORD(lparam); | |
// UpdateRenderArea(); | |
if (WindowResizeCallback) WindowResizeCallback(windowWidth_, windowHeight_); | |
break; | |
case WM_MOVE: | |
windowPosX_ = LOWORD(lparam); | |
windowPosY_ = HIWORD(lparam); | |
break; | |
case WM_CLOSE: | |
case WM_DESTROY: | |
PostQuitMessage(0); | |
break; | |
default: | |
result = DefWindowProcA(window, msg, wparam, lparam); | |
break; | |
} | |
return result; | |
} | |
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd_line, int show) | |
{ | |
// Initialize your window here... | |
bool running = true; | |
while (running) | |
{ | |
MSG msg; | |
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) | |
{ | |
if (msg.message == WM_QUIT) | |
{ | |
running = false; | |
} | |
else | |
{ | |
TranslateMessage(&msg); | |
DispatchMessageA(&msg); | |
} | |
} | |
SetPressedAndReleasedKeys(); | |
// Do rendering and calculations here... | |
RecordLastKeys(); | |
} | |
// finalize here... | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment