Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,530 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config/bind-adv.h"
|
||||
#include "config/resource.h"
|
||||
#include "config/usages.h"
|
||||
|
||||
#include "geninput/hid-mgr.h"
|
||||
|
||||
#include "util/array.h"
|
||||
#include "util/defs.h"
|
||||
#include "util/mem.h"
|
||||
#include "util/str.h"
|
||||
|
||||
struct bind_adv_state {
|
||||
uintptr_t timer_id;
|
||||
struct mapped_action ma;
|
||||
struct array devs;
|
||||
struct hid_stub *cur_hid;
|
||||
struct hid_control *ctls;
|
||||
size_t nctls;
|
||||
bool was_valid;
|
||||
};
|
||||
|
||||
static INT_PTR CALLBACK bind_adv_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
||||
LPARAM lparam);
|
||||
static INT_PTR bind_adv_handle_init(HWND hwnd, struct bind_adv_state *state);
|
||||
static void bind_adv_handle_init_devs(HWND hwnd);
|
||||
static void bind_adv_handle_init_insert_dev(HWND hwnd, struct hid_stub *hid);
|
||||
static INT_PTR bind_adv_handle_change_ctl(HWND hwnd);
|
||||
static INT_PTR bind_adv_handle_change_dev(HWND hwnd);
|
||||
static INT_PTR bind_adv_handle_change_range(HWND hwnd);
|
||||
static INT_PTR bind_adv_handle_tick(HWND hwnd);
|
||||
static INT_PTR bind_adv_handle_ok(HWND hwnd);
|
||||
static INT_PTR bind_adv_handle_fini(HWND hwnd);
|
||||
static bool bind_adv_get_dev_no(HWND hwnd, size_t *dev_no_out);
|
||||
static bool bind_adv_get_ctl_no(HWND hwnd, size_t *ctl_no_out);
|
||||
static bool bind_adv_get_range(HWND hwnd, int32_t *out_min, int32_t *out_max);
|
||||
static bool bind_adv_get_int(HWND control, int32_t *out);
|
||||
static bool bind_adv_is_valid(HWND hwnd);
|
||||
static void bind_adv_validate(HWND hwnd);
|
||||
static void bind_adv_select_dev(HWND hwnd, size_t dev_no);
|
||||
static void bind_adv_select_ctl(HWND hwnd, size_t ctl_no);
|
||||
static void bind_adv_set_range(HWND hwnd, int32_t range_min, int32_t range_max);
|
||||
|
||||
bool bind_adv(HINSTANCE inst, HWND hwnd, struct mapped_action *ma,
|
||||
bool was_valid)
|
||||
{
|
||||
struct bind_adv_state state;
|
||||
INT_PTR ok;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
|
||||
state.ma = *ma;
|
||||
state.was_valid = was_valid;
|
||||
|
||||
ok = DialogBoxParam(inst, MAKEINTRESOURCE(IDD_BIND_ADV), hwnd,
|
||||
bind_adv_dlg_proc, (LPARAM) &state) != 0;
|
||||
|
||||
if (ok) {
|
||||
*ma = state.ma;
|
||||
}
|
||||
|
||||
return ok != 0;
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK bind_adv_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
||||
LPARAM lparam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG:
|
||||
return bind_adv_handle_init(hwnd, (struct bind_adv_state *) lparam);
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wparam)) {
|
||||
case IDC_CONTROL:
|
||||
switch (HIWORD(wparam)) {
|
||||
case CBN_SELCHANGE:
|
||||
return bind_adv_handle_change_ctl(hwnd);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case IDC_DEVICE:
|
||||
switch (HIWORD(wparam)) {
|
||||
case CBN_SELCHANGE:
|
||||
return bind_adv_handle_change_dev(hwnd);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case IDC_BINDING_MIN:
|
||||
case IDC_BINDING_MAX:
|
||||
switch (HIWORD(wparam)) {
|
||||
case EN_CHANGE:
|
||||
return bind_adv_handle_change_range(hwnd);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case IDOK:
|
||||
switch (HIWORD(wparam)) {
|
||||
case BN_CLICKED:
|
||||
return bind_adv_handle_ok(hwnd);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case IDCANCEL:
|
||||
switch (HIWORD(wparam)) {
|
||||
case BN_CLICKED:
|
||||
EndDialog(hwnd, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case WM_TIMER:
|
||||
return bind_adv_handle_tick(hwnd);
|
||||
|
||||
case WM_DESTROY:
|
||||
return bind_adv_handle_fini(hwnd);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static INT_PTR bind_adv_handle_init(HWND hwnd, struct bind_adv_state *state)
|
||||
{
|
||||
struct hid_stub *hid;
|
||||
size_t i;
|
||||
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) state);
|
||||
|
||||
bind_adv_handle_init_devs(hwnd);
|
||||
|
||||
state->timer_id = SetTimer(hwnd, 1, 17, NULL);
|
||||
|
||||
if (!state->was_valid) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < state->devs.nitems ; i++) {
|
||||
hid = *array_item(struct hid_stub *, &state->devs, i);
|
||||
|
||||
if (hid == state->ma.hid) {
|
||||
bind_adv_select_dev(hwnd, (int) i);
|
||||
bind_adv_select_ctl(hwnd, state->ma.control_no);
|
||||
bind_adv_set_range(hwnd, state->ma.value_min,
|
||||
state->ma.value_max);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void bind_adv_handle_init_devs(HWND hwnd)
|
||||
{
|
||||
struct hid_stub *hid;
|
||||
|
||||
hid_mgr_lock();
|
||||
|
||||
for (hid = hid_mgr_get_first_stub()
|
||||
; hid != NULL
|
||||
; hid = hid_mgr_get_next_stub(hid)) {
|
||||
bind_adv_handle_init_insert_dev(hwnd, hid);
|
||||
}
|
||||
|
||||
hid_mgr_unlock();
|
||||
}
|
||||
|
||||
static void bind_adv_handle_init_insert_dev(HWND hwnd, struct hid_stub *hid)
|
||||
{
|
||||
struct bind_adv_state *state;
|
||||
wchar_t *name;
|
||||
size_t nchars;
|
||||
HWND devs;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
devs = GetDlgItem(hwnd, IDC_DEVICE);
|
||||
|
||||
if (!hid_stub_get_name(hid, NULL, &nchars)) {
|
||||
goto size_fail;
|
||||
}
|
||||
|
||||
name = xmalloc(sizeof(*name) * nchars);
|
||||
|
||||
if (!hid_stub_get_name(hid, name, &nchars)) {
|
||||
goto name_fail;
|
||||
}
|
||||
|
||||
*array_append(struct hid_stub *, &state->devs) = hid;
|
||||
|
||||
SendMessage(devs, CB_ADDSTRING, 0, (LPARAM) name);
|
||||
|
||||
name_fail:
|
||||
free(name);
|
||||
|
||||
size_fail:
|
||||
;
|
||||
}
|
||||
|
||||
static INT_PTR bind_adv_handle_change_ctl(HWND hwnd)
|
||||
{
|
||||
size_t ctl_no;
|
||||
|
||||
if (bind_adv_get_ctl_no(hwnd, &ctl_no)) {
|
||||
bind_adv_select_ctl(hwnd, ctl_no);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR bind_adv_handle_change_dev(HWND hwnd)
|
||||
{
|
||||
size_t dev_no;
|
||||
|
||||
if (bind_adv_get_dev_no(hwnd, &dev_no)) {
|
||||
bind_adv_select_dev(hwnd, dev_no);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR bind_adv_handle_change_range(HWND hwnd)
|
||||
{
|
||||
bind_adv_validate(hwnd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR bind_adv_handle_tick(HWND hwnd)
|
||||
{
|
||||
struct bind_adv_state *state;
|
||||
wchar_t wchars[16];
|
||||
size_t ctl_no;
|
||||
int32_t value;
|
||||
HWND label;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
if (!bind_adv_get_ctl_no(hwnd, &ctl_no)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
hid_mgr_lock();
|
||||
|
||||
if (hid_stub_get_value(state->cur_hid, ctl_no, &value)) {
|
||||
wstr_format(wchars, lengthof(wchars), L"%d", value);
|
||||
|
||||
label = GetDlgItem(hwnd, IDC_CURRENT);
|
||||
SetWindowText(label, wchars);
|
||||
}
|
||||
|
||||
hid_mgr_unlock();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR bind_adv_handle_ok(HWND hwnd)
|
||||
{
|
||||
struct bind_adv_state *state;
|
||||
size_t dev_no;
|
||||
size_t ctl_no;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
/* bind_adv_validate() ought to ensure that OK is disabled whenever the
|
||||
user's input is somehow invalid. Still, it never hurts to double check.
|
||||
|
||||
Ignore any OK clicks that we somehow receive with invalid input. */
|
||||
|
||||
if (!bind_adv_get_dev_no(hwnd, &dev_no)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
state->ma.hid = *array_item(struct hid_stub *, &state->devs, dev_no);
|
||||
|
||||
if (!bind_adv_get_ctl_no(hwnd, &ctl_no)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
state->ma.control_no = ctl_no;
|
||||
|
||||
if (!bind_adv_get_range(hwnd, &state->ma.value_min, &state->ma.value_max)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Input OK, shut down this dialog. */
|
||||
|
||||
EndDialog(hwnd, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR bind_adv_handle_fini(HWND hwnd)
|
||||
{
|
||||
struct bind_adv_state *state;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
array_fini(&state->devs);
|
||||
|
||||
KillTimer(hwnd, state->timer_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool bind_adv_get_dev_no(HWND hwnd, size_t *dev_no_out)
|
||||
{
|
||||
const struct bind_adv_state *state;
|
||||
size_t dev_no;
|
||||
HWND devs;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
devs = GetDlgItem(hwnd, IDC_DEVICE);
|
||||
|
||||
dev_no = SendMessage(devs, CB_GETCURSEL, 0, 0);
|
||||
|
||||
if (dev_no >= state->devs.nitems) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dev_no_out != NULL) {
|
||||
*dev_no_out = dev_no;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bind_adv_get_ctl_no(HWND hwnd, size_t *ctl_no_out)
|
||||
{
|
||||
const struct bind_adv_state *state;
|
||||
size_t ctl_no;
|
||||
HWND ctls;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
ctls = GetDlgItem(hwnd, IDC_CONTROL);
|
||||
|
||||
ctl_no = SendMessage(ctls, CB_GETCURSEL, 0, 0);
|
||||
|
||||
if (ctl_no >= state->nctls) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctl_no_out != NULL) {
|
||||
*ctl_no_out = ctl_no;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bind_adv_get_range(HWND hwnd, int32_t *out_min, int32_t *out_max)
|
||||
{
|
||||
HWND wnd_min;
|
||||
HWND wnd_max;
|
||||
|
||||
wnd_min = GetDlgItem(hwnd, IDC_BINDING_MIN);
|
||||
wnd_max = GetDlgItem(hwnd, IDC_BINDING_MAX);
|
||||
|
||||
return bind_adv_get_int(wnd_min, out_min)
|
||||
&& bind_adv_get_int(wnd_max, out_max);
|
||||
}
|
||||
|
||||
static bool bind_adv_get_int(HWND control, int32_t *out)
|
||||
{
|
||||
wchar_t text[16];
|
||||
int32_t tmp;
|
||||
|
||||
text[0] = L'\0';
|
||||
GetWindowText(control, text, lengthof(text));
|
||||
|
||||
if (swscanf(text, L"%d", &tmp) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out != NULL) {
|
||||
*out = tmp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bind_adv_is_valid(HWND hwnd)
|
||||
{
|
||||
if (!bind_adv_get_dev_no(hwnd, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bind_adv_get_ctl_no(hwnd, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bind_adv_get_range(hwnd, NULL, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bind_adv_validate(HWND hwnd)
|
||||
{
|
||||
HWND ok;
|
||||
|
||||
ok = GetDlgItem(hwnd, IDOK);
|
||||
EnableWindow(ok, bind_adv_is_valid(hwnd) ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
static void bind_adv_select_dev(HWND hwnd, size_t dev_no)
|
||||
{
|
||||
struct bind_adv_state *state;
|
||||
struct hid_stub *hid;
|
||||
char chars[256];
|
||||
wchar_t wchars[256];
|
||||
size_t i;
|
||||
HWND ctls;
|
||||
HWND devs;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
ctls = GetDlgItem(hwnd, IDC_CONTROL);
|
||||
devs = GetDlgItem(hwnd, IDC_DEVICE);
|
||||
|
||||
if (dev_no >= state->devs.nitems) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(devs, CB_SETCURSEL, (WPARAM) dev_no, 0);
|
||||
SendMessage(ctls, CB_RESETCONTENT, 0, 0);
|
||||
|
||||
hid = *array_item(struct hid_stub *, &state->devs, dev_no);
|
||||
|
||||
state->cur_hid = hid;
|
||||
|
||||
hid_mgr_lock();
|
||||
|
||||
if (!hid_stub_get_controls(state->cur_hid, NULL, &state->nctls)) {
|
||||
goto size_fail;
|
||||
}
|
||||
|
||||
free(state->ctls);
|
||||
state->ctls = xmalloc(sizeof(*state->ctls) * state->nctls);
|
||||
|
||||
if (!hid_stub_get_controls(state->cur_hid, state->ctls, &state->nctls)) {
|
||||
goto data_fail;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < state->nctls ; i++) {
|
||||
wchars[0] = L'\0';
|
||||
|
||||
usages_get(chars, lengthof(chars), state->ctls[i].usage);
|
||||
MultiByteToWideChar(CP_UTF8, 0, chars, -1, wchars, lengthof(wchars));
|
||||
|
||||
SendMessage(ctls, CB_ADDSTRING, 0, (LPARAM) wchars);
|
||||
}
|
||||
|
||||
hid_mgr_unlock();
|
||||
|
||||
bind_adv_validate(hwnd);
|
||||
|
||||
return;
|
||||
|
||||
data_fail:
|
||||
free(state->ctls);
|
||||
|
||||
state->ctls = NULL;
|
||||
state->nctls = 0;
|
||||
|
||||
size_fail:
|
||||
hid_mgr_unlock();
|
||||
|
||||
bind_adv_validate(hwnd);
|
||||
}
|
||||
|
||||
static void bind_adv_select_ctl(HWND hwnd, size_t ctl_no)
|
||||
{
|
||||
wchar_t text[128];
|
||||
struct bind_adv_state *state;
|
||||
const struct hid_control *ctl;
|
||||
HWND ctls;
|
||||
HWND limit_min;
|
||||
HWND limit_max;
|
||||
|
||||
state = (struct bind_adv_state *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
ctls = GetDlgItem(hwnd, IDC_CONTROL);
|
||||
limit_min = GetDlgItem(hwnd, IDC_LIMIT_MIN);
|
||||
limit_max = GetDlgItem(hwnd, IDC_LIMIT_MAX);
|
||||
|
||||
if (ctl_no >= state->nctls) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(ctls, CB_SETCURSEL, (WPARAM) ctl_no, 0);
|
||||
|
||||
ctl = &state->ctls[ctl_no];
|
||||
|
||||
wstr_format(text, lengthof(text), L"%d", ctl->value_min);
|
||||
SetWindowText(limit_min, text);
|
||||
|
||||
wstr_format(text, lengthof(text), L"%d", ctl->value_max);
|
||||
SetWindowText(limit_max, text);
|
||||
|
||||
bind_adv_validate(hwnd);
|
||||
}
|
||||
|
||||
static void bind_adv_set_range(HWND hwnd, int32_t range_min, int32_t range_max)
|
||||
{
|
||||
wchar_t text[16];
|
||||
HWND wnd_min;
|
||||
HWND wnd_max;
|
||||
|
||||
wnd_min = GetDlgItem(hwnd, IDC_BINDING_MIN);
|
||||
wnd_max = GetDlgItem(hwnd, IDC_BINDING_MAX);
|
||||
|
||||
wstr_format(text, lengthof(text), L"%d", range_min);
|
||||
SetWindowText(wnd_min, text);
|
||||
|
||||
wstr_format(text, lengthof(text), L"%d", range_max);
|
||||
SetWindowText(wnd_max, text);
|
||||
|
||||
bind_adv_validate(hwnd);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user