Sunshine master
Self-hosted game stream host for Moonlight.
input.cpp File Reference

Definitions for input handling on Windows. More...

#include <Windows.h>
#include <cmath>
#include <thread>
#include <vector>
#include <ViGEm/Client.h>
#include "keylayout.h"
#include "misc.h"
#include "src/config.h"
#include "src/globals.h"
#include "src/logging.h"
#include "src/platform/common.h"
Include dependency graph for input.cpp:

Classes

struct  platf::client_input_raw_t
 Per-client inputtino devices for touch and pen input. More...
 
struct  platf::gamepad_context_t
 ViGEm target and report buffers for one virtual gamepad. More...
 
struct  platf::gp_touch_context_t
 Last touch coordinates reported by a virtual gamepad. More...
 
struct  platf::input_raw_t
 Global inputtino device handles shared by clients. More...
 
class  platf::vigem_t
 ViGEm client connection and virtual gamepad collection. More...
 

Macros

#define APPLY_CALIBRATION(val, bias, scale)
 Macro for APPLY CALIBRATION.
 
#define CALLBACK
 Windows callback calling convention marker.
 
#define DPS_TO_DS4_GYRO(x)
 Macro for DPS TO DS4 GYRO.
 
#define MPS2_TO_DS4_ACCEL(x)
 Macro for MPS2 TO DS4 ACCEL.
 

Typedefs

using platf::client_t = util::safe_ptr<_VIGEM_CLIENT_T, vigem_free>
 ViGEm client pointer released with vigem_free.
 
using platf::target_t = util::safe_ptr<_VIGEM_TARGET_T, vigem_target_free>
 ViGEm target pointer released with vigem_target_free.
 

Functions

void platf::abs_mouse (input_t &input, const touch_port_t &touch_port, float x, float y)
 Move the pointer to an absolute client-provided touch coordinate.
 
int platf::alloc_gamepad (input_t &input, const gamepad_id_t &id, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue)
 Create a new virtual gamepad.
 
std::unique_ptr< client_input_tplatf::allocate_client_input_context (input_t &input)
 Allocate a context to store per-client input data.
 
void platf::button_mouse (input_t &input, int button, bool release)
 Press or release a virtual mouse button.
 
void platf::cancel_all_active_touches (client_input_raw_t *raw)
 Cancels all active touches.
 
void platf::ds4_notify (client_t::pointer client, target_t::pointer target, std::uint8_t largeMotor, std::uint8_t smallMotor, DS4_LIGHTBAR_COLOR, void *userdata)
 Handle DualShock 4 virtual gamepad notification events.
 
void platf::ds4_update_ts_and_send (vigem_t *vigem, int nr)
 Sends DS4 input with updated timestamps and repeats to keep timestamp updated.
 
void platf::free_gamepad (input_t &input, int nr)
 Release gamepad resources.
 
void platf::freeInput (void *)
 Release a platform input backend created by input().
 
void platf::gamepad_battery (input_t &input, const gamepad_battery_t &battery)
 Send a gamepad battery event to the OS.
 
void platf::gamepad_motion (input_t &input, const gamepad_motion_t &motion)
 Send a gamepad motion event to the OS.
 
void platf::gamepad_touch (input_t &input, const gamepad_touch_t &touch)
 Send a gamepad touch event to the OS.
 
void platf::gamepad_update (input_t &input, int nr, const gamepad_state_t &gamepad_state)
 Submit updated Sunshine gamepad state to the virtual device.
 
platform_caps::caps_t platf::get_capabilities ()
 Get the supported platform capabilities to advertise to the client.
 
util::point_t platf::get_mouse_loc (input_t &input)
 Get the current mouse position on screen.
 
void platf::hscroll (input_t &input, int distance)
 Apply a horizontal scroll event to the virtual mouse.
 
bool platf::inject_synthetic_pointer_input (input_raw_t *input, HSYNTHETICPOINTERDEVICE device, const POINTER_TYPE_INFO *pointerInfo, UINT32 count)
 Calls InjectSyntheticPointerInput() and switches input desktops if required.
 
input_t platf::input ()
 Create the platform input backend for a stream.
 
void platf::keyboard_update (input_t &input, uint16_t modcode, bool release, uint8_t flags)
 Press or release a virtual keyboard key.
 
void platf::move_mouse (input_t &input, int deltaX, int deltaY)
 Move mouse using the backend coordinate system.
 
void platf::pen_update (client_input_t *input, const touch_port_t &touch_port, const pen_input_t &pen)
 Send a pen event to the OS.
 
void platf::perform_touch_compaction (client_input_raw_t *raw)
 Compacts the touch slots into a contiguous block and updates the active count.
 
POINTER_TYPE_INFO * platf::pointer_by_id (client_input_raw_t *raw, uint32_t pointerId, uint8_t eventType)
 Gets a pointer slot by client-relative pointer ID, claiming a new one if necessary.
 
void platf::populate_common_pointer_info (POINTER_INFO &pointerInfo, const touch_port_t &touchPort, uint8_t eventType, float x, float y)
 Populate common POINTER_INFO members shared between pen and touch events.
 
void platf::repeat_pen (client_input_raw_t *raw)
 Repeats the current pen state to avoid the interactions timing out.
 
void platf::repeat_touch (client_input_raw_t *raw)
 Repeats the current touch state to avoid the interactions timing out.
 
void platf::scroll (input_t &input, int distance)
 Apply a vertical scroll event to the virtual mouse.
 
void platf::send_input (INPUT &i)
 Calls SendInput() and switches input desktops if required.
 
std::vector< supported_gamepad_t > & platf::supported_gamepads (input_t *input)
 Gets the supported gamepads for this platform backend.
 
void platf::touch_update (client_input_t *input, const touch_port_t &touch_port, const touch_input_t &touch)
 Send a touch event to the OS.
 
void platf::unicode (input_t &input, char *utf8, int size)
 Submit UTF-8 text input to the keyboard backend.
 
void platf::x360_notify (client_t::pointer client, target_t::pointer target, std::uint8_t largeMotor, std::uint8_t smallMotor, std::uint8_t, void *userdata)
 Handle Xbox 360 virtual gamepad notification events.
 

Variables

thread_local HDESK platf::_lastKnownInputDesktop = nullptr
 Last known input desktop.
 
constexpr DS4_REPORT_EX platf::ds4_report_init_ex
 DS4 report init ex.
 
constexpr DS4_TOUCH platf::ds4_touch_unused
 DS4 touch unused.
 
constexpr float platf::EARTH_G = 9.80665f
 Meters per second squared represented by one gravity unit.
 
constexpr auto platf::EDGE_TRIGGERED_POINTER_FLAGS = POINTER_FLAG_DOWN | POINTER_FLAG_UP | POINTER_FLAG_CANCELED | POINTER_FLAG_UPDATE
 Protocol or platform constant for edge triggered pointer flags.
 
constexpr auto platf::ISPI_REPEAT_INTERVAL = 50ms
 Protocol or platform constant for ispi repeat interval.
 
constexpr touch_port_t platf::target_touch_port
 Target touch port.
 

Detailed Description

Definitions for input handling on Windows.

Macro Definition Documentation

◆ APPLY_CALIBRATION

#define APPLY_CALIBRATION ( val,
bias,
scale )
Value:
(int32_t) (((float) (val) + (bias)) / (scale))

Macro for APPLY CALIBRATION.

◆ DPS_TO_DS4_GYRO

#define DPS_TO_DS4_GYRO ( x)
Value:
(int32_t) ((x) * (1024 / 64))

Macro for DPS TO DS4 GYRO.

◆ MPS2_TO_DS4_ACCEL

#define MPS2_TO_DS4_ACCEL ( x)
Value:
(int32_t) (((x) / EARTH_G) * 8192)

Macro for MPS2 TO DS4 ACCEL.

Function Documentation

◆ abs_mouse()

void platf::abs_mouse ( input_t & input,
const touch_port_t & touch_port,
float x,
float y )

Move the pointer to an absolute client-provided touch coordinate.

Parameters
inputPlatform input backend that receives the event.
touch_portTouch coordinate bounds used for scaling.
xHorizontal absolute coordinate from the client.
yVertical absolute coordinate from the client.

◆ alloc_gamepad()

int platf::alloc_gamepad ( input_t & input,
const gamepad_id_t & id,
const gamepad_arrival_t & metadata,
feedback_queue_t feedback_queue )

Create a new virtual gamepad.

Parameters
inputThe global input context.
idThe gamepad ID.
metadataController metadata from client (empty if none provided).
feedback_queueThe queue for posting messages back to the client.
Returns
0 on success.

◆ allocate_client_input_context()

std::unique_ptr< client_input_t > platf::allocate_client_input_context ( input_t & input)

Allocate a context to store per-client input data.

Allocates a context to store per-client input data.

Parameters
inputThe global input context.
Returns
A unique pointer to a per-client input data context.

◆ button_mouse()

void platf::button_mouse ( input_t & input,
int button,
bool release )

Press or release a virtual mouse button.

Parameters
inputPlatform input backend that receives the event.
buttonMouse button identifier to press or release.
releaseWhether the key or button event is a release.

◆ cancel_all_active_touches()

void platf::cancel_all_active_touches ( client_input_raw_t * raw)

Cancels all active touches.

Parameters
rawThe raw client-specific input context.

◆ ds4_notify()

void platf::ds4_notify ( client_t::pointer client,
target_t::pointer target,
std::uint8_t largeMotor,
std::uint8_t smallMotor,
DS4_LIGHTBAR_COLOR led_color,
void * userdata )

Handle DualShock 4 virtual gamepad notification events.

Parameters
clientViGEm client.
targetViGEm target.
largeMotorLarge motor strength.
smallMotorSmall motor strength.
led_colorRequested lightbar color.
userdataUser data pointer.

◆ ds4_update_ts_and_send()

void platf::ds4_update_ts_and_send ( vigem_t * vigem,
int nr )

Sends DS4 input with updated timestamps and repeats to keep timestamp updated.

Some applications require updated timestamps values to register DS4 input.

Parameters
vigemThe global ViGEm context object.
nrThe global gamepad index.

◆ free_gamepad()

void platf::free_gamepad ( input_t & input,
int nr )

Release gamepad resources.

Parameters
inputPlatform input backend that receives the event.
nrController index assigned by the client.

◆ freeInput()

void platf::freeInput ( void * p)

Release a platform input backend created by input().

Parameters
pPointer passed to the deleter or conversion helper.

◆ gamepad_battery()

void platf::gamepad_battery ( input_t & input,
const gamepad_battery_t & battery )

Send a gamepad battery event to the OS.

Sends a gamepad battery event to the OS.

Parameters
inputThe global input context.
batteryThe battery event.

◆ gamepad_motion()

void platf::gamepad_motion ( input_t & input,
const gamepad_motion_t & motion )

Send a gamepad motion event to the OS.

Sends a gamepad motion event to the OS.

Parameters
inputThe global input context.
motionThe motion event.

◆ gamepad_touch()

void platf::gamepad_touch ( input_t & input,
const gamepad_touch_t & touch )

Send a gamepad touch event to the OS.

Sends a gamepad touch event to the OS.

Parameters
inputThe global input context.
touchThe touch event.

◆ gamepad_update()

void platf::gamepad_update ( input_t & input,
int nr,
const gamepad_state_t & gamepad_state )

Submit updated Sunshine gamepad state to the virtual device.

Parameters
inputThe input context.
nrThe gamepad index to update.
gamepad_stateThe gamepad button/axis state sent from the client.

◆ get_capabilities()

platform_caps::caps_t platf::get_capabilities ( )

Get the supported platform capabilities to advertise to the client.

Returns the supported platform capabilities to advertise to the client.

Returns
Capability flags.

◆ get_mouse_loc()

util::point_t platf::get_mouse_loc ( input_t & input)

Get the current mouse position on screen.

Parameters
inputThe input_t instance to use.
Returns
Screen coordinates of the mouse.

*Examples**

auto [x, y] = get_mouse_loc(input);

◆ hscroll()

void platf::hscroll ( input_t & input,
int distance )

Apply a horizontal scroll event to the virtual mouse.

Parameters
inputPlatform input backend that receives the event.
distanceHigh-resolution scroll distance reported by the client.

◆ inject_synthetic_pointer_input()

bool platf::inject_synthetic_pointer_input ( input_raw_t * input,
HSYNTHETICPOINTERDEVICE device,
const POINTER_TYPE_INFO * pointerInfo,
UINT32 count )

Calls InjectSyntheticPointerInput() and switches input desktops if required.

Must only be called if InjectSyntheticPointerInput() is available.

Parameters
inputThe global input context.
deviceThe synthetic pointer device handle.
pointerInfoAn array of POINTER_TYPE_INFO structs.
countThe number of elements in pointerInfo.
Returns
true if input was successfully injected.

◆ input()

input_t platf::input ( )

Create the platform input backend for a stream.

Returns
Platform-specific input backend for the active stream.

◆ keyboard_update()

void platf::keyboard_update ( input_t & input,
uint16_t modcode,
bool release,
uint8_t flags )

Press or release a virtual keyboard key.

Parameters
inputPlatform input backend that receives the event.
modcodeModifier key code to update.
releaseWhether the key or button event is a release.
flagsBit flags that modify the requested operation.

◆ move_mouse()

void platf::move_mouse ( input_t & input,
int deltaX,
int deltaY )

Move mouse using the backend coordinate system.

Parameters
inputPlatform input backend that receives the event.
deltaXDelta x.
deltaYDelta y.

◆ pen_update()

void platf::pen_update ( client_input_t * input,
const touch_port_t & touch_port,
const pen_input_t & pen )

Send a pen event to the OS.

Sends a pen event to the OS.

Parameters
inputThe client-specific input context.
touch_portThe current viewport for translating to screen coordinates.
penThe pen event.

◆ perform_touch_compaction()

void platf::perform_touch_compaction ( client_input_raw_t * raw)

Compacts the touch slots into a contiguous block and updates the active count.

Since this swaps entries around, all slot pointers/references are invalid after compaction.

Parameters
rawThe client-specific input context.

◆ pointer_by_id()

POINTER_TYPE_INFO * platf::pointer_by_id ( client_input_raw_t * raw,
uint32_t pointerId,
uint8_t eventType )

Gets a pointer slot by client-relative pointer ID, claiming a new one if necessary.

Parameters
rawThe raw client-specific input context.
pointerIdThe client's pointer ID.
eventTypeThe LI_TOUCH_EVENT value from the client.
Returns
A pointer to the slot entry.

◆ populate_common_pointer_info()

void platf::populate_common_pointer_info ( POINTER_INFO & pointerInfo,
const touch_port_t & touchPort,
uint8_t eventType,
float x,
float y )

Populate common POINTER_INFO members shared between pen and touch events.

Parameters
pointerInfoThe pointer info to populate.
touchPortThe current viewport for translating to screen coordinates.
eventTypeThe type of touch/pen event.
xThe normalized 0.0-1.0 X coordinate.
yThe normalized 0.0-1.0 Y coordinate.

◆ repeat_pen()

void platf::repeat_pen ( client_input_raw_t * raw)

Repeats the current pen state to avoid the interactions timing out.

Parameters
rawThe raw client-specific input context.

◆ repeat_touch()

void platf::repeat_touch ( client_input_raw_t * raw)

Repeats the current touch state to avoid the interactions timing out.

Parameters
rawThe raw client-specific input context.

◆ scroll()

void platf::scroll ( input_t & input,
int distance )

Apply a vertical scroll event to the virtual mouse.

Parameters
inputPlatform input backend that receives the event.
distanceHigh-resolution scroll distance reported by the client.

◆ send_input()

void platf::send_input ( INPUT & i)

Calls SendInput() and switches input desktops if required.

Parameters
iThe INPUT struct to send.

◆ supported_gamepads()

std::vector< supported_gamepad_t > & platf::supported_gamepads ( input_t * input)

Gets the supported gamepads for this platform backend.

This may be called prior to platf::input()!

Parameters
inputPointer to the platform's input_t or nullptr.
Returns
Vector of gamepad options and status.

◆ touch_update()

void platf::touch_update ( client_input_t * input,
const touch_port_t & touch_port,
const touch_input_t & touch )

Send a touch event to the OS.

Sends a touch event to the OS.

Parameters
inputThe client-specific input context.
touch_portThe current viewport for translating to screen coordinates.
touchThe touch event.

◆ unicode()

void platf::unicode ( input_t & input,
char * utf8,
int size )

Submit UTF-8 text input to the keyboard backend.

Parameters
inputPlatform input backend that receives the event.
utf8UTF-8 text submitted by the client.
sizeNumber of bytes or elements requested.

◆ x360_notify()

void platf::x360_notify ( client_t::pointer client,
target_t::pointer target,
std::uint8_t largeMotor,
std::uint8_t smallMotor,
std::uint8_t ,
void * userdata )

Handle Xbox 360 virtual gamepad notification events.

Parameters
clientViGEm client.
targetViGEm target.
largeMotorLarge motor strength.
smallMotorSmall motor strength.
userdataUser data pointer.

Variable Documentation

◆ ds4_report_init_ex

DS4_REPORT_EX platf::ds4_report_init_ex
constexpr
Initial value:
= {
{{.bThumbLX = 0x80,
.bThumbLY = 0x80,
.bThumbRX = 0x80,
.bThumbRY = 0x80,
.wButtons = DS4_BUTTON_DPAD_NONE,
.bSpecial = 0,
.bTriggerL = 0,
.bTriggerR = 0,
.wTimestamp = 0,
.bBatteryLvl = 0xFF,
.wGyroX = 0,
.wGyroY = 0,
.wGyroZ = 0,
.wAccelX = 0,
.wAccelY = 0,
.wAccelZ = 0,
._bUnknown1 = {0x00, 0x00, 0x00, 0x00, 0x00},
.bBatteryLvlSpecial = 0x1A,
._bUnknown2 = {0x00, 0x00},
.bTouchPacketsN = 1,
.sCurrentTouch = ds4_touch_unused,
.sPreviousTouch = {ds4_touch_unused, ds4_touch_unused}}}
}

DS4 report init ex.

◆ ds4_touch_unused

DS4_TOUCH platf::ds4_touch_unused
constexpr
Initial value:
= {
.bPacketCounter = 0,
.bIsUpTrackingNum1 = 0x80,
.bTouchData1 = {0x00, 0x00, 0x00},
.bIsUpTrackingNum2 = 0x80,
.bTouchData2 = {0x00, 0x00, 0x00},
}

DS4 touch unused.

◆ target_touch_port

touch_port_t platf::target_touch_port
constexpr
Initial value:
{
0,
0,
65535,
65535
}

Target touch port.