; Keyboard sampling never mutates simulation. Pending edges survive render-only ; frames and are cleared only by ConsumeInputEdges after one simulation tick. .code SampleHeld PROC uses ebx, first:DWORD, second:DWORD invoke GetAsyncKeyState, first mov ebx, eax cmp second, 0 je @F invoke GetAsyncKeyState, second or eax, ebx @@: shr eax, 15 and eax, 1 ret SampleHeld ENDP SampleEdge PROC uses ebx esi edi, first:DWORD, second:DWORD, held:DWORD, pending:DWORD invoke SampleHeld, first, second mov esi, held mov edi, pending test eax, eax jz edge_released cmp BYTE PTR [esi], 0 jne edge_done mov BYTE PTR [edi], 1 edge_released: mov [esi], al edge_done: ret SampleEdge ENDP ConsumeInputEdges PROC mov keyAction, 0 mov keyCutscene, 0 mov keySkipScene, 0 mov keyAttack, 0 mov keyRestart, 0 mov keyPause, 0 mov keyMap, 0 mov keyHud, 0 mov keyFlashlight, 0 mov keyLightMode, 0 mov keyWeapon1, 0 mov keyWeapon2, 0 mov keyWeapon3, 0 mov keyMenu1, 0 mov keyMenu2, 0 mov keyMenu3, 0 mov keyMenu4, 0 mov keyMenu5, 0 mov keyDismiss, 0 ret ConsumeInputEdges ENDP PollInput PROC uses eax ebx LOCAL regained:DWORD mov regained, 0 invoke GetForegroundWindow cmp eax, hEngineWnd je input_has_focus cmp inputFocused, 0 je @F mov clockReset, 1 @@: mov inputFocused, 0 call ConsumeInputEdges mov keyScreenshot, 0 mov keyForward, 0 mov keyBackward, 0 mov keyStrafeLeft, 0 mov keyStrafeRight, 0 mov keyTurnLeft, 0 mov keyTurnRight, 0 mov keyRun, 0 ; On regain, sample every physical latch but discard the resulting edges. ret input_has_focus: cmp inputFocused, 0 jne @F mov clockReset, 1 mov regained, 1 @@: mov inputFocused, 1 invoke SampleHeld, VK_KEY_W, VK_KEY_UP mov keyForward, al invoke SampleHeld, VK_KEY_S, VK_KEY_DOWN mov keyBackward, al invoke SampleHeld, VK_KEY_A, 0 mov keyStrafeLeft, al invoke SampleHeld, VK_KEY_D, 0 mov keyStrafeRight, al invoke SampleHeld, VK_KEY_LEFT, 0 mov keyTurnLeft, al invoke SampleHeld, VK_KEY_RIGHT, 0 mov keyTurnRight, al invoke SampleHeld, VK_KEY_SHIFT, 0 mov keyRun, al invoke SampleEdge, VK_KEY_E, VK_KEY_SPACE, OFFSET keyActionHeld, OFFSET keyAction invoke SampleEdge, VK_KEY_CONTROL, VK_LBUTTON, OFFSET keyAttackHeld, OFFSET keyAttack ; Separate Space latch prevents a second poll from re-emitting a pending edge. invoke SampleEdge, VK_KEY_SPACE, 0, OFFSET keySpaceAttackHeld, OFFSET keyAttack invoke SampleEdge, VK_KEY_R, 0, OFFSET keyRestartHeld, OFFSET keyRestart invoke SampleEdge, VK_KEY_C, 0, OFFSET keySceneHeld, OFFSET keyCutscene invoke SampleEdge, VK_KEY_TAB, 0, OFFSET keySkipHeld, OFFSET keySkipScene invoke SampleEdge, VK_KEY_M, 0, OFFSET keyMapHeld, OFFSET keyMap invoke SampleEdge, VK_KEY_F12, 0, OFFSET keyShotHeld, OFFSET keyScreenshot invoke SampleEdge, VK_KEY_F1, VK_KEY_H, OFFSET keyHudStyleHeld, OFFSET keyHud invoke SampleEdge, VK_KEY_F, 0, OFFSET keyFlashlightHeld, OFFSET keyFlashlight invoke SampleEdge, VK_KEY_L, 0, OFFSET keyLightModeHeld, OFFSET keyLightMode invoke SampleEdge, VK_KEY_ESCAPE, 0, OFFSET keyPauseHeld, OFFSET keyPause invoke SampleEdge, 13, 0, OFFSET keyDismissHeld, OFFSET keyDismiss invoke SampleEdge, VK_KEY_1, 0, OFFSET keyWeaponHeld1, OFFSET keyWeapon1 invoke SampleEdge, VK_KEY_2, 0, OFFSET keyWeaponHeld2, OFFSET keyWeapon2 invoke SampleEdge, VK_KEY_3, 0, OFFSET keyWeaponHeld3, OFFSET keyWeapon3 invoke SampleEdge, VK_KEY_1, 0, OFFSET keyMenuHeld1, OFFSET keyMenu1 invoke SampleEdge, VK_KEY_2, 0, OFFSET keyMenuHeld2, OFFSET keyMenu2 invoke SampleEdge, VK_KEY_3, 0, OFFSET keyMenuHeld3, OFFSET keyMenu3 invoke SampleEdge, VK_KEY_4, 0, OFFSET keyMenuHeld4, OFFSET keyMenu4 invoke SampleEdge, VK_KEY_5, 0, OFFSET keyMenuHeld5, OFFSET keyMenu5 cmp regained, 0 je input_sample_done call ConsumeInputEdges mov keyScreenshot, 0 input_sample_done: ret PollInput ENDP