diff --git a/src/main/config/config.rc b/src/main/config/config.rc index 9c066323..ef214176 100644 --- a/src/main/config/config.rc +++ b/src/main/config/config.rc @@ -116,12 +116,17 @@ FONT 8, "Ms Shell Dlg" { LTEXT "Keyboard device", IDC_STATIC, 15, 20, 54, 8, SS_LEFT COMBOBOX IDC_KBD_DEVICE, 15, 30, 135, 12, WS_GROUP | WS_TABSTOP | CBS_DROPDOWNLIST | CBS_HASSTRINGS - LTEXT "Card ID file", IDC_STATIC, 15, 50, 36, 8, SS_LEFT - EDITTEXT IDC_CARD_PATH, 15, 60, 135, 14, ES_AUTOHSCROLL - PUSHBUTTON "&Browse...", IDC_BROWSE, 155, 60, 50, 14 + AUTOCHECKBOX "Use top keyboard row for PIN pad input", IDC_ALT_10K, 15, 47, 136, 8 + LTEXT "Card ID file", IDC_CARD_TEXT, 15, 60, 36, 8, SS_LEFT + EDITTEXT IDC_CARD_PATH, 15, 70, 135, 14, ES_AUTOHSCROLL + PUSHBUTTON "&Browse...", IDC_BROWSE, 155, 70, 50, 14 + LTEXT "Smartcard reader", IDC_SCARD_TEXT, 15, 60, 80, 8, SS_LEFT + LTEXT "", IDC_SCARD_READER_NAME, 15, 72, 135, 14, SS_LEFT GROUPBOX "", IDC_GROUP, 5, 5, 210, 80 LTEXT "Keypad status", IDC_STATIC, 155, 20, 46, 8, SS_LEFT LTEXT "", IDC_KEYPAD_STATE, 160, 30, 45, 12, SS_LEFT | SS_CENTERIMAGE + LTEXT "Card present", IDC_SCARD_CARD_TEXT, 155, 60, 46, 8, SS_LEFT + LTEXT "", IDC_SCARD_IS_PRESENT, 160, 70, 45, 12, SS_LEFT | SS_CENTERIMAGE } @@ -170,14 +175,15 @@ FONT 8, "Ms Shell Dlg" LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -IDD_TAB_NETWORK DIALOG 0, 0, 220, 215 +IDD_TAB_NETWORK DIALOG 0, 0, 220, 240 STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU CAPTION "Network" FONT 8, "Ms Shell Dlg" { - LTEXT "", IDC_STATIC, 0, 0, 8, 8, SS_LEFT - AUTOCHECKBOX "Generate card ID files on insertion if they do not already exist", IDC_AUTOGEN, 5, 200, 206, 8 - AUTOCHECKBOX "Use top keyboard row for PIN pad input", IDC_ALT_10K, 5, 185, 141, 8 + AUTOCHECKBOX "Use smartcard readers instead of card ID files", IDC_SCARD, 5, 5, 200, 8 + AUTOCHECKBOX "Use NUMLOCK to deconflict overlapping keypads (ON = P2)", IDC_MUX_KEYPAD, 5, 200, 265, 8 + AUTOCHECKBOX "Use NUMLOCK to share one smartcard reader (ON = P2)", IDC_MUX_SCARD, 5, 212, 265, 8 + AUTOCHECKBOX "Generate card ID files on insertion if they do not already exist", IDC_AUTOGEN, 5, 224, 265, 8 } diff --git a/src/main/config/eam.c b/src/main/config/eam.c index e9bb76ce..bb44aff4 100644 --- a/src/main/config/eam.c +++ b/src/main/config/eam.c @@ -56,9 +56,14 @@ static INT_PTR eam_ui_handle_init(HWND hwnd, const PROPSHEETPAGE *psp); static INT_PTR eam_ui_handle_activate(HWND hwnd); static INT_PTR eam_ui_handle_passivate(HWND hwnd); static INT_PTR eam_ui_handle_tick(HWND hwnd); -static INT_PTR eam_ui_handle_change_alt_10k(HWND hwnd); +static INT_PTR eam_ui_handle_change_scard(HWND hwnd); +static INT_PTR eam_ui_handle_change_mux_keypad(HWND hwnd); +static INT_PTR eam_ui_handle_change_mux_scard(HWND hwnd); static INT_PTR eam_ui_handle_change_autogen(HWND hwnd); static INT_PTR eam_ui_handle_fini(HWND hwnd); +static HWND eam_mux_keypad_dlg; +static HWND *eam_unit_dlgs; +static uint8_t eam_num_units; static INT_PTR CALLBACK eam_unit_ui_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); @@ -66,8 +71,10 @@ static INT_PTR eam_unit_ui_handle_init(HWND hwnd, const struct eam_unit_def *def); static void eam_unit_ui_handle_init_devs(HWND hwnd); static void eam_unit_ui_handle_init_path(HWND hwnd); +static void eam_unit_ui_handle_init_alt_10k(HWND hwnd); static INT_PTR eam_unit_ui_handle_browse(HWND hwnd); static INT_PTR eam_unit_ui_handle_change_device(HWND hwnd); +static INT_PTR eam_unit_ui_handle_change_alt_10k(HWND hwnd); static INT_PTR eam_unit_ui_handle_tick(HWND hwnd); static INT_PTR eam_unit_ui_handle_fini(HWND hwnd); @@ -110,12 +117,18 @@ eam_ui_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) switch (HIWORD(wparam)) { case BN_CLICKED: switch (LOWORD(wparam)) { + case IDC_SCARD: + return eam_ui_handle_change_scard(hwnd); + + case IDC_MUX_KEYPAD: + return eam_ui_handle_change_mux_keypad(hwnd); + + case IDC_MUX_SCARD: + return eam_ui_handle_change_mux_scard(hwnd); + case IDC_AUTOGEN: return eam_ui_handle_change_autogen(hwnd); - case IDC_ALT_10K: - return eam_ui_handle_change_alt_10k(hwnd); - default: return FALSE; } @@ -163,8 +176,16 @@ static INT_PTR eam_ui_handle_init(HWND hwnd, const PROPSHEETPAGE *psp) inst = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE); schema = (struct schema *) psp->lParam; - ypos = 0; + eam_unit_dlgs = xmalloc(sizeof(HWND) * schema->nunits); + eam_num_units = schema->nunits; + GetWindowRect(GetDlgItem(hwnd, IDC_SCARD), &r); + if (eam_io_config_api->get_scard()) { + SendMessage(GetDlgItem(hwnd, IDC_SCARD), BM_SETCHECK, BST_CHECKED, 0); + } + + ypos = r.bottom - r.top + 8; // todo the +8 is hacky bc the bottom is hella big + for (i = 0; i < schema->nunits; i++) { child = CreateDialogParam( inst, @@ -172,6 +193,7 @@ static INT_PTR eam_ui_handle_init(HWND hwnd, const PROPSHEETPAGE *psp) hwnd, eam_unit_ui_dlg_proc, (LPARAM) &schema->units[i]); + eam_unit_dlgs[i] = child; GetWindowRect(child, &r); SetWindowPos( @@ -182,14 +204,30 @@ static INT_PTR eam_ui_handle_init(HWND hwnd, const PROPSHEETPAGE *psp) *array_append(HWND, &ui->children) = child; } + eam_mux_keypad_dlg = GetDlgItem(hwnd, IDC_MUX_KEYPAD); + if (eam_io_config_api->get_mux_keypad()) { + SendMessage(eam_mux_keypad_dlg, BM_SETCHECK, BST_CHECKED, 0); + } + + if (eam_io_config_api->get_mux_scard()) { + SendMessage(GetDlgItem(hwnd, IDC_MUX_SCARD), BM_SETCHECK, BST_CHECKED, 0); + } + if (eam_io_config_api->get_autogen()) { SendMessage(GetDlgItem(hwnd, IDC_AUTOGEN), BM_SETCHECK, BST_CHECKED, 0); } - if (eam_io_config_api->get_alt_10k()) { - SendMessage(GetDlgItem(hwnd, IDC_ALT_10K), BM_SETCHECK, BST_CHECKED, 0); - } + // invoke scard change handler so we can toggle card file / smartcard stuff + eam_ui_handle_change_scard(hwnd); + // invoke a keypad-related change handler so the keypad mux option updates + eam_unit_ui_handle_change_alt_10k(eam_unit_dlgs[0]); + // if only one reader is present, disablo mux options + if (schema->nunits == 1) { + EnableWindow(GetDlgItem(hwnd, IDC_MUX_KEYPAD), false); + EnableWindow(GetDlgItem(hwnd, IDC_MUX_SCARD), false); + } + return TRUE; } @@ -225,15 +263,68 @@ static INT_PTR eam_ui_handle_tick(HWND hwnd) return TRUE; } -static INT_PTR eam_ui_handle_change_alt_10k(HWND hwnd) +static INT_PTR eam_ui_handle_change_scard(HWND hwnd) { HWND btn; - bool alt_10k; + bool scard; + size_t i; - btn = GetDlgItem(hwnd, IDC_ALT_10K); - alt_10k = SendMessage(btn, BM_GETCHECK, 0, 0) == BST_CHECKED; + btn = GetDlgItem(hwnd, IDC_SCARD); + scard = SendMessage(btn, BM_GETCHECK, 0, 0) == BST_CHECKED; + + eam_io_config_api->set_scard(scard); + + // toggle state of card file vs scard components + EnableWindow(GetDlgItem(hwnd, IDC_AUTOGEN), !scard); + EnableWindow(GetDlgItem(hwnd, IDC_MUX_SCARD), scard); + for (i = 0; i < eam_num_units; i++) { + ShowWindow(GetDlgItem(eam_unit_dlgs[i], IDC_CARD_TEXT), !scard); + ShowWindow(GetDlgItem(eam_unit_dlgs[i], IDC_CARD_PATH), !scard); + ShowWindow(GetDlgItem(eam_unit_dlgs[i], IDC_BROWSE), !scard); + ShowWindow(GetDlgItem(eam_unit_dlgs[i], IDC_SCARD_TEXT), scard); + ShowWindow(GetDlgItem(eam_unit_dlgs[i], IDC_SCARD_READER_NAME), scard); + ShowWindow(GetDlgItem(eam_unit_dlgs[i], IDC_SCARD_CARD_TEXT), scard); + ShowWindow(GetDlgItem(eam_unit_dlgs[i], IDC_SCARD_IS_PRESENT), scard); + + if (scard) { + SetWindowTextA( + GetDlgItem(eam_unit_dlgs[i], IDC_SCARD_READER_NAME), + eam_io_config_api->get_scard_reader_name(i)); + } + } - eam_io_config_api->set_alt_10k(alt_10k); + return TRUE; +} + +static INT_PTR eam_ui_handle_change_mux_keypad(HWND hwnd) +{ + HWND btn; + bool mux_keypad; + + btn = GetDlgItem(hwnd, IDC_MUX_KEYPAD); + mux_keypad = SendMessage(btn, BM_GETCHECK, 0, 0) == BST_CHECKED; + + eam_io_config_api->set_mux_keypad(mux_keypad); + + return TRUE; +} + +static INT_PTR eam_ui_handle_change_mux_scard(HWND hwnd) +{ + HWND btn; + bool mux_scard; + size_t i; + + btn = GetDlgItem(hwnd, IDC_MUX_SCARD); + mux_scard = SendMessage(btn, BM_GETCHECK, 0, 0) == BST_CHECKED; + + eam_io_config_api->set_mux_scard(mux_scard); + + for (i = 0; i < eam_num_units; i++) { + SetWindowTextA( + GetDlgItem(eam_unit_dlgs[i], IDC_SCARD_READER_NAME), + eam_io_config_api->get_scard_reader_name(i)); + } return TRUE; } @@ -294,6 +385,15 @@ eam_unit_ui_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) return FALSE; } + case IDC_ALT_10K: + switch (HIWORD(wparam)) { + case BN_CLICKED: + return eam_unit_ui_handle_change_alt_10k(hwnd); + + default: + return FALSE; + } + default: return FALSE; } @@ -326,6 +426,7 @@ eam_unit_ui_handle_init(HWND hwnd, const struct eam_unit_def *def) eam_unit_ui_handle_init_devs(hwnd); eam_unit_ui_handle_init_path(hwnd); + eam_unit_ui_handle_init_alt_10k(hwnd); return TRUE; } @@ -401,6 +502,17 @@ static void eam_unit_ui_handle_init_path(HWND hwnd) } } +static void eam_unit_ui_handle_init_alt_10k(HWND hwnd) +{ + struct eam_unit_ui *ui; + + ui = (struct eam_unit_ui *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + + if (eam_io_config_api->get_alt_10k(ui->def->unit_no)) { + SendMessage(GetDlgItem(hwnd, IDC_ALT_10K), BM_SETCHECK, BST_CHECKED, 0); + } +} + static INT_PTR eam_unit_ui_handle_browse(HWND hwnd) { struct eam_unit_ui *ui; @@ -451,6 +563,28 @@ static INT_PTR eam_unit_ui_handle_change_device(HWND hwnd) eam_io_config_api->set_keypad_device(ui->def->unit_no, hid); } + // enable the keypad mux option if the devices/keys conflict + EnableWindow(eam_mux_keypad_dlg, eam_io_config_api->do_keypads_conflict()); + + return TRUE; +} + +static INT_PTR eam_unit_ui_handle_change_alt_10k(HWND hwnd) +{ + struct eam_unit_ui *ui; + HWND btn; + bool alt_10k; + + ui = (struct eam_unit_ui *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + + btn = GetDlgItem(hwnd, IDC_ALT_10K); + alt_10k = SendMessage(btn, BM_GETCHECK, 0, 0) == BST_CHECKED; + + eam_io_config_api->set_alt_10k(ui->def->unit_no, alt_10k); + + // enable the keypad mux option if the devices/keys conflict + EnableWindow(eam_mux_keypad_dlg, eam_io_config_api->do_keypads_conflict()); + return TRUE; } @@ -459,14 +593,28 @@ static INT_PTR eam_unit_ui_handle_tick(HWND hwnd) struct eam_unit_ui *ui; uint16_t state; wchar_t state_str[9]; + bool card_present; + // keypad state ui = (struct eam_unit_ui *) GetWindowLongPtr(hwnd, GWLP_USERDATA); state = eam_io_get_keypad_state(ui->def->unit_no); wstr_format(state_str, lengthof(state_str), L"%04x", state); SetWindowText(GetDlgItem(hwnd, IDC_KEYPAD_STATE), state_str); - + + // smartcard state + if (eam_io_config_api->get_scard()) { + + eam_io_poll(ui->def->unit_no); + + card_present = eam_io_get_sensor_state(ui->def->unit_no); + + SetWindowText( + GetDlgItem(hwnd, IDC_SCARD_IS_PRESENT), + (card_present ? L"YES" : L"NO")); + } + return TRUE; } diff --git a/src/main/config/resource.h b/src/main/config/resource.h index 0cf49078..0496b7b1 100644 --- a/src/main/config/resource.h +++ b/src/main/config/resource.h @@ -20,7 +20,6 @@ #define IDC_LIGHT 1001 #define IDC_SENSITIVITY 1001 #define IDC_ACTION_NAME 1002 -#define IDC_ALT_10K 1002 #define IDC_KEYPAD_STATE 1002 #define IDC_GAME_TYPE 1003 #define IDC_GROUP 1003 @@ -39,6 +38,15 @@ #define IDC_BINDING_MAX 1010 #define IDC_LIMIT_MAX 1011 #define IDC_CURRENT 1013 +#define IDC_SCARD 1014 +#define IDC_ALT_10K 1015 +#define IDC_MUX_KEYPAD 1016 +#define IDC_MUX_SCARD 1017 +#define IDC_CARD_TEXT 1018 +#define IDC_SCARD_TEXT 1019 +#define IDC_SCARD_READER_NAME 1020 +#define IDC_SCARD_CARD_TEXT 1021 +#define IDC_SCARD_IS_PRESENT 1022 #define IDC_BINDING_EDIT_MANY 40000 #define IDS_APPNAME 40000 #define IDS_BAD_GAME_TYPE 40001 diff --git a/src/main/eamio/Module.mk b/src/main/eamio/Module.mk index f7a7409c..64b8a510 100644 --- a/src/main/eamio/Module.mk +++ b/src/main/eamio/Module.mk @@ -1,6 +1,8 @@ dlls += eamio libs_eamio := geninput util +ldflags_eamio := -lwinscard src_eamio := \ eam-api.c \ eam-impl.c \ eam-s11n.c \ + eam-scard.c diff --git a/src/main/eamio/eam-api.c b/src/main/eamio/eam-api.c index 03203173..1aa4786f 100644 --- a/src/main/eamio/eam-api.c +++ b/src/main/eamio/eam-api.c @@ -14,6 +14,7 @@ #include "eamio/eam-config.h" #include "eamio/eam-impl.h" #include "eamio/eam-s11n.h" +#include "eamio/eam-scard.h" #include "util/fs.h" #include "util/log.h" @@ -24,10 +25,17 @@ static void eam_handle_hotplug_msg(WPARAM wparam, const DEV_BROADCAST_HDR *hdr); static FILE *eam_io_config_open(const char *mode); static void eam_io_config_load(void); static void eam_io_config_save(void); +static bool eam_io_get_scard(void); +static void eam_io_set_scard(bool scard); +static bool eam_io_get_mux_keypad(void); +static void eam_io_set_mux_keypad(bool mux_keypad); +static bool eam_io_get_mux_scard(void); +static void eam_io_set_mux_scard(bool mux_scard); static bool eam_io_get_autogen(void); static void eam_io_set_autogen(bool autogen); -static bool eam_io_get_alt_10k(void); -static void eam_io_set_alt_10k(bool alt_10k); +static bool eam_io_do_keypads_conflict(void); +static bool eam_io_get_alt_10k(uint8_t unit_no); +static void eam_io_set_alt_10k(uint8_t unit_no, bool alt_10k); static struct hid_stub *eam_io_get_keypad_device(uint8_t unit_no); static void eam_io_set_keypad_device(uint8_t unit_no, struct hid_stub *hid); static const char *eam_io_get_card_path(uint8_t unit_no); @@ -46,6 +54,14 @@ static const struct eam_io_config_api eam_io_config_api = { .set_keypad_device = eam_io_set_keypad_device, .get_card_path = eam_io_get_card_path, .set_card_path = eam_io_set_card_path, + .get_scard = eam_io_get_scard, + .set_scard = eam_io_set_scard, + .get_mux_keypad = eam_io_get_mux_keypad, + .set_mux_keypad = eam_io_set_mux_keypad, + .get_mux_scard = eam_io_get_mux_scard, + .set_mux_scard = eam_io_set_mux_scard, + .do_keypads_conflict = eam_io_do_keypads_conflict, + .get_scard_reader_name = eam_scard_get_reader_name, }; void msg_window_setup(HWND hwnd) @@ -99,7 +115,7 @@ void msg_window_teardown(HWND hwnd) static FILE *eam_io_config_open(const char *mode) { - return fopen_appdata("DJHACKERS", "eam_v4_22.bin", mode); + return fopen_appdata("DJHACKERS", "eam_v5_49a.bin", mode); } void eam_io_set_loggers( @@ -161,6 +177,7 @@ void eam_io_fini(void) msg_thread_fini(); eam_impl_destroy(eam_inst); input_fini(); + eam_scard_fini(); } const struct eam_io_config_api *eam_io_get_config_api(void) @@ -182,6 +199,36 @@ static void eam_io_config_save(void) fclose(f); } +static bool eam_io_get_scard(void) +{ + return eam_impl_get_scard(eam_inst); +} + +static void eam_io_set_scard(bool scard) +{ + eam_impl_set_scard(eam_inst, scard); +} + +static bool eam_io_get_mux_keypad(void) +{ + return eam_impl_get_mux_keypad(eam_inst); +} + +static void eam_io_set_mux_keypad(bool mux_keypad) +{ + eam_impl_set_mux_keypad(eam_inst, mux_keypad); +} + +static bool eam_io_get_mux_scard(void) +{ + return eam_impl_get_mux_scard(eam_inst); +} + +static void eam_io_set_mux_scard(bool mux_scard) +{ + eam_impl_set_mux_scard(eam_inst, mux_scard); +} + static bool eam_io_get_autogen(void) { return eam_impl_get_autogen(eam_inst); @@ -192,14 +239,19 @@ static void eam_io_set_autogen(bool autogen) eam_impl_set_autogen(eam_inst, autogen); } -static bool eam_io_get_alt_10k(void) +static bool eam_io_do_keypads_conflict(void) +{ + return eam_impl_do_keypads_conflict(eam_inst); +} + +static bool eam_io_get_alt_10k(uint8_t unit_no) { - return eam_impl_get_alt_10k(eam_inst); + return eam_impl_get_alt_10k(eam_inst, unit_no); } -static void eam_io_set_alt_10k(bool alt_10k) +static void eam_io_set_alt_10k(uint8_t unit_no, bool alt_10k) { - eam_impl_set_alt_10k(eam_inst, alt_10k); + eam_impl_set_alt_10k(eam_inst, unit_no, alt_10k); } static struct hid_stub *eam_io_get_keypad_device(uint8_t unit_no) @@ -229,16 +281,28 @@ uint16_t eam_io_get_keypad_state(uint8_t unit_no) uint8_t eam_io_get_sensor_state(uint8_t unit_no) { - if (eam_impl_get_sensor_state(eam_inst, unit_no)) { + bool has_card; + + if (eam_io_get_scard()) { + has_card = eam_scard_is_present(unit_no); + } else { + has_card = eam_impl_get_sensor_state(eam_inst, unit_no); + } + + if (has_card) { return (1 << EAM_IO_SENSOR_FRONT) | (1 << EAM_IO_SENSOR_BACK); } else { return 0x00; - } + } } uint8_t eam_io_read_card(uint8_t unit_no, uint8_t *card_id, uint8_t nbytes) { - return eam_impl_read_card(eam_inst, unit_no, card_id, nbytes); + if (eam_io_get_scard()) { + return eam_scard_read(unit_no, card_id, nbytes); + } else { + return eam_impl_read_card(eam_inst, unit_no, card_id, nbytes); + } } bool eam_io_card_slot_cmd(uint8_t unit_no, uint8_t cmd) @@ -249,11 +313,14 @@ bool eam_io_card_slot_cmd(uint8_t unit_no, uint8_t cmd) bool eam_io_poll(uint8_t unit_no) { - // ignored + if (eam_io_get_scard()) { + eam_scard_poll(unit_no); + } + return true; } -BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *ctx) +BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *scard) { if (reason == DLL_PROCESS_ATTACH) { eam_hinst = hinst; diff --git a/src/main/eamio/eam-config.h b/src/main/eamio/eam-config.h index ebf4812c..97c882f2 100644 --- a/src/main/eamio/eam-config.h +++ b/src/main/eamio/eam-config.h @@ -7,12 +7,21 @@ struct eam_io_config_api { void (*config_save)(void); bool (*get_autogen)(void); void (*set_autogen)(bool autogen); - bool (*get_alt_10k)(void); - void (*set_alt_10k)(bool alt_10k); + bool (*get_alt_10k)(uint8_t unit_no); + void (*set_alt_10k)(uint8_t unit_no, bool alt_10k); struct hid_stub *(*get_keypad_device)(uint8_t unit_no); void (*set_keypad_device)(uint8_t unit_no, struct hid_stub *hid); const char *(*get_card_path)(uint8_t unit_no); void (*set_card_path)(uint8_t unit_no, const char *path); + bool (*get_scard)(void); + void (*set_scard)(bool scard); + bool (*get_mux_keypad)(void); + void (*set_mux_keypad)(bool mux_keypad); + bool (*get_mux_scard)(void); + void (*set_mux_scard)(bool mux_scard); + + bool (*do_keypads_conflict)(void); + LPSTR (*get_scard_reader_name)(uint8_t unit_no); }; #endif diff --git a/src/main/eamio/eam-impl.c b/src/main/eamio/eam-impl.c index 0c417094..d123e80a 100644 --- a/src/main/eamio/eam-impl.c +++ b/src/main/eamio/eam-impl.c @@ -10,8 +10,10 @@ #include "bemanitools/eamio.h" #include "eamio/eam-impl.h" +#include "eamio/eam-scard.h" #include "geninput/hid-mgr.h" +#include "geninput/kbd-naive.h" #include "util/defs.h" #include "util/fs.h" @@ -31,6 +33,7 @@ struct eam_unit { uint8_t drive_no; uint32_t sensor_time; bool sensor_hot; + bool alt_10k; }; struct eam { @@ -41,8 +44,9 @@ struct eam { CRITICAL_SECTION lock; struct eam_unit units[EAM_UNIT_COUNT]; bool autogen; - bool alt_10k; - bool mux; + bool scard; + bool mux_keypad; + bool mux_scard; }; static const uint32_t eam_keypad_usages[EAM_IO_KEYPAD_COUNT + 1] = { @@ -76,7 +80,7 @@ static const uint32_t eam_keypad_usages_alt[EAM_IO_KEYPAD_COUNT + 1] = { /* Sensor = */ 0x0007002A /* Backspace */ }; -static uint8_t eam_impl_get_active_unit(void); +static bool eam_impl_is_active_unit(struct eam *eam, uint8_t unit_no); static void eam_impl_bind_keypad(struct eam *eam, uint8_t unit_no); static bool eam_impl_autogen(struct eam_unit *unit, uint8_t *card_id); @@ -96,6 +100,7 @@ struct eam *eam_impl_create(void) unit->card_path = NULL; unit->hid = NULL; + unit->alt_10k = false; for (btn_no = 0; btn_no < lengthof(unit->keypad_ctls); btn_no++) { unit->keypad_ctls[btn_no] = (size_t) -1; @@ -108,15 +113,62 @@ struct eam *eam_impl_create(void) } eam->autogen = false; - eam->alt_10k = false; - eam->mux = false; + eam->scard = false; + eam->mux_keypad = false; + eam->mux_scard = false; return eam; } -static uint8_t eam_impl_get_active_unit(void) +static bool eam_impl_is_active_unit(struct eam *eam, uint8_t unit_no) +{ + log_assert(lengthof(eam->units) == 2); + + if (eam->mux_keypad && eam_impl_do_keypads_conflict(eam)) { + // Determine active unit by numlock state + return (GetKeyState(VK_NUMLOCK) & 0x0001) == unit_no; + } else { + return true; + } +} + +bool eam_impl_get_scard(struct eam *eam) +{ + return eam->scard; +} +void eam_impl_set_scard(struct eam *eam, bool scard) +{ + eam->scard = scard != false; + + if (eam->scard) { + eam_scard_init(eam->mux_scard); + } else { + eam_scard_fini(); + } +} + +bool eam_impl_get_mux_keypad(struct eam *eam) +{ + return eam->mux_keypad; +} +void eam_impl_set_mux_keypad(struct eam *eam, bool mux_keypad) +{ + eam->mux_keypad = mux_keypad != false; +} + +bool eam_impl_get_mux_scard(struct eam *eam) +{ + return eam->mux_scard; +} +void eam_impl_set_mux_scard(struct eam *eam, bool mux_scard) { - return GetKeyState(VK_NUMLOCK) & 0x0001; + eam->mux_scard = mux_scard != false; + + if (eam->scard) { + // reinit so we can remap the readers + eam_scard_fini(); + eam_scard_init(eam->mux_scard); + } } bool eam_impl_get_autogen(struct eam *eam) @@ -129,20 +181,40 @@ void eam_impl_set_autogen(struct eam *eam, bool autogen) eam->autogen = autogen != false; } -bool eam_impl_get_alt_10k(struct eam *eam) +bool eam_impl_do_keypads_conflict(struct eam *eam) { - return eam->alt_10k; + log_assert(lengthof(eam->units) == 2); + + // 1. To conflict, both must have an assigned hid device + if (eam->units[0].hid == NULL || eam->units[1].hid == NULL) { + return false; + } + + // 2. To conflict, both must use the same keys (i.e. numpad vs top row) + if (eam->units[0].alt_10k != eam->units[1].alt_10k) { + // keypads are not using the same keys. mux not necessary + return false; + } + + // 3. To conflict, the hids must be the same or either be the naive kbd + return (eam->units[0].hid == eam->units[1].hid || + kbd_is_naive(eam->units[0].hid) || + kbd_is_naive(eam->units[1].hid)); } -void eam_impl_set_alt_10k(struct eam *eam, bool alt_10k) +bool eam_impl_get_alt_10k(struct eam *eam, uint8_t unit_no) { - int i; + log_assert(unit_no < lengthof(eam->units)); - for (i = 0; i < lengthof(eam->units); i++) { - eam->units[i].bound_ctls = false; - } + return eam->units[unit_no].alt_10k; +} - eam->alt_10k = alt_10k != false; +void eam_impl_set_alt_10k(struct eam *eam, uint8_t unit_no, bool alt_10k) +{ + log_assert(unit_no < lengthof(eam->units)); + + eam->units[unit_no].bound_ctls = false; + eam->units[unit_no].alt_10k = alt_10k != false; } struct hid_stub *eam_impl_get_keypad_device(struct eam *eam, uint8_t unit_no) @@ -159,8 +231,6 @@ void eam_impl_set_keypad_device( eam->units[unit_no].hid = hid; eam->units[unit_no].bound_ctls = false; - - eam->mux = hid != NULL && eam->units[0].hid == eam->units[1].hid; } const char *eam_impl_get_card_path(struct eam *eam, uint8_t unit_no) @@ -203,7 +273,7 @@ uint16_t eam_impl_get_keypad_state(struct eam *eam, uint8_t unit_no) log_assert(unit_no < lengthof(eam->units)); - if (eam->mux && eam_impl_get_active_unit() != unit_no) { + if (!eam_impl_is_active_unit(eam, unit_no)) { return 0; } @@ -247,7 +317,7 @@ static void eam_impl_bind_keypad(struct eam *eam, uint8_t unit_no) return; } - if (eam->alt_10k) { + if (eam->units[unit_no].alt_10k) { usages = eam_keypad_usages_alt; } else { usages = eam_keypad_usages; @@ -327,7 +397,7 @@ bool eam_impl_get_sensor_state(struct eam *eam, uint8_t unit_no) /* Bump cooldown as long as sensor button is held (cooldown timer might also be set by a USB hotplug event) */ - if (value != 0 && (!eam->mux || eam_impl_get_active_unit() == unit_no)) { + if (value != 0 && eam_impl_is_active_unit(eam, unit_no)) { unit->sensor_time = now + EAM_SENSOR_COOLDOWN; unit->sensor_hot = true; } diff --git a/src/main/eamio/eam-impl.h b/src/main/eamio/eam-impl.h index 486314d7..b77921d6 100644 --- a/src/main/eamio/eam-impl.h +++ b/src/main/eamio/eam-impl.h @@ -15,10 +15,17 @@ struct eam; struct eam *eam_impl_create(void); +bool eam_impl_get_scard(struct eam *eam); +void eam_impl_set_scard(struct eam *eam, bool scard); +bool eam_impl_get_mux_keypad(struct eam *eam); +void eam_impl_set_mux_keypad(struct eam *eam, bool mux_keypad); +bool eam_impl_get_mux_scard(struct eam *eam); +void eam_impl_set_mux_scard(struct eam *eam, bool mux_scard); bool eam_impl_get_autogen(struct eam *eam); void eam_impl_set_autogen(struct eam *eam, bool autogen); -bool eam_impl_get_alt_10k(struct eam *eam); -void eam_impl_set_alt_10k(struct eam *eam, bool alt_10k); +bool eam_impl_do_keypads_conflict(struct eam *eam); +bool eam_impl_get_alt_10k(struct eam *eam, uint8_t unit_no); +void eam_impl_set_alt_10k(struct eam *eam, uint8_t unit_no, bool alt_10k); struct hid_stub *eam_impl_get_keypad_device(struct eam *eam, uint8_t unit_no); void eam_impl_set_keypad_device( struct eam *eam, uint8_t unit_no, struct hid_stub *hid); diff --git a/src/main/eamio/eam-s11n.c b/src/main/eamio/eam-s11n.c index fd20e70e..243cad47 100644 --- a/src/main/eamio/eam-s11n.c +++ b/src/main/eamio/eam-s11n.c @@ -5,6 +5,7 @@ #include "eamio/eam-s11n.h" #include "util/fs.h" +#include "util/log.h" struct eam *eam_impl_config_load(FILE *f) { @@ -16,6 +17,9 @@ struct eam *eam_impl_config_load(FILE *f) char *dev_node; bool autogen; bool alt_10k; + bool scard; + bool mux_keypad; + bool mux_scard; bool has_card_path; bool has_hid; @@ -25,12 +29,22 @@ struct eam *eam_impl_config_load(FILE *f) goto early_fail; } - if (!read_u8(f, &alt_10k)) { + if (!read_u8(f, &scard)) { + goto early_fail; + } + + if (!read_u8(f, &mux_keypad)) { + goto early_fail; + } + + if (!read_u8(f, &mux_scard)) { goto early_fail; } eam_impl_set_autogen(eam, autogen); - eam_impl_set_alt_10k(eam, alt_10k); + eam_impl_set_mux_keypad(eam, mux_keypad); + eam_impl_set_mux_scard(eam, mux_scard); + eam_impl_set_scard(eam, scard); if (!read_u8(f, &nunits) || nunits != EAM_UNIT_COUNT) { goto early_fail; @@ -47,6 +61,11 @@ struct eam *eam_impl_config_load(FILE *f) goto late_fail; } + if (!read_u8(f, &alt_10k)) { + goto late_fail; + } + eam_impl_set_alt_10k(eam, unit_no, alt_10k); + if (has_card_path) { if (!read_str(f, &card_path)) { goto late_fail; @@ -89,26 +108,36 @@ void eam_impl_config_save(struct eam *eam, FILE *f) uint8_t unit_no; bool autogen; bool alt_10k; + bool scard; + bool mux_keypad; + bool mux_scard; bool has_card_path; bool has_hid; autogen = eam_impl_get_autogen(eam); - alt_10k = eam_impl_get_alt_10k(eam); + scard = eam_impl_get_scard(eam); + mux_keypad = eam_impl_get_mux_keypad(eam); + mux_scard = eam_impl_get_mux_scard(eam); + nunits = EAM_UNIT_COUNT; write_u8(f, &autogen); - write_u8(f, &alt_10k); + write_u8(f, &scard); + write_u8(f, &mux_keypad); + write_u8(f, &mux_scard); write_u8(f, &nunits); for (unit_no = 0; unit_no < EAM_UNIT_COUNT; unit_no++) { card_path = eam_impl_get_card_path(eam, unit_no); hid = eam_impl_get_keypad_device(eam, unit_no); + alt_10k = eam_impl_get_alt_10k(eam, unit_no); has_card_path = card_path != NULL; has_hid = hid != NULL; write_u8(f, &has_card_path); write_u8(f, &has_hid); + write_u8(f, &alt_10k); if (has_card_path) { write_str(f, card_path); diff --git a/src/main/eamio/eam-scard.c b/src/main/eamio/eam-scard.c new file mode 100644 index 00000000..2a19a8b5 --- /dev/null +++ b/src/main/eamio/eam-scard.c @@ -0,0 +1,319 @@ +#include "eam-scard.h" +#include + +#include "util/log.h" + +struct scard { + SCARDCONTEXT hContext; + LPSTR mszReaders; + DWORD pcchReaders; + LPSTR reader_name[EAM_UNIT_COUNT]; + SCARD_READERSTATE rs[EAM_UNIT_COUNT]; + bool mux_reader; +}; + +static struct scard *scard = NULL; + +#define MAX_APDU_SIZE 255 +#define PICC_OPERATING_PARAMS 0xDFu +BYTE PICC_OPERATING_PARAM_CMD[5] = {0xFFu, 0x00u, 0x51u, PICC_OPERATING_PARAMS, 0x00u}; +#define PICC_SUCCESS 0x90u +static const BYTE UID_CMD[5] = {0xFFu, 0xCAu, 0x00u, 0x00u, 0x00u}; +enum scard_atr_protocol { + SCARD_ATR_PROTOCOL_ISO14443_PART3 = 0x03, + SCARD_ATR_PROTOCOL_ISO15693_PART3 = 0x0B, + SCARD_ATR_PROTOCOL_FELICA_212K = 0x11, + SCARD_ATR_PROTOCOL_FELICA_424K = 0x12, +}; + +void eam_scard_init(bool mux_reader) +{ + int curReaderIdx = 0; + LONG ret; + bool success = false; + + if (scard != NULL) { + // already init + return; + } + + // Alloc and init the instance struct + scard = (struct scard *) malloc(sizeof(struct scard)); + if (scard == NULL) { + goto end; + } + memset(scard, 0, sizeof(struct scard)); + scard->mux_reader = mux_reader; + + // Assign readers to each eam unit + ret = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &scard->hContext); + if (ret != SCARD_S_SUCCESS) { + log_warning("SCardEstablishContext failed: %08lX", (ULONG) ret); + goto end; + } + + scard->pcchReaders = SCARD_AUTOALLOCATE; + + ret = SCardListReaders( + scard->hContext, NULL, (LPSTR) &scard->mszReaders, &scard->pcchReaders); + if (ret != SCARD_S_SUCCESS) { + log_warning("SCardListReaders failed: %08lX", (ULONG) ret); + goto end; + } + + // Find up to EAM_UNIT_COUNT readers + for (LPSTR reader = scard->mszReaders; *reader != '\0'; + reader = reader + lstrlen(reader) + 1) { + + // assign the reader + scard->reader_name[curReaderIdx] = reader; + + // are we done? + curReaderIdx++; + if (curReaderIdx == EAM_UNIT_COUNT || mux_reader) { + // all readers assigned (or we are only going to use one) + break; + } + } + + // report results and initialize states + for (int i = 0; i < EAM_UNIT_COUNT; i++) { + // if we are muxing, assign the first reader to every unit + if (mux_reader) { + scard->reader_name[i] = scard->reader_name[0]; + } + + if (scard->reader_name[i] != NULL) { + log_info("unit_no %d scard reader: %s", i, scard->reader_name[i]); + } else { + log_warning("Failed to find reader for unit_no %d", i); + } + + scard->rs[i].szReader = scard->reader_name[i]; + scard->rs[i].dwCurrentState = SCARD_STATE_UNAWARE; + } + + success = true; + +end: + if (!success) { + log_warning("Smartcard Reader init failed"); + eam_scard_fini(); + } +} + +void eam_scard_fini() +{ + if (scard != NULL) { + if (scard->mszReaders != NULL) { + SCardFreeMemory(scard->hContext, scard->mszReaders); + } + + SCardReleaseContext(scard->hContext); + + free(scard); + scard = NULL; + } +} + +bool eam_scard_is_present(uint8_t unit_no) +{ + bool is_active; + + if (scard == NULL) { + return false; + } + + log_assert(unit_no < lengthof(scard->rs)); + + if (scard->mux_reader) { + // Determine active reader by numlock state + is_active = (GetKeyState(VK_NUMLOCK) & 0x0001) == unit_no; + } else { + is_active = true; + } + + if (is_active) { + return (scard->rs[unit_no].dwEventState & SCARD_STATE_PRESENT) != 0; + } else { + return false; + } +} + +uint8_t eam_scard_read(uint8_t unit_no, uint8_t *card_id, uint8_t nbytes) +{ + uint8_t card_type = EAM_IO_CARD_NONE; + + if (scard == NULL) { + return card_type; + } + + log_assert(unit_no < lengthof(scard->rs)); + log_assert(card_id != NULL); + log_assert(nbytes == EAM_CARD_NBYTES); + + /** + * This function was lifted from scard.cpp in spice2x where its called + * scard_update(), then modified for use in the eam io api. Changes in + * support of BT5 coding standards were not made to minimize changes to + * the original code. Error handling was however added so as to + * disconnect from the card reader. + * + * @note The logic for the UID fix option in spice is not present + */ + + // Connect to the smart card. + LONG lRet = 0; + SCARDHANDLE hCard; + DWORD dwActiveProtocol; + + lRet = SCardConnect(scard->hContext, scard->rs[unit_no].szReader, SCARD_SHARE_EXCLUSIVE, + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); + + if (lRet != SCARD_S_SUCCESS) { + log_warning("error connecting to the card: %ld", lRet); + return card_type; + } + + // set the reader params + lRet = 0; + const SCARD_IO_REQUEST *pci = dwActiveProtocol == SCARD_PROTOCOL_T1 ? SCARD_PCI_T1 : SCARD_PCI_T0; + DWORD cbRecv = MAX_APDU_SIZE; + BYTE pbRecv[MAX_APDU_SIZE]; + if ((lRet = SCardTransmit(hCard, pci, PICC_OPERATING_PARAM_CMD, sizeof(PICC_OPERATING_PARAM_CMD), + NULL, pbRecv, &cbRecv)) != SCARD_S_SUCCESS) { + log_warning("error setting PICC params: %ld", lRet); + goto End; + } + + if (cbRecv > 2 && pbRecv[0] != PICC_SUCCESS && pbRecv[1] != PICC_OPERATING_PARAMS) { + log_warning("PICC params not valid 0x%02X != 0x%02X", + pbRecv[1], PICC_OPERATING_PARAMS); + goto End; + } + + // Read ATR to determine card type. + TCHAR szReader[200]; + DWORD cchReader = 200; + BYTE atr[32]; + DWORD cByteAtr = 32; + lRet = SCardStatus(hCard, szReader, &cchReader, NULL, NULL, atr, &cByteAtr); + if (lRet != SCARD_S_SUCCESS) { + log_warning("error getting card status: %ld",lRet); + goto End; + } + + // Only care about 20-byte ATRs returned by arcade-type smart cards + if (cByteAtr != 20) { + log_warning("ignoring card with len(atr) = %ld", cByteAtr); + goto End; + } + + // Figure out if we should reverse the UID returned by the card based on the + // ATR protocol + BYTE cardProtocol = atr[12]; + BOOL shouldReverseUid = false; + if (cardProtocol == SCARD_ATR_PROTOCOL_ISO15693_PART3) { + log_info("card protocol: ISO15693_PART3"); + shouldReverseUid = true; + } else if (cardProtocol == SCARD_ATR_PROTOCOL_ISO14443_PART3) { + log_info("card protocol: ISO14443_PART3"); + } else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_212K) { + log_info("card protocol: FELICA_212K"); + } else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_424K) { + log_info("card protocol: FELICA_424K"); + } else { + log_warning("Unknown NFC Protocol: 0x%02X", cardProtocol); + //return; + } + + // Read UID + cbRecv = MAX_APDU_SIZE; + if ((lRet = SCardTransmit(hCard, pci, UID_CMD, sizeof(UID_CMD), NULL, pbRecv, &cbRecv)) != SCARD_S_SUCCESS) { + log_warning("error querying card UID: %ld", lRet); + goto End; + } + + // check response + // 2 bytes minimum for response code + // 3+ bytes for response code plus one byte card number + if (cbRecv < 3) { + if (cbRecv < 2) { + log_warning("UID query failed - not enough bytes (%ld)", cbRecv); + } else { + log_warning("UID query failed - received {0x%02X} {0x%02X} (%ld bytes)", pbRecv[0], pbRecv[1], cbRecv); + } + goto End; + } + + if (cbRecv < 8) { + log_misc("padding card uid to 8 bytes by adding zeroes at the end"); + memset(&pbRecv[cbRecv], 0, 8 - cbRecv); + } else if (cbRecv > 8) { + log_misc("taking first 8 bytes of len(uid) = %ld", cbRecv); + } + + // Copy UID to struct, reversing if necessary + if (shouldReverseUid) { + for (DWORD i = 0; i < 8; i++) { + card_id[i] = pbRecv[7 - i]; + } + } else { + memcpy(card_id, pbRecv, 8); + } + + log_info( + "reader unit no: %d, card number to be inserted into game: " + "%02X%02X %02X%02X %02X%02X %02X%02X", + unit_no, + card_id[0], + card_id[1], + card_id[2], + card_id[3], + card_id[4], + card_id[5], + card_id[6], + card_id[7]); + + if (card_id[0] == 0xe0 && card_id[1] == 0x04) { + card_type = EAM_IO_CARD_ISO15696; + } else { + card_type = EAM_IO_CARD_FELICA; + } + +End: + SCardDisconnect(hCard, SCARD_LEAVE_CARD); + + return card_type; +} + +void eam_scard_poll(uint8_t unit_no) +{ + SCARD_READERSTATE *rs; + + if (scard != NULL) { + log_assert(unit_no < lengthof(scard->rs)); + + rs = &scard->rs[unit_no]; + + if (rs->szReader == NULL) { + // no reader present for this unit + return; + } + + SCardGetStatusChange(scard->hContext, 0, rs, 1); + } +} + +LPSTR eam_scard_get_reader_name(uint8_t unit_no) +{ + if (scard != NULL) { + log_assert(unit_no < lengthof(scard->rs)); + + if (scard->rs[unit_no].szReader != NULL) { + return scard->reader_name[unit_no]; + } + } + + return "Not Present"; +} \ No newline at end of file diff --git a/src/main/eamio/eam-scard.h b/src/main/eamio/eam-scard.h new file mode 100644 index 00000000..0f713772 --- /dev/null +++ b/src/main/eamio/eam-scard.h @@ -0,0 +1,39 @@ +/** + * Smartcard reader support for eamio + */ +#ifndef EAMIO_SCARD_H +#define EAMIO_SCARD_H + +#include +#include +#include +#include +#include + +#include "eam-impl.h" + +void eam_scard_init(bool mux_reader); +void eam_scard_fini(void); + +/** + * Indicates if a card is currently present on the reader + */ +bool eam_scard_is_present(uint8_t unit_no); + +/** + * Read a present card into card_id buffer + */ +uint8_t eam_scard_read(uint8_t unit_no, uint8_t *card_id, uint8_t nbytes); + +/** + * Poll smartcard reader state + */ +void eam_scard_poll(uint8_t unit_no); + +/** + * Return the name of the reader or "Not Present" if no reader is bound to the + * unit. Intended for use in the config ui. + */ +LPSTR eam_scard_get_reader_name(uint8_t unit_no); + +#endif \ No newline at end of file diff --git a/src/main/geninput/Module.mk b/src/main/geninput/Module.mk index 1521d806..dc2afe7c 100644 --- a/src/main/geninput/Module.mk +++ b/src/main/geninput/Module.mk @@ -23,6 +23,7 @@ src_geninput := \ io-thread.c \ kbd.c \ kbd-data.c \ + kbd-naive.c \ mapper.c \ mapper-s11n.c \ mouse.c \ diff --git a/src/main/geninput/geninput.def b/src/main/geninput/geninput.def index 6ef4cf3e..650e93fe 100644 --- a/src/main/geninput/geninput.def +++ b/src/main/geninput/geninput.def @@ -28,6 +28,7 @@ EXPORTS light_iter_is_valid light_iter_next light_iter_free + kbd_is_naive mapper_config_load mapper_config_save mapper_clear_action_map diff --git a/src/main/geninput/kbd-naive.c b/src/main/geninput/kbd-naive.c new file mode 100644 index 00000000..b3d58674 --- /dev/null +++ b/src/main/geninput/kbd-naive.c @@ -0,0 +1,36 @@ +#include + +#include "geninput/hid.h" +#include "geninput/kbd-naive.h" +#include "geninput/kbd.h" + +static struct hid_stub *kbd_naive_stub = NULL; +static struct hid_ri *kbd_naive_hid_ri = NULL; + +static const char *kbd_naive_dev_node = "kbd-naive"; +static const wchar_t *kbd_naive_dev_name = L"Any (naive binding)"; + +void kbd_naive_init(void) +{ + kbd_naive_stub = hid_mgr_get_named_stub(kbd_naive_dev_node); + + kbd_create(&kbd_naive_hid_ri, kbd_naive_dev_node, kbd_naive_dev_name); + + hid_stub_attach(kbd_naive_stub, (struct hid *) kbd_naive_hid_ri); +} + +void kbd_naive_fini(void) +{ + free(kbd_naive_stub); + kbd_naive_stub = NULL; +} + +void kbd_naive_event_notify(RAWINPUT *ri) +{ + hid_ri_handle_event(kbd_naive_hid_ri, ri); +} + +bool kbd_is_naive(struct hid_stub *stub) +{ + return (stub == kbd_naive_stub); +} \ No newline at end of file diff --git a/src/main/geninput/kbd-naive.h b/src/main/geninput/kbd-naive.h new file mode 100644 index 00000000..6972291b --- /dev/null +++ b/src/main/geninput/kbd-naive.h @@ -0,0 +1,13 @@ +#ifndef GENINPUT_KBD_NAIVE_H +#define GENINPUT_KBD_NAIVE_H + +#include + +#include "geninput/hid-mgr.h" + +void kbd_naive_init(void); +void kbd_naive_fini(void); +void kbd_naive_event_notify(RAWINPUT *ri); +bool kbd_is_naive(struct hid_stub *stub); + +#endif diff --git a/src/main/geninput/kbd.c b/src/main/geninput/kbd.c index 9ae8e5ed..51233bd4 100644 --- a/src/main/geninput/kbd.c +++ b/src/main/geninput/kbd.c @@ -89,7 +89,8 @@ static void kbd_static_init(void) } } -void kbd_create(struct hid_ri **hid_ri, const char *dev_node) +void kbd_create( + struct hid_ri **hid_ri, const char *dev_node, const wchar_t *name_override) { struct kbd *kbd; char *tmp; @@ -98,7 +99,11 @@ void kbd_create(struct hid_ri **hid_ri, const char *dev_node) kbd = xcalloc(sizeof(*kbd)); kbd->super.vptr = &kbd_vtbl; - kbd->name = hid_ri_init_name(&kbd_guid, dev_node); + if (name_override) { + kbd->name = wstr_dup(name_override); + } else { + kbd->name = hid_ri_init_name(&kbd_guid, dev_node); + } *hid_ri = &kbd->super; diff --git a/src/main/geninput/kbd.h b/src/main/geninput/kbd.h index f54f26d9..559c922b 100644 --- a/src/main/geninput/kbd.h +++ b/src/main/geninput/kbd.h @@ -6,6 +6,13 @@ #define KBD_DEVICE_USAGE_KEYBOARD 0x00010006 #define KBD_DEVICE_USAGE_KEYPAD 0x00010007 -void kbd_create(struct hid_ri **hid_ri, const char *dev_node); +/** + * Creates a keyboard device for use with key bindings + * + * @note name_override can be NULL and is only intended to be populated when + * the desired device name is not the name as indicated by the dev_node + */ +void kbd_create( + struct hid_ri **hid_ri, const char *dev_node, const wchar_t *name_override); #endif diff --git a/src/main/geninput/ri.c b/src/main/geninput/ri.c index b3befee9..ae798cf0 100644 --- a/src/main/geninput/ri.c +++ b/src/main/geninput/ri.c @@ -3,6 +3,7 @@ #include "geninput/hid-mgr.h" #include "geninput/hid.h" #include "geninput/kbd.h" +#include "geninput/kbd-naive.h" #include "geninput/mouse.h" #include "geninput/ri.h" @@ -45,6 +46,11 @@ void ri_init(HWND hwnd) (unsigned int) GetLastError()); } + /* Init the naive keyboard before scanning for devices. This allows the + * actual hid devices to be preferred when using the bind dialog in the + * config ui */ + kbd_naive_init(); + ri_scan_devices(); } @@ -104,7 +110,7 @@ void ri_scan_devices(void) if (ridl[i].dwType == RIM_TYPEKEYBOARD) { ri_handles[i].fake_fd = ridl[i].hDevice; - kbd_create(&ri_handles[i].hid_ri, dev_node); + kbd_create(&ri_handles[i].hid_ri, dev_node, NULL); hid_stub_attach(stub, (struct hid *) ri_handles[i].hid_ri); } else if (ridl[i].dwType == RIM_TYPEMOUSE) { @@ -139,6 +145,13 @@ void ri_handle_msg(HRAWINPUT msg) return; } + /* Perform naive kdb updates prior to checking device. If the inputs were + generated by another program instead of from an actual hid device, we + don't want to miss them due to the hDevice check below. */ + if (ri.header.dwType == RIM_TYPEKEYBOARD) { + kbd_naive_event_notify(&ri); + } + if (ri.header.hDevice == NULL) { /* WTF?? I've seen this happen while remote-controlling someone's desktop using TeamViewer, possibly due to an API hook injected by TV @@ -161,6 +174,8 @@ void ri_fini(void) { RAWINPUTDEVICE filter[3]; + kbd_naive_fini(); + free(ri_handles); ri_handles = NULL; ri_ndevs = 0;