Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,626 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "geninput/hid-mgr.h"
|
||||
#include "geninput/mapper.h"
|
||||
|
||||
#include "util/array.h"
|
||||
#include "util/log.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
struct action_iter {
|
||||
struct mapper *mapper;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
struct action_mapping {
|
||||
struct mapped_action src;
|
||||
uint8_t action;
|
||||
uint8_t page;
|
||||
uint8_t bit;
|
||||
};
|
||||
|
||||
struct analog_mapping {
|
||||
struct mapped_analog src;
|
||||
int32_t sensitivity;
|
||||
bool bound;
|
||||
bool valid;
|
||||
bool absolute;
|
||||
double affine_scale;
|
||||
double affine_bias;
|
||||
uint8_t pos;
|
||||
};
|
||||
|
||||
struct light_iter {
|
||||
struct mapper *mapper;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
struct light_mapping {
|
||||
struct mapped_light dest;
|
||||
uint8_t game_light;
|
||||
bool bound;
|
||||
bool valid;
|
||||
double affine_scale;
|
||||
int32_t affine_bias;
|
||||
};
|
||||
|
||||
struct mapper {
|
||||
struct array actions;
|
||||
struct analog_mapping *analogs;
|
||||
uint8_t nanalogs;
|
||||
struct array light_maps;
|
||||
uint8_t *lights;
|
||||
uint8_t nlights;
|
||||
};
|
||||
|
||||
static uint64_t action_mapping_update(struct action_mapping *am);
|
||||
static void analog_mapping_bind(struct analog_mapping *am);
|
||||
static void analog_mapping_update(struct analog_mapping *am);
|
||||
static void light_mapping_bind(struct light_mapping *lm);
|
||||
static void light_mapping_send(struct light_mapping *lm,
|
||||
const struct mapper *m);
|
||||
|
||||
struct mapper *mapper_inst;
|
||||
|
||||
void action_iter_get_mapping(action_iter_t iter, struct mapped_action *ma)
|
||||
{
|
||||
struct action_mapping *am;
|
||||
|
||||
log_assert(action_iter_is_valid(iter));
|
||||
|
||||
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
|
||||
*ma = am->src;
|
||||
}
|
||||
|
||||
uint8_t action_iter_get_action(action_iter_t iter)
|
||||
{
|
||||
struct action_mapping *am;
|
||||
|
||||
log_assert(action_iter_is_valid(iter));
|
||||
|
||||
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
|
||||
|
||||
return am->action;
|
||||
}
|
||||
|
||||
uint8_t action_iter_get_page(action_iter_t iter)
|
||||
{
|
||||
struct action_mapping *am;
|
||||
|
||||
log_assert(action_iter_is_valid(iter));
|
||||
|
||||
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
|
||||
|
||||
return am->page;
|
||||
}
|
||||
|
||||
uint8_t action_iter_get_bit(action_iter_t iter)
|
||||
{
|
||||
struct action_mapping *am;
|
||||
|
||||
log_assert(action_iter_is_valid(iter));
|
||||
|
||||
am = array_item(struct action_mapping, &iter->mapper->actions, iter->i);
|
||||
|
||||
return am->bit;
|
||||
}
|
||||
|
||||
bool action_iter_is_valid(action_iter_t iter)
|
||||
{
|
||||
return iter->i < iter->mapper->actions.nitems;
|
||||
}
|
||||
|
||||
void action_iter_next(action_iter_t iter)
|
||||
{
|
||||
iter->i++;
|
||||
}
|
||||
|
||||
void action_iter_free(action_iter_t iter)
|
||||
{
|
||||
free(iter);
|
||||
}
|
||||
|
||||
static uint64_t action_mapping_update(struct action_mapping *am)
|
||||
{
|
||||
int32_t value;
|
||||
|
||||
if (am->src.hid == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hid_stub_get_value(am->src.hid, am->src.control_no, &value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (value < am->src.value_min || value > am->src.value_max) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1ULL << am->bit;
|
||||
}
|
||||
|
||||
static void analog_mapping_bind(struct analog_mapping *am)
|
||||
{
|
||||
const struct hid_control *ctl;
|
||||
struct hid_control *controls;
|
||||
size_t ncontrols;
|
||||
|
||||
am->bound = true;
|
||||
am->valid = false;
|
||||
|
||||
if (am->src.hid == NULL) {
|
||||
goto unbound_fail;
|
||||
}
|
||||
|
||||
if (!hid_stub_get_controls(am->src.hid, NULL, &ncontrols)) {
|
||||
goto size_fail;
|
||||
}
|
||||
|
||||
if (am->src.control_no >= ncontrols) {
|
||||
goto bounds_fail;
|
||||
}
|
||||
|
||||
controls = xmalloc(sizeof(*controls) * ncontrols);
|
||||
|
||||
if (!hid_stub_get_controls(am->src.hid, controls, &ncontrols)) {
|
||||
goto read_fail;
|
||||
}
|
||||
|
||||
ctl = &controls[am->src.control_no];
|
||||
|
||||
am->affine_bias = ctl->value_min;
|
||||
am->affine_scale = ctl->value_max - ctl->value_min;
|
||||
am->absolute = !(ctl->flags & HID_FLAG_RELATIVE);
|
||||
am->valid = true;
|
||||
|
||||
read_fail:
|
||||
free(controls);
|
||||
|
||||
bounds_fail:
|
||||
size_fail:
|
||||
unbound_fail:
|
||||
return;
|
||||
}
|
||||
|
||||
static void analog_mapping_update(struct analog_mapping *am)
|
||||
{
|
||||
double tmp;
|
||||
int32_t value;
|
||||
|
||||
if (!am->bound) {
|
||||
analog_mapping_bind(am);
|
||||
}
|
||||
|
||||
if (!am->valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hid_stub_get_value(am->src.hid, am->src.control_no, &value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (am->absolute) {
|
||||
tmp = (value - am->affine_bias) / am->affine_scale;
|
||||
am->pos = (uint8_t) ((tmp + 0.5) * 256.0);
|
||||
} else {
|
||||
am->pos += (int8_t) (value * exp(am->sensitivity / 256.0));
|
||||
}
|
||||
}
|
||||
|
||||
void light_iter_get_mapping(light_iter_t iter, struct mapped_light *ml)
|
||||
{
|
||||
struct light_mapping *lm;
|
||||
|
||||
log_assert(light_iter_is_valid(iter));
|
||||
|
||||
lm = array_item(struct light_mapping, &iter->mapper->light_maps, iter->i);
|
||||
*ml = lm->dest;
|
||||
}
|
||||
|
||||
uint8_t light_iter_get_game_light(light_iter_t iter)
|
||||
{
|
||||
struct light_mapping *lm;
|
||||
|
||||
log_assert(light_iter_is_valid(iter));
|
||||
|
||||
lm = array_item(struct light_mapping, &iter->mapper->light_maps, iter->i);
|
||||
|
||||
return lm->game_light;
|
||||
}
|
||||
|
||||
bool light_iter_is_valid(light_iter_t iter)
|
||||
{
|
||||
return iter->i < iter->mapper->light_maps.nitems;
|
||||
}
|
||||
|
||||
void light_iter_next(light_iter_t iter)
|
||||
{
|
||||
iter->i++;
|
||||
}
|
||||
|
||||
void light_iter_free(light_iter_t iter)
|
||||
{
|
||||
free(iter);
|
||||
}
|
||||
|
||||
static void light_mapping_bind(struct light_mapping *lm)
|
||||
{
|
||||
const struct hid_light *light;
|
||||
struct hid_light *light_defs;
|
||||
size_t nlights;
|
||||
|
||||
lm->bound = true;
|
||||
lm->valid = false;
|
||||
|
||||
if (lm->dest.hid == NULL) {
|
||||
goto unbound_fail;
|
||||
}
|
||||
|
||||
if (!hid_stub_get_lights(lm->dest.hid, NULL, &nlights)) {
|
||||
goto size_fail;
|
||||
}
|
||||
|
||||
if (lm->dest.light_no >= nlights) {
|
||||
goto bounds_fail;
|
||||
}
|
||||
|
||||
light_defs = xmalloc(sizeof(*light_defs) * nlights);
|
||||
|
||||
if (!hid_stub_get_lights(lm->dest.hid, light_defs, &nlights)) {
|
||||
goto read_fail;
|
||||
}
|
||||
|
||||
light = &light_defs[lm->dest.light_no];
|
||||
|
||||
lm->affine_bias = light->value_min;
|
||||
lm->affine_scale = light->value_max - light->value_min;
|
||||
lm->valid = true;
|
||||
|
||||
read_fail:
|
||||
free(light_defs);
|
||||
|
||||
bounds_fail:
|
||||
size_fail:
|
||||
unbound_fail:
|
||||
return;
|
||||
}
|
||||
|
||||
static void light_mapping_send(struct light_mapping *lm,
|
||||
const struct mapper *m)
|
||||
{
|
||||
double tmp;
|
||||
uint32_t value;
|
||||
uint8_t intensity;
|
||||
|
||||
if (!lm->bound) {
|
||||
light_mapping_bind(lm);
|
||||
}
|
||||
|
||||
if (!lm->valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lm->game_light >= m->nlights) {
|
||||
return;
|
||||
}
|
||||
|
||||
intensity = m->lights[lm->game_light];
|
||||
tmp = (intensity / 256.0) * lm->affine_scale;
|
||||
value = (int32_t) (tmp + 0.5) + lm->affine_bias;
|
||||
|
||||
hid_stub_set_light(lm->dest.hid, lm->dest.light_no, value);
|
||||
}
|
||||
|
||||
struct mapper *mapper_impl_create(void)
|
||||
{
|
||||
struct mapper *m;
|
||||
|
||||
m = xmalloc(sizeof(*m));
|
||||
|
||||
array_init(&m->actions);
|
||||
|
||||
m->analogs = NULL;
|
||||
m->nanalogs = 0;
|
||||
|
||||
array_init(&m->light_maps);
|
||||
|
||||
m->lights = NULL;
|
||||
m->nlights = 0;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void mapper_impl_clear_action_map(struct mapper *m, uint8_t action,
|
||||
uint8_t page)
|
||||
{
|
||||
struct action_mapping *am;
|
||||
size_t i;
|
||||
|
||||
for (i = 0 ; i < m->actions.nitems ; i++) {
|
||||
am = array_item(struct action_mapping, &m->actions, i);
|
||||
|
||||
if (am->action == action && am->page == page) {
|
||||
array_remove(struct action_mapping, &m->actions, i);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mapper_impl_clear_light_map(struct mapper *m,
|
||||
const struct mapped_light *ml)
|
||||
{
|
||||
struct light_mapping *lm;
|
||||
size_t i;
|
||||
|
||||
for (i = 0 ; i < m->light_maps.nitems ; ) {
|
||||
lm = array_item(struct light_mapping, &m->light_maps, i);
|
||||
|
||||
if (memcmp(&lm->dest, ml, sizeof(*ml)) == 0) {
|
||||
array_remove(struct light_mapping, &m->light_maps, i);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool mapper_impl_get_action_map(struct mapper *m, uint8_t action, uint8_t page,
|
||||
struct mapped_action *ma)
|
||||
{
|
||||
const struct action_mapping *am;
|
||||
size_t i;
|
||||
|
||||
for (i = 0 ; i < m->actions.nitems ; i++) {
|
||||
am = array_item(struct action_mapping, &m->actions, i);
|
||||
|
||||
if (am->action == action && am->page == page) {
|
||||
*ma = am->src;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mapper_impl_get_analog_map(struct mapper *m, uint8_t analog,
|
||||
struct mapped_analog *ma)
|
||||
{
|
||||
memset(ma, 0, sizeof(*ma));
|
||||
|
||||
if (analog >= m->nanalogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*ma = m->analogs[analog].src;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t mapper_impl_get_analog_sensitivity(struct mapper *m, uint8_t analog)
|
||||
{
|
||||
if (analog >= m->nanalogs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m->analogs[analog].sensitivity;
|
||||
}
|
||||
|
||||
uint8_t mapper_impl_get_nanalogs(struct mapper *m)
|
||||
{
|
||||
return m->nanalogs;
|
||||
}
|
||||
|
||||
uint8_t mapper_impl_get_nlights(struct mapper *m)
|
||||
{
|
||||
return m->nlights;
|
||||
}
|
||||
|
||||
uint8_t mapper_impl_get_npages(struct mapper *m)
|
||||
{
|
||||
const struct action_mapping *am;
|
||||
size_t i;
|
||||
int max_page;
|
||||
|
||||
max_page = -1;
|
||||
|
||||
for (i = 0 ; i < m->actions.nitems ; i++) {
|
||||
am = array_item(struct action_mapping, &m->actions, i);
|
||||
|
||||
if (max_page < am->page) {
|
||||
max_page = am->page;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint8_t) (max_page + 1);
|
||||
}
|
||||
|
||||
action_iter_t mapper_impl_iterate_actions(struct mapper *m)
|
||||
{
|
||||
struct action_iter *iter;
|
||||
|
||||
iter = xmalloc(sizeof(*iter));
|
||||
iter->mapper = m;
|
||||
iter->i = 0;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
light_iter_t mapper_impl_iterate_lights(struct mapper *m)
|
||||
{
|
||||
struct light_iter *iter;
|
||||
|
||||
iter = xmalloc(sizeof(*iter));
|
||||
iter->mapper = m;
|
||||
iter->i = 0;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool mapper_impl_is_analog_absolute(struct mapper *m, uint8_t analog)
|
||||
{
|
||||
struct analog_mapping *am;
|
||||
|
||||
if (analog >= m->nanalogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
am = &m->analogs[analog];
|
||||
|
||||
if (!am->bound) {
|
||||
analog_mapping_bind(am);
|
||||
}
|
||||
|
||||
return m->analogs[analog].absolute;
|
||||
}
|
||||
|
||||
void mapper_impl_set_action_map(struct mapper *m, uint8_t action, uint8_t page,
|
||||
uint8_t bit, const struct mapped_action *ma)
|
||||
{
|
||||
struct action_mapping *am;
|
||||
size_t i;
|
||||
|
||||
for (i = 0 ; i < m->actions.nitems ; i++) {
|
||||
am = array_item(struct action_mapping, &m->actions, i);
|
||||
|
||||
if (am->action == action && am->page == page) {
|
||||
am->src = *ma;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
am = array_append(struct action_mapping, &m->actions);
|
||||
|
||||
am->src = *ma;
|
||||
am->action = action;
|
||||
am->page = page;
|
||||
am->bit = bit;
|
||||
}
|
||||
|
||||
bool mapper_impl_set_analog_map(struct mapper *m, uint8_t analog,
|
||||
const struct mapped_analog *ma)
|
||||
{
|
||||
struct analog_mapping *am;
|
||||
|
||||
if (analog >= m->nanalogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
am = &m->analogs[analog];
|
||||
|
||||
am->src = *ma;
|
||||
am->bound = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mapper_impl_set_analog_sensitivity(struct mapper *m, uint8_t analog,
|
||||
int32_t sensitivity)
|
||||
{
|
||||
if (analog >= m->nanalogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m->analogs[analog].sensitivity = sensitivity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mapper_impl_set_light_map(struct mapper *m, const struct mapped_light *ml,
|
||||
uint8_t game_light)
|
||||
{
|
||||
struct light_mapping *lm;
|
||||
size_t i;
|
||||
|
||||
for (i = 0 ; i < m->light_maps.nitems ; i++) {
|
||||
lm = array_item(struct light_mapping, &m->light_maps, i);
|
||||
|
||||
if (memcmp(&lm->dest, ml, sizeof(*ml)) == 0) {
|
||||
lm->game_light = game_light;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lm = array_append(struct light_mapping, &m->light_maps);
|
||||
|
||||
memset(lm, 0, sizeof(*lm));
|
||||
|
||||
lm->dest = *ml;
|
||||
lm->game_light = game_light;
|
||||
}
|
||||
|
||||
void mapper_impl_set_nanalogs(struct mapper *m, uint8_t nanalogs)
|
||||
{
|
||||
free(m->analogs);
|
||||
m->analogs = xcalloc(sizeof(*m->analogs) * nanalogs);
|
||||
m->nanalogs = nanalogs;
|
||||
}
|
||||
|
||||
void mapper_impl_set_nlights(struct mapper *m, uint8_t nlights)
|
||||
{
|
||||
free(m->lights);
|
||||
m->lights = xcalloc(sizeof(*m->lights) * nlights);
|
||||
m->nlights = nlights;
|
||||
}
|
||||
|
||||
uint8_t mapper_impl_read_analog(struct mapper *m, uint8_t analog)
|
||||
{
|
||||
if (analog >= m->nanalogs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m->analogs[analog].pos;
|
||||
}
|
||||
|
||||
uint64_t mapper_impl_update(struct mapper *m)
|
||||
{
|
||||
struct action_mapping *am;
|
||||
struct light_mapping *lm;
|
||||
size_t i;
|
||||
uint64_t result;
|
||||
|
||||
hid_mgr_lock();
|
||||
|
||||
for (i = 0 ; i < m->light_maps.nitems ; i++) {
|
||||
lm = array_item(struct light_mapping, &m->light_maps, i);
|
||||
light_mapping_send(lm, m);
|
||||
}
|
||||
|
||||
for (i = 0 ; i < m->nanalogs ; i++) {
|
||||
analog_mapping_update(&m->analogs[i]);
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
for (i = 0 ; i < m->actions.nitems ; i++) {
|
||||
am = array_item(struct action_mapping, &m->actions, i);
|
||||
result |= action_mapping_update(am);
|
||||
}
|
||||
|
||||
hid_mgr_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void mapper_impl_write_light(struct mapper *m, uint8_t light,
|
||||
uint8_t intensity)
|
||||
{
|
||||
if (light >= m->nlights) {
|
||||
return;
|
||||
}
|
||||
|
||||
m->lights[light] = intensity;
|
||||
}
|
||||
|
||||
void mapper_impl_destroy(struct mapper *m)
|
||||
{
|
||||
free(m->lights);
|
||||
array_fini(&m->light_maps);
|
||||
free(m->analogs);
|
||||
array_fini(&m->actions);
|
||||
free(m);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user