#include #include #include #include #include #include #include #include "fumotris.h" #include "ctrl.h" #include "term.h" struct Windows { HANDLE in_handle; HANDLE timer; DWORD in_len; INPUT_RECORD in_buf[IO_BUF_SIZE]; }; typedef struct Windows *platform; bool WinInitHandles(struct Windows *win) { win->in_handle = GetStdHandle(STD_INPUT_HANDLE); if (win->in_handle == INVALID_HANDLE_VALUE) return false; win->timer = CreateWaitableTimer( NULL, // Timer attributes TRUE, // Manual reset NULL // Name ); if (win->timer == NULL) return false; return true; } bool WinInitConsole(struct Windows *win) { DWORD mode = ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT | ENABLE_PROCESSED_OUTPUT | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT; return SetConsoleMode(win->in_handle, mode) != 0; } bool WinGetRefreshRate(u16f *out) { DEVMODE mode; mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; if(!EnumDisplaySettingsA( NULL, // Device name (null for current) ENUM_CURRENT_SETTINGS, // Mode &mode // Out )) return false; *out = mode.dmDisplayFrequency; return true; } bool WindowsInit(platform win, struct Terminal *term) { if (!WinInitHandles(win)) return false; if (!WinInitConsole(win)) return false; if (!WinGetRefreshRate(&term->refresh_rate)) return false; return true; } void read_key_rec(struct InputRecord *rec, KEY_EVENT_RECORD win_key) { rec->type = BUTTON; rec->bind = win_key.wVirtualKeyCode; rec->is_down = win_key.bKeyDown; rec->is_up = !win_key.bKeyDown; } bool read_mouse_rec(struct InputRecord *rec, MOUSE_EVENT_RECORD win_mouse) { if (win_mouse.dwEventFlags == MOUSE_MOVED) { rec->type = JOYSTICK; rec->bind = 0; rec->js.x = win_mouse.dwMousePosition.X; rec->js.y = win_mouse.dwMousePosition.Y; return true; } if (win_mouse.dwEventFlags == MOUSE_WHEELED) { rec->bind = 0; } else if (win_mouse.dwEventFlags == MOUSE_HWHEELED) { rec->bind = 1; } else { return false; } rec->type = AXIS; rec->axis.value = win_mouse.dwButtonState; return true; } bool read_rec(struct InputRecord *rec, INPUT_RECORD win_rec) { switch (win_rec.EventType) { case KEY_EVENT: read_key_rec(rec, win_rec.Event.KeyEvent); return true; case MOUSE_EVENT: return read_mouse_rec(rec, win_rec.Event.MouseEvent); case WINDOW_BUFFER_SIZE_EVENT: return false; // TODO: Handle window resizing } rec->type = ESCAPE; return false; } bool WinBlockInput(platform win, struct InputBuffer *buf) { if (!ReadConsoleInput( win->in_handle, // Input handle win->in_buf + buf->len, // Record buffer IO_BUF_SIZE - buf->len, // Record buffer length &win->in_len // Out number of records )) return false; struct timespec now; timespec_get(&now, TIME_UTC); for (size_t i = 0; i < win->in_len; i++) { struct InputRecord *rec = &buf->records[buf->len]; if (!read_rec(rec, win->in_buf[i])) continue; rec->timestamp = now; buf->len += 1; } return true; } bool WinWait(platform win, struct timespec relative) { LARGE_INTEGER duration; duration.QuadPart = -10000000 * relative.tv_sec - relative.tv_nsec / 100; if (!SetWaitableTimer( win->timer, // Timer &duration, // Duration 0, // Period NULL, // Completion coroutine NULL, // Completion coroutine arg FALSE // Resume )) return false; DWORD result = WaitForSingleObject(win->timer, INFINITE); if (result != WAIT_OBJECT_0) return false; return true; }