forked from TeamTofuShop/segatools
fgo: fgohook finally added
Credits: - Coburn - domeori - Mitsuhide - OLEG - rakisaionji
This commit is contained in:
20
fgoio/config.c
Normal file
20
fgoio/config.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "fgoio/config.h"
|
||||
|
||||
|
||||
void fgo_io_config_load(
|
||||
struct fgo_io_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename);
|
||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename);
|
||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename);
|
||||
}
|
16
fgoio/config.h
Normal file
16
fgoio/config.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct fgo_io_config {
|
||||
uint8_t vk_test;
|
||||
uint8_t vk_service;
|
||||
uint8_t vk_coin;
|
||||
};
|
||||
|
||||
void fgo_io_config_load(
|
||||
struct fgo_io_config *cfg,
|
||||
const wchar_t *filename);
|
141
fgoio/fgoio.c
Normal file
141
fgoio/fgoio.c
Normal file
@ -0,0 +1,141 @@
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fgoio/fgoio.h"
|
||||
#include "fgoio/config.h"
|
||||
#include "util/dprintf.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 bool fgo_io_coin;
|
||||
|
||||
uint16_t fgo_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT fgo_io_init(void)
|
||||
{
|
||||
fgo_io_config_load(&fgo_io_cfg, L".\\segatools.ini");
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT fgo_io_poll(void)
|
||||
{
|
||||
XINPUT_STATE xi;
|
||||
WORD xb;
|
||||
|
||||
fgo_opbtn = 0;
|
||||
fgo_gamebtn = 0;
|
||||
fgo_stick_x = 0;
|
||||
fgo_stick_y = 0;
|
||||
|
||||
if (GetAsyncKeyState(fgo_io_cfg.vk_test) & 0x8000) {
|
||||
fgo_opbtn |= FGO_IO_OPBTN_TEST;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(fgo_io_cfg.vk_service) & 0x8000) {
|
||||
fgo_opbtn |= FGO_IO_OPBTN_SERVICE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(fgo_io_cfg.vk_coin) & 0x8000) {
|
||||
if (!fgo_io_coin) {
|
||||
fgo_io_coin = true;
|
||||
fgo_opbtn |= FGO_IO_OPBTN_COIN;
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
fgo_gamebtn |= FGO_IO_GAMEBTN_ATTACK;
|
||||
}
|
||||
|
||||
if (xb & XINPUT_GAMEPAD_Y) {
|
||||
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 = normalizedLX * normalizedMagnitude * 32767;
|
||||
fgo_stick_y = normalizedLY * normalizedMagnitude * 32767;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
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_analogs(int16_t *stick_x, int16_t *stick_y)
|
||||
{
|
||||
if (stick_x != NULL) {
|
||||
*stick_x = fgo_stick_x;
|
||||
}
|
||||
|
||||
if (stick_y != NULL) {
|
||||
*stick_y = fgo_stick_y;
|
||||
}
|
||||
}
|
71
fgoio/fgoio.h
Normal file
71
fgoio/fgoio.h
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
FGO_IO_OPBTN_TEST = 0x01,
|
||||
FGO_IO_OPBTN_SERVICE = 0x02,
|
||||
FGO_IO_OPBTN_COIN = 0x04,
|
||||
};
|
||||
|
||||
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_CAMERA = 0x10,
|
||||
};
|
||||
|
||||
/* Get the version of the Fate Grand Order IO API that this DLL supports. This
|
||||
function should return a positive 16-bit integer, where the high byte is
|
||||
the major version and the low byte is the minor version (as defined by the
|
||||
Semantic Versioning standard).
|
||||
|
||||
The latest API version as of this writing is 0x0100. */
|
||||
|
||||
uint16_t fgo_io_get_api_version(void);
|
||||
|
||||
/* Initialize the IO DLL. This is the second function that will be called on
|
||||
your DLL, after fgo_io_get_api_version.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT fgo_io_init(void);
|
||||
|
||||
/* Send any queued outputs (of which there are currently none, though this may
|
||||
change in subsequent API versions) and retrieve any new inputs.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT fgo_io_poll(void);
|
||||
|
||||
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
||||
FGO_IO_OPBTN enum above: this contains bit mask definitions for button
|
||||
states returned in *opbtn. All buttons are active-high.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void fgo_io_get_opbtns(uint8_t *opbtn);
|
||||
|
||||
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||
FGO_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into
|
||||
a left hand side set of inputs and a right hand side set of inputs: the bit
|
||||
mappings are the same in both cases.
|
||||
|
||||
All buttons are active-high, even though some buttons' electrical signals
|
||||
on a real cabinet are active-low.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void fgo_io_get_gamebtns(uint8_t *btn);
|
||||
|
||||
/* Get the position of the cabinet stick as of the last poll. The center
|
||||
position should be equal to or close to 32767.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y);
|
16
fgoio/meson.build
Normal file
16
fgoio/meson.build
Normal file
@ -0,0 +1,16 @@
|
||||
fgoio_lib = static_library(
|
||||
'fgoio',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
c_pch : '../precompiled.h',
|
||||
dependencies : [
|
||||
xinput_lib,
|
||||
],
|
||||
sources : [
|
||||
'fgoio.c',
|
||||
'fgoio.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
],
|
||||
)
|
Reference in New Issue
Block a user