Skip to content

Instantly share code, notes, and snippets.

@citrus610
Created November 2, 2025 10:09
Show Gist options
  • Select an option

  • Save citrus610/32e54da1e36ae71f81d6f08b64b7f40c to your computer and use it in GitHub Desktop.

Select an option

Save citrus610/32e54da1e36ae71f81d6f08b64b7f40c to your computer and use it in GitHub Desktop.
SCP driver interface c++
#include "vxbox.h"
namespace Vxbox
{
Bus::Bus()
{
this->handle = this->get_handle();
};
HANDLE Bus::get_handle()
{
WCHAR path[MAX_PATH];
auto n = this->get_path(path);
if (n < 1) {
return INVALID_HANDLE_VALUE;
}
return CreateFile(
path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
nullptr
);
};
int Bus::get_path(WCHAR* path)
{
GUID guid = {
0xf679f562,
0x3164,
0x42ce,
{ 0xa4, 0xdb, 0xe7, 0xdd, 0xbe, 0x72, 0x39, 0x9 }
};
SP_DEVICE_INTERFACE_DATA device_interface_data = {};
device_interface_data.cbSize = sizeof(device_interface_data);
auto device_info_set = SetupDiGetClassDevs(&guid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (!SetupDiEnumDeviceInterfaces(device_info_set, nullptr, &guid, 0, &device_interface_data)) {
return -1;
}
DWORD size = 0;
SetupDiGetDeviceInterfaceDetail(device_info_set, &device_interface_data, nullptr, 0, &size, nullptr);
auto detail_data_buffer = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(size));
if (detail_data_buffer == NULL) {
return -1;
}
detail_data_buffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(device_info_set, &device_interface_data, detail_data_buffer, size, &size, nullptr))
{
SetupDiDestroyDeviceInfoList(device_info_set);
free(detail_data_buffer);
return -1;
}
memcpy((void*)path, detail_data_buffer->DevicePath, size * sizeof(WCHAR));
SetupDiDestroyDeviceInfoList(device_info_set);
free(detail_data_buffer);
return size;
};
Device::Device()
{
this->state = State();
};
Device::~Device()
{
if (this->id > -1) {
this->plugout();
}
};
bool Device::plugin(int id)
{
if (id < 1 || id > 4) {
return false;
}
if (this->bus.handle == INVALID_HANDLE_VALUE) {
return false;
}
DWORD trasfered = 0;
UCHAR buffer[16] = {
0x10, 0, 0, 0,
UCHAR((id >> 0) & 0xFF),
UCHAR((id >> 8) & 0xFF),
UCHAR((id >> 16) & 0xFF),
UCHAR((id >> 24) & 0xFF),
0, 0, 0, 0,
0, 0, 0, 0
};
auto success = DeviceIoControl(
this->bus.handle,
0x2A4000,
buffer,
_countof(buffer),
nullptr,
0,
&trasfered,
nullptr
);
if (success) {
this->id = id;
return true;
}
this->id = -1;
return false;
};
bool Device::plugout()
{
if (this->id < 1 || this->id > 4) {
return false;
}
if (this->bus.handle == INVALID_HANDLE_VALUE) {
return false;
}
DWORD trasfered = 0;
UCHAR buffer[16] = {
0x10, 0, 0, 0,
UCHAR((id >> 0) & 0xFF),
UCHAR((id >> 8) & 0xFF),
UCHAR((id >> 16) & 0xFF),
UCHAR((id >> 24) & 0xFF),
0, 0, 0, 0,
0, 0, 0, 0
};
auto success = DeviceIoControl(
this->bus.handle,
0x2A4004,
buffer,
_countof(buffer),
nullptr,
0,
&trasfered,
nullptr
);
if (success) {
this->id = -1;
return true;
}
return false;
};
bool Device::send()
{
if (this->id < 1 || this->id > 4) {
return false;
}
if (this->bus.handle == INVALID_HANDLE_VALUE) {
return false;
}
auto to_uchar = [] (bool value[8]) -> UCHAR {
UCHAR uchar = 0;
for (int i = 0; i < 8; ++i) {
uchar |= value[i] << i;
}
return uchar;
};
bool btn_1[8] = {
this->state.up, this->state.down, this->state.left, this->state.right,
this->state.start, this->state.select, this->state.ls, this->state.rs
};
bool btn_2[8] = {
this->state.lb, this->state.rb, false, false,
this->state.a, this->state.b, this->state.x, this->state.y
};
DWORD trasfered = 0;
UCHAR buffer[28] = {
0x1C, 0, 0, 0,
UCHAR((id >> 0) & 0xFF),
UCHAR((id >> 8) & 0xFF),
UCHAR((id >> 16) & 0xFF),
UCHAR((id >> 24) & 0xFF),
0x00,
0x14,
to_uchar(btn_1),
to_uchar(btn_2),
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
return DeviceIoControl(
this->bus.handle,
0x2A400C,
buffer,
_countof(buffer),
nullptr,
0,
&trasfered,
nullptr
);
};
void Device::clear()
{
this->state = State();
};
bool Device::is_plugged_in()
{
return this->id >= 1 && this->id <= 4;
};
};
#pragma once
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <crtdbg.h>
#include <winioctl.h>
#include <INITGUID.H>
#include <Xinput.h>
#include <SetupAPI.h>
#pragma comment (lib, "SetupApi.lib")
namespace Vxbox
{
class Bus
{
public:
HANDLE handle;
public:
Bus();
public:
HANDLE get_handle();
int get_path(WCHAR* path);
};
struct State {
bool up = false;
bool down = false;
bool left = false;
bool right = false;
bool a = false;
bool b = false;
bool x = false;
bool y = false;
bool start = false;
bool select = false;
bool ls = false;
bool rs = false;
bool lb = false;
bool rb = false;
};
class Device
{
public:
Bus bus;
int id;
State state;
public:
Device();
~Device();
public:
bool plugin(int id);
bool plugout();
bool send();
void clear();
bool is_plugged_in();
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment