Keyboard and mouse
Key codes are SDL scancodes (keyboard) or aqua.keys.MOUSE1..MOUSE5 (same encoding as C++ KeyState).
Constants: aqua.keys
Section titled “Constants: aqua.keys”Common entries: A–Z, N0–N9, F1–F12, TAB, ESC, SPACE, ENTER, INSERT, arrows, modifiers, MOUSE1..MOUSE5, MOUSE_BASE, UNBOUND.
| API | Description |
|---|---|
aqua.input.is_down(code) |
Held, raw - true even while the key is being typed into a chat/console box (false for UNBOUND) |
aqua.input.is_bind_down(code) |
Held and binds are live right now - is_down minus the typing case (false for UNBOUND) |
aqua.input.is_key_down(scancode) |
Keyboard held |
aqua.input.is_mouse_down(button) |
1 left, 2 middle, 3 right |
aqua.input.key_pressed(scancode) |
Rising edge this frame (sticky until end of stage 12) |
aqua.input.mouse_clicked(button) |
Rising edge this frame |
aqua.input.mouse() |
x, y, buttons - SDL coords + button bitmask |
aqua.input.wheel() |
Vertical wheel notches this frame (positive = up, 0 idle) |
aqua.input.key_name(code) |
Display label ("E", "MOUSE1", …) |
aqua.input.scoreboard_open() |
TAB held (same check as the built-in scoreboard) |
aqua.input.menu_open() |
aqua menu visible |
aqua.is_menu_open() |
alias of menu visible |
aqua.input.console_open() |
CS2’s own console is up. Read from a value sampled once per frame on the game thread, so it is safe from on_draw too |
aqua.input.binds_suppressed() |
True while a keypress is being typed rather than meant as a bind (console open, menu open, or any script lock) |
aqua.input.lock() |
Free OS cursor, disable relative mouse, block game mouse/keyboard (same capture path as the menu). Per-script; refcounted across scripts. |
aqua.input.unlock() |
Release this script’s lock. Menu open / other scripts may still capture. |
aqua.input.set_locked(bool) |
lock() if true, unlock() if false |
aqua.input.is_locked() |
Whether this script currently holds lock() |
aqua.input.is_capture_active() |
Game input is blocked right now (menu open or any script lock) |
local K = aqua.keys
function on_draw() if aqua.input.menu_open() then return end
if aqua.input.key_pressed(K.F6) then print("F6 pressed") end
if aqua.input.is_down(K.MOUSE1) then -- held end
if aqua.input.mouse_clicked(1) then local mx, my, buttons = aqua.input.mouse() print("click", mx, my) end
if aqua.input.scoreboard_open() and aqua.rate_limit("sb", 0.2) then -- inject panorama payload here endendRaw keys vs binds
Section titled “Raw keys vs binds”is_down / is_key_down / key_pressed are raw: they report the physical key, and they
cannot tell a bind from a key being typed into CS2’s console. That is deliberate - a script
asking for raw key state gets raw key state - but it means a script bind on T will also fire
while you type T into the console.
If your key is acting as a bind, use is_bind_down (or gate on binds_suppressed()), which
is dead while the console or the aqua menu owns the keyboard:
-- bind: must not fire while typing into the consoleif aqua.input.is_bind_down(cfg.key) then toggle_thing()end
-- equivalent, when you need the raw edge helpersif aqua.input.key_pressed(K.T) and not aqua.input.binds_suppressed() then toggle_thing()endThe console half comes from the engine itself (GameUIService_001::IsConsoleVisible), not from a
guess about focus, so it is exact rather than heuristic. Both are read from a value sampled once
per frame on the game thread, so calling them from on_draw is safe.
Wheel: latched for the whole FSN burst like the key/mouse edges, so every script sees
the same value from either callback and one script reading it does not starve another. It
is fed from every wheel event, blocked or not - a script cycling something with the
wheel needs it while the game owns input. The event still reaches the game, so a bare-wheel
binding shares the input with weapon switch; gate on a modifier (or aqua.input.lock()) if
that matters.
local steps = aqua.input.wheel()if steps ~= 0 and aqua.input.is_key_down(aqua.keys.LALT) then station = station + (steps > 0 and 1 or -1)endInput capture (lock / unlock)
Section titled “Input capture (lock / unlock)”Same mechanism the aqua menu uses when open:
- Show the free OS cursor and turn off window relative-mouse mode
- Drop mouse motion/buttons/wheel and keyboard/text events so the game does not see them
- Script-held locks are refcounted; STOP / unload auto-
unlocks that script - Opening the menu while locked keeps capture; closing the menu while still locked keeps capture
- INSERT still toggles the menu; it does not force-unlock scripts
- Does not open the aqua UI or claim menu click regions - only free cursor + block game input
- Scripts can still read
aqua.input.*/ draw overlays while locked
local locked = false
function on_frame_stage_notify(stage) if stage ~= 12 then return end if aqua.input.key_pressed(aqua.keys.F7) then locked = not locked aqua.input.set_locked(locked) print(locked and "input locked" or "input unlocked") endend
-- Always safe: unlock on stop is automatic, but you can unlock early:-- aqua.input.unlock()