FGO: add keyboard input (#61)
Probably self-explanatory :p Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/61 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com>pull/35/head^2
parent
61f95c3f2e
commit
39711a994a
|
@ -158,8 +158,11 @@ coin=0x72
|
|||
; : : AIME. : :
|
||||
; '·:..............................................:·'
|
||||
;
|
||||
; Only XInput is currently supported.
|
||||
|
||||
; Select the input mode. "xinput" for controller, "keyboard" for keyboard.
|
||||
mode=xinput
|
||||
|
||||
[xinput]
|
||||
; XInput bindings
|
||||
;
|
||||
; Left Stick Joystick
|
||||
|
@ -168,3 +171,27 @@ coin=0x72
|
|||
; Left Shoulder Switch Target
|
||||
; A/B Attack
|
||||
; X/Y Noble Phantasm
|
||||
|
||||
; Configure deadzones for the left thumbsticks.
|
||||
; The default value for the left stick is 7849, max value is 32767.
|
||||
stickDeadzone=7849
|
||||
|
||||
[keyboard]
|
||||
; Keyboard bindings:
|
||||
|
||||
; Stick controls (default: WASD)
|
||||
up=0x57
|
||||
left=0x41
|
||||
down=0x53
|
||||
right=0x44
|
||||
|
||||
; Attack (default: Space)
|
||||
attack=0x20
|
||||
; Dash (default: LSHIFT)
|
||||
dash=0xa0
|
||||
; Change Target (default: J)
|
||||
target=0x4A
|
||||
; Re-center camera (default: K)
|
||||
camera=0x4B
|
||||
; Noble Phantasm (default: L)
|
||||
np=0x4C
|
||||
|
|
|
@ -87,7 +87,7 @@ static HRESULT fgo_io4_poll(void *ctx, struct io4_state *state)
|
|||
state->buttons[0] |= 1 << 1;
|
||||
}
|
||||
|
||||
if (gamebtn & FGO_IO_GAMEBTN_NOBLE_PHANTASHM) {
|
||||
if (gamebtn & FGO_IO_GAMEBTN_NOBLE_PHANTASM) {
|
||||
state->buttons[0] |= 1 << 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fgoio/fgoio.h"
|
||||
|
||||
struct fgo_io_backend {
|
||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||
void (*get_analogs)(int16_t *x, int16_t *y);
|
||||
};
|
|
@ -1,11 +1,38 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "fgoio/config.h"
|
||||
|
||||
#include <xinput.h>
|
||||
|
||||
|
||||
void fgo_kb_config_load(
|
||||
struct fgo_kb_config *cfg,
|
||||
const wchar_t *filename) {
|
||||
|
||||
cfg->vk_attack = GetPrivateProfileIntW(L"keyboard", L"attack", ' ', filename);
|
||||
cfg->vk_dash = GetPrivateProfileIntW(L"keyboard", L"dash", VK_LSHIFT, filename);
|
||||
cfg->vk_target = GetPrivateProfileIntW(L"keyboard", L"target", 'J', filename);
|
||||
cfg->vk_camera = GetPrivateProfileIntW(L"keyboard", L"camera", 'K', filename);
|
||||
cfg->vk_np = GetPrivateProfileIntW(L"keyboard", L"np", 'L', filename);
|
||||
|
||||
// Standard WASD
|
||||
cfg->vk_right = GetPrivateProfileIntW(L"keyboard", L"right", 'D', filename);
|
||||
cfg->vk_left = GetPrivateProfileIntW(L"keyboard", L"left", 'A', filename);
|
||||
cfg->vk_down = GetPrivateProfileIntW(L"keyboard", L"down", 'S', filename);
|
||||
cfg->vk_up = GetPrivateProfileIntW(L"keyboard", L"up", 'W', filename);
|
||||
}
|
||||
|
||||
void fgo_xi_config_load(
|
||||
struct fgo_xi_config *cfg,
|
||||
const wchar_t *filename) {
|
||||
|
||||
cfg->stick_deadzone = GetPrivateProfileIntW(L"xinput", L"stickDeadzone", XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, filename);
|
||||
|
||||
}
|
||||
|
||||
void fgo_io_config_load(
|
||||
struct fgo_io_config *cfg,
|
||||
|
@ -17,4 +44,15 @@ void fgo_io_config_load(
|
|||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename);
|
||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename);
|
||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"io4",
|
||||
L"mode",
|
||||
L"xinput",
|
||||
cfg->mode,
|
||||
_countof(cfg->mode),
|
||||
filename);
|
||||
|
||||
fgo_xi_config_load(&cfg->xi, filename);
|
||||
fgo_kb_config_load(&cfg->kb, filename);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,34 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct fgo_kb_config {
|
||||
uint8_t vk_np;
|
||||
uint8_t vk_target;
|
||||
uint8_t vk_dash;
|
||||
uint8_t vk_attack;
|
||||
uint8_t vk_camera;
|
||||
uint8_t vk_right;
|
||||
uint8_t vk_left;
|
||||
uint8_t vk_down;
|
||||
uint8_t vk_up;
|
||||
};
|
||||
|
||||
struct fgo_xi_config {
|
||||
uint16_t stick_deadzone;
|
||||
};
|
||||
|
||||
struct fgo_io_config {
|
||||
uint8_t vk_test;
|
||||
uint8_t vk_service;
|
||||
uint8_t vk_coin;
|
||||
|
||||
wchar_t mode[12];
|
||||
struct fgo_kb_config kb;
|
||||
struct fgo_xi_config xi;
|
||||
};
|
||||
|
||||
void fgo_kb_config_load(struct fgo_kb_config *cfg, const wchar_t *filename);
|
||||
void fgo_xi_config_load(struct fgo_xi_config *cfg, const wchar_t *filename);
|
||||
void fgo_io_config_load(
|
||||
struct fgo_io_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
|
123
fgoio/fgoio.c
123
fgoio/fgoio.c
|
@ -2,37 +2,51 @@
|
|||
#include <xinput.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fgoio/fgoio.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "xi.h"
|
||||
#include "fgoio/config.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static uint8_t fgo_opbtn;
|
||||
static uint8_t fgo_gamebtn;
|
||||
static int16_t fgo_stick_x;
|
||||
static int16_t fgo_stick_y;
|
||||
static struct fgo_io_config fgo_io_cfg;
|
||||
static const struct fgo_io_backend* fgo_io_backend;
|
||||
static bool fgo_io_coin;
|
||||
|
||||
uint16_t fgo_io_get_api_version(void)
|
||||
{
|
||||
uint16_t fgo_io_get_api_version(void) {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT fgo_io_init(void)
|
||||
{
|
||||
HRESULT fgo_io_init(void) {
|
||||
fgo_io_config_load(&fgo_io_cfg, get_config_path());
|
||||
|
||||
return S_OK;
|
||||
HRESULT hr;
|
||||
|
||||
if (wstr_ieq(fgo_io_cfg.mode, L"keyboard")) {
|
||||
hr = fgo_kb_init(&fgo_io_cfg.kb, &fgo_io_backend);
|
||||
} else if (wstr_ieq(fgo_io_cfg.mode, L"xinput")) {
|
||||
hr = fgo_xi_init(&fgo_io_cfg.xi, &fgo_io_backend);
|
||||
} else {
|
||||
hr = E_INVALIDARG;
|
||||
dprintf("FGO IO: Invalid IO mode \"%S\", use keyboard or xinput\n",
|
||||
fgo_io_cfg.mode);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT fgo_io_poll(void)
|
||||
{
|
||||
XINPUT_STATE xi;
|
||||
WORD xb;
|
||||
HRESULT fgo_io_poll(void) {
|
||||
assert(fgo_io_backend != NULL);
|
||||
|
||||
fgo_opbtn = 0;
|
||||
fgo_gamebtn = 0;
|
||||
|
@ -56,97 +70,34 @@ HRESULT fgo_io_poll(void)
|
|||
fgo_io_coin = false;
|
||||
}
|
||||
|
||||
memset(&xi, 0, sizeof(xi));
|
||||
XInputGetState(0, &xi);
|
||||
xb = xi.Gamepad.wButtons;
|
||||
|
||||
if (xi.Gamepad.bLeftTrigger > 64) {
|
||||
fgo_gamebtn |= FGO_IO_GAMEBTN_SPEED_UP;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) {
|
||||
fgo_gamebtn |= FGO_IO_GAMEBTN_TARGET;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_A || xb & XINPUT_GAMEPAD_B) {
|
||||
fgo_gamebtn |= FGO_IO_GAMEBTN_ATTACK;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_Y || xb & XINPUT_GAMEPAD_X) {
|
||||
fgo_gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASHM;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_LEFT_THUMB) {
|
||||
fgo_gamebtn |= FGO_IO_GAMEBTN_CAMERA;
|
||||
}
|
||||
|
||||
float LX = xi.Gamepad.sThumbLX;
|
||||
float LY = xi.Gamepad.sThumbLY;
|
||||
|
||||
// determine how far the controller is pushed
|
||||
float magnitude = sqrt(LX*LX + LY*LY);
|
||||
|
||||
// determine the direction the controller is pushed
|
||||
float normalizedLX = LX / magnitude;
|
||||
float normalizedLY = LY / magnitude;
|
||||
|
||||
float normalizedMagnitude = 0;
|
||||
|
||||
// check if the controller is outside a circular dead zone
|
||||
if (magnitude > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
|
||||
{
|
||||
// clip the magnitude at its expected maximum value
|
||||
if (magnitude > 32767) magnitude = 32767;
|
||||
|
||||
// adjust magnitude relative to the end of the dead zone
|
||||
magnitude -= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;
|
||||
|
||||
// optionally normalize the magnitude with respect to its expected range
|
||||
// giving a magnitude value of 0.0 to 1.0
|
||||
normalizedMagnitude = magnitude / (32767 - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
|
||||
} else // if the controller is in the deadzone zero out the magnitude
|
||||
{
|
||||
magnitude = 0.0;
|
||||
normalizedMagnitude = 0.0;
|
||||
}
|
||||
|
||||
fgo_stick_x = (int16_t)(normalizedLX * normalizedMagnitude * 32767);
|
||||
fgo_stick_y = (int16_t)(normalizedLY * normalizedMagnitude * 32767);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void fgo_io_get_opbtns(uint8_t *opbtn)
|
||||
{
|
||||
void fgo_io_get_opbtns(uint8_t* opbtn) {
|
||||
if (opbtn != NULL) {
|
||||
*opbtn = fgo_opbtn;
|
||||
}
|
||||
}
|
||||
|
||||
void fgo_io_get_gamebtns(uint8_t *btn)
|
||||
{
|
||||
if (btn != NULL) {
|
||||
*btn = fgo_gamebtn;
|
||||
}
|
||||
void fgo_io_get_gamebtns(uint8_t* btn) {
|
||||
assert(fgo_io_backend != NULL);
|
||||
assert(btn != NULL);
|
||||
|
||||
fgo_io_backend->get_gamebtns(btn);
|
||||
}
|
||||
|
||||
void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y)
|
||||
{
|
||||
if (stick_x != NULL) {
|
||||
*stick_x = fgo_stick_x;
|
||||
}
|
||||
void fgo_io_get_analogs(int16_t* stick_x, int16_t* stick_y) {
|
||||
assert(fgo_io_backend != NULL);
|
||||
assert(stick_x != NULL);
|
||||
assert(stick_y != NULL);
|
||||
|
||||
if (stick_y != NULL) {
|
||||
*stick_y = fgo_stick_y;
|
||||
}
|
||||
fgo_io_backend->get_analogs(stick_x, stick_y);
|
||||
}
|
||||
|
||||
HRESULT fgo_io_led_init(void)
|
||||
{
|
||||
HRESULT fgo_io_led_init(void) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
||||
{
|
||||
void fgo_io_led_set_colors(uint8_t board, uint8_t* rgb) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ enum {
|
|||
FGO_IO_GAMEBTN_SPEED_UP = 0x01,
|
||||
FGO_IO_GAMEBTN_TARGET = 0x02,
|
||||
FGO_IO_GAMEBTN_ATTACK = 0x04,
|
||||
FGO_IO_GAMEBTN_NOBLE_PHANTASHM = 0x08,
|
||||
FGO_IO_GAMEBTN_NOBLE_PHANTASM = 0x08,
|
||||
FGO_IO_GAMEBTN_CAMERA = 0x10,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "fgoio/backend.h"
|
||||
#include "fgoio/config.h"
|
||||
#include "fgoio/fgoio.h"
|
||||
#include "fgoio/keyboard.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void fgo_kb_get_gamebtns(uint8_t* gamebtn_out);
|
||||
static void fgo_kb_get_analogs(int16_t* x, int16_t* y);
|
||||
|
||||
static const struct fgo_io_backend fgo_kb_backend = {
|
||||
.get_gamebtns = fgo_kb_get_gamebtns,
|
||||
.get_analogs = fgo_kb_get_analogs
|
||||
};
|
||||
|
||||
static struct fgo_kb_config config;
|
||||
|
||||
HRESULT fgo_kb_init(const struct fgo_kb_config* cfg, const struct fgo_io_backend** backend) {
|
||||
assert(cfg != NULL);
|
||||
assert(backend != NULL);
|
||||
|
||||
dprintf("Keyboard: Using keyboard input\n");
|
||||
*backend = &fgo_kb_backend;
|
||||
config = *cfg;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void fgo_kb_get_gamebtns(uint8_t* gamebtn_out) {
|
||||
assert(gamebtn_out != NULL);
|
||||
|
||||
uint8_t gamebtn = 0;
|
||||
|
||||
if (GetAsyncKeyState(config.vk_np) & 0x8000) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASM;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_target) & 0x8000) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_TARGET;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_dash) & 0x8000) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_SPEED_UP;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_attack) & 0x8000) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_ATTACK;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(config.vk_camera) & 0x8000) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_CAMERA;
|
||||
}
|
||||
|
||||
*gamebtn_out = gamebtn;
|
||||
}
|
||||
|
||||
static void fgo_kb_get_analogs(int16_t* x, int16_t* y) {
|
||||
assert(x != NULL);
|
||||
assert(y != NULL);
|
||||
|
||||
if (GetAsyncKeyState(config.vk_left) & 0x8000) {
|
||||
*x = SHRT_MIN + 1;
|
||||
} else if (GetAsyncKeyState(config.vk_right) & 0x8000) {
|
||||
*x = SHRT_MAX - 1;
|
||||
} else {
|
||||
*x = 0;
|
||||
}
|
||||
if (GetAsyncKeyState(config.vk_down) & 0x8000) {
|
||||
*y = SHRT_MIN + 1;
|
||||
} else if (GetAsyncKeyState(config.vk_up) & 0x8000) {
|
||||
*y = SHRT_MAX - 1;
|
||||
} else {
|
||||
*y = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "fgoio/backend.h"
|
||||
#include "fgoio/config.h"
|
||||
|
||||
HRESULT fgo_kb_init(const struct fgo_kb_config *cfg, const struct fgo_io_backend **backend);
|
|
@ -11,5 +11,10 @@ fgoio_lib = static_library(
|
|||
'fgoio.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'backend.h',
|
||||
'keyboard.c',
|
||||
'keyboard.h',
|
||||
'xi.c',
|
||||
'xi.h',
|
||||
],
|
||||
)
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fgoio/backend.h"
|
||||
#include "fgoio/config.h"
|
||||
#include "fgoio/fgoio.h"
|
||||
#include "fgoio/xi.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void fgo_xi_get_gamebtns(uint8_t* gamebtn_out);
|
||||
static void fgo_xi_get_analogs(int16_t* x, int16_t* y);
|
||||
static HRESULT fgo_xi_config_apply(const struct fgo_xi_config* cfg);
|
||||
|
||||
static const struct fgo_io_backend fgo_xi_backend = {
|
||||
.get_gamebtns = fgo_xi_get_gamebtns,
|
||||
.get_analogs = fgo_xi_get_analogs
|
||||
};
|
||||
|
||||
static float fgo_xi_stick_deadzone;
|
||||
|
||||
const uint16_t max_stick_value = 32767;
|
||||
|
||||
HRESULT fgo_xi_init(const struct fgo_xi_config* cfg, const struct fgo_io_backend** backend) {
|
||||
assert(cfg != NULL);
|
||||
assert(backend != NULL);
|
||||
|
||||
HRESULT hr = fgo_xi_config_apply(cfg);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
dprintf("XInput: Using XInput controller\n");
|
||||
*backend = &fgo_xi_backend;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT fgo_xi_config_apply(const struct fgo_xi_config* cfg) {
|
||||
/* Deadzone check */
|
||||
if (cfg->stick_deadzone > 32767 || cfg->stick_deadzone < 0) {
|
||||
dprintf("XInput: Stick deadzone is too large or negative\n");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
dprintf("XInput: --- Begin configuration ---\n");
|
||||
dprintf("XInput: Left Deadzone . . . . : %i\n", cfg->stick_deadzone);
|
||||
dprintf("XInput: --- End configuration ---\n");
|
||||
|
||||
fgo_xi_stick_deadzone = cfg->stick_deadzone;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void fgo_xi_get_gamebtns(uint8_t* gamebtn_out) {
|
||||
assert(gamebtn_out != NULL);
|
||||
|
||||
XINPUT_STATE xi;
|
||||
memset(&xi, 0, sizeof(xi));
|
||||
XInputGetState(0, &xi);
|
||||
|
||||
uint8_t gamebtn = 0;
|
||||
WORD xb = xi.Gamepad.wButtons;
|
||||
|
||||
if (xi.Gamepad.bLeftTrigger > 64) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_SPEED_UP;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_LEFT_SHOULDER) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_TARGET;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_A || xb & XINPUT_GAMEPAD_B) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_ATTACK;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_Y || xb & XINPUT_GAMEPAD_X) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_NOBLE_PHANTASM;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_LEFT_THUMB) {
|
||||
gamebtn |= FGO_IO_GAMEBTN_CAMERA;
|
||||
}
|
||||
|
||||
*gamebtn_out = gamebtn;
|
||||
}
|
||||
|
||||
static void fgo_xi_get_analogs(int16_t* x, int16_t* y) {
|
||||
|
||||
assert(x != NULL);
|
||||
assert(y != NULL);
|
||||
|
||||
XINPUT_STATE xi;
|
||||
memset(&xi, 0, sizeof(xi));
|
||||
XInputGetState(0, &xi);
|
||||
|
||||
float LX = xi.Gamepad.sThumbLX;
|
||||
float LY = xi.Gamepad.sThumbLY;
|
||||
|
||||
// determine how far the controller is pushed
|
||||
float magnitude = sqrt(LX * LX + LY * LY);
|
||||
|
||||
// determine the direction the controller is pushed
|
||||
float normalizedLX = LX / magnitude;
|
||||
float normalizedLY = LY / magnitude;
|
||||
|
||||
float normalizedMagnitude = 0;
|
||||
|
||||
// check if the controller is outside a circular dead zone
|
||||
if (magnitude > fgo_xi_stick_deadzone) {
|
||||
// clip the magnitude at its expected maximum value
|
||||
if (magnitude > 32767) magnitude = 32767;
|
||||
|
||||
// adjust magnitude relative to the end of the dead zone
|
||||
magnitude -= fgo_xi_stick_deadzone;
|
||||
|
||||
// optionally normalize the magnitude with respect to its expected range
|
||||
// giving a magnitude value of 0.0 to 1.0
|
||||
normalizedMagnitude = magnitude / (32767 - fgo_xi_stick_deadzone);
|
||||
} else // if the controller is in the deadzone zero out the magnitude
|
||||
{
|
||||
normalizedMagnitude = 0;
|
||||
}
|
||||
|
||||
*x = (int16_t) (normalizedLX * normalizedMagnitude * 32767);
|
||||
*y = (int16_t) (normalizedLY * normalizedMagnitude * 32767);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
/* Can't call this xinput.h or it will conflict with <xinput.h> */
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "fgoio/backend.h"
|
||||
#include "fgoio/config.h"
|
||||
|
||||
HRESULT fgo_xi_init(const struct fgo_xi_config *cfg, const struct fgo_io_backend **backend);
|
Loading…
Reference in New Issue