Initial Xinput ISteamInput/ISteamController support.

This commit is contained in:
Mr_Goldberg 2019-09-10 14:54:54 -04:00
parent 4db580d945
commit 2af93427fe
No known key found for this signature in database
GPG key ID: 8597D87419DEF278
12 changed files with 1814 additions and 56 deletions

View file

@ -91,14 +91,62 @@ The default value is simply a number that represents the default value for the s
Support for CPY steam_api(64).dll cracks: See the build in the experimental folder.
Notes:
You must all be on the same LAN for it to work. This is an early work so a lot of games will likely not work.
You must all be on the same LAN for it to work.
IMPORTANT:
Do not run more than one steam game with the same appid at the same time on the same computer with my emu or there might be network issues (dedicated servers should be fine though).
Controller (Note: at the moment this feature is only enabled in the windows experimental builds):
SteamController/SteamInput support is limited to XInput controllers. If your controller is not XInput, there are many tools (at least for windows) that you can use to make it emulate an XInput one.
Steam uses things called action sets for controller configuration. An action set is a group of action names. Action names are bound to buttons, triggers or joysticks.
The emulator needs to know for each action set, which button is linked to which action name. Create a ACTION_SET_NAME.txt file in the steam_settings\controller folder for every action set the game uses.
To see an example for the game Crystar see: steam_settings.EXAMPLE\controller.EXAMPLE
In the action set txt files the format is:
For digital actions (buttons, on or off): ACTION_NAME=BUTTON_NAME
For analog actions (joysticks, triggers): ACTION_NAME=ANALOG_NAME=input source mode
Actions can be bound to more than one button by separating the buttons with , like this: ACTION_NAME=A,B
If you want to configure a game yourself, find the xbox360 or xbox one vdf file for the game and you should be able to figure things out.
For example to get the vdf file for the game Crystar: https://steamdb.info/app/981750/config/
If you look at: steamcontrollerconfigdetails, you will see something like: 1779660455/controller_type: controller_xbox360
1779660455 refers to a file id that you can dl using your favorite steam workshop downloader site.
The url would be: https://steamcommunity.com/sharedfiles/filedetails/?id=1779660455
Valid digital button names:
DUP
DDOWN
DLEFT
DRIGHT
START
BACK
LSTICK
RSTICK
LBUMPER
RBUMPER
A
B
X
Y
DLTRIGGER (emulated buttons, the joy ones are used by games in menus for example. When the game wants to know if the trigger is pressed without the intensity)
DRTRIGGER
DLJOYUP
DLJOYDOWN
DLJOYLEFT
DLJOYRIGHT
DRJOYUP
DRJOYDOWN
DRJOYLEFT
DRJOYRIGHT
Valid analog names:
LTRIGGER
RTRIGGER
LJOY
RJOY
List of valid steam languages:

View file

@ -4,13 +4,13 @@ call build_set_protobuf_directories.bat
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /I%PROTOBUF_X86_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD dll/*.cpp dll/*.cc detours/*.cpp "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /link /OUT:steam_api.dll
cl /LD /I%PROTOBUF_X86_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /link /OUT:steam_api.dll
cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:steamclient.dll
cl /LD steamnetworkingsockets.cpp /EHsc /MP12 /link /OUT:steamnetworkingsockets.dll
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /I%PROTOBUF_X64_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD dll/*.cpp dll/*.cc detours/*.cpp "%PROTOBUF_X64_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /link /OUT:steam_api64.dll
cl /LD /I%PROTOBUF_X64_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c "%PROTOBUF_X64_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /link /OUT:steam_api64.dll
cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:steamclient64.dll
cl /LD steamnetworkingsockets.cpp /EHsc /MP12 /link /OUT:steamnetworkingsockets64.dll

View file

@ -6,11 +6,11 @@ call build_set_protobuf_directories.bat
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG /I%PROTOBUF_X86_DIRECTORY%\include\ dll/*.cpp dll/*.cc detours/*.cpp "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental\steam_api.dll
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DNDEBUG /I%PROTOBUF_X86_DIRECTORY%\include\ dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental\steam_api.dll
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG steamclient.cpp /EHsc /MP12 /Ox /link /OUT:release\experimental\steamclient.dll
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG /I%PROTOBUF_X64_DIRECTORY%\include\ dll/*.cpp dll/*.cc detours/*.cpp "%PROTOBUF_X64_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental\steam_api64.dll
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DNDEBUG /I%PROTOBUF_X64_DIRECTORY%\include\ dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c "%PROTOBUF_X64_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental\steam_api64.dll
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG steamclient.cpp /EHsc /MP12 /Ox /link /OUT:release\experimental\steamclient64.dll
copy Readme_experimental.txt release\experimental\Readme.txt

599
controller/gamepad.c Normal file
View file

@ -0,0 +1,599 @@
/**
* Gamepad Input Library
* Sean Middleditch
* Copyright (C) 2010 Sean Middleditch
* LICENSE: MIT/X
*/
#include <math.h>
#include <string.h>
#include <errno.h>
#include <malloc.h>
#define GAMEPAD_EXPORT 1
#include "gamepad.h"
/* Platform-specific includes */
#if defined(_WIN32)
# define WIN32_LEAN_AND_MEAN 1
# undef UNICODE
# include "windows.h"
# include "xinput.h"
# pragma comment(lib, "xinput.lib")
#elif defined(__linux__)
# include <linux/joystick.h>
# include <stdio.h>
# include <fcntl.h>
# include <unistd.h>
# include <libudev.h>
#else
# error "Unknown platform in gamepad.c"
#endif
#define BUTTON_TO_FLAG(b) (1 << (b))
/* Axis information */
typedef struct GAMEPAD_AXIS GAMEPAD_AXIS;
struct GAMEPAD_AXIS {
int x, y;
float nx, ny;
float length;
float angle;
GAMEPAD_STICKDIR dirLast, dirCurrent;
};
/* Trigger value information */
typedef struct GAMEPAD_TRIGINFO GAMEPAD_TRIGINFO;
struct GAMEPAD_TRIGINFO {
int value;
float length;
GAMEPAD_BOOL pressedLast, pressedCurrent;
};
/* Structure for state of a particular gamepad */
typedef struct GAMEPAD_STATE GAMEPAD_STATE;
struct GAMEPAD_STATE {
GAMEPAD_AXIS stick[STICK_COUNT];
GAMEPAD_TRIGINFO trigger[TRIGGER_COUNT];
int bLast, bCurrent, flags;
#if defined(__linux__)
char* device;
int fd;
int effect;
#endif
};
/* State of the four gamepads */
static GAMEPAD_STATE STATE[4];
/* Note whether a gamepad is currently connected */
#define FLAG_CONNECTED (1<<0)
#define FLAG_RUMBLE (1<<1)
/* Prototypes for utility functions */
static void GamepadResetState (GAMEPAD_DEVICE gamepad);
static void GamepadUpdateCommon (void);
static void GamepadUpdateDevice (GAMEPAD_DEVICE gamepad);
static void GamepadUpdateStick (GAMEPAD_AXIS* axis, float deadzone);
static void GamepadUpdateTrigger (GAMEPAD_TRIGINFO* trig);
/* Various values of PI */
#define PI_1_4 0.78539816339744f
#define PI_1_2 1.57079632679489f
#define PI_3_4 2.35619449019234f
#define PI 3.14159265358979f
/* Platform-specific implementation code */
#if defined(_WIN32)
void GamepadInit(void) {
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
STATE[i].flags = 0;
}
}
void GamepadUpdate(void) {
GamepadUpdateCommon();
}
static void GamepadUpdateDevice(GAMEPAD_DEVICE gamepad) {
XINPUT_STATE xs;
if (XInputGetState(gamepad, &xs) == 0) {
/* reset if the device was not already connected */
if ((STATE[gamepad].flags & FLAG_CONNECTED) == 0) {
GamepadResetState(gamepad);
}
/* mark that we are connected w/ rumble support */
STATE[gamepad].flags |= FLAG_CONNECTED|FLAG_RUMBLE;
/* update state */
STATE[gamepad].bCurrent = xs.Gamepad.wButtons;
STATE[gamepad].trigger[TRIGGER_LEFT].value = xs.Gamepad.bLeftTrigger;
STATE[gamepad].trigger[TRIGGER_RIGHT].value = xs.Gamepad.bRightTrigger;
STATE[gamepad].stick[STICK_LEFT].x = xs.Gamepad.sThumbLX;
STATE[gamepad].stick[STICK_LEFT].y = xs.Gamepad.sThumbLY;
STATE[gamepad].stick[STICK_RIGHT].x = xs.Gamepad.sThumbRX;
STATE[gamepad].stick[STICK_RIGHT].y = xs.Gamepad.sThumbRY;
} else {
/* disconnected */
STATE[gamepad].flags &= ~FLAG_CONNECTED;
}
}
void GamepadShutdown(void) {
/* no Win32 shutdown required */
}
void GamepadSetRumble(GAMEPAD_DEVICE gamepad, float left, float right) {
if ((STATE[gamepad].flags & FLAG_RUMBLE) != 0) {
XINPUT_VIBRATION vib;
ZeroMemory(&vib, sizeof(vib));
vib.wLeftMotorSpeed = (WORD)(left * 65535);
vib.wRightMotorSpeed = (WORD)(right * 65535);
XInputSetState(gamepad, &vib);
}
}
#elif defined(__linux__)
/* UDev handles */
static struct udev* UDEV = NULL;
static struct udev_monitor* MON = NULL;
static void GamepadAddDevice(const char* devPath);
static void GamepadRemoveDevice(const char* devPath);
/* Helper to add a new device */
static void GamepadAddDevice(const char* devPath) {
int i;
/* try to find a free controller */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if ((STATE[i].flags & FLAG_CONNECTED) == 0) {
break;
}
}
if (i == GAMEPAD_COUNT) {
return;
}
/* copy the device path */
STATE[i].device = strdup(devPath);
if (STATE[i].device == NULL) {
return;
}
/* reset device state */
GamepadResetState((GAMEPAD_DEVICE)i);
/* attempt to open the device in read-write mode, which we need fo rumble */
STATE[i].fd = open(STATE[i].device, O_RDWR|O_NONBLOCK);
if (STATE[i].fd != -1) {
STATE[i].flags = FLAG_CONNECTED|FLAG_RUMBLE;
return;
}
/* attempt to open in read-only mode if access was denied */
if (errno == EACCES) {
STATE[i].fd = open(STATE[i].device, O_RDONLY|O_NONBLOCK);
if (STATE[i].fd != -1) {
STATE[i].flags = FLAG_CONNECTED;
return;
}
}
/* could not open the device at all */
free(STATE[i].device);
STATE[i].device = NULL;
}
/* Helper to remove a device */
static void GamepadRemoveDevice(const char* devPath) {
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if (STATE[i].device != NULL && strcmp(STATE[i].device, devPath) == 0) {
if (STATE[i].fd != -1) {
close(STATE[i].fd);
STATE[i].fd = -1;
}
free(STATE[i].device);
STATE[i].device = 0;
STATE[i].flags = 0;
break;
}
}
}
void GamepadInit(void) {
struct udev_list_entry* devices;
struct udev_list_entry* item;
struct udev_enumerate* enu;
int i;
/* initialize connection state */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
STATE[i].flags = 0;
STATE[i].fd = STATE[i].effect = -1;
}
/* open the udev handle */
UDEV = udev_new();
if (UDEV == NULL) {
/* FIXME: flag error? */
return;
}
/* open monitoring device (safe to fail) */
MON = udev_monitor_new_from_netlink(UDEV, "udev");
/* FIXME: flag error if hot-plugging can't be supported? */
if (MON != NULL) {
udev_monitor_enable_receiving(MON);
udev_monitor_filter_add_match_subsystem_devtype(MON, "input", NULL);
}
/* enumerate joypad devices */
enu = udev_enumerate_new(UDEV);
udev_enumerate_add_match_subsystem(enu, "input");
udev_enumerate_scan_devices(enu);
devices = udev_enumerate_get_list_entry(enu);
udev_list_entry_foreach(item, devices) {
const char* name;
const char* sysPath;
const char* devPath;
struct udev_device* dev;
name = udev_list_entry_get_name(item);
dev = udev_device_new_from_syspath(UDEV, name);
sysPath = udev_device_get_syspath(dev);
devPath = udev_device_get_devnode(dev);
if (sysPath != NULL && devPath != NULL && strstr(sysPath, "/js") != 0) {
GamepadAddDevice(devPath);
}
udev_device_unref(dev);
}
/* cleanup */
udev_enumerate_unref(enu);
}
void GamepadUpdate(void) {
if (MON != NULL) {
fd_set r;
struct timeval tv;
int fd = udev_monitor_get_fd(MON);
/* set up a poll on the udev device */
FD_ZERO(&r);
FD_SET(fd, &r);
tv.tv_sec = 0;
tv.tv_usec = 0;
select(fd + 1, &r, 0, 0, &tv);
/* test if we have a device change */
if (FD_ISSET(fd, &r)) {
struct udev_device* dev = udev_monitor_receive_device(MON);
if (dev) {
const char* devNode = udev_device_get_devnode(dev);
const char* sysPath = udev_device_get_syspath(dev);
const char* action = udev_device_get_action(dev);
sysPath = udev_device_get_syspath(dev);
action = udev_device_get_action(dev);
if (strstr(sysPath, "/js") != 0) {
if (strcmp(action, "remove") == 0) {
GamepadRemoveDevice(devNode);
} else if (strcmp(action, "add") == 0) {
GamepadAddDevice(devNode);
}
}
udev_device_unref(dev);
}
}
}
GamepadUpdateCommon();
}
static void GamepadUpdateDevice(GAMEPAD_DEVICE gamepad) {
if (STATE[gamepad].flags & FLAG_CONNECTED) {
struct js_event je;
while (read(STATE[gamepad].fd, &je, sizeof(je)) > 0) {
int button;
switch (je.type) {
case JS_EVENT_BUTTON:
/* determine which button the event is for */
switch (je.number) {
case 0: button = BUTTON_A; break;
case 1: button = BUTTON_B; break;
case 2: button = BUTTON_X; break;
case 3: button = BUTTON_Y; break;
case 4: button = BUTTON_LEFT_SHOULDER; break;
case 5: button = BUTTON_RIGHT_SHOULDER; break;
case 6: button = BUTTON_BACK; break;
case 7: button = BUTTON_START; break;
case 8: button = 0; break; /* XBOX button */
case 9: button = BUTTON_LEFT_THUMB; break;
case 10: button = BUTTON_RIGHT_THUMB; break;
default: button = 0; break;
}
/* set or unset the button */
if (je.value) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(button);
} else {
STATE[gamepad].bCurrent ^= BUTTON_TO_FLAG(button);
}
break;
case JS_EVENT_AXIS:
/* normalize and store the axis */
switch (je.number) {
case 0: STATE[gamepad].stick[STICK_LEFT].x = je.value; break;
case 1: STATE[gamepad].stick[STICK_LEFT].y = -je.value; break;
case 2: STATE[gamepad].trigger[TRIGGER_LEFT].value = (je.value + 32768) >> 8; break;
case 3: STATE[gamepad].stick[STICK_RIGHT].x = je.value; break;
case 4: STATE[gamepad].stick[STICK_RIGHT].y = -je.value; break;
case 5: STATE[gamepad].trigger[TRIGGER_RIGHT].value = (je.value + 32768) >> 8; break;
case 6:
if (je.value == -32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_LEFT);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_RIGHT);
} else if (je.value == 32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_RIGHT);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_LEFT);
} else {
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_LEFT) & ~BUTTON_TO_FLAG(BUTTON_DPAD_RIGHT);
}
break;
case 7:
if (je.value == -32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_UP);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_DOWN);
} else if (je.value == 32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_DOWN);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_UP);
} else {
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_UP) & ~BUTTON_TO_FLAG(BUTTON_DPAD_DOWN);
}
break;
default: break;
}
break;
default:
break;
}
}
}
}
void GamepadShutdown(void) {
int i;
/* cleanup udev */
udev_monitor_unref(MON);
udev_unref(UDEV);
/* cleanup devices */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if (STATE[i].device != NULL) {
free(STATE[i].device);
}
if (STATE[i].fd != -1) {
close(STATE[i].fd);
}
}
}
void GamepadSetRumble(GAMEPAD_DEVICE gamepad, float left, float right) {
if (STATE[gamepad].fd != -1) {
struct input_event play;
/* delete any existing effect */
if (STATE[gamepad].effect != -1) {
/* stop the effect */
play.type = EV_FF;
play.code = STATE[gamepad].effect;
play.value = 0;
write(STATE[gamepad].fd, (const void*)&play, sizeof(play));
/* delete the effect */
ioctl(STATE[gamepad].fd, EVIOCRMFF, STATE[gamepad].effect);
}
/* if rumble parameters are non-zero, start the new effect */
if (left != 0.f || right != 0.f) {
struct ff_effect ff;
/* define an effect for this rumble setting */
ff.type = FF_RUMBLE;
ff.id = -1;
ff.u.rumble.strong_magnitude = (unsigned short)(left * 65535);
ff.u.rumble.weak_magnitude = (unsigned short)(right * 65535);
ff.replay.length = 5;
ff.replay.delay = 0;
/* upload the effect */
if (ioctl(STATE[gamepad].fd, EVIOCSFF, &ff) != -1) {
STATE[gamepad].effect = ff.id;
}
/* play the effect */
play.type = EV_FF;
play.code = STATE[gamepad].effect;
play.value = 1;
write(STATE[gamepad].fd, (const void*)&play, sizeof(play));
}
}
}
#else /* !defined(_WIN32) && !defined(__linux__) */
# error "Unknown platform in gamepad.c"
#endif /* end of platform implementations */
GAMEPAD_BOOL GamepadIsConnected(GAMEPAD_DEVICE device) {
return (STATE[device].flags & FLAG_CONNECTED) != 0 ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonDown(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
return (STATE[device].bCurrent & BUTTON_TO_FLAG(button)) != 0 ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonTriggered(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
return ((STATE[device].bLast & BUTTON_TO_FLAG(button)) == 0 &&
(STATE[device].bCurrent & BUTTON_TO_FLAG(button)) != 0) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonReleased(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
return ((STATE[device].bCurrent & BUTTON_TO_FLAG(button)) == 0 &&
(STATE[device].bLast & BUTTON_TO_FLAG(button)) != 0) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
int GamepadTriggerValue(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return STATE[device].trigger[trigger].value;
}
float GamepadTriggerLength(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return STATE[device].trigger[trigger].length;
}
GAMEPAD_BOOL GamepadTriggerDown(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return STATE[device].trigger[trigger].pressedCurrent;
}
GAMEPAD_BOOL GamepadTriggerTriggered(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return (STATE[device].trigger[trigger].pressedCurrent &&
!STATE[device].trigger[trigger].pressedLast) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadTriggerReleased(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return (!STATE[device].trigger[trigger].pressedCurrent &&
STATE[device].trigger[trigger].pressedLast) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
void GamepadStickXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, int *outX, int *outY) {
*outX = STATE[device].stick[stick].x;
*outY = STATE[device].stick[stick].y;
}
float GamepadStickLength(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
return STATE[device].stick[stick].length;
}
void GamepadStickNormXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, float *outX, float *outY) {
*outX = STATE[device].stick[stick].nx;
*outY = STATE[device].stick[stick].ny;
}
float GamepadStickAngle(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
return STATE[device].stick[stick].angle;
}
GAMEPAD_STICKDIR GamepadStickDir(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
return STATE[device].stick[stick].dirCurrent;
}
GAMEPAD_BOOL GamepadStickDirTriggered(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, GAMEPAD_STICKDIR dir) {
return (STATE[device].stick[stick].dirCurrent == dir &&
STATE[device].stick[stick].dirCurrent != STATE[device].stick[stick].dirLast) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
/* initialize common gamepad state */
static void GamepadResetState(GAMEPAD_DEVICE gamepad) {
memset(STATE[gamepad].stick, 0, sizeof(STATE[gamepad].stick));
memset(STATE[gamepad].trigger, 0, sizeof(STATE[gamepad].trigger));
STATE[gamepad].bLast = STATE[gamepad].bCurrent = 0;
}
/* Update individual sticks */
static void GamepadUpdateCommon(void) {
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
/* store previous button state */
STATE[i].bLast = STATE[i].bCurrent;
/* per-platform update routines */
GamepadUpdateDevice((GAMEPAD_DEVICE)i);
/* calculate refined stick and trigger values */
if ((STATE[i].flags & FLAG_CONNECTED) != 0) {
GamepadUpdateStick(&STATE[i].stick[STICK_LEFT], GAMEPAD_DEADZONE_LEFT_STICK);
GamepadUpdateStick(&STATE[i].stick[STICK_RIGHT], GAMEPAD_DEADZONE_RIGHT_STICK);
GamepadUpdateTrigger(&STATE[i].trigger[TRIGGER_LEFT]);
GamepadUpdateTrigger(&STATE[i].trigger[TRIGGER_RIGHT]);
}
}
}
/* Update stick info */
static void GamepadUpdateStick(GAMEPAD_AXIS* axis, float deadzone) {
// determine magnitude of stick
axis->length = sqrtf((float)(axis->x*axis->x) + (float)(axis->y*axis->y));
if (axis->length > deadzone) {
// clamp length to maximum value
if (axis->length > 32767.0f) {
axis->length = 32767.0f;
}
// normalized X and Y values
axis->nx = axis->x / axis->length;
axis->ny = axis->y / axis->length;
// adjust length for deadzone and find normalized length
axis->length -= deadzone;
axis->length /= (32767.0f - deadzone);
// find angle of stick in radians
axis->angle = atan2f((float)axis->y, (float)axis->x);
} else {
axis->x = axis->y = 0;
axis->nx = axis->ny = 0.0f;
axis->length = axis->angle = 0.0f;
}
/* update the stick direction */
axis->dirLast = axis->dirCurrent;
axis->dirCurrent = STICKDIR_CENTER;
/* check direction to see if it's non-centered */
if (axis->length != 0.f) {
if (axis->angle >= PI_1_4 && axis->angle < PI_3_4) {
axis->dirCurrent = STICKDIR_UP;
} else if (axis->angle >= -PI_3_4 && axis->angle < -PI_1_4) {
axis->dirCurrent = STICKDIR_DOWN;
} else if (axis->angle >= PI_3_4 || axis->angle < -PI_3_4) {
axis->dirCurrent = STICKDIR_LEFT;
} else /* if (axis->angle < PI_1_4 && axis->angle >= -PI_1_4) */ {
axis->dirCurrent = STICKDIR_RIGHT;
}
}
}
/* Update trigger info */
static void GamepadUpdateTrigger(GAMEPAD_TRIGINFO* trig) {
trig->pressedLast = trig->pressedCurrent;
if (trig->value > GAMEPAD_DEADZONE_TRIGGER) {
trig->length = ((trig->value - GAMEPAD_DEADZONE_TRIGGER) / (255.0f - GAMEPAD_DEADZONE_TRIGGER));
trig->pressedCurrent = GAMEPAD_TRUE;
} else {
trig->value = 0;
trig->length = 0.0f;
trig->pressedCurrent = GAMEPAD_FALSE;
}
}

324
controller/gamepad.h Normal file
View file

@ -0,0 +1,324 @@
/**
* Gamepad Input Library
* Sean Middleditch <sean@middleditch.us>
* Copyright (C) 2010,2011 Sean Middleditch
* LICENSE: MIT/X
*/
#if !defined(GAMEPAD_H)
#define GAMEPAD_H 1
#if defined(__cplusplus)
extern "C" {
#endif
#define GAMEPAD_STATIC_LIB
#if defined(GAMEPAD_STATIC_LIB)
# define GAMEPAD_API
#else
# if defined(_WIN32)
# if defined(GAMEPAD_EXPORT)
# define GAMEPAD_API __declspec(dllexport)
# else
# define GAMEPAD_API __declspec(dllimport)
# endif
# elif defined(__GNUC__) && defined(GAMEPAD_EXPORT)
# define GAMEPAD_API __attribute__((visibility("default")))
# else
# define GAMEPAD_API extern
# endif
#endif
/**
* Enumeration of the possible devices.
*
* Only four devices are supported as this is the limit of Windows.
*/
enum GAMEPAD_DEVICE {
GAMEPAD_0 = 0, /**< First gamepad */
GAMEPAD_1 = 1, /**< Second gamepad */
GAMEPAD_2 = 2, /**< Third gamepad */
GAMEPAD_3 = 3, /**< Fourth gamepad */
GAMEPAD_COUNT /**< Maximum number of supported gamepads */
};
/**
* Enumeration of the possible buttons.
*/
enum GAMEPAD_BUTTON {
BUTTON_DPAD_UP = 0, /**< UP on the direction pad */
BUTTON_DPAD_DOWN = 1, /**< DOWN on the direction pad */
BUTTON_DPAD_LEFT = 2, /**< LEFT on the direction pad */
BUTTON_DPAD_RIGHT = 3, /**< RIGHT on the direction pad */
BUTTON_START = 4, /**< START button */
BUTTON_BACK = 5, /**< BACK button */
BUTTON_LEFT_THUMB = 6, /**< Left analog stick button */
BUTTON_RIGHT_THUMB = 7, /**< Right analog stick button */
BUTTON_LEFT_SHOULDER = 8, /**< Left bumper button */
BUTTON_RIGHT_SHOULDER = 9, /**< Right bumper button */
BUTTON_A = 12, /**< A button */
BUTTON_B = 13, /**< B button */
BUTTON_X = 14, /**< X button */
BUTTON_Y = 15, /**< Y button */
BUTTON_COUNT /**< Maximum number of supported buttons */
};
/**
* Enumeration of the possible pressure/trigger buttons.
*/
enum GAMEPAD_TRIGGER {
TRIGGER_LEFT = 0, /**< Left trigger */
TRIGGER_RIGHT = 1, /**< Right trigger */
TRIGGER_COUNT /**< Number of triggers */
};
/**
* Enumeration of the analog sticks.
*/
enum GAMEPAD_STICK {
STICK_LEFT = 0, /**< Left stick */
STICK_RIGHT = 1, /**< Right stick */
STICK_COUNT /**< Number of analog sticks */
};
/**
* Enumeration of main stick directions.
*
* This is used for some of the convenience routines in the library.
*/
enum GAMEPAD_STICKDIR {
STICKDIR_CENTER = 0, /**< CENTER, no direction */
STICKDIR_UP = 1, /**< UP direction */
STICKDIR_DOWN = 2, /**< DOWN direction */
STICKDIR_LEFT = 3, /**< LEFT direction */
STICKDIR_RIGHT = 4, /**< RIGHT direction */
STICKDIR_COUNT
};
/**
* Enumeration for true/false values
*/
enum GAMEPAD_BOOL {
GAMEPAD_FALSE = 0, /**< FALSE value for boolean parameters */
GAMEPAD_TRUE = 1 /**< TRUE value for boolean parameters */
};
typedef enum GAMEPAD_DEVICE GAMEPAD_DEVICE;
typedef enum GAMEPAD_BUTTON GAMEPAD_BUTTON;
typedef enum GAMEPAD_TRIGGER GAMEPAD_TRIGGER;
typedef enum GAMEPAD_STICK GAMEPAD_STICK;
typedef enum GAMEPAD_STICKDIR GAMEPAD_STICKDIR;
typedef enum GAMEPAD_BOOL GAMEPAD_BOOL;
#define GAMEPAD_DEADZONE_LEFT_STICK 7849 /**< Suggested deadzone magnitude for left analog stick */
#define GAMEPAD_DEADZONE_RIGHT_STICK 8689 /**< Suggested deadzone magnitude for right analog stick */
#define GAMEPAD_DEADZONE_TRIGGER 30 /**< Suggested deadzone for triggers */
/**
* Initialize the library.
*
* This is critical on non-Windows platforms.
*/
GAMEPAD_API void GamepadInit(void);
/**
* Shutdown the library.
*
* This will release resources allocated by the library internally.
*
* This should be called after forking as well.
*/
GAMEPAD_API void GamepadShutdown(void);
/**
* Updates the state of the gamepads.
*
* This must be called (at least) once per game loop.
*/
GAMEPAD_API void GamepadUpdate(void);
/**
* Test if a particular gamepad is connected.
*
* \param device The device to check.
* \returns GAMEPAD_TRUE if the device is connected, GAMEPAD_FALSE if it is not.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadIsConnected(GAMEPAD_DEVICE device);
/**
* Test if a particular button is being pressed.
*
* \param device The device to check.
* \param button The button to check.
* \returns GAMEPAD_TRUE if the button is down, GAMEPAD_FALSE if it is not.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadButtonDown(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button);
/**
* Test if a particular button has been depressed since the previous call to GamepadUpdate.
*
* \param device The device to check.
* \param button The button to check.
* \returns GAMEPAD_TRUE if the button has been pressed, GAMEPAD_FALSE if it is not or if it was depressed the previous frame.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadButtonTriggered(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button);
/**
* Test if a particular button has been released since the previous call to GamepadUpdate.
*
* \param device The device to check.
* \param button The button to check.
* \returns GAMEPAD_TRUE if the button has been released, GAMEPAD_FALSE if it is down or if it was not down the previous frame.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadButtonReleased(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button);
/**
* Get the trigger value (depression magnitude) in its raw form.
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns Trigger depression magnitude (0 to 32767).
*/
GAMEPAD_API int GamepadTriggerValue(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Get the trigger value (depression magnitude) in normalized form.
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns Trigger depression magnitude (0 to 1).
*/
GAMEPAD_API float GamepadTriggerLength(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Test if a trigger is depressed
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns GAMEPAD_TRUE if down, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadTriggerDown(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Test if a trigger is depressed
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns GAMEPAD_TRUE if triggered, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadTriggerTriggered(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Test if a trigger is depressed
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns GAMEPAD_TRUE if released, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadTriggerReleased(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Set the rumble motors on/off.
*
* To turn off the rumble effect, set values to 0 for both motors.
*
* The left motor is the low-frequency/strong motor, and the right motor is the high-frequency/weak motor.
*
* \param device The device to update.
* \param left Left motor strengh (0 to 1).
* \param right Right motor strengh (0 to 1).
*/
GAMEPAD_API void GamepadSetRumble(GAMEPAD_DEVICE device, float left, float right);
/**
* Query the position of an analog stick as raw values.
*
* The values retrieved by this function represent the magnitude of the analog
* stick in each direction. Note that it shouldn't be possible to get full
* magnitude in one direction unless the other direction has a magnitude of
* zero, as the stick has a circular movement range.
*
* \param device The device to check.
* \param stick The stick to check.
* \param outX Pointer to integer to store the X magnitude in (-32767 to 32767).
* \param outX Pointer to integer to store the Y magnitude in (-32767 to 32767).
*/
GAMEPAD_API void GamepadStickXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, int* outX, int* outY);
/**
* Query the position of an analog stick as normalized values.
*
* The values retrieved by this function represent the magnitude of the analog
* stick in each direction. Note that it shouldn't be possible to get full
* magnitude in one direction unless the other direction has a magnitude of
* zero, as the stick has a circular movement range.
*
* \param device The device to check.
* \param stick The stick to check.
* \param outX Pointer to float to store the X magnitude in (-1 to 1).
* \param outX Pointer to float to store the Y magnitude in (-1 to 1).
*/
GAMEPAD_API void GamepadStickNormXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, float* outX, float* outY);
/**
* Query the magnitude of an analog stick.
*
* This returns the normalized value of the magnitude of the stick. That is,
* if the stick is pushed all the way in any direction, it returns 1.0.
*
* \param device The device to check.
* \param stick The stick to check.
* \returns The magnitude of the stick (0 to 1).
*/
GAMEPAD_API float GamepadStickLength(GAMEPAD_DEVICE device, GAMEPAD_STICK stick);
/**
* Query the direction of a stick (in radians).
*
* This returns the direction of the stick. This value is in radians, not
* degrees. Zero is to the right, and the angle increases in a
* counter-clockwise direction.
*
* \param device The device to check.
* \param stick The stick to check.
* \returns The angle of the stick (0 to 2*PI).
*/
GAMEPAD_API float GamepadStickAngle(GAMEPAD_DEVICE device, GAMEPAD_STICK stick);
/**
* Get the direction the stick is pushed in (if any).
*
* This is a useful utility function for when the stick should be treated as a simple
* directional pad, such as for menu UIs.
*
* \param device The device to check.
* \param stick The trigger to check.
* \returns The stick's current direction.
*/
GAMEPAD_API GAMEPAD_STICKDIR GamepadStickDir(GAMEPAD_DEVICE device, GAMEPAD_STICK stick);
/**
* Test whether a stick has been pressed in a particular direction since the last update.
*
* This only returns true if the stick was centered last frame.
*
* This is a useful utility function for when the stick should be treated as a simple
* directional pad, such as for menu UIs.
*
* \param device The device to check.
* \param stick The trigger to check.
* \param stickdir The direction to check for.
* \returns GAMEPAD_TRUE if the stick is pressed in the specified direction, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadStickDirTriggered(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, GAMEPAD_STICKDIR dir);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif

View file

@ -58,6 +58,12 @@ struct Image_Data {
std::string data;
};
struct Controller_Settings {
std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_sets = {{"ship_controls", {{"analog_controls", {{"LJOY"}, "joystick_move"}}}}, {"menu_controls", {{"menu_up", {{"DLJOYUP", "DUP"}, ""}}, {"menu_down", {{"DLJOYDOWN", "DDOWN"}, ""}}}}};
std::map<std::string, std::string> action_set_layer_parents;
std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_set_layers;
};
class Settings {
CSteamID steam_id;
CGameID game_id;
@ -126,6 +132,9 @@ public:
//images
std::map<int, struct Image_Data> images;
int add_image(std::string data, uint32 width, uint32 height);
//controller
struct Controller_Settings controller_settings;
};
#endif

View file

@ -18,6 +18,8 @@
#include "settings_parser.h"
#include <fstream>
#include <cctype>
#include <sstream>
#include <iterator>
static void load_custom_broadcasts(std::string broadcasts_filepath, std::set<uint32> &custom_broadcasts)
{
@ -32,6 +34,77 @@ static void load_custom_broadcasts(std::string broadcasts_filepath, std::set<uin
}
}
template<typename Out>
static void split_string(const std::string &s, char delim, Out result) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
static void load_gamecontroller_settings(Settings *settings)
{
std::string path = Local_Storage::get_game_settings_path() + "controller";
std::vector<std::string> paths = Local_Storage::get_filenames_path(path);
for (auto & p: paths) {
size_t length = p.length();
if (length < 4) continue;
if ( std::toupper(p.back()) != 'T') continue;
if ( std::toupper(p[length - 2]) != 'X') continue;
if ( std::toupper(p[length - 3]) != 'T') continue;
if (p[length - 4] != '.') continue;
PRINT_DEBUG("controller config %s\n", p.c_str());
std::string action_set_name = p.substr(0, length - 4);
std::transform(action_set_name.begin(), action_set_name.end(), action_set_name.begin(),[](unsigned char c){ return std::toupper(c); });
std::string controller_config_path = path + PATH_SEPARATOR + p;
std::ifstream input( controller_config_path );
if (input.is_open()) {
std::map<std::string, std::pair<std::set<std::string>, std::string>> button_pairs;
for( std::string line; getline( input, line ); ) {
if (!line.empty() && line[line.length()-1] == '\n') {
line.pop_back();
}
if (!line.empty() && line[line.length()-1] == '\r') {
line.pop_back();
}
std::string action_name;
std::string button_name;
std::string source_mode;
std::size_t deliminator = line.find("=");
if (deliminator != 0 && deliminator != std::string::npos && deliminator != line.size()) {
action_name = line.substr(0, deliminator);
std::size_t deliminator2 = line.find("=", deliminator + 1);
if (deliminator2 != std::string::npos && deliminator2 != line.size()) {
button_name = line.substr(deliminator + 1, deliminator2 - (deliminator + 1));
source_mode = line.substr(deliminator2 + 1);
} else {
button_name = line.substr(deliminator + 1);
source_mode = "";
}
}
std::transform(action_name.begin(), action_name.end(), action_name.begin(),[](unsigned char c){ return std::toupper(c); });
std::transform(button_name.begin(), button_name.end(), button_name.begin(),[](unsigned char c){ return std::toupper(c); });
std::pair<std::set<std::string>, std::string> button_config = {{}, source_mode};
split_string(button_name, ',', std::inserter(button_config.first, button_config.first.begin()));
button_pairs[action_name] = button_config;
PRINT_DEBUG("Added %s %s %s\n", action_name.c_str(), button_name.c_str(), source_mode.c_str());
}
settings->controller_settings.action_sets[action_set_name] = button_pairs;
PRINT_DEBUG("Added %u action names to %s\n", button_pairs.size(), action_set_name.c_str());
}
}
}
uint32 create_localstorage_settings(Settings **settings_client_out, Settings **settings_server_out, Local_Storage **local_storage_out)
{
@ -386,6 +459,8 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
}
}
load_gamecontroller_settings(settings_client);
*settings_client_out = settings_client;
*settings_server_out = settings_server;
*local_storage_out = local_storage;

View file

@ -66,7 +66,7 @@ Steam_Client::Steam_Client()
steam_remote_storage = new Steam_Remote_Storage(settings_client, local_storage, callback_results_client);
steam_screenshots = new Steam_Screenshots();
steam_http = new Steam_HTTP(settings_client, network, callback_results_client, callbacks_client);
steam_controller = new Steam_Controller();
steam_controller = new Steam_Controller(settings_client, callback_results_client, callbacks_client, run_every_runcb);
steam_ugc = new Steam_UGC(settings_client, callback_results_client, callbacks_client);
steam_applist = new Steam_Applist();
steam_music = new Steam_Music(callbacks_client);

View file

@ -27,7 +27,11 @@
#include "steam_remote_storage.h"
#include "steam_screenshots.h"
#include "steam_http.h"
#ifdef CONTROLLER_SUPPORT
#include "steam_controller.h"
#else
#include "steam_controller_disabled.h"
#endif
#include "steam_ugc.h"
#include "steam_applist.h"
#include "steam_music.h"

View file

@ -16,6 +16,55 @@
<http://www.gnu.org/licenses/>. */
#include "base.h"
#include "../controller/gamepad.h"
#include <cctype>
struct Controller_Map {
std::map<ControllerDigitalActionHandle_t, std::set<int>> active_digital;
std::map<ControllerAnalogActionHandle_t, std::pair<std::set<int>, enum EInputSourceMode>> active_analog;
};
struct Controller_Action {
ControllerHandle_t controller_handle;
struct Controller_Map active_map;
ControllerDigitalActionHandle_t active_set;
Controller_Action(ControllerHandle_t controller_handle) {
this->controller_handle = controller_handle;
}
void activate_action_set(ControllerDigitalActionHandle_t active_set, std::map<ControllerActionSetHandle_t, struct Controller_Map> &controller_maps) {
auto map = controller_maps.find(active_set);
if (map == controller_maps.end()) return;
this->active_set = active_set;
this->active_map = map->second;
}
std::set<int> button_id(ControllerDigitalActionHandle_t handle) {
auto a = active_map.active_digital.find(handle);
if (a == active_map.active_digital.end()) return {};
return a->second;
}
std::pair<std::set<int>, enum EInputSourceMode> analog_id(ControllerAnalogActionHandle_t handle) {
auto a = active_map.active_analog.find(handle);
if (a == active_map.active_analog.end()) return std::pair<std::set<int>, enum EInputSourceMode>({}, k_EInputSourceMode_None);
return a->second;
}
};
enum EXTRA_GAMEPAD_BUTTONS {
BUTTON_LTRIGGER = BUTTON_COUNT + 1,
BUTTON_RTRIGGER = BUTTON_COUNT + 2,
BUTTON_STICK_LEFT_UP = BUTTON_COUNT + 3,
BUTTON_STICK_LEFT_DOWN = BUTTON_COUNT + 4,
BUTTON_STICK_LEFT_LEFT = BUTTON_COUNT + 5,
BUTTON_STICK_LEFT_RIGHT = BUTTON_COUNT + 6,
BUTTON_STICK_RIGHT_UP = BUTTON_COUNT + 7,
BUTTON_STICK_RIGHT_DOWN = BUTTON_COUNT + 8,
BUTTON_STICK_RIGHT_LEFT = BUTTON_COUNT + 9,
BUTTON_STICK_RIGHT_RIGHT = BUTTON_COUNT + 10,
};
class Steam_Controller :
public ISteamController001,
@ -26,12 +75,154 @@ public ISteamController006,
public ISteamController,
public ISteamInput
{
class Settings *settings;
class SteamCallResults *callback_results;
class SteamCallBacks *callbacks;
class RunEveryRunCB *run_every_runcb;
std::map<std::string, int> button_strings = {
{"DUP", BUTTON_DPAD_UP},
{"DDOWN", BUTTON_DPAD_DOWN},
{"DLEFT", BUTTON_DPAD_LEFT},
{"DRIGHT", BUTTON_DPAD_RIGHT},
{"START", BUTTON_START},
{"BACK", BUTTON_BACK},
{"LSTICK", BUTTON_LEFT_THUMB},
{"RSTICK", BUTTON_RIGHT_THUMB},
{"LBUMPER", BUTTON_LEFT_SHOULDER},
{"RBUMPER", BUTTON_RIGHT_SHOULDER},
{"A", BUTTON_A},
{"B", BUTTON_B},
{"X", BUTTON_X},
{"Y", BUTTON_Y},
{"DLTRIGGER", BUTTON_LTRIGGER},
{"DRTRIGGER", BUTTON_RTRIGGER},
{"DLJOYUP", BUTTON_STICK_LEFT_UP},
{"DLJOYDOWN", BUTTON_STICK_LEFT_DOWN},
{"DLJOYLEFT", BUTTON_STICK_LEFT_LEFT},
{"DLJOYRIGHT", BUTTON_STICK_LEFT_RIGHT},
{"DRJOYUP", BUTTON_STICK_RIGHT_UP},
{"DRJOYDOWN", BUTTON_STICK_RIGHT_DOWN},
{"DRJOYLEFT", BUTTON_STICK_RIGHT_LEFT},
{"DRJOYRIGHT", BUTTON_STICK_RIGHT_RIGHT},
};
std::map<std::string, int> analog_strings = {
{"LTRIGGER", TRIGGER_LEFT},
{"RTRIGGER", TRIGGER_RIGHT},
{"LJOY", STICK_LEFT + 10},
{"RJOY", STICK_RIGHT + 10},
};
std::map<std::string, enum EInputSourceMode> analog_input_modes = {
{"joystick_move", k_EInputSourceMode_JoystickMove},
{"joystick_camera", k_EInputSourceMode_JoystickCamera},
{"trigger", k_EInputSourceMode_Trigger},
};
std::map<std::string, ControllerActionSetHandle_t> action_handles;
std::map<std::string, ControllerDigitalActionHandle_t> digital_action_handles;
std::map<std::string, ControllerAnalogActionHandle_t> analog_action_handles;
std::map<ControllerActionSetHandle_t, struct Controller_Map> controller_maps;
std::map<ControllerHandle_t, struct Controller_Action> controllers;
bool disabled;
void set_handles(std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_sets) {
uint64 handle_num = 1;
for (auto & set : action_sets) {
ControllerActionSetHandle_t action_handle_num = handle_num;
++handle_num;
action_handles[set.first] = action_handle_num;
for (auto & config_key : set.second) {
uint64 current_handle_num = handle_num;
++handle_num;
for (auto & button_string : config_key.second.first) {
auto digital = button_strings.find(button_string);
if (digital != button_strings.end()) {
ControllerDigitalActionHandle_t digital_handle_num = current_handle_num;
digital_action_handles[config_key.first] = digital_handle_num;
controller_maps[action_handle_num].active_digital[digital_handle_num].insert(digital->second);
} else {
auto analog = analog_strings.find(button_string);
if (analog != analog_strings.end()) {
ControllerAnalogActionHandle_t analog_handle_num = current_handle_num;
enum EInputSourceMode source_mode;
if (analog->second == TRIGGER_LEFT || analog->second == TRIGGER_RIGHT) {
source_mode = k_EInputSourceMode_Trigger;
} else {
source_mode = k_EInputSourceMode_JoystickMove;
}
auto input_mode = analog_input_modes.find(config_key.second.second);
if (input_mode != analog_input_modes.end()) {
source_mode = input_mode->second;
}
analog_action_handles[config_key.first] = analog_handle_num;
controller_maps[action_handle_num].active_analog[analog_handle_num].first.insert(analog->second);
controller_maps[action_handle_num].active_analog[analog_handle_num].second = source_mode;
} else {
PRINT_DEBUG("Did not recognize controller button %s\n", button_string.c_str());
continue;
}
}
}
}
}
}
public:
static void steam_run_every_runcb(void *object)
{
PRINT_DEBUG("steam_controller_run_every_runcb\n");
Steam_Controller *steam_controller = (Steam_Controller *)object;
steam_controller->RunCallbacks();
}
Steam_Controller(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
{
this->settings = settings;
this->run_every_runcb = run_every_runcb;
this->run_every_runcb->add(&Steam_Controller::steam_run_every_runcb, this);
this->callback_results = callback_results;
this->callbacks = callbacks;
set_handles(settings->controller_settings.action_sets);
disabled = !action_handles.size();
}
~Steam_Controller()
{
//TODO rm network callbacks
this->run_every_runcb->remove(&Steam_Controller::steam_run_every_runcb, this);
}
// Init and Shutdown must be called when starting/ending use of this interface
bool Init()
{
PRINT_DEBUG("Steam_Controller::Init()\n");
std::lock_guard<std::recursive_mutex> lock(global_mutex);
if (disabled) {
return true;
}
GamepadInit();
GamepadUpdate();
for (int i = 1; i < 5; ++i) {
controllers.insert(std::pair<ControllerHandle_t, struct Controller_Action>(i, Controller_Action(i)));
}
return true;
}
@ -44,6 +235,12 @@ bool Init( const char *pchAbsolutePathToControllerConfigVDF )
bool Shutdown()
{
PRINT_DEBUG("Steam_Controller::Shutdown()\n");
std::lock_guard<std::recursive_mutex> lock(global_mutex);
if (disabled) {
return true;
}
GamepadShutdown();
return true;
}
@ -58,6 +255,11 @@ void SetOverrideMode( const char *pchMode )
void RunFrame()
{
PRINT_DEBUG("Steam_Controller::RunFrame()\n");
if (disabled) {
return;
}
GamepadUpdate();
}
bool GetControllerState( uint32 unControllerIndex, SteamControllerState001_t *pState )
@ -71,16 +273,28 @@ bool GetControllerState( uint32 unControllerIndex, SteamControllerState001_t *pS
// Returns the number of handles written to handlesOut
int GetConnectedControllers( ControllerHandle_t *handlesOut )
{
PRINT_DEBUG("GetConnectedControllers\n");
PRINT_DEBUG("Steam_Controller::GetConnectedControllers\n");
if (!handlesOut) return 0;
if (disabled) {
return 0;
}
int count = 0;
if (GamepadIsConnected(GAMEPAD_0)) {*handlesOut = GAMEPAD_0 + 1; ++handlesOut; ++count;};
if (GamepadIsConnected(GAMEPAD_1)) {*handlesOut = GAMEPAD_1 + 1; ++handlesOut; ++count;};
if (GamepadIsConnected(GAMEPAD_2)) {*handlesOut = GAMEPAD_2 + 1; ++handlesOut; ++count;};
if (GamepadIsConnected(GAMEPAD_3)) {*handlesOut = GAMEPAD_3 + 1; ++handlesOut; ++count;};
PRINT_DEBUG("returned %i connected controllers\n", count);
return count;
}
// Invokes the Steam overlay and brings up the binding screen
// Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode
bool ShowBindingPanel( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("ShowBindingPanel\n");
PRINT_DEBUG("Steam_Controller::ShowBindingPanel\n");
return false;
}
@ -89,8 +303,15 @@ bool ShowBindingPanel( ControllerHandle_t controllerHandle )
// Lookup the handle for an Action Set. Best to do this once on startup, and store the handles for all future API calls.
ControllerActionSetHandle_t GetActionSetHandle( const char *pszActionSetName )
{
PRINT_DEBUG("GetActionSetHandle %s\n", pszActionSetName);
return 124;
PRINT_DEBUG("Steam_Controller::GetActionSetHandle %s\n", pszActionSetName);
if (!pszActionSetName) return 0;
std::string upper_action_name(pszActionSetName);
std::transform(upper_action_name.begin(), upper_action_name.end(), upper_action_name.begin(),[](unsigned char c){ return std::toupper(c); });
auto set_handle = action_handles.find(upper_action_name);
if (set_handle == action_handles.end()) return 0;
return set_handle->second;
}
@ -99,34 +320,41 @@ ControllerActionSetHandle_t GetActionSetHandle( const char *pszActionSetName )
// your state loops, instead of trying to place it in all of your state transitions.
void ActivateActionSet( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle )
{
PRINT_DEBUG("ActivateActionSet\n");
PRINT_DEBUG("Steam_Controller::ActivateActionSet %llu %llu\n", controllerHandle, actionSetHandle);
auto controller = controllers.find(controllerHandle);
if (controller == controllers.end()) return;
controller->second.activate_action_set(actionSetHandle, controller_maps);
}
ControllerActionSetHandle_t GetCurrentActionSet( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("GetCurrentActionSet\n");
return 124;
PRINT_DEBUG("Steam_Controller::GetCurrentActionSet %llu\n", controllerHandle);
auto controller = controllers.find(controllerHandle);
if (controller == controllers.end()) return 0;
return controller->second.active_set;
}
void ActivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle )
{
PRINT_DEBUG("ActivateActionSetLayer\n");
PRINT_DEBUG("Steam_Controller::ActivateActionSetLayer\n");
}
void DeactivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle )
{
PRINT_DEBUG("DeactivateActionSetLayer\n");
PRINT_DEBUG("Steam_Controller::DeactivateActionSetLayer\n");
}
void DeactivateAllActionSetLayers( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("DeactivateAllActionSetLayers\n");
PRINT_DEBUG("Steam_Controller::DeactivateAllActionSetLayers\n");
}
int GetActiveActionSetLayers( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t *handlesOut )
{
PRINT_DEBUG("GetActiveActionSetLayers\n");
PRINT_DEBUG("Steam_Controller::GetActiveActionSetLayers\n");
return 0;
}
@ -136,17 +364,72 @@ int GetActiveActionSetLayers( ControllerHandle_t controllerHandle, ControllerAct
// Lookup the handle for a digital action. Best to do this once on startup, and store the handles for all future API calls.
ControllerDigitalActionHandle_t GetDigitalActionHandle( const char *pszActionName )
{
PRINT_DEBUG("GetDigitalActionHandle %s\n", pszActionName);
return 123;
PRINT_DEBUG("Steam_Controller::GetDigitalActionHandle %s\n", pszActionName);
if (!pszActionName) return 0;
std::string upper_action_name(pszActionName);
std::transform(upper_action_name.begin(), upper_action_name.end(), upper_action_name.begin(),[](unsigned char c){ return std::toupper(c); });
auto handle = digital_action_handles.find(upper_action_name);
if (handle == digital_action_handles.end()) return 0;
return handle->second;
}
// Returns the current state of the supplied digital game action
ControllerDigitalActionData_t GetDigitalActionData( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle )
{
PRINT_DEBUG("GetDigitalActionData\n");
PRINT_DEBUG("Steam_Controller::GetDigitalActionData %llu %llu\n", controllerHandle, digitalActionHandle);
ControllerDigitalActionData_t digitalData;
digitalData.bActive = false;
digitalData.bState = false;
auto controller = controllers.find(controllerHandle);
if (controller == controllers.end()) return digitalData;
std::set<int> buttons = controller->second.button_id(digitalActionHandle);
if (!buttons.size()) return digitalData;
digitalData.bActive = true;
GAMEPAD_DEVICE device = (GAMEPAD_DEVICE)(controllerHandle - 1);
for (auto button : buttons) {
bool pressed = false;
if (button < BUTTON_COUNT) {
pressed = GamepadButtonDown(device, (GAMEPAD_BUTTON)button);
} else {
switch (button) {
case BUTTON_LTRIGGER:
pressed = GamepadTriggerLength(device, TRIGGER_LEFT) > 0.8;
break;
case BUTTON_RTRIGGER:
pressed = GamepadTriggerLength(device, TRIGGER_RIGHT) > 0.8;
break;
case BUTTON_STICK_LEFT_UP:
case BUTTON_STICK_LEFT_DOWN:
case BUTTON_STICK_LEFT_LEFT:
case BUTTON_STICK_LEFT_RIGHT:
pressed = GamepadStickLength(device, STICK_LEFT) > 0.1 &&
((int)GamepadStickDir(device, STICK_LEFT) == ((button - BUTTON_STICK_LEFT_UP) + 1));
break;
case BUTTON_STICK_RIGHT_UP:
case BUTTON_STICK_RIGHT_DOWN:
case BUTTON_STICK_RIGHT_LEFT:
case BUTTON_STICK_RIGHT_RIGHT:
pressed = GamepadStickLength(device, STICK_RIGHT) > 0.1 &&
((int)GamepadStickDir(device, STICK_RIGHT) == ((button - BUTTON_STICK_RIGHT_UP) + 1));
break;
default:
break;
}
}
if (pressed) {
digitalData.bState = true;
break;
}
}
return digitalData;
}
@ -155,32 +438,58 @@ ControllerDigitalActionData_t GetDigitalActionData( ControllerHandle_t controlle
// originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles
int GetDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, EControllerActionOrigin *originsOut )
{
PRINT_DEBUG("GetDigitalActionOrigins\n");
PRINT_DEBUG("Steam_Controller::GetDigitalActionOrigins\n");
return 0;
}
int GetDigitalActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputDigitalActionHandle_t digitalActionHandle, EInputActionOrigin *originsOut )
{
PRINT_DEBUG("GetDigitalActionOrigins steaminput\n");
PRINT_DEBUG("Steam_Controller::GetDigitalActionOrigins steaminput\n");
return 0;
}
// Lookup the handle for an analog action. Best to do this once on startup, and store the handles for all future API calls.
ControllerAnalogActionHandle_t GetAnalogActionHandle( const char *pszActionName )
{
PRINT_DEBUG("GetAnalogActionHandle %s\n", pszActionName);
return 125;
PRINT_DEBUG("Steam_Controller::GetAnalogActionHandle %s\n", pszActionName);
if (!pszActionName) return 0;
std::string upper_action_name(pszActionName);
std::transform(upper_action_name.begin(), upper_action_name.end(), upper_action_name.begin(),[](unsigned char c){ return std::toupper(c); });
auto handle = analog_action_handles.find(upper_action_name);
if (handle == analog_action_handles.end()) return 0;
return handle->second;
}
// Returns the current state of these supplied analog game action
ControllerAnalogActionData_t GetAnalogActionData( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle )
{
PRINT_DEBUG("GetAnalogActionData\n");
PRINT_DEBUG("Steam_Controller::GetAnalogActionData %llu %llu\n", controllerHandle, analogActionHandle);
ControllerAnalogActionData_t data;
data.eMode = k_EInputSourceMode_None;
data.x = data.y = 0;
data.bActive = false;
auto controller = controllers.find(controllerHandle);
if (controller == controllers.end()) return data;
auto analog = controller->second.analog_id(analogActionHandle);
if (!analog.first.size()) return data;
data.bActive = true;
data.eMode = analog.second;
for (auto a : analog.first) {
if (a >= 10) {
int joystick_id = a - 10;
GamepadStickNormXY((GAMEPAD_DEVICE)(controllerHandle - 1), (GAMEPAD_STICK) joystick_id, &data.x, &data.y);
} else {
data.x = GamepadTriggerLength((GAMEPAD_DEVICE)(controllerHandle - 1), (GAMEPAD_TRIGGER) a);
}
}
return data;
}
@ -189,32 +498,32 @@ ControllerAnalogActionData_t GetAnalogActionData( ControllerHandle_t controllerH
// originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles
int GetAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, EControllerActionOrigin *originsOut )
{
PRINT_DEBUG("GetAnalogActionOrigins\n");
PRINT_DEBUG("Steam_Controller::GetAnalogActionOrigins\n");
return 0;
}
int GetAnalogActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputAnalogActionHandle_t analogActionHandle, EInputActionOrigin *originsOut )
{
PRINT_DEBUG("GetAnalogActionOrigins steaminput\n");
PRINT_DEBUG("Steam_Controller::GetAnalogActionOrigins steaminput\n");
return 0;
}
void StopAnalogActionMomentum( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction )
{
PRINT_DEBUG("StopAnalogActionMomentum\n");
PRINT_DEBUG("Steam_Controller::StopAnalogActionMomentum\n");
}
// Trigger a haptic pulse on a controller
void TriggerHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec )
{
PRINT_DEBUG("TriggerHapticPulse\n");
PRINT_DEBUG("Steam_Controller::TriggerHapticPulse\n");
}
void TriggerHapticPulse( uint32 unControllerIndex, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec )
{
PRINT_DEBUG("TriggerHapticPulse old\n");
PRINT_DEBUG("Steam_Controller::TriggerHapticPulse old\n");
TriggerHapticPulse(unControllerIndex, eTargetPad, usDurationMicroSec );
}
@ -222,28 +531,32 @@ void TriggerHapticPulse( uint32 unControllerIndex, ESteamControllerPad eTargetPa
// nFlags is currently unused and reserved for future use.
void TriggerRepeatedHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags )
{
PRINT_DEBUG("TriggerRepeatedHapticPulse\n");
PRINT_DEBUG("Steam_Controller::TriggerRepeatedHapticPulse\n");
}
// Tigger a vibration event on supported controllers.
void TriggerVibration( ControllerHandle_t controllerHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed )
{
PRINT_DEBUG("TriggerVibration\n");
PRINT_DEBUG("Steam_Controller::TriggerVibration %hu %hu\n", usLeftSpeed, usRightSpeed);
auto controller = controllers.find(controllerHandle);
if (controller == controllers.end()) return;
GamepadSetRumble((GAMEPAD_DEVICE)(controllerHandle - 1), ((double)usLeftSpeed) / 65535.0, ((double)usRightSpeed) / 65535.0);
}
// Set the controller LED color on supported controllers.
void SetLEDColor( ControllerHandle_t controllerHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags )
{
PRINT_DEBUG("SetLEDColor\n");
PRINT_DEBUG("Steam_Controller::SetLEDColor\n");
}
// Returns the associated gamepad index for the specified controller, if emulating a gamepad
int GetGamepadIndexForController( ControllerHandle_t ulControllerHandle )
{
PRINT_DEBUG("GetGamepadIndexForController\n");
PRINT_DEBUG("Steam_Controller::GetGamepadIndexForController\n");
return 0;
}
@ -251,7 +564,7 @@ int GetGamepadIndexForController( ControllerHandle_t ulControllerHandle )
// Returns the associated controller handle for the specified emulated gamepad
ControllerHandle_t GetControllerForGamepadIndex( int nIndex )
{
PRINT_DEBUG("GetControllerForGamepadIndex\n");
PRINT_DEBUG("Steam_Controller::GetControllerForGamepadIndex\n");
return 0;
}
@ -259,7 +572,7 @@ ControllerHandle_t GetControllerForGamepadIndex( int nIndex )
// Returns raw motion data from the specified controller
ControllerMotionData_t GetMotionData( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("GetMotionData\n");
PRINT_DEBUG("Steam_Controller::GetMotionData\n");
ControllerMotionData_t data = {};
return data;
}
@ -269,13 +582,13 @@ ControllerMotionData_t GetMotionData( ControllerHandle_t controllerHandle )
// Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode
bool ShowDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle, float flScale, float flXPosition, float flYPosition )
{
PRINT_DEBUG("ShowDigitalActionOrigins\n");
PRINT_DEBUG("Steam_Controller::ShowDigitalActionOrigins\n");
return true;
}
bool ShowAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle, float flScale, float flXPosition, float flYPosition )
{
PRINT_DEBUG("ShowAnalogActionOrigins\n");
PRINT_DEBUG("Steam_Controller::ShowAnalogActionOrigins\n");
return true;
}
@ -283,13 +596,13 @@ bool ShowAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerAna
// Returns a localized string (from Steam's language setting) for the specified origin
const char *GetStringForActionOrigin( EControllerActionOrigin eOrigin )
{
PRINT_DEBUG("GetStringForActionOrigin\n");
PRINT_DEBUG("Steam_Controller::GetStringForActionOrigin\n");
return "Button String";
}
const char *GetStringForActionOrigin( EInputActionOrigin eOrigin )
{
PRINT_DEBUG("GetStringForActionOrigin steaminput\n");
PRINT_DEBUG("Steam_Controller::GetStringForActionOrigin steaminput\n");
return "Button String";
}
@ -297,75 +610,82 @@ const char *GetStringForActionOrigin( EInputActionOrigin eOrigin )
// Get a local path to art for on-screen glyph for a particular origin
const char *GetGlyphForActionOrigin( EControllerActionOrigin eOrigin )
{
PRINT_DEBUG("GetGlyphForActionOrigin\n");
PRINT_DEBUG("Steam_Controller::GetGlyphForActionOrigin\n");
return "";
}
const char *GetGlyphForActionOrigin( EInputActionOrigin eOrigin )
{
PRINT_DEBUG("GetGlyphForActionOrigin steaminput\n");
PRINT_DEBUG("Steam_Controller::GetGlyphForActionOrigin steaminput\n");
return "";
}
// Returns the input type for a particular handle
ESteamInputType GetInputTypeForHandle( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("GetInputTypeForHandle\n");
return k_ESteamInputType_Unknown;
PRINT_DEBUG("Steam_Controller::GetInputTypeForHandle\n");
auto controller = controllers.find(controllerHandle);
if (controller == controllers.end()) return k_ESteamInputType_Unknown;
return k_ESteamInputType_XBox360Controller;
}
const char *GetStringForXboxOrigin( EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetStringForXboxOrigin\n");
PRINT_DEBUG("Steam_Controller::GetStringForXboxOrigin\n");
return "";
}
const char *GetGlyphForXboxOrigin( EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetGlyphForXboxOrigin\n");
PRINT_DEBUG("Steam_Controller::GetGlyphForXboxOrigin\n");
return "";
}
EControllerActionOrigin GetActionOriginFromXboxOrigin_( ControllerHandle_t controllerHandle, EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetActionOriginFromXboxOrigin\n");
PRINT_DEBUG("Steam_Controller::GetActionOriginFromXboxOrigin\n");
return k_EControllerActionOrigin_None;
}
EInputActionOrigin GetActionOriginFromXboxOrigin( InputHandle_t inputHandle, EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetActionOriginFromXboxOrigin steaminput\n");
PRINT_DEBUG("Steam_Controller::GetActionOriginFromXboxOrigin steaminput\n");
return k_EInputActionOrigin_None;
}
EControllerActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EControllerActionOrigin eSourceOrigin )
{
PRINT_DEBUG("TranslateActionOrigin\n");
PRINT_DEBUG("Steam_Controller::TranslateActionOrigin\n");
return k_EControllerActionOrigin_None;
}
EInputActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EInputActionOrigin eSourceOrigin )
{
PRINT_DEBUG("TranslateActionOrigin steaminput\n");
PRINT_DEBUG("Steam_Controller::TranslateActionOrigin steaminput\n");
return k_EInputActionOrigin_None;
}
bool GetControllerBindingRevision( ControllerHandle_t controllerHandle, int *pMajor, int *pMinor )
{
PRINT_DEBUG("GetControllerBindingRevision\n");
PRINT_DEBUG("Steam_Controller::GetControllerBindingRevision\n");
return false;
}
bool GetDeviceBindingRevision( InputHandle_t inputHandle, int *pMajor, int *pMinor )
{
PRINT_DEBUG("GetDeviceBindingRevision\n");
PRINT_DEBUG("Steam_Controller::GetDeviceBindingRevision\n");
return false;
}
uint32 GetRemotePlaySessionID( InputHandle_t inputHandle )
{
PRINT_DEBUG("GetRemotePlaySessionID\n");
PRINT_DEBUG("Steam_Controller::GetRemotePlaySessionID\n");
return 0;
}
void RunCallbacks()
{
RunFrame();
}
};

View file

@ -0,0 +1,375 @@
/* Copyright (C) 2019 Mr Goldberg
This file is part of the Goldberg Emulator
The Goldberg Emulator is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
The Goldberg Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the Goldberg Emulator; if not, see
<http://www.gnu.org/licenses/>. */
#include "base.h"
class Steam_Controller :
public ISteamController001,
public ISteamController003,
public ISteamController004,
public ISteamController005,
public ISteamController006,
public ISteamController,
public ISteamInput
{
public:
Steam_Controller(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
{
}
// Init and Shutdown must be called when starting/ending use of this interface
bool Init()
{
PRINT_DEBUG("Steam_Controller::Init()\n");
return true;
}
bool Init( const char *pchAbsolutePathToControllerConfigVDF )
{
PRINT_DEBUG("Steam_Controller::Init() old\n");
return Init();
}
bool Shutdown()
{
PRINT_DEBUG("Steam_Controller::Shutdown()\n");
return true;
}
void SetOverrideMode( const char *pchMode )
{
PRINT_DEBUG("Steam_Controller::SetOverrideMode\n");
}
// Synchronize API state with the latest Steam Controller inputs available. This
// is performed automatically by SteamAPI_RunCallbacks, but for the absolute lowest
// possible latency, you call this directly before reading controller state.
void RunFrame()
{
PRINT_DEBUG("Steam_Controller::RunFrame()\n");
}
bool GetControllerState( uint32 unControllerIndex, SteamControllerState001_t *pState )
{
PRINT_DEBUG("Steam_Controller::GetControllerState()\n");
return false;
}
// Enumerate currently connected controllers
// handlesOut should point to a STEAM_CONTROLLER_MAX_COUNT sized array of ControllerHandle_t handles
// Returns the number of handles written to handlesOut
int GetConnectedControllers( ControllerHandle_t *handlesOut )
{
PRINT_DEBUG("GetConnectedControllers\n");
return 0;
}
// Invokes the Steam overlay and brings up the binding screen
// Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode
bool ShowBindingPanel( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("ShowBindingPanel\n");
return false;
}
// ACTION SETS
// Lookup the handle for an Action Set. Best to do this once on startup, and store the handles for all future API calls.
ControllerActionSetHandle_t GetActionSetHandle( const char *pszActionSetName )
{
PRINT_DEBUG("GetActionSetHandle %s\n", pszActionSetName);
return 124;
}
// Reconfigure the controller to use the specified action set (ie 'Menu', 'Walk' or 'Drive')
// This is cheap, and can be safely called repeatedly. It's often easier to repeatedly call it in
// your state loops, instead of trying to place it in all of your state transitions.
void ActivateActionSet( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle )
{
PRINT_DEBUG("ActivateActionSet\n");
}
ControllerActionSetHandle_t GetCurrentActionSet( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("GetCurrentActionSet\n");
return 124;
}
void ActivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle )
{
PRINT_DEBUG("ActivateActionSetLayer\n");
}
void DeactivateActionSetLayer( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle )
{
PRINT_DEBUG("DeactivateActionSetLayer\n");
}
void DeactivateAllActionSetLayers( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("DeactivateAllActionSetLayers\n");
}
int GetActiveActionSetLayers( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t *handlesOut )
{
PRINT_DEBUG("GetActiveActionSetLayers\n");
return 0;
}
// ACTIONS
// Lookup the handle for a digital action. Best to do this once on startup, and store the handles for all future API calls.
ControllerDigitalActionHandle_t GetDigitalActionHandle( const char *pszActionName )
{
PRINT_DEBUG("GetDigitalActionHandle %s\n", pszActionName);
return 123;
}
// Returns the current state of the supplied digital game action
ControllerDigitalActionData_t GetDigitalActionData( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle )
{
PRINT_DEBUG("GetDigitalActionData\n");
ControllerDigitalActionData_t digitalData;
digitalData.bActive = false;
return digitalData;
}
// Get the origin(s) for a digital action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action.
// originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles
int GetDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, EControllerActionOrigin *originsOut )
{
PRINT_DEBUG("GetDigitalActionOrigins\n");
return 0;
}
int GetDigitalActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputDigitalActionHandle_t digitalActionHandle, EInputActionOrigin *originsOut )
{
PRINT_DEBUG("GetDigitalActionOrigins steaminput\n");
return 0;
}
// Lookup the handle for an analog action. Best to do this once on startup, and store the handles for all future API calls.
ControllerAnalogActionHandle_t GetAnalogActionHandle( const char *pszActionName )
{
PRINT_DEBUG("GetAnalogActionHandle %s\n", pszActionName);
return 125;
}
// Returns the current state of these supplied analog game action
ControllerAnalogActionData_t GetAnalogActionData( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle )
{
PRINT_DEBUG("GetAnalogActionData\n");
ControllerAnalogActionData_t data;
data.eMode = k_EInputSourceMode_None;
data.x = data.y = 0;
data.bActive = false;
return data;
}
// Get the origin(s) for an analog action within an action set. Returns the number of origins supplied in originsOut. Use this to display the appropriate on-screen prompt for the action.
// originsOut should point to a STEAM_CONTROLLER_MAX_ORIGINS sized array of EControllerActionOrigin handles
int GetAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, EControllerActionOrigin *originsOut )
{
PRINT_DEBUG("GetAnalogActionOrigins\n");
return 0;
}
int GetAnalogActionOrigins( InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputAnalogActionHandle_t analogActionHandle, EInputActionOrigin *originsOut )
{
PRINT_DEBUG("GetAnalogActionOrigins steaminput\n");
return 0;
}
void StopAnalogActionMomentum( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction )
{
PRINT_DEBUG("StopAnalogActionMomentum\n");
}
// Trigger a haptic pulse on a controller
void TriggerHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec )
{
PRINT_DEBUG("TriggerHapticPulse\n");
}
void TriggerHapticPulse( uint32 unControllerIndex, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec )
{
PRINT_DEBUG("TriggerHapticPulse old\n");
TriggerHapticPulse(unControllerIndex, eTargetPad, usDurationMicroSec );
}
// Trigger a pulse with a duty cycle of usDurationMicroSec / usOffMicroSec, unRepeat times.
// nFlags is currently unused and reserved for future use.
void TriggerRepeatedHapticPulse( ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags )
{
PRINT_DEBUG("TriggerRepeatedHapticPulse\n");
}
// Tigger a vibration event on supported controllers.
void TriggerVibration( ControllerHandle_t controllerHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed )
{
PRINT_DEBUG("TriggerVibration\n");
}
// Set the controller LED color on supported controllers.
void SetLEDColor( ControllerHandle_t controllerHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags )
{
PRINT_DEBUG("SetLEDColor\n");
}
// Returns the associated gamepad index for the specified controller, if emulating a gamepad
int GetGamepadIndexForController( ControllerHandle_t ulControllerHandle )
{
PRINT_DEBUG("GetGamepadIndexForController\n");
return 0;
}
// Returns the associated controller handle for the specified emulated gamepad
ControllerHandle_t GetControllerForGamepadIndex( int nIndex )
{
PRINT_DEBUG("GetControllerForGamepadIndex\n");
return 0;
}
// Returns raw motion data from the specified controller
ControllerMotionData_t GetMotionData( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("GetMotionData\n");
ControllerMotionData_t data = {};
return data;
}
// Attempt to display origins of given action in the controller HUD, for the currently active action set
// Returns false is overlay is disabled / unavailable, or the user is not in Big Picture mode
bool ShowDigitalActionOrigins( ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle, float flScale, float flXPosition, float flYPosition )
{
PRINT_DEBUG("ShowDigitalActionOrigins\n");
return true;
}
bool ShowAnalogActionOrigins( ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle, float flScale, float flXPosition, float flYPosition )
{
PRINT_DEBUG("ShowAnalogActionOrigins\n");
return true;
}
// Returns a localized string (from Steam's language setting) for the specified origin
const char *GetStringForActionOrigin( EControllerActionOrigin eOrigin )
{
PRINT_DEBUG("GetStringForActionOrigin\n");
return "Button String";
}
const char *GetStringForActionOrigin( EInputActionOrigin eOrigin )
{
PRINT_DEBUG("GetStringForActionOrigin steaminput\n");
return "Button String";
}
// Get a local path to art for on-screen glyph for a particular origin
const char *GetGlyphForActionOrigin( EControllerActionOrigin eOrigin )
{
PRINT_DEBUG("GetGlyphForActionOrigin\n");
return "";
}
const char *GetGlyphForActionOrigin( EInputActionOrigin eOrigin )
{
PRINT_DEBUG("GetGlyphForActionOrigin steaminput\n");
return "";
}
// Returns the input type for a particular handle
ESteamInputType GetInputTypeForHandle( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("GetInputTypeForHandle\n");
return k_ESteamInputType_Unknown;
}
const char *GetStringForXboxOrigin( EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetStringForXboxOrigin\n");
return "";
}
const char *GetGlyphForXboxOrigin( EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetGlyphForXboxOrigin\n");
return "";
}
EControllerActionOrigin GetActionOriginFromXboxOrigin_( ControllerHandle_t controllerHandle, EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetActionOriginFromXboxOrigin\n");
return k_EControllerActionOrigin_None;
}
EInputActionOrigin GetActionOriginFromXboxOrigin( InputHandle_t inputHandle, EXboxOrigin eOrigin )
{
PRINT_DEBUG("GetActionOriginFromXboxOrigin steaminput\n");
return k_EInputActionOrigin_None;
}
EControllerActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EControllerActionOrigin eSourceOrigin )
{
PRINT_DEBUG("TranslateActionOrigin\n");
return k_EControllerActionOrigin_None;
}
EInputActionOrigin TranslateActionOrigin( ESteamInputType eDestinationInputType, EInputActionOrigin eSourceOrigin )
{
PRINT_DEBUG("TranslateActionOrigin steaminput\n");
return k_EInputActionOrigin_None;
}
bool GetControllerBindingRevision( ControllerHandle_t controllerHandle, int *pMajor, int *pMinor )
{
PRINT_DEBUG("GetControllerBindingRevision\n");
return false;
}
bool GetDeviceBindingRevision( InputHandle_t inputHandle, int *pMajor, int *pMinor )
{
PRINT_DEBUG("GetDeviceBindingRevision\n");
return false;
}
uint32 GetRemotePlaySessionID( InputHandle_t inputHandle )
{
PRINT_DEBUG("GetRemotePlaySessionID\n");
return 0;
}
};

View file

@ -87,6 +87,8 @@ bool GetImageSize( int iImage, uint32 *pnWidth, uint32 *pnHeight )
{
PRINT_DEBUG("GetImageSize %i\n", iImage);
if (!iImage || !pnWidth || !pnHeight) return false;
std::lock_guard<std::recursive_mutex> lock(global_mutex);
auto image = settings->images.find(iImage);
if (image == settings->images.end()) return false;
@ -102,6 +104,8 @@ bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize )
{
PRINT_DEBUG("GetImageRGBA %i\n", iImage);
if (!iImage || !pubDest || !nDestBufferSize) return false;
std::lock_guard<std::recursive_mutex> lock(global_mutex);
auto image = settings->images.find(iImage);
if (image == settings->images.end()) return false;