You may find that you need granular control over blocking the users mouse or keyboard.

In this guide we’ll walk through implementing interacting with an in-game window via a particular key or mouse button, for example, the middle mouse click. You’ll want to follow this pattern if:

  • You want a window that is not interactive by default
  • You want the user to be able to opt-in to interacting with the window

Simple Approach

The easiest way to accomplish this is with the below code snippet.

class ScoreboardWindow {
	private browserWindow: RenderWindow | null = null;
	private overrides: InputOverrides;
	private boundMouseDown = this.onMouseDown.bind(this);

	public constructor() {
		this.browserWindow = overlay.windows.createWindow({
			// ...
		});

		// Setup our input scope, this makes input blocking multi-window compatibile.
		this.overrides = overlay.input.scope("ScoreboardWindow");
	}

	private onScoreboardWindowShow() {
		// Block the game from receiving middle mouse clicks
		this.overrides.setKeyInputBlock(0x04, true);
		// Make sure the cursor does not appear over the window
		this.overrides.setGlobalCursorOverride(false);
		// Listen to mouse down events while the window is open
		overlay.windows.on("mouseDown", this.boundMouseDown);
	}

	private onScoreboardWindowHide() {
		overlay.windows.off("mouseDown", this.boundMouseDown);
		this.resetOverrides();
	}

	private onMouseDown(event: MouseButtonEvent) {
		if (!this.browserWindow?.isVisible()) {
			return;
		}

		// If they click mouse1 and its not on the window
		// aka if they click outside the window
		// we should hide the window
		if (event.key === 0x01 && !event.window) {
			this.browserWindow?.hide();
			return;
		}

		// If they didn't click middle mouse button
		if (event.key !== 0x04) {
			return;
		}

		// Show the cursor
		this.overrides.setGlobalCursorOverride(true);
		// Block mouse input to the game
		this.overrides.setGlobalMouseBlock(true);
		// Allow interacting with the browser window
		this.browserWindow?.setCursorOverride(true);
	}

	// Its important to make sure to reset all blocks when appropraite
	private resetOverrides() {
		this.overrides.setKeyInputBlock(0x04, false);
		this.overrides.setGlobalCursorOverride(false);
		this.overrides.setGlobalMouseBlock(false);
		this.browserWindow?.setCursorOverride(false);
	}
}

Scope

The problem that the scope method solves is the following:

Imagine you have two windows that have opt-in interactivity. If you use the advanced API mentioned below to try and handle the blocking yourself:

  1. The user opens Window A
  2. The user clicks middle mouse to interact with Window A
  3. The user opens Window B, with Window A still open
  4. The user closes Window A
  5. Window A removes cursor blocking that it previously set
  6. Problem: Now the user cant properly interact with Window B

scope solves this by globally registering each scope, and not removing a given block until all scopes have removed it. This can of course be implemented on your own if you desire different functionality.

API Overview (Advanced)

Below is the raw API to manage input blocking, though we recommend using our scope helper in most cases. Internally, scope wraps these methods to provide the above behavior.

Global Mouse Block

The following allows you to block the game from receiving mouse input:

setGlobalMouseBlock(block: boolean): void;
getGlobalMouseBlock(): boolean;

Global Cursor Override

Force the cursor to be shown or hidden:

setGlobalCursorOverride(show: boolean): void;
getGlobalCursorOverride(): boolean;

Keyboard Block

Block the game from receiving keyboard input:

setGlobalKeyboardBlock(block: boolean): void;
getGlobalKeyboardBlock(): boolean;

Keyboard Input Block

Block the game from receiving input from a specific key:

setKeyInputBlock(key: VirtualKey, block: boolean): void;
getKeyInputBlock(key: VirtualKey): boolean;