clean up and standardize types across the codebase, unify atomic operations, improve UTF-8 handling throughout the system, remove obsolete input and named queue interfaces, redesign process preparation and creation, tighten IPC and service boundaries, improve error handling and reliability, minor documentation cleanup, fix doom surfaces, fix panic in ini parsing.
This commit is contained in:
1 parent
899225f551
commit
c0ad63c27f
226 files changed
+6562
-4147
No files matched your search
+26
-485
@@ -1,5 +1,6 @@
|
||||
// Kernel input core. This file owns canonical keyboard and mouse state shared by input drivers and syscalls.
|
||||
|
||||
#include <ntlite/atomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
@@ -11,62 +12,16 @@
|
||||
#include <kernel/ke_debug.h>
|
||||
#include <kernel/ke_display.h>
|
||||
#include <kernel/ke_event.h>
|
||||
#include <kernel/ke_dpc.h>
|
||||
#include <kernel/ob_object.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
#define KEY_QUEUE_SIZE 256u
|
||||
#define KEY_QUEUE_MASK (KEY_QUEUE_SIZE - 1u)
|
||||
#define MOUSE_QUEUE_SIZE 128u
|
||||
#define MOUSE_QUEUE_MASK (MOUSE_QUEUE_SIZE - 1u)
|
||||
#define MANAGER_QUEUE_SIZE 256u
|
||||
#define MANAGER_QUEUE_MASK (MANAGER_QUEUE_SIZE - 1u)
|
||||
#define MAX_INPUT_KEYS 256u
|
||||
#define KEY_REPEAT_DELAY_US 500000ull
|
||||
#define KEY_REPEAT_PERIOD_US 33000ull
|
||||
|
||||
typedef struct KEY_CHAR_PAIR {
|
||||
INPUT_KEY key;
|
||||
char normal;
|
||||
char shifted;
|
||||
} KEY_CHAR_PAIR;
|
||||
|
||||
static KE_INPUT_CONTEXT gDefaultInputContext;
|
||||
static KE_INPUT_MANAGER gInputManager;
|
||||
static KE_ID_ALLOCATOR gInputDeviceIds = KE_ID_ALLOCATOR_INIT(1u);
|
||||
|
||||
static char KiInputKeyToChar(KE_INPUT_CONTEXT* context, INPUT_KEY key);
|
||||
static void KiInputServiceRepeat(KE_INPUT_CONTEXT* context);
|
||||
|
||||
// Advances the physical input snapshot generation after visible state changes.
|
||||
static void KiInputBumpGeneration(KE_INPUT_CONTEXT* context) {
|
||||
_InterlockedIncrement64(&context->Generation);
|
||||
}
|
||||
|
||||
static const KEY_CHAR_PAIR gCharMap[] = {
|
||||
{ INPUT_KEY_1, '1', '!' }, { INPUT_KEY_2, '2', '@' },
|
||||
{ INPUT_KEY_3, '3', '#' }, { INPUT_KEY_4, '4', '$' },
|
||||
{ INPUT_KEY_5, '5', '%' }, { INPUT_KEY_6, '6', '^' },
|
||||
{ INPUT_KEY_7, '7', '&' }, { INPUT_KEY_8, '8', '*' },
|
||||
{ INPUT_KEY_9, '9', '(' }, { INPUT_KEY_0, '0', ')' },
|
||||
{ INPUT_KEY_MINUS, '-', '_' }, { INPUT_KEY_EQUAL, '=', '+' },
|
||||
{ INPUT_KEY_LEFT_BRACKET, '[', '{' }, { INPUT_KEY_RIGHT_BRACKET, ']', '}' },
|
||||
{ INPUT_KEY_BACKSLASH, '\\', '|' }, { INPUT_KEY_SEMICOLON, ';', ':' },
|
||||
{ INPUT_KEY_APOSTROPHE, '\'', '"' }, { INPUT_KEY_GRAVE, '`', '~' },
|
||||
{ INPUT_KEY_COMMA, ',', '<' }, { INPUT_KEY_PERIOD, '.', '>' },
|
||||
{ INPUT_KEY_SLASH, '/', '?' },
|
||||
{ INPUT_KEY_SPACE, ' ', ' ' }, { INPUT_KEY_TAB, '\t', '\t' },
|
||||
{ INPUT_KEY_ENTER, '\n', '\n' }, { INPUT_KEY_BACKSPACE, '\b', '\b' },
|
||||
{ INPUT_KEY_KP_DIVIDE, '/', '/' }, { INPUT_KEY_KP_MULTIPLY, '*', '*' },
|
||||
{ INPUT_KEY_KP_MINUS, '-', '-' }, { INPUT_KEY_KP_PLUS, '+', '+' },
|
||||
{ INPUT_KEY_KP_ENTER, '\n', '\n' }, { INPUT_KEY_KP_1, '1', '1' },
|
||||
{ INPUT_KEY_KP_2, '2', '2' }, { INPUT_KEY_KP_3, '3', '3' },
|
||||
{ INPUT_KEY_KP_4, '4', '4' }, { INPUT_KEY_KP_5, '5', '5' },
|
||||
{ INPUT_KEY_KP_6, '6', '6' }, { INPUT_KEY_KP_7, '7', '7' },
|
||||
{ INPUT_KEY_KP_8, '8', '8' }, { INPUT_KEY_KP_9, '9', '9' },
|
||||
{ INPUT_KEY_KP_0, '0', '0' }, { INPUT_KEY_KP_PERIOD, '.', '.' },
|
||||
};
|
||||
|
||||
// Updates the waitable manager event to match queued physical input.
|
||||
static void KiInputRefreshManagerEvent(KE_INPUT_CONTEXT* context) {
|
||||
if (!context->ManagerWaitEvent) return;
|
||||
@@ -80,187 +35,30 @@ static void KiInputQueueManagerEvent(KE_INPUT_CONTEXT* context, const KE_INPUT_M
|
||||
int next = (context->ManagerTail + 1) & (int)MANAGER_QUEUE_MASK;
|
||||
if (next == context->ManagerHead) return;
|
||||
KE_INPUT_MANAGER_EVENT queued = *event;
|
||||
queued.Sequence = (uint64_t)_InterlockedIncrement64(&context->ManagerSequence);
|
||||
queued.Sequence = (uint64_t)NtlAtomicIncrement64(&context->ManagerSequence);
|
||||
context->ManagerQueue[context->ManagerTail] = queued;
|
||||
context->ManagerTail = next;
|
||||
KiInputRefreshManagerEvent(context);
|
||||
}
|
||||
|
||||
// Updates the waitable keyboard event to match queued keyboard input.
|
||||
static void KiInputRefreshKeyboardEvent(KE_INPUT_CONTEXT* context) {
|
||||
if (!context->WaitEvent) return;
|
||||
if (context->KeyHead != context->KeyTail) KeSignalEvent(context->WaitEvent);
|
||||
else KeClearEvent(context->WaitEvent);
|
||||
}
|
||||
|
||||
// Queues a keyboard event and wakes waiters when the event was accepted.
|
||||
static void KiInputQueueKey(KE_INPUT_CONTEXT* context, INPUT_KEY key, char ch) {
|
||||
if (key == INPUT_KEY_NONE) return;
|
||||
int next = (context->KeyTail + 1) & (int)KEY_QUEUE_MASK;
|
||||
if (next == context->KeyHead) return;
|
||||
context->KeyQueue[context->KeyTail].Key = key;
|
||||
context->KeyQueue[context->KeyTail].Character = ch;
|
||||
context->KeyQueue[context->KeyTail].Modifiers = context->Modifiers;
|
||||
context->KeyTail = next;
|
||||
KiInputRefreshKeyboardEvent(context);
|
||||
}
|
||||
|
||||
// Implements the input Queue Has Space operation.
|
||||
static bool KiInputQueueHasSpace(KE_INPUT_CONTEXT* context) {
|
||||
int next = (context->KeyTail + 1) & (int)KEY_QUEUE_MASK;
|
||||
return next != context->KeyHead;
|
||||
}
|
||||
|
||||
// Implements the input Key Is Repeatable operation.
|
||||
static bool KiInputKeyIsRepeatable(INPUT_KEY key) {
|
||||
if (key == INPUT_KEY_NONE) return false;
|
||||
|
||||
switch (key) {
|
||||
case INPUT_KEY_LEFT_SHIFT:
|
||||
case INPUT_KEY_RIGHT_SHIFT:
|
||||
case INPUT_KEY_LEFT_CTRL:
|
||||
case INPUT_KEY_RIGHT_CTRL:
|
||||
case INPUT_KEY_LEFT_ALT:
|
||||
case INPUT_KEY_RIGHT_ALT:
|
||||
case INPUT_KEY_LEFT_GUI:
|
||||
case INPUT_KEY_RIGHT_GUI:
|
||||
case INPUT_KEY_CAPS_LOCK:
|
||||
case INPUT_KEY_NUM_LOCK:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the input Now Ticks operation.
|
||||
static uint64_t KiInputNowTicks(KE_INPUT_CONTEXT* context) {
|
||||
if (context->Hal && context->Hal->Timer.QueryTicks)
|
||||
return context->Hal->Timer.QueryTicks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the input Start Repeat operation.
|
||||
static void KiInputStartRepeat(KE_INPUT_CONTEXT* context, INPUT_KEY key, uint64_t now) {
|
||||
if (!KiInputKeyIsRepeatable(key)) return;
|
||||
context->RepeatKey = key;
|
||||
context->RepeatNextTick = now + KEY_REPEAT_DELAY_US;
|
||||
}
|
||||
|
||||
// Implements the input Stop Repeat operation.
|
||||
static void KiInputStopRepeat(KE_INPUT_CONTEXT* context, INPUT_KEY key) {
|
||||
if (context->RepeatKey == key) {
|
||||
context->RepeatKey = INPUT_KEY_NONE;
|
||||
context->RepeatNextTick = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the input Service Repeat operation.
|
||||
static void KiInputServiceRepeat(KE_INPUT_CONTEXT* context) {
|
||||
INPUT_KEY key = context->RepeatKey;
|
||||
if (!KiInputKeyIsRepeatable(key) || key >= MAX_INPUT_KEYS || !context->KeyDown[key]) {
|
||||
context->RepeatKey = INPUT_KEY_NONE;
|
||||
context->RepeatNextTick = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t now = KiInputNowTicks(context);
|
||||
if (now == 0 || now < context->RepeatNextTick)
|
||||
return;
|
||||
|
||||
if (!KiInputQueueHasSpace(context)) {
|
||||
context->RepeatNextTick = now + KEY_REPEAT_PERIOD_US;
|
||||
return;
|
||||
}
|
||||
|
||||
KiInputQueueKey(context, key, KiInputKeyToChar(context, key));
|
||||
context->RepeatNextTick = now + KEY_REPEAT_PERIOD_US;
|
||||
}
|
||||
|
||||
// Implements the input Repeat Dpc Routine operation.
|
||||
static void KiInputRepeatDpcRoutine(KDPC* dpc, void* context, void* systemArgument1, void* systemArgument2) {
|
||||
(void)dpc;
|
||||
(void)systemArgument1;
|
||||
(void)systemArgument2;
|
||||
|
||||
KiInputServiceRepeat((KE_INPUT_CONTEXT*)context);
|
||||
}
|
||||
|
||||
// Implements the input Set Modifier operation.
|
||||
static void KiInputSetModifier(KE_INPUT_CONTEXT* context, INPUT_KEY key, bool pressed) {
|
||||
uint32_t bit = 0;
|
||||
switch (key) {
|
||||
case INPUT_KEY_LEFT_SHIFT: bit = INPUT_MOD_LSHIFT; break;
|
||||
case INPUT_KEY_RIGHT_SHIFT: bit = INPUT_MOD_RSHIFT; break;
|
||||
case INPUT_KEY_LEFT_CTRL: bit = INPUT_MOD_LCTRL; break;
|
||||
case INPUT_KEY_RIGHT_CTRL: bit = INPUT_MOD_RCTRL; break;
|
||||
case INPUT_KEY_LEFT_ALT: bit = INPUT_MOD_LALT; break;
|
||||
case INPUT_KEY_RIGHT_ALT: bit = INPUT_MOD_RALT; break;
|
||||
case INPUT_KEY_LEFT_GUI: bit = INPUT_MOD_LGUI; break;
|
||||
case INPUT_KEY_RIGHT_GUI: bit = INPUT_MOD_RGUI; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (bit) {
|
||||
if (pressed) context->Modifiers |= bit;
|
||||
else context->Modifiers &= ~bit;
|
||||
}
|
||||
|
||||
if (pressed && key == INPUT_KEY_CAPS_LOCK) context->Modifiers ^= INPUT_MOD_CAPS_LOCK;
|
||||
if (pressed && key == INPUT_KEY_NUM_LOCK) context->Modifiers ^= INPUT_MOD_NUM_LOCK;
|
||||
}
|
||||
|
||||
// Implements the input Key To Char operation.
|
||||
static char KiInputKeyToChar(KE_INPUT_CONTEXT* context, INPUT_KEY key) {
|
||||
if (key >= INPUT_KEY_A && key <= INPUT_KEY_Z) {
|
||||
bool shifted = (context->Modifiers & INPUT_MOD_SHIFT) != 0;
|
||||
bool caps = (context->Modifiers & INPUT_MOD_CAPS_LOCK) != 0;
|
||||
char c = (char)('a' + (key - INPUT_KEY_A));
|
||||
if (shifted ^ caps) c = (char)(c - 'a' + 'A');
|
||||
return c;
|
||||
}
|
||||
|
||||
bool shifted = (context->Modifiers & INPUT_MOD_SHIFT) != 0;
|
||||
for (size_t i = 0; i < sizeof(gCharMap) / sizeof(gCharMap[0]); i++) {
|
||||
if (gCharMap[i].key == key)
|
||||
return shifted ? gCharMap[i].shifted : gCharMap[i].normal;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the input Initialize operation.
|
||||
void KeInputInitialize(const HAL_API* hal) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
ObInitializeObjectHeader(&gInputManager.Header, ObjectTypeInputManager);
|
||||
context->Hal = hal;
|
||||
memset((void*)context->KeyDown, 0, sizeof(context->KeyDown));
|
||||
context->Modifiers = 0;
|
||||
context->Generation = 0;
|
||||
context->KeyHead = context->KeyTail = 0;
|
||||
context->RepeatKey = INPUT_KEY_NONE;
|
||||
context->RepeatNextTick = 0;
|
||||
context->MouseHead = context->MouseTail = 0;
|
||||
context->ManagerHead = context->ManagerTail = 0;
|
||||
context->ManagerSequence = 0;
|
||||
context->MouseBoundsWidth = 1920;
|
||||
context->MouseBoundsHeight = 1080;
|
||||
context->MouseWheel = 0;
|
||||
context->MouseButtons = 0;
|
||||
KeInitializeDpc(&context->RepeatDpc, KiInputRepeatDpcRoutine, context);
|
||||
|
||||
if (!context->WaitEvent) {
|
||||
KSTATUS s = KeEventCreate(EventManualReset, 0, &context->WaitEvent);
|
||||
if (!KSUCCESS(s))
|
||||
DbgPrint("Input: keyboard wait event create failed st=0x%x\n", s);
|
||||
}
|
||||
if (!context->ManagerWaitEvent) {
|
||||
KSTATUS s = KeEventCreate(EventManualReset, 0, &context->ManagerWaitEvent);
|
||||
if (!KSUCCESS(s))
|
||||
DbgPrint("Input: manager wait event create failed st=0x%x\n", s);
|
||||
}
|
||||
KiInputRefreshKeyboardEvent(context);
|
||||
KiInputRefreshManagerEvent(context);
|
||||
|
||||
int w = 1920, h = 1080;
|
||||
int32_t w = 1920, h = 1080;
|
||||
DISPLAY_MODE mode;
|
||||
if (KSUCCESS(KeDisplayGetMode(&mode))) {
|
||||
w = (int)mode.Width;
|
||||
@@ -332,43 +130,19 @@ __declspec(dllexport) void KeInputSubmitKey(const INPUT_KEY_EVENT* event) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (!event) return;
|
||||
INPUT_KEY key = event->Key;
|
||||
if (key == INPUT_KEY_NONE || key >= MAX_INPUT_KEYS) return;
|
||||
if (key == INPUT_KEY_NONE || key >= 256u) return;
|
||||
|
||||
KE_INPUT_MANAGER_EVENT managerEvent;
|
||||
memset(&managerEvent, 0, sizeof(managerEvent));
|
||||
// Forward physical transitions without interpreting key state or repeat policy.
|
||||
KE_INPUT_MANAGER_EVENT managerEvent = {0};
|
||||
managerEvent.Type = SYS_INPUT_MANAGER_EVENT_KEY;
|
||||
managerEvent.Data.Key = *event;
|
||||
KiInputQueueManagerEvent(context, &managerEvent);
|
||||
|
||||
bool wasDown = context->KeyDown[key] != 0;
|
||||
bool pressed = event->Pressed;
|
||||
|
||||
if (pressed) {
|
||||
// The input core owns typematic repeat. Treat repeated hardware make
|
||||
// events as idempotent so PS/2 typematic and USB HID share one policy.
|
||||
if (wasDown)
|
||||
return;
|
||||
|
||||
context->KeyDown[key] = 1u;
|
||||
KiInputSetModifier(context, key, true);
|
||||
KiInputBumpGeneration(context);
|
||||
KiInputQueueKey(context, key, KiInputKeyToChar(context, key));
|
||||
KiInputStartRepeat(context, key, KiInputNowTicks(context));
|
||||
} else {
|
||||
if (!wasDown)
|
||||
return;
|
||||
|
||||
context->KeyDown[key] = 0u;
|
||||
KiInputSetModifier(context, key, false);
|
||||
KiInputBumpGeneration(context);
|
||||
KiInputStopRepeat(context, key);
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the input Commit Mouse Position operation.
|
||||
static bool KiInputCommitMousePosition(KE_INPUT_CONTEXT* context, int nx, int ny, uint8_t buttons) {
|
||||
int bw = context->MouseBoundsWidth;
|
||||
int bh = context->MouseBoundsHeight;
|
||||
static void KiInputCommitMousePosition(KE_INPUT_CONTEXT* context, int32_t nx, int32_t ny) {
|
||||
int32_t bw = context->MouseBoundsWidth;
|
||||
int32_t bh = context->MouseBoundsHeight;
|
||||
|
||||
if (bw < 1) bw = 1;
|
||||
if (bh < 1) bh = 1;
|
||||
@@ -377,11 +151,8 @@ static bool KiInputCommitMousePosition(KE_INPUT_CONTEXT* context, int nx, int ny
|
||||
if (nx >= bw) nx = bw - 1;
|
||||
if (ny >= bh) ny = bh - 1;
|
||||
|
||||
bool changed = (nx != context->MouseX) || (ny != context->MouseY) || (buttons != context->MouseButtons);
|
||||
context->MouseX = nx;
|
||||
context->MouseY = ny;
|
||||
context->MouseButtons = buttons;
|
||||
return changed;
|
||||
}
|
||||
|
||||
// Implements the input Submit Mouse operation.
|
||||
@@ -395,23 +166,12 @@ __declspec(dllexport) void KeInputSubmitMouse(const INPUT_MOUSE_EVENT* event) {
|
||||
managerEvent.Data.Mouse = *event;
|
||||
KiInputQueueManagerEvent(context, &managerEvent);
|
||||
|
||||
int oldX = context->MouseX;
|
||||
int oldY = context->MouseY;
|
||||
int nx = oldX + event->dx;
|
||||
int ny = oldY + event->dy;
|
||||
int32_t oldX = context->MouseX;
|
||||
int32_t oldY = context->MouseY;
|
||||
int32_t nx = oldX + event->dx;
|
||||
int32_t ny = oldY + event->dy;
|
||||
|
||||
bool changed = KiInputCommitMousePosition(context, nx, ny, event->buttons);
|
||||
if (event->wheel != 0) {
|
||||
context->MouseWheel += event->wheel;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) KiInputBumpGeneration(context);
|
||||
|
||||
int next = (context->MouseTail + 1) & (int)MOUSE_QUEUE_MASK;
|
||||
if (next != context->MouseHead) {
|
||||
context->MouseQueue[context->MouseTail] = *event;
|
||||
context->MouseTail = next;
|
||||
}
|
||||
KiInputCommitMousePosition(context, nx, ny);
|
||||
}
|
||||
|
||||
// Implements the input Submit Mouse Absolute operation.
|
||||
@@ -419,8 +179,8 @@ __declspec(dllexport) void KeInputSubmitMouseAbsolute(const INPUT_MOUSE_ABSOLUTE
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (!event) return;
|
||||
|
||||
int oldX = context->MouseX;
|
||||
int oldY = context->MouseY;
|
||||
int32_t oldX = context->MouseX;
|
||||
int32_t oldY = context->MouseY;
|
||||
|
||||
INPUT_MOUSE_EVENT managerMouse;
|
||||
managerMouse.dx = event->x - oldX;
|
||||
@@ -433,213 +193,42 @@ __declspec(dllexport) void KeInputSubmitMouseAbsolute(const INPUT_MOUSE_ABSOLUTE
|
||||
managerEvent.Data.Mouse = managerMouse;
|
||||
KiInputQueueManagerEvent(context, &managerEvent);
|
||||
|
||||
bool changed = KiInputCommitMousePosition(context, event->x, event->y, event->buttons);
|
||||
if (event->wheel != 0) {
|
||||
context->MouseWheel += event->wheel;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) KiInputBumpGeneration(context);
|
||||
|
||||
INPUT_MOUSE_EVENT rel;
|
||||
rel.dx = context->MouseX - oldX;
|
||||
rel.dy = context->MouseY - oldY;
|
||||
rel.wheel = event->wheel;
|
||||
rel.buttons = event->buttons;
|
||||
|
||||
int next = (context->MouseTail + 1) & (int)MOUSE_QUEUE_MASK;
|
||||
if (next != context->MouseHead) {
|
||||
context->MouseQueue[context->MouseTail] = rel;
|
||||
context->MouseTail = next;
|
||||
}
|
||||
KiInputCommitMousePosition(context, event->x, event->y);
|
||||
}
|
||||
|
||||
// Implements the input Submit Mouse Absolute Scaled operation.
|
||||
__declspec(dllexport) void KeInputSubmitMouseAbsoluteScaled(uint32_t rawX, uint32_t rawY, uint32_t maxX, uint32_t maxY, int wheel, uint8_t buttons) {
|
||||
__declspec(dllexport) void KeInputSubmitMouseAbsoluteScaled(uint32_t rawX, uint32_t rawY, uint32_t maxX, uint32_t maxY, int32_t wheel, uint8_t buttons) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
int bw = context->MouseBoundsWidth;
|
||||
int bh = context->MouseBoundsHeight;
|
||||
int32_t bw = context->MouseBoundsWidth;
|
||||
int32_t bh = context->MouseBoundsHeight;
|
||||
if (bw < 1) bw = 1;
|
||||
if (bh < 1) bh = 1;
|
||||
|
||||
INPUT_MOUSE_ABSOLUTE_EVENT ev;
|
||||
ev.x = maxX ? (int)(((uint64_t)rawX * (uint64_t)(bw - 1)) / (uint64_t)maxX) : 0;
|
||||
ev.y = maxY ? (int)(((uint64_t)rawY * (uint64_t)(bh - 1)) / (uint64_t)maxY) : 0;
|
||||
ev.x = maxX ? (int32_t)(((uint64_t)rawX * (uint64_t)(bw - 1)) / (uint64_t)maxX) : 0;
|
||||
ev.y = maxY ? (int32_t)(((uint64_t)rawY * (uint64_t)(bh - 1)) / (uint64_t)maxY) : 0;
|
||||
ev.wheel = wheel;
|
||||
ev.buttons = buttons;
|
||||
KeInputSubmitMouseAbsolute(&ev);
|
||||
}
|
||||
|
||||
// Returns the next queued key without consuming it.
|
||||
INPUT_KEY KeInputKbPoll(void) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (context->KeyHead == context->KeyTail) KiInputServiceRepeat(context);
|
||||
return (context->KeyHead == context->KeyTail) ? INPUT_KEY_NONE : context->KeyQueue[context->KeyHead].Key;
|
||||
}
|
||||
|
||||
// Waits for keyboard input in one context or until the timeout expires.
|
||||
static KSTATUS KiInputWaitKey(KE_INPUT_CONTEXT* context, uint8_t alertable, uint64_t timeoutMs) {
|
||||
if (!context)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KiInputServiceRepeat(context);
|
||||
if (context->KeyHead != context->KeyTail)
|
||||
return NTLSTATUS_SUCCESS;
|
||||
if (!context->WaitEvent)
|
||||
return NTLSTATUS_FAILURE;
|
||||
|
||||
while (true) {
|
||||
EVENT* event = context->WaitEvent;
|
||||
uint32_t selected = 0;
|
||||
KSTATUS s = KeWaitForMultipleEvents(&event, 1, alertable, timeoutMs, &selected);
|
||||
if (!KSUCCESS(s))
|
||||
return s;
|
||||
|
||||
KiInputServiceRepeat(context);
|
||||
if (context->KeyHead != context->KeyTail)
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Waits for keyboard input in the default input context.
|
||||
KSTATUS KeInputWaitKey(uint8_t alertable, uint64_t timeoutMs) {
|
||||
return KiInputWaitKey(&gDefaultInputContext, alertable, timeoutMs);
|
||||
}
|
||||
|
||||
// Services typematic repeat from the scheduler timer bottom half.
|
||||
void KeInputTimerTick(void) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
INPUT_KEY key = context->RepeatKey;
|
||||
if (!KiInputKeyIsRepeatable(key) || key >= MAX_INPUT_KEYS || !context->KeyDown[key])
|
||||
return;
|
||||
|
||||
uint64_t now = KiInputNowTicks(context);
|
||||
if (now != 0 && now >= context->RepeatNextTick)
|
||||
KeInsertQueueDpc(&context->RepeatDpc, (void*)0, (void*)0);
|
||||
}
|
||||
|
||||
// Implements the input Is Key Down operation.
|
||||
bool KeInputIsKeyDown(INPUT_KEY key) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (key == INPUT_KEY_NONE || key >= MAX_INPUT_KEYS) return false;
|
||||
return context->KeyDown[key] != 0;
|
||||
}
|
||||
|
||||
// Peeks one keyboard event from an input context without consuming it.
|
||||
static bool KiInputPeekEvent(KE_INPUT_CONTEXT* context, INPUT_KEY_RECORD* record) {
|
||||
if (!context || !record) return false;
|
||||
if (context->KeyHead == context->KeyTail) KiInputServiceRepeat(context);
|
||||
if (context->KeyHead == context->KeyTail) return false;
|
||||
|
||||
INPUT_KEY_QUEUE_ENTRY entry = context->KeyQueue[context->KeyHead];
|
||||
record->Key = entry.Key;
|
||||
record->Char = entry.Character;
|
||||
record->Modifiers = entry.Modifiers;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads one keyboard event from an input context.
|
||||
static bool KiInputReadEvent(KE_INPUT_CONTEXT* context, INPUT_KEY_RECORD* record) {
|
||||
if (!KiInputPeekEvent(context, record)) return false;
|
||||
context->KeyHead = (context->KeyHead + 1) & (int)KEY_QUEUE_MASK;
|
||||
KiInputRefreshKeyboardEvent(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Peeks one keyboard event from the default input context.
|
||||
bool KeInputPeekEvent(INPUT_KEY_RECORD* record) {
|
||||
return KiInputPeekEvent(&gDefaultInputContext, record);
|
||||
}
|
||||
|
||||
// Reads one keyboard event from the default input context.
|
||||
bool KeInputReadEvent(INPUT_KEY_RECORD* record) {
|
||||
return KiInputReadEvent(&gDefaultInputContext, record);
|
||||
}
|
||||
|
||||
// Implements the input Read Key operation.
|
||||
INPUT_KEY KeInputReadKey(void) {
|
||||
INPUT_KEY_RECORD record;
|
||||
return KeInputReadEvent(&record) ? record.Key : INPUT_KEY_NONE;
|
||||
}
|
||||
|
||||
// Implements the input Read Char operation.
|
||||
char KeInputReadChar(void) {
|
||||
INPUT_KEY_RECORD record;
|
||||
return KeInputReadEvent(&record) ? record.Char : 0;
|
||||
}
|
||||
|
||||
// Implements the input Get Modifiers operation.
|
||||
uint32_t KeInputGetModifiers(void) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
return context->Modifiers;
|
||||
}
|
||||
|
||||
// Snapshots the current physical global input state without consuming events.
|
||||
KSTATUS KeInputQueryGlobalState(SYS_GLOBAL_INPUT_STATE* out) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (!out) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
out->Size = sizeof(*out);
|
||||
out->Flags = SYS_GLOBAL_INPUT_STATE_FLAG_NONE;
|
||||
out->Generation = (uint64_t)context->Generation;
|
||||
out->Modifiers = context->Modifiers;
|
||||
memset(out->KeyDown, 0, sizeof(out->KeyDown));
|
||||
|
||||
for (uint32_t key = 0; key < MAX_INPUT_KEYS; key++) {
|
||||
if (context->KeyDown[key])
|
||||
out->KeyDown[key >> 3] |= (uint8_t)(1u << (key & 7u));
|
||||
}
|
||||
|
||||
out->MouseX = context->MouseX;
|
||||
out->MouseY = context->MouseY;
|
||||
out->MouseWheel = context->MouseWheel;
|
||||
out->MouseButtons = context->MouseButtons;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the input Mouse Peek operation.
|
||||
bool KeInputMousePeek(INPUT_MOUSE_EVENT* event) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (!event) return false;
|
||||
if (context->MouseHead == context->MouseTail) return false;
|
||||
|
||||
*event = context->MouseQueue[context->MouseHead];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Implements the input Mouse Read operation.
|
||||
bool KeInputMouseRead(INPUT_MOUSE_EVENT* event) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (!KeInputMousePeek(event)) return false;
|
||||
context->MouseHead = (context->MouseHead + 1) & (int)MOUSE_QUEUE_MASK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Implements the input Mouse Get Position operation.
|
||||
void KeInputMouseGetPosition(int* x, int* y) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (x) *x = context->MouseX;
|
||||
if (y) *y = context->MouseY;
|
||||
}
|
||||
|
||||
// Implements the input Mouse Set Position operation.
|
||||
void KeInputMouseSetPosition(int x, int y) {
|
||||
void KeInputMouseSetPosition(int32_t x, int32_t y) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
int bw = context->MouseBoundsWidth;
|
||||
int bh = context->MouseBoundsHeight;
|
||||
int32_t bw = context->MouseBoundsWidth;
|
||||
int32_t bh = context->MouseBoundsHeight;
|
||||
if (bw < 1) bw = 1;
|
||||
if (bh < 1) bh = 1;
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
if (x >= bw) x = bw - 1;
|
||||
if (y >= bh) y = bh - 1;
|
||||
bool changed = (x != context->MouseX) || (y != context->MouseY);
|
||||
context->MouseX = x;
|
||||
context->MouseY = y;
|
||||
if (changed) KiInputBumpGeneration(context);
|
||||
}
|
||||
|
||||
// Implements the input Mouse Set Bounds operation.
|
||||
void KeInputMouseSetBounds(int w, int h) {
|
||||
void KeInputMouseSetBounds(int32_t w, int32_t h) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (w < 1) w = 1;
|
||||
if (h < 1) h = 1;
|
||||
@@ -647,51 +236,3 @@ void KeInputMouseSetBounds(int w, int h) {
|
||||
context->MouseBoundsHeight = h;
|
||||
KeInputMouseSetPosition(context->MouseX, context->MouseY);
|
||||
}
|
||||
|
||||
// Destroys an input queue handle.
|
||||
static void KiInputQueueDestroy(OBJECT* object) {
|
||||
INPUT_QUEUE* queue = CONTAINING_RECORD(object, INPUT_QUEUE, Header);
|
||||
if (queue->WaitEvent) {
|
||||
ObDereferenceObject(&queue->WaitEvent->Header);
|
||||
queue->WaitEvent = (EVENT*)0;
|
||||
}
|
||||
queue->Context = (KE_INPUT_CONTEXT*)0;
|
||||
}
|
||||
|
||||
// Opens the default keyboard input queue as a waitable object.
|
||||
KSTATUS KeInputOpenQueue(INPUT_QUEUE** out) {
|
||||
KE_INPUT_CONTEXT* context = &gDefaultInputContext;
|
||||
if (!out) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*out = (INPUT_QUEUE*)0;
|
||||
if (!context->WaitEvent) return NTLSTATUS_FAILURE;
|
||||
|
||||
INPUT_QUEUE* queue = (INPUT_QUEUE*)ObAllocateObject(ObjectTypeInputQueue, sizeof(INPUT_QUEUE));
|
||||
if (!queue) return NTLSTATUS_NO_MEMORY;
|
||||
queue->Header.Destroy = KiInputQueueDestroy;
|
||||
queue->Context = context;
|
||||
ObReferenceObject(&context->WaitEvent->Header);
|
||||
queue->WaitEvent = context->WaitEvent;
|
||||
*out = queue;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Peeks one keyboard event from the queue's owning context.
|
||||
bool KeInputQueuePeekEvent(INPUT_QUEUE* queue, INPUT_KEY_RECORD* record) {
|
||||
return queue ? KiInputPeekEvent(queue->Context, record) : false;
|
||||
}
|
||||
|
||||
// Reads one keyboard event from the queue's owning context.
|
||||
bool KeInputQueueReadEvent(INPUT_QUEUE* queue, INPUT_KEY_RECORD* record) {
|
||||
return queue ? KiInputReadEvent(queue->Context, record) : false;
|
||||
}
|
||||
|
||||
// Waits for keyboard input in the queue's owning context.
|
||||
KSTATUS KeInputQueueWaitKey(INPUT_QUEUE* queue, uint8_t alertable, uint64_t timeoutMs) {
|
||||
return queue ? KiInputWaitKey(queue->Context, alertable, timeoutMs)
|
||||
: NTLSTATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Returns the event that wakes when keyboard input can be read.
|
||||
EVENT* KeInputQueueWaitEvent(INPUT_QUEUE* queue) {
|
||||
return queue ? queue->WaitEvent : (EVENT*)0;
|
||||
}
|
||||
Reference in new issue
Block a user