Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,426 @@
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config/bind.h"
|
||||
#include "config/bind-adv.h"
|
||||
#include "config/resource.h"
|
||||
#include "config/schema.h"
|
||||
#include "config/usages.h"
|
||||
|
||||
#include "geninput/input-config.h"
|
||||
#include "geninput/mapper.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/mem.h"
|
||||
#include "util/winres.h"
|
||||
|
||||
static INT_PTR CALLBACK buttons_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
||||
LPARAM lparam);
|
||||
static bool buttons_get_control_name(const struct mapped_action *ma,
|
||||
wchar_t *str, size_t nchars);
|
||||
static INT_PTR buttons_handle_init(HWND hwnd, const PROPSHEETPAGE *psp);
|
||||
static INT_PTR buttons_handle_binding_adv(HWND hwnd);
|
||||
static INT_PTR buttons_handle_binding_clear(HWND hwnd);
|
||||
static INT_PTR buttons_handle_binding_edit(HWND hwnd, BOOL bind_many);
|
||||
static INT_PTR buttons_handle_switch_page(HWND hwnd, NMUPDOWN *n);
|
||||
static INT_PTR buttons_handle_fini(HWND hwnd);
|
||||
static void buttons_update(HWND hwnd);
|
||||
static void buttons_update_bindings(HWND hwnd);
|
||||
static void buttons_update_pager(HWND hwnd);
|
||||
|
||||
struct buttons_tab {
|
||||
const struct schema *schema;
|
||||
uint8_t page_no;
|
||||
uint8_t npages;
|
||||
};
|
||||
|
||||
HPROPSHEETPAGE buttons_tab_create(HINSTANCE inst, const struct schema *schema)
|
||||
{
|
||||
PROPSHEETPAGE psp;
|
||||
|
||||
memset(&psp, 0, sizeof(psp));
|
||||
psp.dwSize = sizeof(psp);
|
||||
psp.dwFlags = PSP_DEFAULT;
|
||||
psp.hInstance = inst;
|
||||
psp.pszTemplate = MAKEINTRESOURCE(IDD_TAB_BUTTONS);
|
||||
psp.pfnDlgProc = buttons_dlg_proc;
|
||||
psp.lParam = (LPARAM) schema;
|
||||
|
||||
return CreatePropertySheetPage(&psp);
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK buttons_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
||||
LPARAM lparam)
|
||||
{
|
||||
NMHDR *n;
|
||||
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG:
|
||||
return buttons_handle_init(hwnd, (const PROPSHEETPAGE *) lparam);
|
||||
|
||||
case WM_NOTIFY:
|
||||
n = (NMHDR *) lparam;
|
||||
|
||||
switch (n->idFrom) {
|
||||
case IDC_PAGE:
|
||||
switch (n->code) {
|
||||
case UDN_DELTAPOS:
|
||||
return buttons_handle_switch_page(hwnd,
|
||||
(NMUPDOWN *) n);
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
case IDC_BINDINGS:
|
||||
switch (n->code) {
|
||||
case NM_DBLCLK:
|
||||
return buttons_handle_binding_edit(hwnd, FALSE);
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wparam)) {
|
||||
case IDC_BINDING_ADV:
|
||||
return buttons_handle_binding_adv(hwnd);
|
||||
|
||||
case IDC_BINDING_CLEAR:
|
||||
return buttons_handle_binding_clear(hwnd);
|
||||
|
||||
case IDC_BINDING_EDIT:
|
||||
return buttons_handle_binding_edit(hwnd, FALSE);
|
||||
|
||||
case IDC_BINDING_EDIT_MANY:
|
||||
return buttons_handle_binding_edit(hwnd, TRUE);
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
case WM_DESTROY:
|
||||
return buttons_handle_fini(hwnd);
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static INT_PTR buttons_handle_init(HWND hwnd, const PROPSHEETPAGE *psp)
|
||||
{
|
||||
struct buttons_tab *self;
|
||||
HWND bindings_ctl;
|
||||
HINSTANCE inst;
|
||||
LVCOLUMN col;
|
||||
LVITEM item;
|
||||
wchar_t str[128];
|
||||
size_t i;
|
||||
|
||||
self = xmalloc(sizeof(*self));
|
||||
self->schema = (const struct schema *) psp->lParam;
|
||||
self->page_no = 0;
|
||||
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) self);
|
||||
|
||||
inst = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
||||
bindings_ctl = GetDlgItem(hwnd, IDC_BINDINGS);
|
||||
|
||||
ListView_SetExtendedListViewStyle(bindings_ctl,
|
||||
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
|
||||
|
||||
LoadString(inst, IDS_COL_ACTION, str, lengthof(str));
|
||||
|
||||
col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
|
||||
col.fmt = LVCFMT_LEFT;
|
||||
col.cx = 120;
|
||||
col.pszText = str;
|
||||
|
||||
ListView_InsertColumn(bindings_ctl, 0, &col);
|
||||
|
||||
LoadString(inst, IDS_COL_BUTTON, str, lengthof(str));
|
||||
|
||||
col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
|
||||
col.fmt = LVCFMT_LEFT;
|
||||
col.cx = 120;
|
||||
col.pszText = str;
|
||||
|
||||
ListView_InsertColumn(bindings_ctl, 1, &col);
|
||||
|
||||
for (i = 0 ; i < self->schema->nactions ; i++) {
|
||||
memset(&item, 0, sizeof(item));
|
||||
|
||||
LoadString(inst, self->schema->actions[i].name_rsrc, str,
|
||||
lengthof(str));
|
||||
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = (int) i;
|
||||
item.iSubItem = 0;
|
||||
item.pszText = str;
|
||||
|
||||
ListView_InsertItem(bindings_ctl, &item);
|
||||
}
|
||||
|
||||
buttons_update(hwnd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void buttons_update(HWND hwnd)
|
||||
{
|
||||
buttons_update_pager(hwnd);
|
||||
buttons_update_bindings(hwnd);
|
||||
|
||||
/* Flickery, but seems to be the only way to avoid label garbling when
|
||||
the page label changes. Need to do better. */
|
||||
InvalidateRect(hwnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void buttons_update_pager(HWND hwnd)
|
||||
{
|
||||
struct buttons_tab *self;
|
||||
HINSTANCE inst;
|
||||
wchar_t str[128];
|
||||
|
||||
inst = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
||||
self = (struct buttons_tab *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
self->npages = mapper_get_npages() + 1;
|
||||
|
||||
rswprintf(str, lengthof(str), inst, IDS_PAGE, self->page_no + 1,
|
||||
self->npages);
|
||||
SetWindowText(GetDlgItem(hwnd, IDC_PAGE_TEXT), str);
|
||||
}
|
||||
|
||||
static void buttons_update_bindings(HWND hwnd)
|
||||
{
|
||||
action_iter_t pos;
|
||||
struct mapped_action ma;
|
||||
struct buttons_tab *self;
|
||||
HINSTANCE inst;
|
||||
HWND bindings_ctl;
|
||||
LVITEM item;
|
||||
wchar_t str[128];
|
||||
size_t i;
|
||||
|
||||
self = (struct buttons_tab *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
inst = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
||||
bindings_ctl = GetDlgItem(hwnd, IDC_BINDINGS);
|
||||
|
||||
/* Clear binding cell text */
|
||||
|
||||
for (i = 0 ; i < self->schema->nactions ; i++) {
|
||||
memset(&item, 0, sizeof(item));
|
||||
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = (int) i;
|
||||
item.iSubItem = 1;
|
||||
item.pszText = L"";
|
||||
|
||||
ListView_SetItem(bindings_ctl, &item);
|
||||
}
|
||||
|
||||
/* Repopulate bindings */
|
||||
|
||||
hid_mgr_lock();
|
||||
|
||||
for (pos = mapper_iterate_actions()
|
||||
; action_iter_is_valid(pos)
|
||||
; action_iter_next(pos)) {
|
||||
if (action_iter_get_page(pos) != self->page_no) {
|
||||
continue;
|
||||
}
|
||||
|
||||
action_iter_get_mapping(pos, &ma);
|
||||
|
||||
if (!buttons_get_control_name(&ma, str, lengthof(str))) {
|
||||
/* Can't read device metadata, device is probably unplugged */
|
||||
LoadString(inst, IDS_NOT_PRESENT, str, lengthof(str));
|
||||
}
|
||||
|
||||
memset(&item, 0, sizeof(item));
|
||||
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = (int) action_iter_get_action(pos);
|
||||
item.iSubItem = 1;
|
||||
item.pszText = str;
|
||||
|
||||
ListView_SetItem(bindings_ctl, &item);
|
||||
}
|
||||
|
||||
action_iter_free(pos);
|
||||
hid_mgr_unlock();
|
||||
}
|
||||
|
||||
static bool buttons_get_control_name(const struct mapped_action *ma,
|
||||
wchar_t *str, size_t nchars)
|
||||
{
|
||||
char chars[128];
|
||||
struct hid_control *controls;
|
||||
size_t ncontrols;
|
||||
|
||||
if (!hid_stub_get_controls(ma->hid, NULL, &ncontrols)) {
|
||||
goto count_fail;
|
||||
}
|
||||
|
||||
controls = xmalloc(ncontrols * sizeof(*controls));
|
||||
|
||||
if (!hid_stub_get_controls(ma->hid, controls, &ncontrols)) {
|
||||
goto data_fail;
|
||||
}
|
||||
|
||||
if (ma->control_no >= ncontrols) {
|
||||
goto bounds_fail;
|
||||
}
|
||||
|
||||
usages_get(chars, lengthof(chars), controls[ma->control_no].usage);
|
||||
MultiByteToWideChar(CP_UTF8, 0, chars, lengthof(chars), str, nchars);
|
||||
|
||||
free(controls);
|
||||
|
||||
return true;
|
||||
|
||||
bounds_fail:
|
||||
data_fail:
|
||||
free(controls);
|
||||
|
||||
count_fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static INT_PTR buttons_handle_binding_adv(HWND hwnd)
|
||||
{
|
||||
HINSTANCE inst;
|
||||
struct mapped_action ma;
|
||||
struct buttons_tab *self;
|
||||
int action_no;
|
||||
uint8_t bit;
|
||||
bool is_valid;
|
||||
|
||||
inst = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
||||
self = (struct buttons_tab *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
action_no = ListView_GetSelectionMark(GetDlgItem(hwnd, IDC_BINDINGS));
|
||||
|
||||
if (action_no < 0 || action_no >= (int) self->schema->nactions) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bit = self->schema->actions[action_no].bit;
|
||||
|
||||
is_valid = mapper_get_action_map((uint8_t) action_no, self->page_no, &ma);
|
||||
|
||||
if (bind_adv(inst, hwnd, &ma, is_valid)) {
|
||||
mapper_set_action_map((uint8_t) action_no, self->page_no, bit, &ma);
|
||||
buttons_update(hwnd);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR buttons_handle_binding_clear(HWND hwnd)
|
||||
{
|
||||
struct buttons_tab *self;
|
||||
int action_no;
|
||||
|
||||
self = (struct buttons_tab *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
action_no = ListView_GetSelectionMark(GetDlgItem(hwnd, IDC_BINDINGS));
|
||||
|
||||
if (action_no < 0 || action_no >= (int) self->schema->nactions) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mapper_clear_action_map((uint8_t) action_no, self->page_no);
|
||||
buttons_update(hwnd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR buttons_handle_binding_edit(HWND hwnd, BOOL bind_many)
|
||||
{
|
||||
HINSTANCE inst;
|
||||
HWND listview;
|
||||
struct buttons_tab *self;
|
||||
struct mapped_action ma;
|
||||
int action_start;
|
||||
int action_no;
|
||||
uint8_t bit;
|
||||
|
||||
inst = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
||||
self = (struct buttons_tab *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
listview = GetDlgItem(hwnd, IDC_BINDINGS);
|
||||
|
||||
action_start = ListView_GetSelectionMark(listview);
|
||||
|
||||
if (action_start < 0 || action_start >= (int) self->schema->nactions) {
|
||||
/* wtf... */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for(action_no = action_start;
|
||||
action_no < self->schema->nactions;
|
||||
action_no++) {
|
||||
// Make sure the next listview item is visible
|
||||
ListView_SetItemState (listview, action_no, LVIS_FOCUSED | LVIS_SELECTED, 0x000F);
|
||||
ListView_EnsureVisible(listview, action_no, FALSE);
|
||||
|
||||
bit = self->schema->actions[action_no].bit;
|
||||
|
||||
if (bind_control(inst, hwnd, &self->schema->actions[action_no], &ma)) {
|
||||
mapper_set_action_map((uint8_t) action_no, self->page_no, bit, &ma);
|
||||
buttons_update(hwnd);
|
||||
|
||||
log_misc("Bind act %d -> dev %p ctl %u range [%d, %d]",
|
||||
self->schema->actions[action_no].bit, ma.hid,
|
||||
(unsigned int) ma.control_no, ma.value_min, ma.value_max);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!bind_many) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR buttons_handle_switch_page(HWND hwnd, NMUPDOWN *n)
|
||||
{
|
||||
struct buttons_tab *self;
|
||||
|
||||
self = (struct buttons_tab *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
/* The buttons on a horizontal spinner are backwards -.- */
|
||||
|
||||
if (n->iDelta > 0 && self->page_no > 0) {
|
||||
self->page_no--;
|
||||
buttons_update(hwnd);
|
||||
} else if (n->iDelta < 0 && self->page_no < self->npages - 1) {
|
||||
self->page_no++;
|
||||
buttons_update(hwnd);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR buttons_handle_fini(HWND hwnd)
|
||||
{
|
||||
struct buttons_tab *self;
|
||||
|
||||
self = (struct buttons_tab *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
free(self);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user