This guide covers the block-while-open workflow. For the full input-blocking API (including granular per-key
control), see Blocking Input. For per-window input options, see Render
Windows.
How Input Blocking Works
Four things to know before writing any code:- The game keeps receiving input by default. Overlay windows render on top of the game, but they don’t steal input from it - the game still acts on every key press and mouse click unless you explicitly block it. Blocking is always opt-in.
- There are two levels of control. Each
RenderWindowhas its own input flags -hasInput,hasInputBlock, andhasCursorOverride, all enabled by default - that govern input on that window. Separately, the globaloverlay.inputmodule blocks input to the game as a whole: all mouse input, all keyboard input, or a single key, plus forcing the cursor to show. - Blocks are stateful and manual. Nothing releases a block when your window hides or closes. Every block you set stays active until you clear it yourself.
- Scopes make blocks safe across windows.
overlay.input.scope(name)returns a handle whose blocks are reference-counted: a block engages when the first scope sets it and releases only after every scope that set it has cleared it.
Blocking Input While a Window Is Open
Define the keybind and window
Set up a keybind and a hidden in-game window. This is the same wiring covered in Show/Hide Window
Keybinds, so we’ll keep it brief:
main.ts
notesWindow.ts
Create an input scope
Get a scoped handle for this window’s blocks. Even if you only have one window today, starting from a scope
means a second window can block input later without the two fighting over state:
notesWindow.ts
Full Block vs. Opt-In Interaction
Blocking everything while the window is visible is right for windows the user summons briefly. For windows that stay on screen (a scoreboard, a HUD), you usually want them passive by default with an opt-in gesture to interact.- Full block while visible
- Opt-in with a key
The pattern above: the window’s visibility and the input blocks toggle together. Use this when the window only
appears when the user wants to interact with it - settings panels, note editors, search boxes. The window is
interactive out of the box (
hasInput, hasInputBlock, and hasCursorOverride all default to true), so the
global blocks are the only extra wiring.Dismissing on Outside Clicks
While the mouse block is active, Overlayed still receives mouse events - only the game stops seeing them. That lets you close the panel when the user clicks anywhere outside it. OnmouseDown events, event.window is unset when the
click didn’t land on any overlay window:
notesWindow.ts
Sharing Blocks Across Windows
When several windows can block input, naive bookkeeping breaks: window A releases the cursor override on close, and suddenly window B - still open - loses its cursor. Scopes exist to prevent exactly this. Each block tracks which scopes hold it; the firstset*(true) engages it, and it only disengages when the last holder calls set*(false).
Give each window its own scope and have it set and release blocks as if it were alone - the reference counting
resolves the overlap.
The scope handle only has setters. To inspect the effective state actually applied to the game, use the raw getters:
FAQ
Do my keybinds still fire while keyboard input is blocked?
Do my keybinds still fire while keyboard input is blocked?
Yes. The blocking APIs stop the game from receiving input - they don’t stop Overlayed. Keybinds are captured
by Overlayed’s native keyboard hook rather than through the game, so the keybind that opened your window still
closes it while
setGlobalKeyboardBlock(true) is active. The mouse side works the same way: the Blocking
Input reference example listens for mouseDown events while the global mouse block
is engaged.What's the difference between a window's input block and the global blocks?
What's the difference between a window's input block and the global blocks?
The per-window
hasInputBlock option (and setInputBlock) blocks input on that window from passing through to
the game - it’s about interactions with the window itself. The global setGlobalKeyboardBlock and
setGlobalMouseBlock stop the game from receiving that kind of input entirely, whether or not it’s anywhere
near your window. Typing needs the global keyboard block: keystrokes aren’t “on” a window the way clicks are.What happens when two windows both block input?
What happens when two windows both block input?
If both use scopes, the block engages when the first scope sets it and releases only after both have cleared
it - closing one window never yanks input handling out from under the other. If you bypass scopes with
overlay.input.raw, the last write wins and you own the coordination problem.How do I check whether a block is currently active?
How do I check whether a block is currently active?
Scope handles are write-only. Read the effective state with the raw getters -
overlay.input.raw.getGlobalKeyboardBlock(),
getGlobalMouseBlock(), getGlobalCursorOverride(), and getKeyInputBlock(key). These report what is actually
applied to the game, regardless of which scope set it.Can I block the mouse but not the keyboard (or just one key)?
Can I block the mouse but not the keyboard (or just one key)?
Yes. The mouse block, keyboard block, cursor override, and per-key blocks are all independent - set any
combination.
setKeyInputBlock(key, true) blocks a single key while everything else flows to the game, which
is the basis of the opt-in interaction pattern above.Is anything released automatically when my window hides or closes?
Is anything released automatically when my window hides or closes?
No. Blocks set through
overlay.input are independent of window lifecycle - hiding, closing, or destroying the
window leaves them in place. Always release blocks in the same code path that hides the window. Since releasing
a block you never set is a no-op, resetting everything unconditionally is safe.The cursor doesn't show over my window - why?
The cursor doesn't show over my window - why?
There are two cursor knobs. The per-window override (
hasCursorOverride, on by default) forces the cursor to
show when it’s over the window. The global override - setGlobalCursorOverride(true) - forces the cursor
game-wide, which is what you want while an interactive panel is open so the user can see the pointer travel to
it. If the cursor isn’t appearing at all, set the global override.What key codes does setKeyInputBlock take?
What key codes does setKeyInputBlock take?
VirtualKey codes, exported from @overlayed/app. Note these are not the KeyboardEvent#code strings that
keybinds use - they’re numeric codes, like 0x01 for left mouse and 0x04 for middle mouse, as used in the
Blocking Input reference examples.Next Steps
Blocking Input Reference
The full input-blocking API: scopes, raw setters, and per-key blocks.
Render Windows
Per-window input, input block, and cursor override options.
Window Events
Global mouse, keyboard, and resolution events on the windows object.
Show/Hide Window Keybinds
Wire the keybind that summons the window you’re blocking input for.

