mirror of
https://gitlab.com/parallel-launcher/parallel-launcher
synced 2025-10-05 16:12:45 +02:00
221 lines
5.5 KiB
C
221 lines
5.5 KiB
C
#define SDL_MAIN_HANDLED 1
|
|
|
|
#include <SDL2/SDL.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#if defined(_WIN32)
|
|
#include <Windows.h>
|
|
#elif defined(__APPLE__)
|
|
#include <unistd.h>
|
|
#else
|
|
#include <threads.h>
|
|
#include <time.h>
|
|
#endif
|
|
|
|
#define SPE_CONNECT 0
|
|
#define SPE_DISCONNECT 1
|
|
#define SPE_BUTTON 2
|
|
#define SPE_AXIS 3
|
|
#define SPE_HAT 4
|
|
|
|
typedef unsigned char ubyte;
|
|
typedef unsigned short ushort;
|
|
|
|
static FILE *s_output = NULL;
|
|
|
|
static inline void writeByte( ubyte x ) {
|
|
if( fputc( x, s_output ) == EOF ) exit( 32 );
|
|
}
|
|
|
|
static inline void writeShort( short x ) {
|
|
if( fwrite( &x, 2, 1, s_output ) != 1 ) exit( 32 );
|
|
}
|
|
|
|
static inline void writeUShort( ushort x ) {
|
|
if( fwrite( &x, 2, 1, s_output ) != 1 ) exit( 32 );
|
|
}
|
|
|
|
static inline void writeInt( int x ) {
|
|
if( fwrite( &x, 4, 1, s_output ) != 1 ) exit( 32 );
|
|
}
|
|
|
|
static inline void writeString( const char *str ) {
|
|
if( str != NULL && fputs( str, s_output ) == EOF ) exit( 32 );
|
|
writeByte( 0 );
|
|
}
|
|
|
|
static void se_connected( int port ) {
|
|
const ushort vendorId = SDL_JoystickGetDeviceVendor( port );
|
|
const ushort productId = SDL_JoystickGetDeviceProduct( port );
|
|
const SDL_JoystickGUID uuid = SDL_JoystickGetDeviceGUID( port );
|
|
|
|
SDL_GameController *controller = NULL;
|
|
SDL_Joystick *joypad = NULL;
|
|
const char *name = NULL;
|
|
|
|
ushort numButtons = 15;
|
|
ushort numAxes = 6;
|
|
ushort numHats = 0;
|
|
|
|
if( SDL_IsGameController( port ) ) {
|
|
controller = SDL_GameControllerOpen( port );
|
|
if( controller == NULL ) return;
|
|
|
|
joypad = SDL_GameControllerGetJoystick( controller );
|
|
if( joypad == NULL ) return;
|
|
|
|
name = SDL_GameControllerName( controller );
|
|
} else {
|
|
joypad = SDL_JoystickOpen( port );
|
|
if( joypad == NULL ) return;
|
|
|
|
name = SDL_JoystickNameForIndex( port );
|
|
numButtons = (ushort)SDL_JoystickNumButtons( joypad );
|
|
numAxes = (ushort)SDL_JoystickNumAxes( joypad );
|
|
numHats = (ushort)SDL_JoystickNumHats( joypad );
|
|
}
|
|
|
|
const int id = SDL_JoystickInstanceID( joypad );
|
|
|
|
writeByte( SPE_CONNECT );
|
|
writeInt( id );
|
|
writeString( name );
|
|
writeUShort( vendorId );
|
|
writeUShort( productId );
|
|
fwrite( uuid.data, 1, 16, s_output );
|
|
writeUShort( numButtons );
|
|
writeUShort( numAxes );
|
|
writeUShort( numHats );
|
|
|
|
if( controller ) {
|
|
for( ushort i = 0; i < numButtons; i++ ) {
|
|
writeByte( SDL_GameControllerGetButton( controller, (SDL_GameControllerButton)i ) );
|
|
}
|
|
for( ushort i = 0; i < numAxes; i++ ) {
|
|
writeShort( SDL_GameControllerGetAxis( controller, (SDL_GameControllerAxis)i ) );
|
|
}
|
|
} else {
|
|
for( ushort i = 0; i < numButtons; i++ ) {
|
|
writeByte( SDL_JoystickGetButton( joypad, i ) );
|
|
}
|
|
for( ushort i = 0; i < numAxes; i++ ) {
|
|
writeShort( SDL_JoystickGetAxis( joypad, i ) );
|
|
}
|
|
for( ushort i = 0; i < numHats; i++ ) {
|
|
writeByte( SDL_JoystickGetHat( joypad, i ) );
|
|
}
|
|
}
|
|
|
|
fflush( s_output );
|
|
}
|
|
|
|
static inline void se_disconnected( int id ) {
|
|
writeByte( SPE_DISCONNECT );
|
|
writeInt( id );
|
|
fflush( s_output );
|
|
}
|
|
|
|
static inline void se_button( int id, ubyte button, ubyte state ) {
|
|
writeByte( SPE_BUTTON );
|
|
writeInt( id );
|
|
writeByte( button );
|
|
writeByte( state );
|
|
fflush( s_output );
|
|
}
|
|
|
|
static inline void se_axis( int id, ubyte axis, short state ) {
|
|
writeByte( SPE_AXIS );
|
|
writeInt( id );
|
|
writeByte( axis );
|
|
writeShort( state );
|
|
fflush( s_output );
|
|
}
|
|
|
|
static inline void se_hat( int id, ubyte hat, ubyte state ) {
|
|
writeByte( SPE_HAT );
|
|
writeInt( id );
|
|
writeByte( hat );
|
|
writeByte( state );
|
|
fflush( s_output );
|
|
}
|
|
|
|
int main( int argc, char *argv[] ) {
|
|
if( argc < 2 || !argv[1] || !argv[1][0] ) return 22;
|
|
|
|
s_output = fopen( argv[1], "wb" );
|
|
if( !s_output ) return 2;
|
|
#ifdef _WIN32
|
|
setvbuf( s_output, NULL, _IOFBF, 4096 );
|
|
#endif
|
|
|
|
writeByte( 0x06 );
|
|
fflush( s_output );
|
|
|
|
SDL_Init( SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_EVENTS );
|
|
SDL_JoystickEventState( SDL_ENABLE );
|
|
SDL_GameControllerEventState( SDL_ENABLE );
|
|
|
|
SDL_LockJoysticks();
|
|
const int numConnected = SDL_NumJoysticks();
|
|
for( int i = 0; i < numConnected; i++ ) {
|
|
se_connected( i );
|
|
}
|
|
SDL_UnlockJoysticks();
|
|
|
|
if( argc >= 3 && strcmp( argv[2], "--sync" ) == 0 ) {
|
|
SDL_Quit();
|
|
fflush( s_output );
|
|
return 0;
|
|
}
|
|
|
|
SDL_Event event;
|
|
while( 1 ) {
|
|
while( SDL_PollEvent( &event ) ) {
|
|
switch( event.type ) {
|
|
case SDL_JOYDEVICEADDED:
|
|
SDL_LockJoysticks();
|
|
se_connected( event.jdevice.which );
|
|
SDL_UnlockJoysticks();
|
|
break;
|
|
case SDL_JOYDEVICEREMOVED:
|
|
se_disconnected( event.jdevice.which );
|
|
break;
|
|
case SDL_CONTROLLERBUTTONDOWN:
|
|
case SDL_CONTROLLERBUTTONUP:
|
|
se_button( event.cbutton.which, event.cbutton.button, event.cbutton.state );
|
|
break;
|
|
case SDL_JOYBUTTONDOWN:
|
|
case SDL_JOYBUTTONUP:
|
|
if( SDL_GameControllerFromInstanceID( event.jbutton.which ) != NULL ) break;
|
|
se_button( event.cbutton.which, event.cbutton.button, event.cbutton.state );
|
|
break;
|
|
case SDL_CONTROLLERAXISMOTION:
|
|
se_axis( event.caxis.which, event.caxis.axis, event.caxis.value );
|
|
break;
|
|
case SDL_JOYAXISMOTION:
|
|
if( SDL_GameControllerFromInstanceID( event.jbutton.which ) != NULL ) break;
|
|
se_axis( event.caxis.which, event.caxis.axis, event.caxis.value );
|
|
break;
|
|
case SDL_JOYHATMOTION:
|
|
if( SDL_GameControllerFromInstanceID( event.jbutton.which ) != NULL ) break;
|
|
se_hat( event.jhat.which, event.jhat.hat, event.jhat.value );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
Sleep( 10 );
|
|
#elif defined(__APPLE__)
|
|
usleep( 10000u );
|
|
#else
|
|
thrd_sleep(&(struct timespec){
|
|
.tv_sec = 0,
|
|
.tv_nsec = 10000000ll
|
|
}, NULL);
|
|
#endif
|
|
}
|
|
}
|