Skip to content

Commit

Permalink
Merge pull request #9 from walkco/feature/bluetooth
Browse files Browse the repository at this point in the history
Basic Bluetooth support.
  • Loading branch information
walkco committed Jan 19, 2023
2 parents 2cb60a0 + 664c540 commit 6f30d7d
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 44 deletions.
18 changes: 15 additions & 3 deletions .vscode/launch.json
Expand Up @@ -2,16 +2,28 @@
"version": "0.2.0",
"configurations": [
{
"name": "Build and debug",
"name": "Build and debug stadia-vigem",
"type": "cppvsdbg",
"request": "launch",
"program": "bin/stadia-vigem.exe",
"program": "bin/stadia-vigem-x64.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"preLaunchTask": "Build debug binary"
"preLaunchTask": "Build debug binary (x64)"
},
{
"name": "Build and debug stadia-tester",
"type": "cppvsdbg",
"request": "launch",
"program": "bin/stadia-tester-x64.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"preLaunchTask": "Build debug binary (x64)"
}
]
}
69 changes: 61 additions & 8 deletions Build.ps1
Expand Up @@ -9,8 +9,6 @@ $script:CommonFlags = @("/Zi", "/W4", "/EHsc", "/DWIN32", "/D_UNICODE", "/DUNICO
$script:DebugFlags = @( "/Od" )
$script:ReleaseFlags = @("/GL", "/O2")

$script:OutputName = "stadia-vigem-"

function Import-Prerequisites {

if ($SkipBuildToolsSetup -eq $true) {
Expand Down Expand Up @@ -48,13 +46,61 @@ function Invoke-BuildTools {
Invoke-CmdScript "$($latestVsInstallationInfo.InstallationPath)\VC\Auxiliary\Build\vcvarsall.bat" $Architecture
}

function Invoke-Build {
function Invoke-Build-libstadia {
param (
$Architecture
)

$OutputName = "libstadia-$Architecture.lib"
$Flags = If ($Configuration -eq "DEBUG") {$script:DebugFlags} else {$script:ReleaseFlags}

$StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch

Write-Host "*** ${OutputName}: Build started ***"
Write-Host

$StopWatch.Start()

& "cl.exe" /c $Flags $CommonFlags /Ilibstadia/include /Foobj/libstadia/ libstadia/src/*.c
& "lib.exe" /out:bin/$OutputName obj/libstadia/*.obj

$StopWatch.Stop()

Write-Host
Write-Host "*** ${OutputName}: Build finished in $($StopWatch.Elapsed) ***"
}

function Invoke-Build-Stadia-Tester {
param (
$Architecture
)

$OutputName = "stadia-tester-$Architecture.exe"
$Flags = If ($Configuration -eq "DEBUG") {$script:DebugFlags} else {$script:ReleaseFlags}

$StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch

Write-Host "*** ${OutputName}: Build started ***"
Write-Host

$StopWatch.Start()

& "cl.exe" $Flags $CommonFlags /Ilibstadia/include /Foobj/stadia-tester/ /Febin/$OutputName stadia-tester/src/*.c User32.lib

$StopWatch.Stop()

Write-Host
Write-Host "*** ${OutputName}: Build finished in $($StopWatch.Elapsed) ***"
}

function Invoke-Build-Stadia-ViGEm {
param (
$Architecture
)

$OutputName = "$script:OutputName$Architecture.exe"
$OutputName = "stadia-vigem-$Architecture.exe"
$Flags = If ($Configuration -eq "DEBUG") {$script:DebugFlags} else {$script:ReleaseFlags}
$LibraryPath = "bin/libstadia-$Architecture.lib"

$StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch

Expand All @@ -63,8 +109,8 @@ function Invoke-Build {

$StopWatch.Start()

& "rc.exe" /foobj/stadia-vigem.res res/res.rc
& "cl.exe" $Flags $CommonFlags /IViGEmClient/include /Foobj/ /Febin/$OutputName ViGEmClient/src/*.cpp obj/stadia-vigem.res src/*.c
& "rc.exe" /foobj/stadia-vigem/stadia-vigem.res stadia-vigem/res/res.rc
& "cl.exe" $Flags $CommonFlags /Ilibstadia/include /IViGEmClient/include /Istadia-vigem/include /Foobj/stadia-vigem/ /Febin/$OutputName ViGEmClient/src/*.cpp obj/stadia-vigem/stadia-vigem.res stadia-vigem/src/*.c $LibraryPath

$StopWatch.Stop()

Expand All @@ -76,19 +122,26 @@ function Invoke-Build {

New-Item -Path "bin" -ItemType Directory -Force > $null
New-Item -Path "obj" -ItemType Directory -Force > $null
New-Item -Path "obj/libstadia" -ItemType Directory -Force > $null
New-Item -Path "obj/stadia-tester" -ItemType Directory -Force > $null
New-Item -Path "obj/stadia-vigem" -ItemType Directory -Force > $null

Import-Prerequisites

Write-Host "-- Build started. Configuration: $Configuration, Architecture: $Architecture --"

if ($Architecture -eq "x86" -Or $Architecture -eq "ALL") {
Invoke-BuildTools -Architecture "x86"
Invoke-Build -Architecture "x86"
Invoke-Build-libstadia -Architecture "x86"
Invoke-Build-Stadia-Tester -Architecture "x86"
Invoke-Build-Stadia-ViGEm -Architecture "x86"
}

if ($Architecture -eq "x64" -Or $Architecture -eq "ALL") {
Invoke-BuildTools -Architecture "x64"
Invoke-Build -Architecture "x64"
Invoke-Build-libstadia -Architecture "x64"
#Invoke-Build-Stadia-Tester -Architecture "x64"
Invoke-Build-Stadia-ViGEm -Architecture "x64"
}

Write-Host "-- Build completed. --"
8 changes: 4 additions & 4 deletions README.md
@@ -1,10 +1,10 @@
# Stadia-ViGEm

Xbox 360 controller emulation for Stadia controller. Supports multiple devices and vibration. Forked from Mi-ViGEm (https://github.com/grayver/Mi-ViGEm) by grayver.
Xbox 360 emulation driver is provided by ViGEm (https://github.com/ViGEm/ViGEmBus), by Benjamin Höglinger.
Xbox 360 controller emulation for Stadia controller. Supports controllers connected via USB & bluetooth. Supports multiple devices and vibration (wired only). Forked from Mi-ViGEm (https://github.com/grayver/Mi-ViGEm) by grayver.
Xbox 360 controller emulation driver is provided by ViGEm (https://github.com/ViGEm/ViGEmBus), by Benjamin Höglinger.

## Requirements
- Windows 10 (should work on Windows 7 and 8 also)
- Windows 11 (should work on Windows 7-10 also)
- ViGEm bus installed (can be downloaded [here](https://github.com/ViGEm/ViGEmBus/releases))

## How it works
Expand All @@ -18,7 +18,7 @@ Stadia-ViGEm creates a virtual Xbox 360 controller which results in double input
- Click "+" button
- Browse to the Stadia-ViGEm executable you normally use (Stadia-ViGEm-x86.exe or Stadia-ViGEm-x64.exe)
- On Devices tab:
- Tick box next to the Stadia controller entry (my controller is named as "Google LLC Stadia Controller rev. A")
- Tick box next to the Stadia controller entry (wired controllers are named "Google LLC Stadia Controller rev. A" & bluetooth controllers are named "HID-compliant game controller")
- Tick "Enable device hiding" at the bottom of the window
- Reboot your PC

Expand Down
File renamed without changes.
34 changes: 27 additions & 7 deletions src/stadia.h → libstadia/include/stadia.h
Expand Up @@ -10,10 +10,13 @@
#define STADIA_ERROR_VIBRATION_INIT_FAILURE 0x1
#define STADIA_ERROR_THREAD_CREATE_FAILURE 0x2

#define STADIA_HW_VENDOR_ID 0x18D1
#define STADIA_HW_PRODUCT_ID 0x9400
#define STADIA_USB_HW_VENDOR_ID 0x18D1
#define STADIA_USB_HW_PRODUCT_ID 0x9400
#define STADIA_USB_HW_FILTER TEXT("VID_18D1&PID_9400")

#define STADIA_HW_FILTER TEXT("VID_18D1&PID_9400")
#define STADIA_BLT_HW_VENDOR_ID 0x18D1
#define STADIA_BLT_HW_PRODUCT_ID 0x9400
#define STADIA_BLT_HW_FILTER TEXT("vid&0218d1_pid&9400")

#define STADIA_BUTTON_NONE 0x00000000
#define STADIA_BUTTON_A 0x00000001
Expand All @@ -32,9 +35,6 @@
#define STADIA_BUTTON_MENU 0x00002000
#define STADIA_BUTTON_STADIA_BTN 0x00004000

void (*stadia_update_callback)(struct stadia_controller *, struct stadia_state *);
void (*stadia_destroy_callback)(struct stadia_controller *);

struct stadia_state
{
DWORD buttons;
Expand All @@ -49,7 +49,27 @@ struct stadia_state
BYTE right_trigger;
};

struct stadia_controller;
struct stadia_controller
{
struct hid_device *device;

SRWLOCK state_lock;
struct stadia_state state;

BOOL active;
HANDLE stopping_event;
HANDLE output_event;

SRWLOCK vibration_lock;
BYTE small_motor;
BYTE big_motor;

HANDLE input_thread;
HANDLE output_thread;
};

void (*stadia_update_callback)(struct stadia_controller *, struct stadia_state *);
void (*stadia_destroy_callback)(struct stadia_controller *);

struct stadia_controller *stadia_controller_create(struct hid_device *device);
void stadia_controller_set_vibration(struct stadia_controller *controller, BYTE small_motor, BYTE big_motor);
Expand Down
File renamed without changes.
File renamed without changes.
25 changes: 4 additions & 21 deletions src/stadia.c → libstadia/src/stadia.c
Expand Up @@ -22,25 +22,6 @@

static const BYTE init_vibration[5] = {STADIA_VIBRATION_IDENTIFIER, 0x00, 0x00, 0x00, 0x00};

struct stadia_controller
{
struct hid_device *device;

SRWLOCK state_lock;
struct stadia_state state;

BOOL active;
HANDLE stopping_event;
HANDLE output_event;

SRWLOCK vibration_lock;
BYTE small_motor;
BYTE big_motor;

HANDLE input_thread;
HANDLE output_thread;
};

static const DWORD dpad_map[8] =
{
STADIA_BUTTON_UP,
Expand Down Expand Up @@ -144,10 +125,12 @@ static DWORD WINAPI _stadia_output_thread(LPVOID lparam)

struct stadia_controller *stadia_controller_create(struct hid_device *device)
{
if (hid_send_output_report(device, init_vibration, sizeof(init_vibration), STADIA_READ_TIMEOUT) <= 0)
if (!hid_send_output_report(device, init_vibration, sizeof(init_vibration), STADIA_READ_TIMEOUT) <= 0)
{
last_error = STADIA_ERROR_VIBRATION_INIT_FAILURE;
return NULL;
// Don't error out for now.
// TODO: Fix vibration for bluetooth controllers.
//return NULL;
}

SECURITY_ATTRIBUTES security = {.nLength = sizeof(SECURITY_ATTRIBUTES),
Expand Down
File renamed without changes.
86 changes: 86 additions & 0 deletions stadia-tester/src/main.c
@@ -0,0 +1,86 @@
#include <assert.h>
#include <stdio.h>

#include <Windows.h>
#include <hidsdi.h>

#define DEVICE_USAGE_GAMEPAD 0x05

int main() {
printf("Looking for HID controller(s)...\n");

HWND hwnd = GetConsoleWindow();

RAWINPUTDEVICE devices[1];
devices[0].dwFlags = RIDEV_INPUTSINK;
devices[0].usUsage = DEVICE_USAGE_GAMEPAD;
devices[0].usUsagePage = 1;
devices[0].hwndTarget = hwnd;

UINT count = 0;
if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) == -1) {
printf("GetRawInputDeviceList failed. Error code: %d\n", GetLastError());
return GetLastError();
}

printf("Found %d gamepad devices.\n", count);

PRAWINPUTDEVICELIST device_list = malloc(count * sizeof(RAWINPUTDEVICELIST));

if (GetRawInputDeviceList(device_list, &count, sizeof(RAWINPUTDEVICELIST)) == -1) {
printf("GetRawInputDeviceList failed. Error code: %d\n", GetLastError());
return GetLastError();
}

for (UINT i = 0; i < count; i++) {
DWORD device_type = device_list[i].dwType;

if (device_type != RIM_TYPEHID) {
continue;
}

printf("%d: ", i);

// char device_name[1000] = {0};
// UINT device_name_size = sizeof(device_name);
// if (GetRawInputDeviceInfo(device_list[i].hDevice, RIDI_DEVICENAME, device_name, &device_name_size) <= 0) {
// printf("GetRawInputDeviceInfo failed. Error code: %d\n", GetLastError());
// return GetLastError();
// }
// printf("%s\n", device_name);

// switch (device_type) {
// case RIM_TYPEHID:
// printf("The device is an HID that is not a keyboard and not a mouse.\n");
// break;
// case RIM_TYPEKEYBOARD:
// printf("The device is a keyboard.\n");
// break;
// case RIM_TYPEMOUSE:
// printf("The device is a mouse.\n");
// break;
// default:
// printf("The device is an unknown type.\n");
// break;
// }

// printf("-- Begin device info --\n");

RID_DEVICE_INFO device_info;
UINT device_info_size = sizeof(device_info);
device_info.cbSize = device_info_size;
GetRawInputDeviceInfo(device_list[i].hDevice, RIDI_DEVICEINFO, &device_info, &device_info_size);

printf("%x %x\n", device_info.hid.dwVendorId, device_info.hid.dwProductId);

// printf("VendorId: %x\n", device_info.hid.dwVendorId);
// printf("ProductId: %x\n", device_info.hid.dwProductId);
// printf("VersionNumber: %x\n", device_info.hid.dwVersionNumber);

// printf("-- End device info --\n");
}

free(device_list);

return 0;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/main.c → stadia-vigem/src/main.c
Expand Up @@ -212,7 +212,7 @@ static BOOL remove_device(struct stadia_controller *controller)

static void refresh_devices()
{
LPTSTR stadia_hw_path_filters[3] = {STADIA_HW_FILTER, NULL};
LPTSTR stadia_hw_path_filters[3] = {STADIA_USB_HW_FILTER, STADIA_BLT_HW_FILTER, NULL};
struct hid_device_info *device_info = hid_enumerate(stadia_hw_path_filters);
struct hid_device_info *cur;
BOOL found = FALSE;
Expand Down
File renamed without changes.

0 comments on commit 6f30d7d

Please sign in to comment.