// Native logical-input client. RSSRV owns keyboard interpretation and pointer policy; this file speaks its Port protocol. #include #include #include #include #include #include static volatile long gDefaultInputSession; static KSTATUS NtlInputGetDefaultSession(SYS_HANDLE* sessionOut); // Connects to the RSSRV listener published at /Services/Input. KSTATUS NtlInputConnect(SYS_HANDLE* sessionOut) { if (!sessionOut) return NTLSTATUS_INVALID_PARAMETER; *sessionOut = SYS_HANDLE_INVALID; SYS_HANDLE resourceSession = SYS_HANDLE_INVALID; KSTATUS status = NtlResourceConnect(&resourceSession); if (!KSUCCESS(status)) return status; SYS_HANDLE listener = SYS_HANDLE_INVALID; status = NtlResourceLookup(resourceSession, SysSvFromCstr(NTL_INPUT_SERVICE_PATH), SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT, &listener); (void)NtlResourceClose(resourceSession); if (!KSUCCESS(status)) return status; status = NtlResourceConnectListener(listener, sessionOut); (void)SysCloseHandle(listener); return status; } // Disconnects one logical-input session. KSTATUS NtlInputClose(SYS_HANDLE session) { if (session == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER; (void)SysDisconnectPort(session); return SysCloseHandle(session); } // Executes one fixed input-service request and validates its reply envelope. static KSTATUS NtlInputCall(SYS_HANDLE session, uint32_t operation, uint64_t timeoutMilliseconds, NTL_INPUT_REPLY* replyOut) { if (session == SYS_HANDLE_INVALID || !replyOut) return NTLSTATUS_INVALID_PARAMETER; NTL_INPUT_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_INPUT_PROTOCOL_VERSION; request.Operation = operation; request.Flags = NTL_INPUT_FLAG_NONE; request.TimeoutMilliseconds = timeoutMilliseconds; NTL_INPUT_REPLY reply; memset(&reply, 0, sizeof(reply)); SYS_PORT_MESSAGE_INFO info; memset(&info, 0, sizeof(info)); info.Size = sizeof(info); SYS_CALL_PORT_REQUEST call; memset(&call, 0, sizeof(call)); call.Size = sizeof(call); call.EndpointHandle = session; call.Flags = SYS_PORT_FLAG_NONE; call.RequestPayload = &request; call.RequestLength = sizeof(request); call.ReplyPayload = &reply; call.ReplyCapacity = sizeof(reply); call.ReplyInfoOut = &info; call.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; KSTATUS status = SysCallPort(&call); if (!KSUCCESS(status)) return status; if (info.Type != SYS_PORT_MESSAGE_REPLY || info.PayloadLength != sizeof(reply) || info.HandleCount != 0 || reply.Size != sizeof(reply) || reply.Version != NTL_INPUT_PROTOCOL_VERSION || reply.Operation != operation || reply.Flags != NTL_INPUT_FLAG_NONE) return NTLSTATUS_FAILURE; *replyOut = reply; return reply.Status; } // Reads one logical keyboard event. KSTATUS NtlInputReadEvent(SYS_HANDLE session, uint64_t timeoutMilliseconds, INPUT_KEY_RECORD* recordOut) { if (!recordOut) return NTLSTATUS_INVALID_PARAMETER; if (session == SYS_HANDLE_INVALID) { KSTATUS connectStatus = NtlInputGetDefaultSession(&session); if (!KSUCCESS(connectStatus)) return connectStatus; } NTL_INPUT_REPLY reply; KSTATUS status = NtlInputCall(session, NTL_INPUT_OP_READ_KEY, timeoutMilliseconds, &reply); if (KSUCCESS(status)) *recordOut = reply.Key; return status; } // Peeks one logical keyboard event. KSTATUS NtlInputPeekEvent(SYS_HANDLE session, uint64_t timeoutMilliseconds, INPUT_KEY_RECORD* recordOut) { if (!recordOut) return NTLSTATUS_INVALID_PARAMETER; if (session == SYS_HANDLE_INVALID) { KSTATUS connectStatus = NtlInputGetDefaultSession(&session); if (!KSUCCESS(connectStatus)) return connectStatus; } NTL_INPUT_REPLY reply; KSTATUS status = NtlInputCall(session, NTL_INPUT_OP_PEEK_KEY, timeoutMilliseconds, &reply); if (KSUCCESS(status)) *recordOut = reply.Key; return status; } // Reads one logical mouse event. KSTATUS NtlInputReadMouse(SYS_HANDLE session, uint64_t timeoutMilliseconds, INPUT_MOUSE_EVENT* eventOut) { if (!eventOut) return NTLSTATUS_INVALID_PARAMETER; if (session == SYS_HANDLE_INVALID) { KSTATUS connectStatus = NtlInputGetDefaultSession(&session); if (!KSUCCESS(connectStatus)) return connectStatus; } NTL_INPUT_REPLY reply; KSTATUS status = NtlInputCall(session, NTL_INPUT_OP_READ_MOUSE, timeoutMilliseconds, &reply); if (KSUCCESS(status)) *eventOut = reply.Mouse; return status; } // Peeks one logical mouse event. KSTATUS NtlInputPeekMouse(SYS_HANDLE session, uint64_t timeoutMilliseconds, INPUT_MOUSE_EVENT* eventOut) { if (!eventOut) return NTLSTATUS_INVALID_PARAMETER; if (session == SYS_HANDLE_INVALID) { KSTATUS connectStatus = NtlInputGetDefaultSession(&session); if (!KSUCCESS(connectStatus)) return connectStatus; } NTL_INPUT_REPLY reply; KSTATUS status = NtlInputCall(session, NTL_INPUT_OP_PEEK_MOUSE, timeoutMilliseconds, &reply); if (KSUCCESS(status)) *eventOut = reply.Mouse; return status; } // Queries one RSSRV-owned logical input snapshot. KSTATUS NtlInputQueryState(SYS_HANDLE session, NTL_INPUT_STATE* stateOut) { if (!stateOut) return NTLSTATUS_INVALID_PARAMETER; if (session == SYS_HANDLE_INVALID) { KSTATUS connectStatus = NtlInputGetDefaultSession(&session); if (!KSUCCESS(connectStatus)) return connectStatus; } NTL_INPUT_REPLY reply; KSTATUS status = NtlInputCall(session, NTL_INPUT_OP_QUERY_STATE, 0, &reply); if (KSUCCESS(status)) *stateOut = reply.State; return status; } // Returns one process-local cached input session, connecting it on first use. static KSTATUS NtlInputGetDefaultSession(SYS_HANDLE* sessionOut) { if (!sessionOut) return NTLSTATUS_INVALID_PARAMETER; long current = gDefaultInputSession; if (current != 0) { *sessionOut = (SYS_HANDLE)(uint32_t)current; return NTLSTATUS_SUCCESS; } SYS_HANDLE created = SYS_HANDLE_INVALID; KSTATUS status = NtlInputConnect(&created); if (!KSUCCESS(status)) return status; long previous = _InterlockedCompareExchange(&gDefaultInputSession, (long)created, 0); if (previous != 0) { (void)NtlInputClose(created); created = (SYS_HANDLE)(uint32_t)previous; } *sessionOut = created; return NTLSTATUS_SUCCESS; } // Peeks the next logical key without consuming it. KSTATUS NtlInputPollKeyboard(INPUT_KEY* keyOut) { if (!keyOut) return NTLSTATUS_INVALID_PARAMETER; SYS_HANDLE session = SYS_HANDLE_INVALID; KSTATUS status = NtlInputGetDefaultSession(&session); if (!KSUCCESS(status)) return status; INPUT_KEY_RECORD record; status = NtlInputPeekEvent(session, 0, &record); if (KSUCCESS(status)) *keyOut = record.Key; return status; } // Queries one logical key's current down state. KSTATUS NtlInputIsKeyDown(INPUT_KEY key, bool* downOut) { if (!downOut || key == INPUT_KEY_NONE || key >= NTL_INPUT_KEY_BYTES * 8u) return NTLSTATUS_INVALID_PARAMETER; NTL_INPUT_STATE state; KSTATUS status = NtlInputQueryDefaultState(&state); if (!KSUCCESS(status)) return status; *downOut = (state.KeyDown[key >> 3] & (uint8_t)(1u << (key & 7u))) != 0; return NTLSTATUS_SUCCESS; } // Consumes logical key records until one has a character representation. KSTATUS NtlInputReadKeyboardChar(char* charOut) { if (!charOut) return NTLSTATUS_INVALID_PARAMETER; SYS_HANDLE session = SYS_HANDLE_INVALID; KSTATUS status = NtlInputGetDefaultSession(&session); if (!KSUCCESS(status)) return status; for (;;) { INPUT_KEY_RECORD record; status = NtlInputReadEvent(session, SYS_PORT_TIMEOUT_INFINITE, &record); if (!KSUCCESS(status)) return status; if (record.Char != 0) { *charOut = record.Char; return NTLSTATUS_SUCCESS; } } } // Reads one logical key. KSTATUS NtlInputReadKey(INPUT_KEY* keyOut) { if (!keyOut) return NTLSTATUS_INVALID_PARAMETER; SYS_HANDLE session = SYS_HANDLE_INVALID; KSTATUS status = NtlInputGetDefaultSession(&session); if (!KSUCCESS(status)) return status; INPUT_KEY_RECORD record; status = NtlInputReadEvent(session, SYS_PORT_TIMEOUT_INFINITE, &record); if (KSUCCESS(status)) *keyOut = record.Key; return status; } // Returns the current logical modifier mask, or zero if the service cannot be queried. uint32_t NtlInputGetKeyModifiers(void) { NTL_INPUT_STATE state; return KSUCCESS(NtlInputQueryDefaultState(&state)) ? state.Modifiers : 0u; } // Queries the process-default logical input session. KSTATUS NtlInputQueryDefaultState(NTL_INPUT_STATE* stateOut) { if (!stateOut) return NTLSTATUS_INVALID_PARAMETER; SYS_HANDLE session = SYS_HANDLE_INVALID; KSTATUS status = NtlInputGetDefaultSession(&session); if (!KSUCCESS(status)) return status; return NtlInputQueryState(session, stateOut); } // Returns the current RSSRV-owned logical pointer position. KSTATUS NtlInputGetMousePos(int* xOut, int* yOut) { if (!xOut || !yOut) return NTLSTATUS_INVALID_PARAMETER; NTL_INPUT_STATE state; KSTATUS status = NtlInputQueryDefaultState(&state); if (!KSUCCESS(status)) return status; *xOut = state.MouseX; *yOut = state.MouseY; return NTLSTATUS_SUCCESS; }