Deleted input/alloc logic that isn't actually used.
This commit is contained in:
@@ -1,236 +0,0 @@
|
|||||||
// configfile.c - handles loading and saving the configuration options
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "configfile.h"
|
|
||||||
|
|
||||||
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
|
||||||
|
|
||||||
enum ConfigOptionType {
|
|
||||||
CONFIG_TYPE_BOOL,
|
|
||||||
CONFIG_TYPE_UINT,
|
|
||||||
CONFIG_TYPE_FLOAT,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ConfigOption {
|
|
||||||
const char *name;
|
|
||||||
enum ConfigOptionType type;
|
|
||||||
union {
|
|
||||||
bool *boolValue;
|
|
||||||
unsigned int *uintValue;
|
|
||||||
float *floatValue;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
*Config options and default values
|
|
||||||
*/
|
|
||||||
bool configFullscreen = false;
|
|
||||||
// Keyboard mappings (scancode values)
|
|
||||||
unsigned int configKeyA = 0x26;
|
|
||||||
unsigned int configKeyB = 0x33;
|
|
||||||
unsigned int configKeyStart = 0x39;
|
|
||||||
unsigned int configKeyR = 0x36;
|
|
||||||
unsigned int configKeyZ = 0x25;
|
|
||||||
unsigned int configKeyCUp = 0x148;
|
|
||||||
unsigned int configKeyCDown = 0x150;
|
|
||||||
unsigned int configKeyCLeft = 0x14B;
|
|
||||||
unsigned int configKeyCRight = 0x14D;
|
|
||||||
unsigned int configKeyStickUp = 0x11;
|
|
||||||
unsigned int configKeyStickDown = 0x1F;
|
|
||||||
unsigned int configKeyStickLeft = 0x1E;
|
|
||||||
unsigned int configKeyStickRight = 0x20;
|
|
||||||
|
|
||||||
|
|
||||||
static const struct ConfigOption options[] = {
|
|
||||||
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configFullscreen},
|
|
||||||
{.name = "key_a", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyA},
|
|
||||||
{.name = "key_b", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyB},
|
|
||||||
{.name = "key_start", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStart},
|
|
||||||
{.name = "key_r", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyR},
|
|
||||||
{.name = "key_z", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyZ},
|
|
||||||
{.name = "key_cup", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCUp},
|
|
||||||
{.name = "key_cdown", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCDown},
|
|
||||||
{.name = "key_cleft", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCLeft},
|
|
||||||
{.name = "key_cright", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCRight},
|
|
||||||
{.name = "key_stickup", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickUp},
|
|
||||||
{.name = "key_stickdown", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickDown},
|
|
||||||
{.name = "key_stickleft", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickLeft},
|
|
||||||
{.name = "key_stickright", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickRight},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reads an entire line from a file (excluding the newline character) and returns an allocated string
|
|
||||||
// Returns NULL if no lines could be read from the file
|
|
||||||
static char *read_file_line(FILE *file) {
|
|
||||||
char *buffer;
|
|
||||||
size_t bufferSize = 8;
|
|
||||||
size_t offset = 0; // offset in buffer to write
|
|
||||||
|
|
||||||
buffer = malloc(bufferSize);
|
|
||||||
while (1) {
|
|
||||||
// Read a line from the file
|
|
||||||
if (fgets(buffer + offset, bufferSize - offset, file) == NULL) {
|
|
||||||
free(buffer);
|
|
||||||
return NULL; // Nothing could be read.
|
|
||||||
}
|
|
||||||
offset = strlen(buffer);
|
|
||||||
assert(offset > 0);
|
|
||||||
|
|
||||||
// If a newline was found, remove the trailing newline and exit
|
|
||||||
if (buffer[offset - 1] == '\n') {
|
|
||||||
buffer[offset - 1] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feof(file)) // EOF was reached
|
|
||||||
break;
|
|
||||||
|
|
||||||
// If no newline or EOF was reached, then the whole line wasn't read.
|
|
||||||
bufferSize *= 2; // Increase buffer size
|
|
||||||
buffer = realloc(buffer, bufferSize);
|
|
||||||
assert(buffer != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the position of the first non-whitespace character
|
|
||||||
static char *skip_whitespace(char *str) {
|
|
||||||
while (isspace(*str))
|
|
||||||
str++;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NULL-terminates the current whitespace-delimited word, and returns a pointer to the next word
|
|
||||||
static char *word_split(char *str) {
|
|
||||||
// Precondition: str must not point to whitespace
|
|
||||||
assert(!isspace(*str));
|
|
||||||
|
|
||||||
// Find either the next whitespace char or end of string
|
|
||||||
while (!isspace(*str) && *str != '\0')
|
|
||||||
str++;
|
|
||||||
if (*str == '\0') // End of string
|
|
||||||
return str;
|
|
||||||
|
|
||||||
// Terminate current word
|
|
||||||
*(str++) = '\0';
|
|
||||||
|
|
||||||
// Skip whitespace to next word
|
|
||||||
return skip_whitespace(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Splits a string into words, and stores the words into the 'tokens' array
|
|
||||||
// 'maxTokens' is the length of the 'tokens' array
|
|
||||||
// Returns the number of tokens parsed
|
|
||||||
static unsigned int tokenize_string(char *str, int maxTokens, char **tokens) {
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
str = skip_whitespace(str);
|
|
||||||
while (str[0] != '\0' && count < maxTokens) {
|
|
||||||
tokens[count] = str;
|
|
||||||
str = word_split(str);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loads the config file specified by 'filename'
|
|
||||||
void configfile_load(const char *filename) {
|
|
||||||
FILE *file;
|
|
||||||
char *line;
|
|
||||||
|
|
||||||
printf("Loading configuration from '%s'\n", filename);
|
|
||||||
|
|
||||||
file = fopen(filename, "r");
|
|
||||||
if (file == NULL) {
|
|
||||||
// Create a new config file and save defaults
|
|
||||||
printf("Config file '%s' not found. Creating it.\n", filename);
|
|
||||||
configfile_save(filename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each line in the file
|
|
||||||
while ((line = read_file_line(file)) != NULL) {
|
|
||||||
char *p = line;
|
|
||||||
char *tokens[2];
|
|
||||||
int numTokens;
|
|
||||||
|
|
||||||
while (isspace(*p))
|
|
||||||
p++;
|
|
||||||
numTokens = tokenize_string(p, 2, tokens);
|
|
||||||
if (numTokens != 0) {
|
|
||||||
if (numTokens == 2) {
|
|
||||||
const struct ConfigOption *option = NULL;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
|
|
||||||
if (strcmp(tokens[0], options[i].name) == 0) {
|
|
||||||
option = &options[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (option == NULL)
|
|
||||||
printf("unknown option '%s'\n", tokens[0]);
|
|
||||||
else {
|
|
||||||
switch (option->type) {
|
|
||||||
case CONFIG_TYPE_BOOL:
|
|
||||||
if (strcmp(tokens[1], "true") == 0)
|
|
||||||
*option->boolValue = true;
|
|
||||||
else if (strcmp(tokens[1], "false") == 0)
|
|
||||||
*option->boolValue = false;
|
|
||||||
break;
|
|
||||||
case CONFIG_TYPE_UINT:
|
|
||||||
sscanf(tokens[1], "%u", option->uintValue);
|
|
||||||
break;
|
|
||||||
case CONFIG_TYPE_FLOAT:
|
|
||||||
sscanf(tokens[1], "%f", option->floatValue);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0); // bad type
|
|
||||||
}
|
|
||||||
printf("option: '%s', value: '%s'\n", tokens[0], tokens[1]);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
puts("error: expected value");
|
|
||||||
}
|
|
||||||
free(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes the config file to 'filename'
|
|
||||||
void configfile_save(const char *filename) {
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
printf("Saving configuration to '%s'\n", filename);
|
|
||||||
|
|
||||||
file = fopen(filename, "w");
|
|
||||||
if (file == NULL) {
|
|
||||||
// error
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
|
|
||||||
const struct ConfigOption *option = &options[i];
|
|
||||||
|
|
||||||
switch (option->type) {
|
|
||||||
case CONFIG_TYPE_BOOL:
|
|
||||||
fprintf(file, "%s %s\n", option->name, *option->boolValue ? "true" : "false");
|
|
||||||
break;
|
|
||||||
case CONFIG_TYPE_UINT:
|
|
||||||
fprintf(file, "%s %u\n", option->name, *option->uintValue);
|
|
||||||
break;
|
|
||||||
case CONFIG_TYPE_FLOAT:
|
|
||||||
fprintf(file, "%s %f\n", option->name, *option->floatValue);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0); // unknown type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef CONFIGFILE_H
|
|
||||||
#define CONFIGFILE_H
|
|
||||||
|
|
||||||
extern bool configFullscreen;
|
|
||||||
extern unsigned int configKeyA;
|
|
||||||
extern unsigned int configKeyB;
|
|
||||||
extern unsigned int configKeyStart;
|
|
||||||
extern unsigned int configKeyR;
|
|
||||||
extern unsigned int configKeyZ;
|
|
||||||
extern unsigned int configKeyCUp;
|
|
||||||
extern unsigned int configKeyCDown;
|
|
||||||
extern unsigned int configKeyCLeft;
|
|
||||||
extern unsigned int configKeyCRight;
|
|
||||||
extern unsigned int configKeyStickUp;
|
|
||||||
extern unsigned int configKeyStickDown;
|
|
||||||
extern unsigned int configKeyStickLeft;
|
|
||||||
extern unsigned int configKeyStickRight;
|
|
||||||
|
|
||||||
void configfile_load(const char *filename);
|
|
||||||
void configfile_save(const char *filename);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#ifndef CONTROLLER_API
|
|
||||||
#define CONTROLLER_API
|
|
||||||
|
|
||||||
#include <ultra64.h>
|
|
||||||
|
|
||||||
struct ControllerAPI {
|
|
||||||
void (*init)(void);
|
|
||||||
void (*read)(OSContPad *pad);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
#ifdef TARGET_WEB
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <emscripten/html5.h>
|
|
||||||
#include "macros.h"
|
|
||||||
#include "controller_keyboard.h"
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
const char *code;
|
|
||||||
int scancode;
|
|
||||||
} keymap_browser[] = {
|
|
||||||
{"Escape", 0x01},
|
|
||||||
{"Digit1", 0x02 },
|
|
||||||
{"Digit2", 0x03 },
|
|
||||||
{"Digit3", 0x04 },
|
|
||||||
{"Digit4", 0x05 },
|
|
||||||
{"Digit5", 0x06 },
|
|
||||||
{"Digit6", 0x07 },
|
|
||||||
{"Digit7", 0x08 },
|
|
||||||
{"Digit8", 0x09 },
|
|
||||||
{"Digit9", 0x0a },
|
|
||||||
{"Digit0", 0x0b },
|
|
||||||
{"Minus", 0x0c },
|
|
||||||
{"Equal", 0x0d },
|
|
||||||
{"Backspace", 0x0e },
|
|
||||||
{"Tab", 0x0f },
|
|
||||||
{"KeyQ", 0x10 },
|
|
||||||
{"KeyW", 0x11 },
|
|
||||||
{"KeyE", 0x12 },
|
|
||||||
{"KeyR", 0x13 },
|
|
||||||
{"KeyT", 0x14 },
|
|
||||||
{"KeyY", 0x15 },
|
|
||||||
{"KeyU", 0x16 },
|
|
||||||
{"KeyI", 0x17 },
|
|
||||||
{"KeyO", 0x18 },
|
|
||||||
{"KeyP", 0x19 },
|
|
||||||
{"BracketLeft", 0x1a },
|
|
||||||
{"BracketRight", 0x1b },
|
|
||||||
{"Enter", 0x1c },
|
|
||||||
{"ControlLeft", 0x1d },
|
|
||||||
{"KeyA", 0x1e },
|
|
||||||
{"KeyS", 0x1f },
|
|
||||||
{"KeyD", 0x20 },
|
|
||||||
{"KeyF", 0x21 },
|
|
||||||
{"KeyG", 0x22 },
|
|
||||||
{"KeyH", 0x23 },
|
|
||||||
{"KeyJ", 0x24 },
|
|
||||||
{"KeyK", 0x25 },
|
|
||||||
{"KeyL", 0x26 },
|
|
||||||
{"Semicolon", 0x27 },
|
|
||||||
{"Quote", 0x28 },
|
|
||||||
{"Backquote", 0x29 },
|
|
||||||
{"ShiftLeft", 0x2a },
|
|
||||||
{"Backslash", 0x2b },
|
|
||||||
{"KeyZ", 0x2c },
|
|
||||||
{"KeyX", 0x2d },
|
|
||||||
{"KeyC", 0x2e },
|
|
||||||
{"KeyV", 0x2f },
|
|
||||||
{"KeyB", 0x30 },
|
|
||||||
{"KeyN", 0x31 },
|
|
||||||
{"KeyM", 0x32 },
|
|
||||||
{"Comma", 0x33 },
|
|
||||||
{"Period", 0x34 },
|
|
||||||
{"Slash", 0x35 },
|
|
||||||
{"ShiftRight", 0x36 },
|
|
||||||
{"NumpadMultiply", 0x37 },
|
|
||||||
{"AltLeft", 0x38 },
|
|
||||||
{"Space", 0x39 },
|
|
||||||
{"CapsLock", 0x3a },
|
|
||||||
{"F1", 0x3b },
|
|
||||||
{"F2", 0x3c },
|
|
||||||
{"F3", 0x3d },
|
|
||||||
{"F4", 0x3e },
|
|
||||||
{"F5", 0x3f },
|
|
||||||
{"F6", 0x40 },
|
|
||||||
{"F7", 0x41 },
|
|
||||||
{"F8", 0x42 },
|
|
||||||
{"F9", 0x43 },
|
|
||||||
{"F10", 0x44 },
|
|
||||||
{"NumLock", 0x45 },
|
|
||||||
{"ScrollLock", 0x46 },
|
|
||||||
{"Numpad7", 0x47 },
|
|
||||||
{"Numpad8", 0x48 },
|
|
||||||
{"Numpad9", 0x49 },
|
|
||||||
{"NumpadSubtract", 0x4a },
|
|
||||||
{"Numpad4", 0x4b },
|
|
||||||
{"Numpad5", 0x4c },
|
|
||||||
{"Numpad6", 0x4d },
|
|
||||||
{"NumpadAdd", 0x4e },
|
|
||||||
{"Numpad1", 0x4f },
|
|
||||||
{"Numpad2", 0x50 },
|
|
||||||
{"Numpad3", 0x51 },
|
|
||||||
{"Numpad0", 0x52 },
|
|
||||||
{"NumpadDecimal", 0x53 },
|
|
||||||
{"PrintScreen", 0x54 },
|
|
||||||
// 0x55
|
|
||||||
{"IntlBackslash", 0x56 },
|
|
||||||
{"F11", 0x57 },
|
|
||||||
{"F12", 0x58 },
|
|
||||||
{"IntlRo", 0x59 },
|
|
||||||
//{"Katakana", 0 },
|
|
||||||
//{"Hiragana", 0 },
|
|
||||||
{"NumpadEnter", 0x11c },
|
|
||||||
{"ControlRight", 0x11d },
|
|
||||||
{"NumpadDivide", 0x135 },
|
|
||||||
{"AltRight", 0x138 },
|
|
||||||
{"Home", 0x147 },
|
|
||||||
{"ArrowUp", 0x148 },
|
|
||||||
{"PageUp", 0x149 },
|
|
||||||
{"ArrowLeft", 0x14b },
|
|
||||||
{"ArrowRight", 0x14d },
|
|
||||||
{"End", 0x14f },
|
|
||||||
{"ArrowDown", 0x150 },
|
|
||||||
{"PageDown", 0x151 },
|
|
||||||
{"Insert", 0x152 },
|
|
||||||
{"Delete", 0x153 },
|
|
||||||
{"Pause", 0x21d },
|
|
||||||
{"MetaLeft", 0x15b },
|
|
||||||
{"MetaRight", 0x15c },
|
|
||||||
{"ContextMenu", 0x15d },
|
|
||||||
};
|
|
||||||
|
|
||||||
static EM_BOOL controller_emscripten_keyboard_handler(int event_type, const EmscriptenKeyboardEvent *key_event, UNUSED void *user_data) {
|
|
||||||
for (size_t i = 0; i < sizeof(keymap_browser) / sizeof(keymap_browser[0]); i++) {
|
|
||||||
if (strcmp(key_event->code, keymap_browser[i].code) == 0) {
|
|
||||||
if (event_type == EMSCRIPTEN_EVENT_KEYDOWN) {
|
|
||||||
return keyboard_on_key_down(keymap_browser[i].scancode);
|
|
||||||
} else if (event_type == EMSCRIPTEN_EVENT_KEYUP) {
|
|
||||||
return keyboard_on_key_up(keymap_browser[i].scancode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EM_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static EM_BOOL controller_emscripten_keyboard_blur_handler(UNUSED int event_type, UNUSED const EmscriptenFocusEvent *focus_event, UNUSED void *user_data) {
|
|
||||||
keyboard_on_all_keys_up();
|
|
||||||
return EM_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void controller_emscripten_keyboard_init(void) {
|
|
||||||
// Should be #window according to docs, but that crashes
|
|
||||||
const char *target = EMSCRIPTEN_EVENT_TARGET_WINDOW;
|
|
||||||
|
|
||||||
emscripten_set_keydown_callback(target, NULL, EM_FALSE, controller_emscripten_keyboard_handler);
|
|
||||||
emscripten_set_keyup_callback(target, NULL, EM_FALSE, controller_emscripten_keyboard_handler);
|
|
||||||
emscripten_set_blur_callback(target, NULL, EM_FALSE, controller_emscripten_keyboard_blur_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef CONTROLLER_KEYBOARD_EMSCRIPTEN_H
|
|
||||||
#define CONTROLLER_KEYBOARD_EMSCRIPTEN_H
|
|
||||||
|
|
||||||
#ifdef TARGET_WEB
|
|
||||||
void controller_emscripten_keyboard_init(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#include "macros.h"
|
|
||||||
|
|
||||||
#include "lib/src/libultra_internal.h"
|
|
||||||
#include "lib/src/osContInternal.h"
|
|
||||||
|
|
||||||
#include "controller_recorded_tas.h"
|
|
||||||
#include "controller_keyboard.h"
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
|
||||||
#include "controller_xinput.h"
|
|
||||||
#else
|
|
||||||
#include "controller_sdl.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#include "controller_wup.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct ControllerAPI *controller_implementations[] = {
|
|
||||||
&controller_recorded_tas,
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
|
||||||
&controller_xinput,
|
|
||||||
#else
|
|
||||||
&controller_sdl,
|
|
||||||
#endif
|
|
||||||
#ifdef __linux__
|
|
||||||
&controller_wup,
|
|
||||||
#endif
|
|
||||||
&controller_keyboard,
|
|
||||||
};
|
|
||||||
|
|
||||||
s32 osContInit(UNUSED OSMesgQueue *mq, u8 *controllerBits, UNUSED OSContStatus *status) {
|
|
||||||
for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) {
|
|
||||||
controller_implementations[i]->init();
|
|
||||||
}
|
|
||||||
*controllerBits = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 osContStartReadData(UNUSED OSMesgQueue *mesg) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void osContGetReadData(OSContPad *pad) {
|
|
||||||
pad->button = 0;
|
|
||||||
pad->stick_x = 0;
|
|
||||||
pad->stick_y = 0;
|
|
||||||
pad->errnum = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) {
|
|
||||||
controller_implementations[i]->read(pad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <ultra64.h>
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
#ifdef TARGET_WEB
|
|
||||||
#include "controller_emscripten_keyboard.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../configfile.h"
|
|
||||||
|
|
||||||
static int keyboard_buttons_down;
|
|
||||||
|
|
||||||
static int keyboard_mapping[13][2];
|
|
||||||
|
|
||||||
static int keyboard_map_scancode(int scancode) {
|
|
||||||
int ret = 0;
|
|
||||||
for (size_t i = 0; i < sizeof(keyboard_mapping) / sizeof(keyboard_mapping[0]); i++) {
|
|
||||||
if (keyboard_mapping[i][0] == scancode) {
|
|
||||||
ret |= keyboard_mapping[i][1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keyboard_on_key_down(int scancode) {
|
|
||||||
int mapped = keyboard_map_scancode(scancode);
|
|
||||||
keyboard_buttons_down |= mapped;
|
|
||||||
return mapped != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keyboard_on_key_up(int scancode) {
|
|
||||||
int mapped = keyboard_map_scancode(scancode);
|
|
||||||
keyboard_buttons_down &= ~mapped;
|
|
||||||
return mapped != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void keyboard_on_all_keys_up(void) {
|
|
||||||
keyboard_buttons_down = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_keyboard_mapping(int index, int mask, int scancode) {
|
|
||||||
keyboard_mapping[index][0] = scancode;
|
|
||||||
keyboard_mapping[index][1] = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void keyboard_init(void) {
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
set_keyboard_mapping(i++, 0x80000, configKeyStickUp);
|
|
||||||
set_keyboard_mapping(i++, 0x10000, configKeyStickLeft);
|
|
||||||
set_keyboard_mapping(i++, 0x40000, configKeyStickDown);
|
|
||||||
set_keyboard_mapping(i++, 0x20000, configKeyStickRight);
|
|
||||||
set_keyboard_mapping(i++, A_BUTTON, configKeyA);
|
|
||||||
set_keyboard_mapping(i++, B_BUTTON, configKeyB);
|
|
||||||
set_keyboard_mapping(i++, Z_TRIG, configKeyZ);
|
|
||||||
set_keyboard_mapping(i++, U_CBUTTONS, configKeyCUp);
|
|
||||||
set_keyboard_mapping(i++, L_CBUTTONS, configKeyCLeft);
|
|
||||||
set_keyboard_mapping(i++, D_CBUTTONS, configKeyCDown);
|
|
||||||
set_keyboard_mapping(i++, R_CBUTTONS, configKeyCRight);
|
|
||||||
set_keyboard_mapping(i++, R_TRIG, configKeyR);
|
|
||||||
set_keyboard_mapping(i++, START_BUTTON, configKeyStart);
|
|
||||||
|
|
||||||
#ifdef TARGET_WEB
|
|
||||||
controller_emscripten_keyboard_init();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void keyboard_read(OSContPad *pad) {
|
|
||||||
pad->button |= keyboard_buttons_down;
|
|
||||||
if ((keyboard_buttons_down & 0x30000) == 0x10000) {
|
|
||||||
pad->stick_x = -128;
|
|
||||||
}
|
|
||||||
if ((keyboard_buttons_down & 0x30000) == 0x20000) {
|
|
||||||
pad->stick_x = 127;
|
|
||||||
}
|
|
||||||
if ((keyboard_buttons_down & 0xc0000) == 0x40000) {
|
|
||||||
pad->stick_y = -128;
|
|
||||||
}
|
|
||||||
if ((keyboard_buttons_down & 0xc0000) == 0x80000) {
|
|
||||||
pad->stick_y = 127;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ControllerAPI controller_keyboard = {
|
|
||||||
keyboard_init,
|
|
||||||
keyboard_read
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef CONTROLLER_KEYBOARD_H
|
|
||||||
#define CONTROLLER_KEYBOARD_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
bool keyboard_on_key_down(int scancode);
|
|
||||||
bool keyboard_on_key_up(int scancode);
|
|
||||||
void keyboard_on_all_keys_up(void);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern struct ControllerAPI controller_keyboard;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <ultra64.h>
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
static FILE *fp;
|
|
||||||
|
|
||||||
static void tas_init(void) {
|
|
||||||
fp = fopen("cont.m64", "rb");
|
|
||||||
if (fp != NULL) {
|
|
||||||
uint8_t buf[0x400];
|
|
||||||
fread(buf, 1, sizeof(buf), fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tas_read(OSContPad *pad) {
|
|
||||||
if (fp != NULL) {
|
|
||||||
uint8_t bytes[4] = {0};
|
|
||||||
fread(bytes, 1, 4, fp);
|
|
||||||
pad->button = (bytes[0] << 8) | bytes[1];
|
|
||||||
pad->stick_x = bytes[2];
|
|
||||||
pad->stick_y = bytes[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ControllerAPI controller_recorded_tas = {
|
|
||||||
tas_init,
|
|
||||||
tas_read
|
|
||||||
};
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef CONTROLLER_RECORDED_TAS_H
|
|
||||||
#define CONTROLLER_RECORDED_TAS_H
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
extern struct ControllerAPI controller_recorded_tas;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
#if !defined(_WIN32) && !defined(_WIN64)
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#include <ultra64.h>
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
#define DEADZONE 4960
|
|
||||||
|
|
||||||
static bool init_ok;
|
|
||||||
static SDL_GameController *sdl_cntrl;
|
|
||||||
|
|
||||||
static void controller_sdl_init(void) {
|
|
||||||
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) {
|
|
||||||
fprintf(stderr, "SDL init error: %s\n", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_ok = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void controller_sdl_read(OSContPad *pad) {
|
|
||||||
if (!init_ok) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GameControllerUpdate();
|
|
||||||
|
|
||||||
if (sdl_cntrl != NULL && !SDL_GameControllerGetAttached(sdl_cntrl)) {
|
|
||||||
SDL_GameControllerClose(sdl_cntrl);
|
|
||||||
sdl_cntrl = NULL;
|
|
||||||
}
|
|
||||||
if (sdl_cntrl == NULL) {
|
|
||||||
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
|
||||||
if (SDL_IsGameController(i)) {
|
|
||||||
sdl_cntrl = SDL_GameControllerOpen(i);
|
|
||||||
if (sdl_cntrl != NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sdl_cntrl == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_START)) pad->button |= START_BUTTON;
|
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) pad->button |= Z_TRIG;
|
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) pad->button |= R_TRIG;
|
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_A)) pad->button |= A_BUTTON;
|
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_X)) pad->button |= B_BUTTON;
|
|
||||||
|
|
||||||
int16_t leftx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTX);
|
|
||||||
int16_t lefty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTY);
|
|
||||||
int16_t rightx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_RIGHTX);
|
|
||||||
int16_t righty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_RIGHTY);
|
|
||||||
|
|
||||||
int16_t ltrig = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
|
||||||
int16_t rtrig = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
|
||||||
|
|
||||||
#ifdef TARGET_WEB
|
|
||||||
// Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562
|
|
||||||
// It sets down y to 32768.0f / 32767.0f, which is greater than the allowed 1.0f,
|
|
||||||
// which SDL then converts to a int16_t by multiplying by 32767.0f, which overflows into -32768.
|
|
||||||
// Maximum up will hence never become -32768 with the current version of SDL2,
|
|
||||||
// so this workaround should be safe in compliant browsers.
|
|
||||||
if (lefty == -32768) {
|
|
||||||
lefty = 32767;
|
|
||||||
}
|
|
||||||
if (righty == -32768) {
|
|
||||||
righty = 32767;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (rightx < -0x4000) pad->button |= L_CBUTTONS;
|
|
||||||
if (rightx > 0x4000) pad->button |= R_CBUTTONS;
|
|
||||||
if (righty < -0x4000) pad->button |= U_CBUTTONS;
|
|
||||||
if (righty > 0x4000) pad->button |= D_CBUTTONS;
|
|
||||||
|
|
||||||
if (ltrig > 30 * 256) pad->button |= Z_TRIG;
|
|
||||||
if (rtrig > 30 * 256) pad->button |= R_TRIG;
|
|
||||||
|
|
||||||
uint32_t magnitude_sq = (uint32_t)(leftx * leftx) + (uint32_t)(lefty * lefty);
|
|
||||||
if (magnitude_sq > (uint32_t)(DEADZONE * DEADZONE)) {
|
|
||||||
// Game expects stick coordinates within -80..80
|
|
||||||
// 32768 / 409 = ~80
|
|
||||||
pad->stick_x = leftx / 409;
|
|
||||||
pad->stick_y = -lefty / 409;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ControllerAPI controller_sdl = {
|
|
||||||
controller_sdl_init,
|
|
||||||
controller_sdl_read
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef CONTROLLER_SDL_H
|
|
||||||
#define CONTROLLER_SDL_H
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
extern struct ControllerAPI controller_sdl;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#ifdef __linux__
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include <ultra64.h>
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
void *wup_start(void *a);
|
|
||||||
bool wup_get_controller_input(uint16_t *buttons, uint8_t axis[6]);
|
|
||||||
|
|
||||||
static int8_t saturate(int v) {
|
|
||||||
v = v * 3 / 2;
|
|
||||||
return v < -128 ? -128 : v > 127 ? 127 : v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void controller_wup_init(void) {
|
|
||||||
pthread_t pid;
|
|
||||||
pthread_create(&pid, NULL, wup_start, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void controller_wup_read(OSContPad *pad) {
|
|
||||||
uint16_t buttons;
|
|
||||||
uint8_t axis[6];
|
|
||||||
if (wup_get_controller_input(&buttons, axis)) {
|
|
||||||
if (buttons & 0x0001) pad->button |= START_BUTTON;
|
|
||||||
if (buttons & 0x0008) pad->button |= Z_TRIG;
|
|
||||||
if (buttons & 0x0004) pad->button |= R_TRIG;
|
|
||||||
if (buttons & 0x0100) pad->button |= A_BUTTON;
|
|
||||||
if (buttons & 0x0200) pad->button |= B_BUTTON;
|
|
||||||
if (buttons & 0x1000) pad->button |= L_TRIG;
|
|
||||||
if (axis[2] < 0x40) pad->button |= L_CBUTTONS;
|
|
||||||
if (axis[2] > 0xC0) pad->button |= R_CBUTTONS;
|
|
||||||
if (axis[3] < 0x40) pad->button |= D_CBUTTONS;
|
|
||||||
if (axis[3] > 0xC0) pad->button |= U_CBUTTONS;
|
|
||||||
int8_t stick_x = saturate(axis[0] - 128 - 0);
|
|
||||||
int8_t stick_y = saturate(axis[1] - 128 - 0);
|
|
||||||
if (stick_x != 0 || stick_y != 0) {
|
|
||||||
pad->stick_x = stick_x;
|
|
||||||
pad->stick_y = stick_y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ControllerAPI controller_wup = {
|
|
||||||
controller_wup_init,
|
|
||||||
controller_wup_read
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef CONTROLLER_WUP_H
|
|
||||||
#define CONTROLLER_WUP_H
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
extern struct ControllerAPI controller_wup;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#if defined(_WIN32) || defined(_WIN64)
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <xinput.h>
|
|
||||||
|
|
||||||
#include <ultra64.h>
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
#define DEADZONE 4960
|
|
||||||
|
|
||||||
static void xinput_init(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xinput_read(OSContPad *pad) {
|
|
||||||
for (int i = 0; i < XUSER_MAX_COUNT; i++) {
|
|
||||||
XINPUT_STATE state;
|
|
||||||
memset(&state, 0, sizeof(XINPUT_STATE));
|
|
||||||
if (XInputGetState(i, &state) == ERROR_SUCCESS) {
|
|
||||||
XINPUT_GAMEPAD *gp = &state.Gamepad;
|
|
||||||
if (gp->wButtons & XINPUT_GAMEPAD_START) pad->button |= START_BUTTON;
|
|
||||||
if (gp->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) pad->button |= Z_TRIG;
|
|
||||||
if (gp->bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) pad->button |= Z_TRIG;
|
|
||||||
if (gp->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) pad->button |= R_TRIG;
|
|
||||||
if (gp->bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) pad->button |= R_TRIG;
|
|
||||||
if (gp->wButtons & XINPUT_GAMEPAD_A) pad->button |= A_BUTTON;
|
|
||||||
if (gp->wButtons & XINPUT_GAMEPAD_X) pad->button |= B_BUTTON;
|
|
||||||
if (gp->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) pad->button |= L_TRIG;
|
|
||||||
if (gp->sThumbRX < -0x4000) pad->button |= L_CBUTTONS;
|
|
||||||
if (gp->sThumbRX > 0x4000) pad->button |= R_CBUTTONS;
|
|
||||||
if (gp->sThumbRY < -0x4000) pad->button |= D_CBUTTONS;
|
|
||||||
if (gp->sThumbRY > 0x4000) pad->button |= U_CBUTTONS;
|
|
||||||
|
|
||||||
uint32_t magnitude_sq = (uint32_t)(gp->sThumbLX * gp->sThumbLX) + (uint32_t)(gp->sThumbLY * gp->sThumbLY);
|
|
||||||
if (magnitude_sq > (uint32_t)(DEADZONE * DEADZONE)) {
|
|
||||||
// Game expects stick coordinates within -80..80
|
|
||||||
// 32768 / 409 = ~80
|
|
||||||
pad->stick_x = gp->sThumbLX / 409;
|
|
||||||
pad->stick_y = gp->sThumbLY / 409;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ControllerAPI controller_xinput = {
|
|
||||||
xinput_init,
|
|
||||||
xinput_read
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef CONTROLLER_XINPUT_H
|
|
||||||
#define CONTROLLER_XINPUT_H
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
|
||||||
|
|
||||||
#include "controller_api.h"
|
|
||||||
|
|
||||||
extern struct ControllerAPI controller_xinput;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,362 +0,0 @@
|
|||||||
#if !defined(__MINGW32__) && !defined(__BSD__) && !defined(TARGET_WEB)
|
|
||||||
// See LICENSE for license
|
|
||||||
|
|
||||||
#define _XOPEN_SOURCE 600
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
//#include <libudev.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "macros.h"
|
|
||||||
|
|
||||||
#if (!defined(LIBUSBX_API_VERSION) || LIBUSBX_API_VERSION < 0x01000102) && (!defined(LIBUSB_API_VERSION) || LIBUSB_API_VERSION < 0x01000102)
|
|
||||||
#error libusb(x) 1.0.16 or higher is required
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EP_IN 0x81
|
|
||||||
#define EP_OUT 0x02
|
|
||||||
|
|
||||||
#define STATE_NORMAL 0x10
|
|
||||||
#define STATE_WAVEBIRD 0x20
|
|
||||||
|
|
||||||
const int BUTTON_OFFSET_VALUES[16] = {
|
|
||||||
BTN_START,
|
|
||||||
BTN_TR2,
|
|
||||||
BTN_TR,
|
|
||||||
BTN_TL,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
BTN_SOUTH,
|
|
||||||
BTN_WEST,
|
|
||||||
BTN_EAST,
|
|
||||||
BTN_NORTH,
|
|
||||||
BTN_DPAD_LEFT,
|
|
||||||
BTN_DPAD_RIGHT,
|
|
||||||
BTN_DPAD_DOWN,
|
|
||||||
BTN_DPAD_UP,
|
|
||||||
};
|
|
||||||
|
|
||||||
const int AXIS_OFFSET_VALUES[6] = {
|
|
||||||
ABS_X,
|
|
||||||
ABS_Y,
|
|
||||||
ABS_RX,
|
|
||||||
ABS_RY,
|
|
||||||
ABS_Z,
|
|
||||||
ABS_RZ
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ports
|
|
||||||
{
|
|
||||||
bool connected;
|
|
||||||
bool extra_power;
|
|
||||||
unsigned char type;
|
|
||||||
uint16_t buttons;
|
|
||||||
uint8_t axis[6];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct adapter
|
|
||||||
{
|
|
||||||
volatile bool quitting;
|
|
||||||
struct libusb_device *device;
|
|
||||||
struct libusb_device_handle *handle;
|
|
||||||
pthread_t thread;
|
|
||||||
unsigned char rumble[5];
|
|
||||||
struct ports controllers[4];
|
|
||||||
struct adapter *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool raw_mode;
|
|
||||||
|
|
||||||
static volatile int quitting;
|
|
||||||
|
|
||||||
static struct adapter adapters;
|
|
||||||
|
|
||||||
static const char *uinput_path;
|
|
||||||
|
|
||||||
bool wup_get_controller_input(uint16_t *buttons, uint8_t axis[6]) {
|
|
||||||
struct adapter *adapter = adapters.next;
|
|
||||||
if (adapter != NULL) {
|
|
||||||
*buttons = adapter->controllers[0].buttons;
|
|
||||||
memcpy(axis, adapter->controllers[0].axis, 6);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char connected_type(unsigned char status)
|
|
||||||
{
|
|
||||||
unsigned char type = status & (STATE_NORMAL | STATE_WAVEBIRD);
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case STATE_NORMAL:
|
|
||||||
case STATE_WAVEBIRD:
|
|
||||||
return type;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_payload(int i, struct ports *port, unsigned char *payload)
|
|
||||||
{
|
|
||||||
unsigned char status = payload[0];
|
|
||||||
unsigned char type = connected_type(status);
|
|
||||||
|
|
||||||
if (type != 0 && !port->connected)
|
|
||||||
{
|
|
||||||
//uinput_create(i, port, type);
|
|
||||||
port->type = type;
|
|
||||||
port->connected = true;
|
|
||||||
}
|
|
||||||
else if (type == 0 && port->connected)
|
|
||||||
{
|
|
||||||
//uinput_destroy(i, port);
|
|
||||||
port->connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!port->connected)
|
|
||||||
return;
|
|
||||||
|
|
||||||
port->extra_power = ((status & 0x04) != 0);
|
|
||||||
|
|
||||||
if (type != port->type)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "controller on port %d changed controller type???", i+1);
|
|
||||||
port->type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t btns = (uint16_t) payload[1] << 8 | (uint16_t) payload[2];
|
|
||||||
port->buttons = btns;
|
|
||||||
//printf("Btns: %04x\n", btns);
|
|
||||||
|
|
||||||
//printf("Axis:");
|
|
||||||
for (int j = 0; j < 6; j++)
|
|
||||||
{
|
|
||||||
unsigned char value = payload[j+3];
|
|
||||||
port->axis[j] = value;
|
|
||||||
//printf(" %02x", value);
|
|
||||||
}
|
|
||||||
//puts("");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t to_ms(struct timespec* t) {
|
|
||||||
return t->tv_sec * 1000 + t->tv_nsec / 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *adapter_thread(void *data)
|
|
||||||
{
|
|
||||||
struct adapter *a = (struct adapter *)data;
|
|
||||||
|
|
||||||
int bytes_transferred;
|
|
||||||
unsigned char payload[1] = { 0x13 };
|
|
||||||
|
|
||||||
int transfer_ret = libusb_interrupt_transfer(a->handle, EP_OUT, payload, sizeof(payload), &bytes_transferred, 0);
|
|
||||||
|
|
||||||
if (transfer_ret != 0) {
|
|
||||||
fprintf(stderr, "libusb_interrupt_transfer: %s\n", libusb_error_name(transfer_ret));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (bytes_transferred != sizeof(payload)) {
|
|
||||||
fprintf(stderr, "libusb_interrupt_transfer %d/%lu bytes transferred.\n", bytes_transferred, sizeof(payload));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!a->quitting)
|
|
||||||
{
|
|
||||||
//struct timespec time_before = { 0 }, time_after = { 0 };
|
|
||||||
unsigned char payload[37];
|
|
||||||
int size = 0;
|
|
||||||
//clock_gettime(CLOCK_MONOTONIC, &time_before);
|
|
||||||
int transfer_ret = libusb_interrupt_transfer(a->handle, EP_IN, payload, sizeof(payload), &size, 0);
|
|
||||||
//clock_gettime(CLOCK_MONOTONIC, &time_after);
|
|
||||||
//printf("Time taken: %d\n", (int)(to_ms(&time_after) - to_ms(&time_before)));
|
|
||||||
if (transfer_ret != 0) {
|
|
||||||
fprintf(stderr, "libusb_interrupt_transfer error %d\n", transfer_ret);
|
|
||||||
a->quitting = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (size != 37 || payload[0] != 0x21)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
unsigned char *controller = &payload[1];
|
|
||||||
|
|
||||||
unsigned char rumble[5] = { 0x11, 0, 0, 0, 0 };
|
|
||||||
//struct timespec current_time = { 0 };
|
|
||||||
//clock_gettime(CLOCK_REALTIME, ¤t_time);
|
|
||||||
//printf("Time: %d %d\n", (int)current_time.tv_sec, (int)current_time.tv_nsec);
|
|
||||||
for (int i = 0; i < 4; i++, controller += 9)
|
|
||||||
{
|
|
||||||
handle_payload(i, &a->controllers[i], controller);
|
|
||||||
rumble[i+1] = 0;
|
|
||||||
/*if (a->controllers[i].extra_power && a->controllers[i].type == STATE_NORMAL)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < MAX_FF_EVENTS; j++)
|
|
||||||
{
|
|
||||||
struct ff_event *e = &a->controllers[i].ff_events[j];
|
|
||||||
if (e->in_use)
|
|
||||||
{
|
|
||||||
if (ts_lessthan(&e->start_time, ¤t_time) && ts_greaterthan(&e->end_time, ¤t_time))
|
|
||||||
rumble[i+1] = 1;
|
|
||||||
else
|
|
||||||
update_ff_start_stop(e, ¤t_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(rumble, a->rumble, sizeof(rumble)) != 0)
|
|
||||||
{
|
|
||||||
memcpy(a->rumble, rumble, sizeof(rumble));
|
|
||||||
transfer_ret = libusb_interrupt_transfer(a->handle, EP_OUT, a->rumble, sizeof(a->rumble), &size, 0);
|
|
||||||
if (transfer_ret != 0) {
|
|
||||||
fprintf(stderr, "libusb_interrupt_transfer error %d\n", transfer_ret);
|
|
||||||
a->quitting = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
/*if (a->controllers[i].connected)
|
|
||||||
uinput_destroy(i, &a->controllers[i]);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_adapter(struct libusb_device *dev)
|
|
||||||
{
|
|
||||||
struct adapter *a = calloc(1, sizeof(struct adapter));
|
|
||||||
if (a == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "FATAL: calloc() failed");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
a->device = dev;
|
|
||||||
|
|
||||||
if (libusb_open(a->device, &a->handle) != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Error opening device 0x%p\n", a->device);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (libusb_kernel_driver_active(a->handle, 0) == 1) {
|
|
||||||
fprintf(stderr, "Detaching kernel driver\n");
|
|
||||||
if (libusb_detach_kernel_driver(a->handle, 0)) {
|
|
||||||
fprintf(stderr, "Error detaching handle 0x%p from kernel\n", a->handle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct adapter *old_head = adapters.next;
|
|
||||||
adapters.next = a;
|
|
||||||
a->next = old_head;
|
|
||||||
|
|
||||||
pthread_create(&a->thread, NULL, adapter_thread, a);
|
|
||||||
|
|
||||||
fprintf(stderr, "adapter 0x%p connected\n", a->device);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_adapter(struct libusb_device *dev)
|
|
||||||
{
|
|
||||||
struct adapter *a = &adapters;
|
|
||||||
while (a->next != NULL)
|
|
||||||
{
|
|
||||||
if (a->next->device == dev)
|
|
||||||
{
|
|
||||||
a->next->quitting = true;
|
|
||||||
pthread_join(a->next->thread, NULL);
|
|
||||||
fprintf(stderr, "adapter 0x%p disconnected\n", a->next->device);
|
|
||||||
libusb_close(a->next->handle);
|
|
||||||
struct adapter *new_next = a->next->next;
|
|
||||||
free(a->next);
|
|
||||||
a->next = new_next;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
a = a->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int LIBUSB_CALL hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, libusb_hotplug_event event, void *user_data)
|
|
||||||
{
|
|
||||||
(void)ctx;
|
|
||||||
(void)user_data;
|
|
||||||
if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
|
|
||||||
{
|
|
||||||
add_adapter(dev);
|
|
||||||
}
|
|
||||||
else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
|
|
||||||
{
|
|
||||||
remove_adapter(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *wup_start(UNUSED void *a)
|
|
||||||
{
|
|
||||||
libusb_init(NULL);
|
|
||||||
|
|
||||||
struct libusb_device **devices;
|
|
||||||
|
|
||||||
int count = libusb_get_device_list(NULL, &devices);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
struct libusb_device_descriptor desc;
|
|
||||||
libusb_get_device_descriptor(devices[i], &desc);
|
|
||||||
if (desc.idVendor == 0x057e && desc.idProduct == 0x0337)
|
|
||||||
add_adapter(devices[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
libusb_free_device_list(devices, 1);
|
|
||||||
|
|
||||||
libusb_hotplug_callback_handle callback;
|
|
||||||
|
|
||||||
int hotplug_capability = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
|
|
||||||
if (hotplug_capability) {
|
|
||||||
int hotplug_ret = libusb_hotplug_register_callback(NULL,
|
|
||||||
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
|
|
||||||
LIBUSB_HOTPLUG_NO_FLAGS, 0x057e, 0x0337,
|
|
||||||
LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, &callback);
|
|
||||||
|
|
||||||
if (hotplug_ret != LIBUSB_SUCCESS) {
|
|
||||||
fprintf(stderr, "cannot register hotplug callback, hotplugging not enabled\n");
|
|
||||||
hotplug_capability = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pump events until shutdown & all helper threads finish cleaning up
|
|
||||||
while (!quitting)
|
|
||||||
libusb_handle_events_completed(NULL, (int *)&quitting);
|
|
||||||
|
|
||||||
while (adapters.next)
|
|
||||||
remove_adapter(adapters.next->device);
|
|
||||||
|
|
||||||
if (hotplug_capability)
|
|
||||||
libusb_hotplug_deregister_callback(NULL, callback);
|
|
||||||
|
|
||||||
libusb_exit(NULL);
|
|
||||||
return (void *)0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user