Compare commits

...

15 Commits

Author SHA1 Message Date
Nemirtingas
dbc17f3c85 Merge branch 'open_xinput' into 'master'
WIP: Open xinput - More than 4 controllers on Windows

See merge request Mr_Goldberg/goldberg_emulator!29
2021-02-08 13:34:27 +00:00
Mr_Goldberg
bfa1e95f7b
Use the same interface for both enabled and disabled controller builds. 2021-02-07 19:09:48 -05:00
Mr_Goldberg
69d5facf4f
Cleanup steamclient loader a bit. 2021-02-07 19:05:22 -05:00
Mr_Goldberg
5f8a454e3f
Fixed mouse getting stuck in the middle of the overlay in some games. 2021-02-06 22:38:51 -05:00
Mr_Goldberg
6dfe11503b
Dll loading feature now only tries loading .dll files. 2021-02-06 22:37:59 -05:00
Mr_Goldberg
5873398790
Fix some header issues that broke some interfaces. 2021-02-04 12:49:01 -05:00
Mr_Goldberg
9a63cf868d
Listen socket ids should be different from connection socket ids. 2021-01-31 21:50:31 -05:00
Mr_Goldberg
37b329c9c5
Implement networking sockets connection status/info functions. 2021-01-31 21:50:11 -05:00
Nemirtingas
a02531673b Merge remote-tracking branch 'Mr_Goldberg/master' into open_xinput 2020-01-20 08:56:18 +01:00
Nemirtingas
2a9f693965 Remove initialization var, its done in steam_controller 2020-01-19 12:14:03 +01:00
Nemirtingas
6d486e6ea5 Fix controller add linux 2020-01-19 11:53:31 +01:00
Nemirtingas
835b2dd3ed Add open xinput vibration, fix linux duplicate controller 2020-01-19 11:40:11 +01:00
Nemirtingas
1da2cb0213 Merge remote-tracking branch 'Mr_Goldberg/master' into open_xinput 2020-01-19 11:27:09 +01:00
Nemirtingas
f00e0f6222 Update gamepad.c 2020-01-18 22:59:54 +00:00
Nemirtingas
35aed23c1c Support more than 4 xinput controllers on windows
There are some bugs in the Linux controller implementation
2020-01-18 23:54:01 +01:00
14 changed files with 698 additions and 542 deletions

View File

@ -8,7 +8,7 @@ call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_OVERLAY /DGLEW_STATIC /IImGui /Iglew\include /DNDEBUG /I%PROTOBUF_X86_DIRECTORY%\include\ dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/impls/*.cpp ImGui/impls/windows/*.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp "%PROTOBUF_X86_LIBRARY%" glew\glew.c opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental_steamclient\steamclient.dll
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
cl steamclient_loader/*.cpp advapi32.lib user32.lib /EHsc /MP12 /Od /link /debug:none /OUT:release\experimental_steamclient\steamclient_loader.exe
cl steamclient_loader/*.cpp advapi32.lib user32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental_steamclient\steamclient_loader.exe
copy steamclient_loader\ColdClientLoader.ini release\experimental_steamclient\
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def

View File

@ -15,11 +15,18 @@
/* Platform-specific includes */
#if defined(_WIN32)
# define WIN32_LEAN_AND_MEAN 1
# undef UNICODE
# include "windows.h"
# include "xinput.h"
# pragma comment(lib, "XINPUT9_1_0.lib")
#undef UNICODE
#define INITGUID
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#include <Windows.h>
#include <SetupAPI.h>
#include <winioctl.h>
#pragma comment(lib, "Setupapi.lib")
#include <stdint.h>
#elif defined(__linux__)
# include <linux/joystick.h>
# include <stdio.h>
@ -58,7 +65,11 @@ struct GAMEPAD_STATE {
GAMEPAD_AXIS stick[STICK_COUNT];
GAMEPAD_TRIGINFO trigger[TRIGGER_COUNT];
int bLast, bCurrent, flags;
#if defined(__linux__)
#if defined(_WIN32)
WCHAR* device;
HANDLE hDevice;
uint8_t type;
#elif defined(__linux__)
char* device;
int fd;
int effect;
@ -67,8 +78,8 @@ struct GAMEPAD_STATE {
#endif
};
/* State of the four gamepads */
static GAMEPAD_STATE STATE[4];
/* State of the gamepads */
static GAMEPAD_STATE STATE[GAMEPAD_COUNT];
/* Note whether a gamepad is currently connected */
#define FLAG_CONNECTED (1<<0)
@ -90,54 +101,482 @@ static void GamepadUpdateTrigger (GAMEPAD_TRIGINFO* trig);
/* Platform-specific implementation code */
#if defined(_WIN32)
void GamepadInit(void) {
/*
* Open XInput code from:
* https://gitlab.com/Nemirtingas/open_xinput
*/
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
#define XINPUT_GAMEPAD_START 0x0010
#define XINPUT_GAMEPAD_BACK 0x0020
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
#define XINPUT_GAMEPAD_GUIDE 0x0400
#define XINPUT_GAMEPAD_A 0x1000
#define XINPUT_GAMEPAD_B 0x2000
#define XINPUT_GAMEPAD_X 0x4000
#define XINPUT_GAMEPAD_Y 0x8000
DEFINE_GUID(GUID_DEVINTERFACE_XINPUT, 0xEC87F1E3, 0xC13B, 0x4100, 0xB5, 0xF7, 0x8B, 0x84, 0xD5, 0x42, 0x60, 0xCB);
#define IOCTL_XINPUT_BASE 0x8000
#define XINPUT_READ_ACCESS ( 0x0001 )
#define XINPUT_WRITE_ACCESS ( 0x0002 )
#define XINPUT_RW_ACCESS ( (XINPUT_READ_ACCESS) | (XINPUT_WRITE_ACCESS) )
#define IOCTL_XINPUT_INIT CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x00, XINPUT_READ_ACCESS)
#define IOCTL_XINPUT_GET_CAPABILITIES CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x04, XINPUT_RW_ACCESS)
#define IOCTL_XINPUT_8 CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x08, XINPUT_RW_ACCESS)
#define IOCTL_XINPUT_GET_DATA CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x0C, XINPUT_RW_ACCESS)
#define IOCTL_XINPUT_SET_DATA CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x10, XINPUT_WRITE_ACCESS)
#define IOCTL_XINPUT_20 CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x14, XINPUT_WRITE_ACCESS)
#define IOCTL_XINPUT_GET_BATTERY_INFO CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x18, XINPUT_RW_ACCESS)
#define IOCTL_XINPUT_28 CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x1C, XINPUT_WRITE_ACCESS)
#define IOCTL_XINPUT_32 CTL_CODE(IOCTL_XINPUT_BASE, 0x800, 0x20, XINPUT_RW_ACCESS)
#pragma pack(push, 1)
struct buff_in_t
{
int16_t field_0;
uint8_t field_2;
};
struct buff_out_xbox_t
{
uint8_t field_0;
uint8_t field_1;
uint8_t status;
uint8_t field_3;
uint8_t field_4;
uint32_t dwPacketNumber;
uint8_t field_9;
uint8_t field_A;
uint16_t wButtons;
uint8_t bLeftTrigger;
uint8_t bRightTrigger;
int16_t sThumbLX;
int16_t sThumbLY;
int16_t sThumbRX;
int16_t sThumbRY;
uint32_t field_17;
uint16_t field_1B;
};
struct buff_out_xbox_one_t
{
uint8_t status;
uint8_t field_1;
uint8_t field_2;
uint32_t dwPacketNumber;
uint8_t field_7;
uint16_t wButtons;
uint8_t bLeftTrigger;
uint8_t bRightTrigger;
int16_t sThumbLX;
int16_t sThumbLY;
int16_t sThumbRX;
int16_t sThumbRY;
uint16_t field_14;
};
#pragma pack(pop)
static HRESULT DeviceIo(HANDLE hDevice, DWORD ioControlCode, LPVOID inBuff, DWORD inBuffSize, LPVOID outBuff, DWORD outBuffSize, LPOVERLAPPED pOverlapped)
{
HRESULT result;
int BytesReturned;
DWORD lpBytesReturned;
lpBytesReturned = 0;
BytesReturned = DeviceIoControl(hDevice, ioControlCode, inBuff, inBuffSize, outBuff, outBuffSize, &lpBytesReturned, pOverlapped);
if (BytesReturned == TRUE)
return ERROR_SUCCESS;
if (GetLastError() == ERROR_IO_PENDING && pOverlapped)
result = 0x8000000A;
else
result = 0x80004005;
return result;
}
static HRESULT DeviceInIo(HANDLE hDevice, DWORD nioctl, void* buff, size_t buff_size)
{
return DeviceIo(hDevice, nioctl, NULL, 0, buff, buff_size, NULL);
}
static HRESULT DeviceOutIo(HANDLE hDevice, DWORD nioctl, void* buff, size_t buff_size)
{
return DeviceIo(hDevice, nioctl, buff, buff_size, NULL, 0, NULL);
}
static HRESULT DeviceInOutIo(HANDLE hDevice, DWORD nioctl, void* in_buff, size_t in_buff_size, void* out_buff, size_t out_buff_size)
{
return DeviceIo(hDevice, nioctl, in_buff, in_buff_size, out_buff, out_buff_size, NULL);
}
static int parse_xboxone_buffer(GAMEPAD_STATE *state, struct buff_out_xbox_one_t* buff)
{
int button;
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
STATE[i].flags = 0;
for (i = XINPUT_GAMEPAD_DPAD_UP; i <= XINPUT_GAMEPAD_Y; i<<=1)
{
switch (i)
{
case XINPUT_GAMEPAD_DPAD_UP : button = BUTTON_DPAD_UP; break;
case XINPUT_GAMEPAD_DPAD_DOWN : button = BUTTON_DPAD_DOWN; break;
case XINPUT_GAMEPAD_DPAD_LEFT : button = BUTTON_DPAD_LEFT; break;
case XINPUT_GAMEPAD_DPAD_RIGHT : button = BUTTON_DPAD_RIGHT; break;
case XINPUT_GAMEPAD_START : button = BUTTON_START; break;
case XINPUT_GAMEPAD_BACK : button = BUTTON_BACK; break;
case XINPUT_GAMEPAD_LEFT_THUMB : button = BUTTON_LEFT_THUMB; break;
case XINPUT_GAMEPAD_RIGHT_THUMB : button = BUTTON_RIGHT_THUMB; break;
case XINPUT_GAMEPAD_LEFT_SHOULDER : button = BUTTON_LEFT_SHOULDER; break;
case XINPUT_GAMEPAD_RIGHT_SHOULDER: button = BUTTON_RIGHT_SHOULDER; break;
//case XINPUT_GAMEPAD_GUIDE : button = BUTTON_GUIDE; break;
case XINPUT_GAMEPAD_GUIDE : continue;
case 0x0800 : continue;
case XINPUT_GAMEPAD_A : button = BUTTON_A; break;
case XINPUT_GAMEPAD_B : button = BUTTON_B; break;
case XINPUT_GAMEPAD_X : button = BUTTON_X; break;
case XINPUT_GAMEPAD_Y : button = BUTTON_Y; break;
default: button = 0;
}
if (buff->wButtons & i) {
state->bCurrent |= BUTTON_TO_FLAG(button);
}
else {
state->bCurrent &= ~BUTTON_TO_FLAG(button);
}
}
state->stick[STICK_LEFT].x = buff->sThumbLX;
state->stick[STICK_LEFT].y = buff->sThumbLY;
state->stick[STICK_RIGHT].x = buff->sThumbRX;
state->stick[STICK_RIGHT].y = buff->sThumbRY;
state->trigger[TRIGGER_LEFT].value = buff->bLeftTrigger;
state->trigger[TRIGGER_RIGHT].value = buff->bRightTrigger;
return buff->status == 1;
}
static int parse_xbox_buffer(GAMEPAD_STATE* state, struct buff_out_xbox_t* buff)
{
int button;
int i;
for (i = XINPUT_GAMEPAD_DPAD_UP; i <= XINPUT_GAMEPAD_Y; i<<=1)
{
switch (i)
{
case XINPUT_GAMEPAD_DPAD_UP : button = BUTTON_DPAD_UP; break;
case XINPUT_GAMEPAD_DPAD_DOWN : button = BUTTON_DPAD_DOWN; break;
case XINPUT_GAMEPAD_DPAD_LEFT : button = BUTTON_DPAD_LEFT; break;
case XINPUT_GAMEPAD_DPAD_RIGHT : button = BUTTON_DPAD_RIGHT; break;
case XINPUT_GAMEPAD_START : button = BUTTON_START; break;
case XINPUT_GAMEPAD_BACK : button = BUTTON_BACK; break;
case XINPUT_GAMEPAD_LEFT_THUMB : button = BUTTON_LEFT_THUMB; break;
case XINPUT_GAMEPAD_RIGHT_THUMB : button = BUTTON_RIGHT_THUMB; break;
case XINPUT_GAMEPAD_LEFT_SHOULDER : button = BUTTON_LEFT_SHOULDER; break;
case XINPUT_GAMEPAD_RIGHT_SHOULDER: button = BUTTON_RIGHT_SHOULDER; break;
//case XINPUT_GAMEPAD_GUIDE : button = BUTTON_GUIDE; break;
case XINPUT_GAMEPAD_GUIDE : continue;
case 0x0800 : continue;
case XINPUT_GAMEPAD_A : button = BUTTON_A; break;
case XINPUT_GAMEPAD_B : button = BUTTON_B; break;
case XINPUT_GAMEPAD_X : button = BUTTON_X; break;
case XINPUT_GAMEPAD_Y : button = BUTTON_Y; break;
default: button = 0;
}
if (buff->wButtons & i) {
state->bCurrent |= BUTTON_TO_FLAG(button);
}
else {
state->bCurrent &= ~BUTTON_TO_FLAG(button);
}
}
state->stick[STICK_LEFT].x = buff->sThumbLX;
state->stick[STICK_LEFT].y = buff->sThumbLY;
state->stick[STICK_RIGHT].x = buff->sThumbRX;
state->stick[STICK_RIGHT].y = buff->sThumbRY;
state->trigger[TRIGGER_LEFT].value = buff->bLeftTrigger;
state->trigger[TRIGGER_RIGHT].value = buff->bRightTrigger;
return buff->status == 1;
}
static int get_gamepad_data(GAMEPAD_STATE* state)
{
union
{
struct buff_out_xbox_t xboxOutBuff;
struct buff_out_xbox_one_t xboxOneOutBuff;
} out_buff;
union
{
struct buff_in_t xboxInBuff;
uint8_t xbonOneInBuff;
} in_buff;
DWORD inBuffSize;
DWORD outBuffSize;
unsigned int res;
int online;
memset(&out_buff, 0, sizeof(out_buff));
memset(&in_buff, 0, sizeof(in_buff));
if (state->type == 256)
{// I don't know if its xboxOne stuff
in_buff.xbonOneInBuff = 0;
inBuffSize = sizeof(in_buff.xbonOneInBuff);
outBuffSize = sizeof(out_buff.xboxOneOutBuff);
}
else
{
in_buff.xboxInBuff.field_0 = 257;
in_buff.xboxInBuff.field_2 = 0;
inBuffSize = sizeof(in_buff.xboxInBuff);
outBuffSize = sizeof(out_buff.xboxOutBuff);
}
res = DeviceInOutIo(state->hDevice, IOCTL_XINPUT_GET_DATA, &in_buff, inBuffSize, &out_buff, outBuffSize);
if (res < 0)
return 0;
if (state->type == 256)
online = parse_xboxone_buffer(state, &out_buff.xboxOneOutBuff);
else
online = parse_xbox_buffer(state, &out_buff.xboxOutBuff);
return online;
}
static int get_gamepad_infos(GAMEPAD_STATE* state)
{
WORD buffer[6] = { 0 };
int success = (DeviceInIo(state->hDevice, IOCTL_XINPUT_INIT, buffer, sizeof(buffer)) >= 0 ? 1 : 0);
if (success)
{
if (!(buffer[2] & 0x80))
{
for (int i = 0; i < (buffer[1] & 0xFF); ++i)
{
state->type = buffer[0];
//id.vendorID = buffer[4];
//id.productID = buffer[5];
{
char buff[5] = { 0 };
buff[1] = 13;
buff[4] = 1;
DeviceOutIo(state->hDevice, IOCTL_XINPUT_SET_DATA, buff, sizeof(buff));
}
}
}
}
return success;
}
static void send_gamepad_vibration(GAMEPAD_STATE *state, float left, float right, int rumble_length_ms)
{
uint8_t buff[5] = { 0 };
if (left > 1.0f)
left = 1.0f;
if (right > 1.0f)
right = 1.0f;
buff[0] = 0;
buff[2] = (uint8_t)(left * 255.0f);
buff[3] = (uint8_t)(right * 255.0f);
buff[4] = 2;
DeviceOutIo(state->hDevice, IOCTL_XINPUT_SET_DATA, buff, sizeof(buff));
}
static void GamepadAddDevice(WCHAR* devPath);
static void GamepadRemoveDevice(WCHAR* devPath);
static void GamepadDetect()
{
HDEVINFO device_info_set;
SP_DEVICE_INTERFACE_DATA interface_data;
SP_DEVICE_INTERFACE_DETAIL_DATA_W* data;
DWORD detail_size = MAX_PATH * sizeof(WCHAR);
DWORD idx;
device_info_set = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_XINPUT, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
//HeapAlloc(GetProcessHeap(), 0, sizeof(*data) + detail_size);
data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)malloc(sizeof(*data) + detail_size);
data->cbSize = sizeof(*data);
ZeroMemory(&interface_data, sizeof(interface_data));
interface_data.cbSize = sizeof(interface_data);
idx = 0;
while (SetupDiEnumDeviceInterfaces(device_info_set, NULL, &GUID_DEVINTERFACE_XINPUT, idx++, &interface_data))
{
if (!SetupDiGetDeviceInterfaceDetailW(device_info_set,
&interface_data, data, sizeof(*data) + detail_size, NULL, NULL))
continue;
GamepadAddDevice(data->DevicePath);
}
free(data);
//HeapFree(GetProcessHeap(), 0, data);
SetupDiDestroyDeviceInfoList(device_info_set);
for (int i = 0; i != GAMEPAD_COUNT; ++i) {
if ((STATE[i].flags & FLAG_CONNECTED) && STATE[i].device) {
if (!get_gamepad_data(&STATE[i])) {
GamepadRemoveDevice(STATE[i].device);
}
}
}
}
/* Helper to add a new device */
static void GamepadAddDevice(const WCHAR* devPath) {
int controller = GAMEPAD_COUNT;
HANDLE hDevice;
int i;
/* try to find a free controller */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if ((STATE[i].flags & FLAG_CONNECTED) == 0 && controller == GAMEPAD_COUNT) {
controller = i;
continue;
}
if (STATE[i].device && wcscmp(devPath, STATE[i].device) == 0) {
return;
}
}
if (controller == -1) {
return;
}
hDevice = CreateFileW(devPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hDevice == NULL || hDevice == INVALID_HANDLE_VALUE)
return;
/* copy the device path */
STATE[controller].device = _wcsdup(devPath);
if (STATE[controller].device == NULL) {
CloseHandle(hDevice);
return;
}
STATE[controller].hDevice = hDevice;
if (get_gamepad_infos(&STATE[controller]) == 0) {
STATE[controller].hDevice = INVALID_HANDLE_VALUE;
CloseHandle(hDevice);
return;
}
/* reset device state */
GamepadResetState((GAMEPAD_DEVICE)controller);
STATE[controller].flags |= FLAG_CONNECTED;
}
/* Helper to remove a device */
static void GamepadRemoveDevice(const WCHAR* devPath) {
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if (STATE[i].device != NULL && wcscmp(STATE[i].device, devPath) == 0) {
if (STATE[i].hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(STATE[i].hDevice);
STATE[i].hDevice = INVALID_HANDLE_VALUE;
}
free(STATE[i].device);
STATE[i].device = NULL;
STATE[i].flags = 0;
break;
}
}
}
void GamepadInit(void) {
int i;
/* initialize connection state */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
STATE[i].flags = 0;
STATE[i].hDevice = INVALID_HANDLE_VALUE;
STATE[i].device = NULL;
}
GamepadDetect();
}
void GamepadUpdate(void) {
static unsigned long last = 0;
unsigned long cur = time(NULL);
if (last + 2 < cur) {
GamepadDetect();
last = cur;
}
GamepadUpdateCommon();
}
static int adjust_values_trigger(double min, double max, double value)
{
return (((value + (0 - min)) / (max - min)) * 255.0);
}
static int adjust_values_stick(double min, double max, double value)
{
return (((value + (0 - min)) / (max - min)) * (65535.0)) - 32768.0;
}
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;
if (STATE[gamepad].flags & FLAG_CONNECTED) {
get_gamepad_data(&STATE[gamepad]);
}
}
void GamepadShutdown(void) {
/* no Win32 shutdown required */
int i;
/* cleanup devices */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if (STATE[i].device != NULL) {
free(STATE[i].device);
}
if (STATE[i].hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(STATE[i].hDevice);
}
}
}
void GamepadSetRumble(GAMEPAD_DEVICE gamepad, float left, float right, unsigned int rumble_length_ms) {
//TODO: rumble_length_ms
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);
if (STATE[gamepad].hDevice != INVALID_HANDLE_VALUE) {
send_gamepad_vibration(&STATE[gamepad], left, right, rumble_length_ms);
}
}
@ -242,11 +681,13 @@ static void GamepadDetect()
/* Helper to add a new device */
static void GamepadAddDevice(const char* devPath) {
int i;
int controller = GAMEPAD_COUNT;
/* try to find a free controller */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if ((STATE[i].flags & FLAG_CONNECTED) == 0) {
break;
if ((STATE[i].flags & FLAG_CONNECTED) == 0 && controller == GAMEPAD_COUNT) {
controller = i;
continue;
}
if (STATE[i].device && strcmp(devPath, STATE[i].device) == 0) {
@ -254,7 +695,7 @@ static void GamepadAddDevice(const char* devPath) {
}
}
if (i == GAMEPAD_COUNT) {
if (controller == GAMEPAD_COUNT) {
return;
}
@ -268,19 +709,18 @@ static void GamepadAddDevice(const char* devPath) {
}
/* copy the device path */
STATE[i].device = strdup(devPath);
if (STATE[i].device == NULL) {
STATE[controller].device = strdup(devPath);
if (STATE[controller].device == NULL) {
return;
}
/* reset device state */
GamepadResetState((GAMEPAD_DEVICE)i);
GamepadResetState((GAMEPAD_DEVICE)controller);
fcntl(fd, F_SETFL, O_NONBLOCK);
STATE[i].fd = fd;
STATE[i].flags |= FLAG_CONNECTED;
STATE[controller].fd = fd;
STATE[controller].flags |= FLAG_CONNECTED;
int controller = i;
{
int i, t;
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
@ -414,6 +854,9 @@ static int adjust_values_stick(double min, double max, double value)
}
static void GamepadUpdateDevice(GAMEPAD_DEVICE gamepad) {
if (gamepad >= GAMEPAD_COUNT)
return;
if (STATE[gamepad].flags & FLAG_CONNECTED) {
struct input_event events[32];
int i, len;
@ -547,6 +990,9 @@ void GamepadShutdown(void) {
}
void GamepadSetRumble(GAMEPAD_DEVICE gamepad, float left, float right, unsigned int rumble_length_ms) {
if (gamepad >= GAMEPAD_COUNT)
return;
if (STATE[gamepad].fd != -1) {
struct input_event play;
struct ff_effect ff;
@ -580,74 +1026,122 @@ void GamepadSetRumble(GAMEPAD_DEVICE gamepad, float left, float right, unsigned
#endif /* end of platform implementations */
GAMEPAD_BOOL GamepadIsConnected(GAMEPAD_DEVICE device) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
return (STATE[device].flags & FLAG_CONNECTED) != 0 ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonDown(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
return (STATE[device].bCurrent & BUTTON_TO_FLAG(button)) != 0 ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonTriggered(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
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) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
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) {
if (device >= GAMEPAD_COUNT)
return 0;
return STATE[device].trigger[trigger].value;
}
float GamepadTriggerLength(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
if (device >= GAMEPAD_COUNT)
return 0.0f;
return STATE[device].trigger[trigger].length;
}
GAMEPAD_BOOL GamepadTriggerDown(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
return STATE[device].trigger[trigger].pressedCurrent;
}
GAMEPAD_BOOL GamepadTriggerTriggered(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
return (STATE[device].trigger[trigger].pressedCurrent &&
!STATE[device].trigger[trigger].pressedLast) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadTriggerReleased(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
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) {
if (device >= GAMEPAD_COUNT)
return;
*outX = STATE[device].stick[stick].x;
*outY = STATE[device].stick[stick].y;
}
float GamepadStickLength(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
if (device >= GAMEPAD_COUNT)
return 0.0f;
return STATE[device].stick[stick].length;
}
void GamepadStickNormXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, float *outX, float *outY) {
if (device >= GAMEPAD_COUNT)
return;
*outX = STATE[device].stick[stick].nx;
*outY = STATE[device].stick[stick].ny;
}
float GamepadStickAngle(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
if (device >= GAMEPAD_COUNT)
return 0.0f;
return STATE[device].stick[stick].angle;
}
GAMEPAD_STICKDIR GamepadStickDir(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
if (device >= GAMEPAD_COUNT)
return STICKDIR_CENTER;
return STATE[device].stick[stick].dirCurrent;
}
GAMEPAD_BOOL GamepadStickDirTriggered(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, GAMEPAD_STICKDIR dir) {
if (device >= GAMEPAD_COUNT)
return GAMEPAD_FALSE;
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) {
if (gamepad >= GAMEPAD_COUNT)
return;
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;

View File

@ -32,13 +32,25 @@ extern "C" {
/**
* Enumeration of the possible devices.
*
* Only four devices are supported as this is the limit of Windows.
* With open_xinput you can have more than 4 controllers on 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_0 = 0, /**< First gamepad */
GAMEPAD_1 = 1, /**< Second gamepad */
GAMEPAD_2 = 2, /**< Third gamepad */
GAMEPAD_3 = 3, /**< Fourth gamepad */
GAMEPAD_4 = 4,
GAMEPAD_5 = 5,
GAMEPAD_6 = 6,
GAMEPAD_7 = 7,
GAMEPAD_8 = 8,
GAMEPAD_9 = 9,
GAMEPAD_10 = 10,
GAMEPAD_11 = 11,
GAMEPAD_12 = 12,
GAMEPAD_13 = 13,
GAMEPAD_14 = 14,
GAMEPAD_15 = 15,
GAMEPAD_COUNT /**< Maximum number of supported gamepads */
};

View File

@ -649,6 +649,13 @@ static void load_dlls()
std::vector<std::string> paths = Local_Storage::get_filenames_path(path);
for (auto & p: paths) {
std::string full_path = path + p;
size_t length = full_path.length();
if (length < 4) continue;
if (std::toupper(full_path[length - 1]) != 'L') continue;
if (std::toupper(full_path[length - 2]) != 'L') continue;
if (std::toupper(full_path[length - 3]) != 'D') continue;
if (full_path[length - 4] != '.') continue;
PRINT_DEBUG("Trying to load %s\n", full_path.c_str());
if (LoadLibraryA(full_path.c_str())) {
PRINT_DEBUG("LOADED %s\n", full_path.c_str());

View File

@ -27,11 +27,7 @@
#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,18 @@
<http://www.gnu.org/licenses/>. */
#include "base.h"
#ifndef CONTROLLER_SUPPORT
inline void GamepadInit(void) {}
inline void GamepadShutdown(void) {}
inline void GamepadUpdate(void) {}
inline GAMEPAD_BOOL GamepadIsConnected(GAMEPAD_DEVICE device) { return GAMEPAD_FALSE; }
inline GAMEPAD_BOOL GamepadButtonDown(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) { return GAMEPAD_FALSE; }
inline float GamepadTriggerLength(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) { return 0.0; }
inline GAMEPAD_STICKDIR GamepadStickDir(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) { return STICKDIR_CENTER; }
inline void GamepadStickNormXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, float* outX, float* outY) {}
inline float GamepadStickLength(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) { return 0.0; }
inline void GamepadSetRumble(GAMEPAD_DEVICE device, float left, float right, unsigned int rumble_length_ms) {}
#endif
struct Controller_Map {
std::map<ControllerDigitalActionHandle_t, std::set<int>> active_digital;
@ -305,10 +317,16 @@ int GetConnectedControllers( ControllerHandle_t *handlesOut )
}
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;};
for (int i = GAMEPAD_0; i < GAMEPAD_COUNT; ++i)
{
if (GamepadIsConnected((GAMEPAD_DEVICE)i))
{
*handlesOut = i + 1;
++handlesOut;
++count;
};
}
PRINT_DEBUG("returned %i connected controllers\n", count);
return count;
@ -756,7 +774,7 @@ int GetGamepadIndexForController( ControllerHandle_t ulControllerHandle )
// Returns the associated controller handle for the specified emulated gamepad
ControllerHandle_t GetControllerForGamepadIndex( int nIndex )
{
PRINT_DEBUG("Steam_Controller::GetControllerForGamepadIndex\n");
PRINT_DEBUG("Steam_Controller::GetControllerForGamepadIndex %i\n", nIndex);
ControllerHandle_t out = nIndex + 1;
auto controller = controllers.find(out);
if (controller == controllers.end()) return 0;
@ -890,7 +908,7 @@ const char *GetGlyphForActionOrigin( EInputActionOrigin eOrigin )
// Returns the input type for a particular handle
ESteamInputType GetInputTypeForHandle( ControllerHandle_t controllerHandle )
{
PRINT_DEBUG("Steam_Controller::GetInputTypeForHandle\n");
PRINT_DEBUG("Steam_Controller::GetInputTypeForHandle %llu\n", controllerHandle);
auto controller = controllers.find(controllerHandle);
if (controller == controllers.end()) return k_ESteamInputType_Unknown;
return k_ESteamInputType_XBox360Controller;

View File

@ -1,375 +0,0 @@
/* 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

@ -107,11 +107,16 @@ Steam_Networking_Sockets(class Settings *settings, class Networking *network, cl
this->run_every_runcb->remove(&Steam_Networking_Sockets::steam_run_every_runcb, this);
}
static unsigned long get_socket_id()
{
static unsigned long socket_id;
socket_id++;
return socket_id;
}
HSteamListenSocket new_listen_socket(int nSteamConnectVirtualPort)
{
static HSteamListenSocket socket_id;
++socket_id;
HSteamListenSocket socket_id = get_socket_id();
if (socket_id == k_HSteamListenSocket_Invalid) ++socket_id;
auto conn = std::find_if(listen_sockets.begin(), listen_sockets.end(), [&nSteamConnectVirtualPort](struct Listen_Socket const& conn) { return conn.virtual_port == nSteamConnectVirtualPort;});
@ -165,8 +170,7 @@ HSteamNetConnection new_connect_socket(SteamNetworkingIdentity remote_identity,
socket.user_data = -1;
socket.poll_group = k_HSteamNetPollGroup_Invalid;
static HSteamNetConnection socket_id;
++socket_id;
HSteamNetConnection socket_id = get_socket_id();
if (socket_id == k_HSteamNetConnection_Invalid) ++socket_id;
if (connect_sockets.insert(std::make_pair(socket_id, socket)).second == false) {
@ -833,7 +837,25 @@ int ReceiveMessagesOnListenSocket( HSteamListenSocket hSocket, SteamNetworkingMe
bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo )
{
PRINT_DEBUG("Steam_Networking_Sockets::GetConnectionInfo\n");
return false;
if (!pInfo)
return false;
std::lock_guard<std::recursive_mutex> lock(global_mutex);
auto connect_socket = connect_sockets.find(hConn);
if (connect_socket == connect_sockets.end()) return false;
memset(pInfo, 0, sizeof(SteamNetConnectionInfo_t));
pInfo->m_identityRemote = connect_socket->second.remote_identity;
pInfo->m_nUserData = connect_socket->second.user_data;
pInfo->m_hListenSocket = connect_socket->second.listen_socket_id;
//pInfo->m_addrRemote; //TODO
pInfo->m_idPOPRemote = 0;
pInfo->m_idPOPRelay = 0;
pInfo->m_eState = convert_status(connect_socket->second.status);
pInfo->m_eEndReason = 0; //TODO
pInfo->m_szEndDebug[0] = 0;
sprintf(pInfo->m_szConnectionDescription, "%u", hConn);
return true;
}
@ -878,7 +900,7 @@ int ReceiveMessagesOnListenSocket( HSteamListenSocket hSocket, SteamNetworkingMe
/// Returns information about the specified connection.
bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo001_t *pInfo )
{
PRINT_DEBUG("Steam_Networking_Sockets::GetConnectionInfo\n");
PRINT_DEBUG("Steam_Networking_Sockets::GetConnectionInfo001\n");
return false;
}
@ -888,7 +910,21 @@ bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo001_t *
bool GetQuickConnectionStatus( HSteamNetConnection hConn, SteamNetworkingQuickConnectionStatus *pStats )
{
PRINT_DEBUG("Steam_Networking_Sockets::GetQuickConnectionStatus\n");
return false;
if (!pStats)
return false;
std::lock_guard<std::recursive_mutex> lock(global_mutex);
auto connect_socket = connect_sockets.find(hConn);
if (connect_socket == connect_sockets.end()) return false;
memset(pStats, 0, sizeof(SteamNetworkingQuickConnectionStatus));
pStats->m_eState = convert_status(connect_socket->second.status);
pStats->m_nPing = 10; //TODO: calculate real numbers?
pStats->m_flConnectionQualityLocal = 1.0;
pStats->m_flConnectionQualityRemote = 1.0;
//TODO: rest
return true;
}

View File

@ -18,13 +18,15 @@ bool Windows_Hook::start_hook()
{
GetRawInputBuffer = ::GetRawInputBuffer;
GetRawInputData = ::GetRawInputData;
SetCursorPos = ::SetCursorPos;
PRINT_DEBUG("Hooked Windows\n");
BeginHook();
HookFuncs(
std::make_pair<void**, void*>(&(PVOID&)GetRawInputBuffer, &Windows_Hook::MyGetRawInputBuffer),
std::make_pair<void**, void*>(&(PVOID&)GetRawInputData , &Windows_Hook::MyGetRawInputData)
std::make_pair<void**, void*>(&(PVOID&)GetRawInputData , &Windows_Hook::MyGetRawInputData),
std::make_pair<void**, void*>(&(PVOID&)SetCursorPos , &Windows_Hook::MySetCursorPos)
);
EndHook();
@ -169,6 +171,18 @@ UINT WINAPI Windows_Hook::MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand,
return 0;
}
BOOL WINAPI Windows_Hook::MySetCursorPos(int x, int y)
{
if (get_steam_client()->steam_overlay->ShowOverlay()) {
POINT p;
GetCursorPos(&p);
x = p.x;
y = p.y;
}
return Windows_Hook::Inst()->SetCursorPos(x, y);
}
/////////////////////////////////////////////////////////////////////////////////////
Windows_Hook::Windows_Hook() :

View File

@ -26,11 +26,13 @@ private:
// Hook to Windows window messages
decltype(GetRawInputBuffer)* GetRawInputBuffer;
decltype(GetRawInputData)* GetRawInputData;
decltype(SetCursorPos)* SetCursorPos;
static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static UINT WINAPI MyGetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader);
static UINT WINAPI MyGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader);
static BOOL WINAPI MySetCursorPos(int x, int y);
public:
virtual ~Windows_Hook();

View File

@ -52,7 +52,6 @@ public:
/// setting the options "immediately" after creation.
virtual HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &address, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0;
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
/// Like CreateListenSocketIP, but clients will connect using ConnectP2P
///
/// nVirtualPort specifies how clients can connect to this socket using
@ -81,7 +80,6 @@ public:
/// SteamNetworkingConfigValue_t for more about why this is preferable to
/// setting the options "immediately" after creation.
virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0;
#endif
/// Accept an incoming connection that has been received on a listen socket.
///
@ -411,8 +409,6 @@ public:
/// other connections.)
virtual int ReceiveMessagesOnPollGroup( HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0;
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
//
// Clients connecting to dedicated servers hosted in a data center,
// using central-authority-granted tickets.
@ -608,7 +604,6 @@ public:
/// If you expect to be using relayed connections, then you probably want
/// to call ISteamNetworkingUtils::InitRelayNetworkAccess() when your app initializes
virtual bool ReceivedP2PCustomSignal( const void *pMsg, int cbMsg, ISteamNetworkingCustomSignalingRecvContext *pContext ) = 0;
#endif // #ifndef STEAMNETWORKINGSOCKETS_ENABLE_SDR
//
// Certificate provision by the application. On Steam, we normally handle all this automatically

View File

@ -8,7 +8,6 @@
class ISteamNetworkingUtils001
{
public:
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
//
// Initialization
@ -149,7 +148,6 @@ public:
/// Get list of all POP IDs. Returns the number of entries that were filled into
/// your list.
virtual int GetPOPList( SteamNetworkingPOPID *list, int nListSz ) = 0;
#endif // #ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
//
// Misc

View File

@ -8,7 +8,6 @@
class ISteamNetworkingUtils002
{
public:
#ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
//
// Initialization and status check
@ -152,7 +151,6 @@ public:
/// Get list of all POP IDs. Returns the number of entries that were filled into
/// your list.
virtual int GetPOPList( SteamNetworkingPOPID *list, int nListSz ) = 0;
#endif // #ifdef STEAMNETWORKINGSOCKETS_ENABLE_SDR
//
// Misc

View File

@ -45,7 +45,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
}
if (GetFileAttributesA(CurrentDirectory) == INVALID_FILE_ATTRIBUTES) {
MessageBoxA(NULL, "Couldn't find the configuration file(ColdClientLoader.ini).", "ColdClientLoader", MB_ICONERROR);
ExitProcess(NULL);
return 0;
}
GetPrivateProfileStringA("SteamClient", "SteamClient64Dll", "", Client64Path, MAX_PATH, CurrentDirectory);
@ -60,27 +60,23 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
SetEnvironmentVariableA("SteamGameId", AppId);
}
CHAR TMP[MAX_PATH] = { 0 };
CHAR TMP[MAX_PATH] = {};
if (!IsNotRelativePathOrRemoveFileName(Client64Path, false)) {
ZeroMemory(TMP, sizeof(TMP));
lstrcpyA(TMP, Client64Path);
ZeroMemory(Client64Path, sizeof(Client64Path));
GetFullPathNameA(TMP, MAX_PATH, Client64Path, NULL);
}
if (!IsNotRelativePathOrRemoveFileName(ClientPath, false)) {
ZeroMemory(TMP, sizeof(TMP));
lstrcpyA(TMP, ClientPath);
ZeroMemory(ClientPath, sizeof(ClientPath));
GetFullPathNameA(TMP, MAX_PATH, ClientPath, NULL);
}
if (!IsNotRelativePathOrRemoveFileName(ExeFile, false)) {
ZeroMemory(TMP, sizeof(TMP));
lstrcpyA(TMP, ExeFile);
ZeroMemory(ExeFile, sizeof(ExeFile));
GetFullPathNameA(TMP, MAX_PATH, ExeFile, NULL);
}
if (!IsNotRelativePathOrRemoveFileName(ExeRunDir, false)) {
ZeroMemory(TMP, sizeof(TMP));
lstrcpyA(TMP, ExeRunDir);
ZeroMemory(ExeRunDir, sizeof(ExeRunDir));
GetFullPathNameA(TMP, MAX_PATH, ExeRunDir, NULL);
@ -88,17 +84,17 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
if (GetFileAttributesA(Client64Path) == INVALID_FILE_ATTRIBUTES) {
MessageBoxA(NULL, "Couldn't find the requested SteamClient64Dll.", "ColdClientLoader", MB_ICONERROR);
ExitProcess(NULL);
return 0;
}
if (GetFileAttributesA(ClientPath) == INVALID_FILE_ATTRIBUTES) {
MessageBoxA(NULL, "Couldn't find the requested SteamClientDll.", "ColdClientLoader", MB_ICONERROR);
ExitProcess(NULL);
return 0;
}
if (GetFileAttributesA(ExeFile) == INVALID_FILE_ATTRIBUTES) {
MessageBoxA(NULL, "Couldn't find the requested Exe file.", "ColdClientLoader", MB_ICONERROR);
ExitProcess(NULL);
return 0;
}
CHAR CommandLine[8192];
@ -106,98 +102,65 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
if (!ExeFile[0] || !CreateProcessA(ExeFile, CommandLine, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, ExeRunDir, &info, &processInfo))
{
MessageBoxA(NULL, "Unable to load the requested EXE file.", "ColdClientLoader", MB_ICONERROR);
ExitProcess(NULL);
return 0;
}
HKEY Registrykey;
// Declare some variables to be used for Steam registry.
DWORD UserId = 0x03100004771F810D & 0xffffffff;
DWORD ProcessID = GetCurrentProcessId();
if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS, &Registrykey) != ERROR_SUCCESS)
bool orig_steam = false;
DWORD keyType = REG_SZ;
CHAR OrgSteamCDir[MAX_PATH] = { 0 };
CHAR OrgSteamCDir64[MAX_PATH] = { 0 };
DWORD Size1 = MAX_PATH;
DWORD Size2 = MAX_PATH;
if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS)
{
orig_steam = true;
// Get original values to restore later.
RegQueryValueExA(Registrykey, "SteamClientDll", 0, &keyType, (LPBYTE)& OrgSteamCDir, &Size1);
RegQueryValueExA(Registrykey, "SteamClientDll64", 0, &keyType, (LPBYTE)& OrgSteamCDir64, &Size2);
} else {
if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", 0, 0, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &Registrykey, NULL) != ERROR_SUCCESS)
{
MessageBoxA(NULL, "Unable to patch Steam process informations on the Windows registry.", "ColdClientLoader", MB_ICONERROR);
TerminateProcess(processInfo.hProcess, NULL);
ExitProcess(NULL);
}
else
{
// Set values to Windows registry.
RegSetValueExA(Registrykey, "ActiveUser", NULL, REG_DWORD, (LPBYTE)& UserId, sizeof(DWORD));
RegSetValueExA(Registrykey, "pid", NULL, REG_DWORD, (LPBYTE)& ProcessID, sizeof(DWORD));
{
// Before saving to the registry check again if the path was valid and if the file exist
if (GetFileAttributesA(ClientPath) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExA(Registrykey, "SteamClientDll", NULL, REG_SZ, (LPBYTE)ClientPath, (DWORD)lstrlenA(ClientPath) + 1);
}
else {
RegSetValueExA(Registrykey, "SteamClientDll", NULL, REG_SZ, (LPBYTE)"", 0);
}
if (GetFileAttributesA(Client64Path) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExA(Registrykey, "SteamClientDll64", NULL, REG_SZ, (LPBYTE)Client64Path, (DWORD)lstrlenA(Client64Path) + 1);
}
else {
RegSetValueExA(Registrykey, "SteamClientDll64", NULL, REG_SZ, (LPBYTE)"", 0);
}
}
RegSetValueExA(Registrykey, "Universe", NULL, REG_SZ, (LPBYTE)"Public", (DWORD)lstrlenA("Public") + 1);
// Close the HKEY Handle.
RegCloseKey(Registrykey);
ResumeThread(processInfo.hThread);
WaitForSingleObject(processInfo.hThread, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
ExitProcess(NULL);
return 0;
}
}
else
// Set values to Windows registry.
RegSetValueExA(Registrykey, "ActiveUser", NULL, REG_DWORD, (LPBYTE)& UserId, sizeof(DWORD));
RegSetValueExA(Registrykey, "pid", NULL, REG_DWORD, (LPBYTE)& ProcessID, sizeof(DWORD));
{
DWORD keyType = REG_SZ;
CHAR OrgSteamCDir[MAX_PATH] = { 0 };
CHAR OrgSteamCDir64[MAX_PATH] = { 0 };
DWORD Size1 = MAX_PATH;
DWORD Size2 = MAX_PATH;
// Get original values to restore later.
RegQueryValueExA(Registrykey, "SteamClientDll", 0, &keyType, (LPBYTE)& OrgSteamCDir, &Size1);
RegQueryValueExA(Registrykey, "SteamClientDll64", 0, &keyType, (LPBYTE)& OrgSteamCDir64, &Size2);
// Set values to Windows registry.
RegSetValueExA(Registrykey, "ActiveUser", NULL, REG_DWORD, (LPBYTE)& UserId, sizeof(DWORD));
RegSetValueExA(Registrykey, "pid", NULL, REG_DWORD, (LPBYTE)& ProcessID, sizeof(DWORD));
{
// Before saving to the registry check again if the path was valid and if the file exist
if (GetFileAttributesA(ClientPath) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExA(Registrykey, "SteamClientDll", NULL, REG_SZ, (LPBYTE)ClientPath, (DWORD)lstrlenA(ClientPath) + 1);
}
else {
RegSetValueExA(Registrykey, "SteamClientDll", NULL, REG_SZ, (LPBYTE)"", 0);
}
if (GetFileAttributesA(Client64Path) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExA(Registrykey, "SteamClientDll64", NULL, REG_SZ, (LPBYTE)Client64Path, (DWORD)lstrlenA(Client64Path) + 1);
}
else {
RegSetValueExA(Registrykey, "SteamClientDll64", NULL, REG_SZ, (LPBYTE)"", 0);
}
// Before saving to the registry check again if the path was valid and if the file exist
if (GetFileAttributesA(ClientPath) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExA(Registrykey, "SteamClientDll", NULL, REG_SZ, (LPBYTE)ClientPath, (DWORD)lstrlenA(ClientPath) + 1);
}
RegSetValueExA(Registrykey, "Universe", NULL, REG_SZ, (LPBYTE)"Public", (DWORD)lstrlenA("Public") + 1);
else {
RegSetValueExA(Registrykey, "SteamClientDll", NULL, REG_SZ, (LPBYTE)"", 0);
}
if (GetFileAttributesA(Client64Path) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExA(Registrykey, "SteamClientDll64", NULL, REG_SZ, (LPBYTE)Client64Path, (DWORD)lstrlenA(Client64Path) + 1);
}
else {
RegSetValueExA(Registrykey, "SteamClientDll64", NULL, REG_SZ, (LPBYTE)"", 0);
}
}
RegSetValueExA(Registrykey, "Universe", NULL, REG_SZ, (LPBYTE)"Public", (DWORD)lstrlenA("Public") + 1);
// Close the HKEY Handle.
RegCloseKey(Registrykey);
// Close the HKEY Handle.
RegCloseKey(Registrykey);
ResumeThread(processInfo.hThread);
WaitForSingleObject(processInfo.hThread, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
ResumeThread(processInfo.hThread);
WaitForSingleObject(processInfo.hThread, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
if (orig_steam) {
if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS)
{
// Restore the values.
@ -207,9 +170,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
// Close the HKEY Handle.
RegCloseKey(Registrykey);
}
ExitProcess(NULL);
}
return 1;
return 0;
}