GameInput callbacks

While GameInput is primarily designed around a polling model, cases exist where it's best to notify applications asynchronously. To support this, the IGameInput interface exposes a few methods for registering callback functions that are invoked when certain events of interest occur.

Internally, GameInput serializes the dispatching of callbacks so that only one callback is executed at a time. GameInput guarantees that callbacks are dispatched in chronological order. These guarantees simplify the code that an application needs to write in its callback functions.

GameInput allows a maximum of 64 callbacks, regardless of type, to be registered at any time. Callbacks are dispatched from an internal worker thread in GameInput. For more information about how this works, along with options for manually scheduling this work, see GameInput work queues.

Device callbacks

Device callbacks provide a way for applications to know when input devices connect, disconnect, or change, as shown in the following syntax. Most commonly, this is used to detect when devices connect and disconnect, but other device events can also be of interest.

HRESULT RegisterDeviceCallback(
    _In_opt_ IGameInputDevice * device,
    _In_ GameInputKind inputKind,
    _In_opt_ void * context,
    _In_ GameInputDeviceCallback callbackFunc,
    _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken * callbackToken);

Device callbacks can be registered with optional filters. This includes filtering to devices that produce specific kinds of input, filtering to a specific device, or both. The callback receives a GameInputDeviceEvent value that indicates whether the device was connected or disconnected, or whether one of its properties—such as the keyboard layout, haptic information, or XInput index—was updated.

In addition to device events, the RegisterDeviceCallback method is used for device enumeration. When the callback is registered, it's called asynchronously with GameInputDeviceEventConnected for every matching device that's already connected, and then for subsequent events as they occur. Combining device enumeration with subsequent events into a single atomic operation avoids race conditions that many applications unintentionally suffer from in their input code.

Note

In GameInput v3 and earlier, RegisterDeviceCallback also takes statusFilter and enumerationKind parameters, and the callback receives the current and previous GameInputDeviceStatus values instead of a device event. The GameInputEnumerationKind parameter controls whether enumeration is performed, and whether it blocks. Keyboard layout changes and system button presses are reported through separate callbacks registered with RegisterKeyboardLayoutCallback and RegisterSystemButtonCallback. In GameInput v4, keyboard layout changes are reported as device events, and system buttons are reported as readings of kind GameInputKindSystemButton.

Reading callbacks

By reading callbacks, applications can be notified whenever new readings arrive in the input stream as shown in the following syntax. Although many applications will find that polling for input is better, situations exist where event-driven input might be preferable. For example, the main menu UI of a game might be better suited to event-based input. Another example is an input mapping UI that must wait for input after prompting the user for their selection.

HRESULT RegisterReadingCallback(
    _In_opt_ IGameInputDevice * device,
    _In_ GameInputKind inputKind,
    _In_ float analogThreshold,
    _In_opt_ void * context,
    _In_ GameInputReadingCallback callbackFunc,
    _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken * callbackToken);

Like device callbacks, reading callbacks can be registered with several optional filters. This is especially useful for reading callbacks, because applications might be interested in a specific subset of readings from the input stream. The RegisterReadingCallback method allows filtering to devices that produce specific kinds of input and/or filtering to a specific device's input.

Applications can also specify a filter for analog input values (such as the thumbsticks of a gamepad) that require some minimum amount of movement before the callback fires. This can drastically reduce the callback frequency when high-resolution analog state changes aren't required. A good example of this is the implementation of an input mapping UI when waiting for an input change after prompting the user for their selection.

Unregistering callbacks

After a callback is successfully registered, the application must guarantee that any resources that are required to execute the callback remain valid. This includes both resources that are consumed by the callback's code, as well as the callback function itself, for example, if the callback function is hosted in a DLL that the application loads and unloads on demand.

To safely reclaim these resources, an application must first unregister the callback by passing the token that was received from the Register*Callback method into the UnregisterCallback method. If the callback is being executed on another thread when this method is called, it blocks until the callback finishes executing. Callbacks must be unregistered eventually because only 64 callbacks are allowed at any time.

Starting with GameInput v4, UnregisterCallback can also be called from within a callback function, including the callback that's being unregistered. In this case, it doesn't block. The callback finishes its current invocation and isn't called again.

In GameInput v3 and earlier, a callback can't unregister itself from within its own callback function. Instead, call the StopCallback method, which ensures that the callback isn't called again without unregistering it, and then unregister the callback later from outside the callback.

Reference API documentation

See also

GameInput fundamentals

Advanced GameInput topics

Input API reference