1
0
mirror of https://github.com/libretro/RetroArch synced 2025-02-24 09:40:07 +00:00

In Android builds, add input_android_physical_keyboard configuration option and its corresponding menu entry to force a device to act as a physical keyboard.

When running on Android, RetroArch considers most devices that emit dpad events as gamepads, even if they also emit other keyboard events; this is usually the right thing to do, but it has the side effect of not letting some actual keyboards (e.g.: Logitech K480) act as such inside RetroArch. This configuration option allows users to manually select a specific input device to act as a physical keyboard instead of a gamepad, which is handy when emulating computers as opposed to consoles.
This commit is contained in:
Gonzalo Peche 2023-01-03 23:27:43 +01:00 committed by LibretroAdmin
parent 860ffb2b6a
commit 9efc1f500d
16 changed files with 490 additions and 9 deletions

@ -1430,6 +1430,9 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
SETTING_ARRAY("input_driver", settings->arrays.input_driver, false, NULL, true);
SETTING_ARRAY("input_joypad_driver", settings->arrays.input_joypad_driver, false, NULL, true);
SETTING_ARRAY("input_keyboard_layout", settings->arrays.input_keyboard_layout, false, NULL, true);
#ifdef ANDROID
SETTING_ARRAY("input_android_physical_keyboard", settings->arrays.input_android_physical_keyboard, false, NULL, true);
#endif
SETTING_ARRAY("led_driver", settings->arrays.led_driver, false, NULL, true);
SETTING_ARRAY("netplay_mitm_server", settings->arrays.netplay_mitm_server, false, NULL, true);
SETTING_ARRAY("midi_driver", settings->arrays.midi_driver, false, NULL, true);

@ -434,6 +434,10 @@ typedef struct settings
char input_keyboard_layout[64];
#ifdef ANDROID
char input_android_physical_keyboard[255];
#endif
char audio_device[255];
char camera_device[255];
char netplay_mitm_server[255];

@ -95,15 +95,6 @@ uint8_t *android_keyboard_state_get(unsigned port)
return android_key_state[port];
}
static void android_keyboard_free(void)
{
unsigned i, j;
for (i = 0; i < DEFAULT_MAX_PADS; i++)
for (j = 0; j < MAX_KEYS; j++)
android_key_state[i][j] = 0;
}
/* TODO/FIXME -
* fix game focus toggle */
@ -192,6 +183,20 @@ static typeof(AMotionEvent_getButtonState) *p_AMotionEvent_getButtonState;
static void *libandroid_handle;
#endif
static void android_keyboard_free(void)
{
unsigned i, j;
for (i = 0; i < DEFAULT_MAX_PADS; i++)
for (j = 0; j < MAX_KEYS; j++)
android_key_state[i][j] = 0;
for (i = 0; i < (unsigned) kbd_num; i++)
kbd_id[i] = -1;
kbd_num = 0;
}
static bool android_input_lookup_name_prekitkat(char *buf,
int *vendorId, int *productId, size_t size, int id)
{
@ -297,6 +302,59 @@ static bool android_input_lookup_name(char *buf,
return true;
}
static bool android_input_can_be_keyboard_jni(int id)
{
jmethodID getKeyboardType = NULL;
jobject device = NULL;
jint keyboard_type = -1;
jmethodID method = NULL;
jclass class = NULL;
const char *str = NULL;
JNIEnv *env = (JNIEnv*)jni_thread_getenv();
if (!env)
return false;
FIND_CLASS(env, class, "android/view/InputDevice");
if (!class)
return false;
GET_STATIC_METHOD_ID(env, method, class, "getDevice",
"(I)Landroid/view/InputDevice;");
if (!method)
return false;
CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id);
if (!device)
return false;
GET_METHOD_ID(env, getKeyboardType, class, "getKeyboardType", "()I");
if (!getKeyboardType)
return false;
CALL_INT_METHOD(env, keyboard_type, device, getKeyboardType);
if (keyboard_type < 0)
return false;
return keyboard_type == AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
bool android_input_can_be_keyboard(void *data, int port)
{
android_input_t *android = (android_input_t *) data;
if (!android)
return false;
if (port < 0 || port >= android->pads_connected)
return false;
state_device_t *device = &android->pad_states[port];
if (!device->id && string_is_empty(device->name))
return false;
return android_input_can_be_keyboard_jni(device->id);
}
static void android_input_poll_main_cmd(void)
{
int8_t cmd;
@ -867,6 +925,55 @@ static int android_input_recover_port(android_input_t *android, int id)
}
static bool is_configured_as_physical_keyboard(int vendor_id, int product_id, const char *device_name)
{
settings_t *settings = config_get_ptr();
char keyboard_name[sizeof(settings->arrays.input_android_physical_keyboard)];
int keyboard_vendor_id;
int keyboard_product_id;
bool is_keyboard;
bool compare_by_id;
if (sscanf(settings->arrays.input_android_physical_keyboard, "%04x:%04x ", &keyboard_vendor_id, &keyboard_product_id) != 2)
{
strlcpy(keyboard_name, settings->arrays.input_android_physical_keyboard, sizeof(keyboard_name));
is_keyboard = string_is_equal(device_name, keyboard_name);
compare_by_id = false;
}
else
{
is_keyboard = vendor_id == keyboard_vendor_id && product_id == keyboard_product_id;
compare_by_id = true;
}
if (is_keyboard)
{
/*
* Check that there is not already a similar physical keyboard attached
* attached to the system
*/
for (int i = 0; i < kbd_num; i++)
{
char kbd_device_name[256] = { 0 };
int kbd_vendor_id = 0;
int kbd_product_id = 0;
if (!engine_lookup_name(kbd_device_name, &kbd_vendor_id,
&kbd_product_id, sizeof(kbd_device_name), kbd_id[i]))
return false;
if (compare_by_id && vendor_id == kbd_vendor_id && product_id == kbd_product_id)
return false;
if (!compare_by_id && string_is_equal(device_name, kbd_device_name))
return false;
}
return true;
}
return false;
}
static void handle_hotplug(android_input_t *android,
struct android_app *android_app, int *port, int id,
int source)
@ -1146,6 +1253,18 @@ static void handle_hotplug(android_input_t *android,
return;
}
/* If the device is a keyboard, didn't match any of the devices above
* and is designated as the physical keyboard, then assume it is a keyboard,
* register the id, and return unless the
* maximum number of keyboards are already registered. */
else if ((source & AINPUT_SOURCE_KEYBOARD) && kbd_num < MAX_NUM_KEYBOARDS &&
is_configured_as_physical_keyboard(vendorId, productId, device_name))
{
kbd_id[kbd_num] = id;
kbd_num++;
return;
}
/* if device was not keyboard only, yet did not match any of the devices
* then try to autoconfigure as gamepad based on device_name. */
else if (!string_is_empty(device_name))

@ -778,6 +778,12 @@ MSG_HASH(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE,
"deferred_dropdown_box_list_input_device_type"
)
#ifdef ANDROID
MSG_HASH(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD,
"deferred_dropdown_box_list_input_select_physical_keyboard"
)
#endif
MSG_HASH(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION,
"deferred_dropdown_box_list_input_description"
@ -1560,6 +1566,12 @@ MSG_HASH(
"input_nowinkey_enable"
)
#endif
#ifdef ANDROID
MSG_HASH(
MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD,
"input_android_physical_keyboard"
)
#endif
MSG_HASH(
MENU_ENUM_LABEL_INPUT_SENSORS_ENABLE,
"input_sensors_enable"
@ -1758,6 +1770,7 @@ MSG_HASH(
MENU_ENUM_LABEL_INPUT_SMALL_KEYBOARD_ENABLE,
"input_small_keyboard_enable"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_TOUCH_ENABLE,
"input_touch_enable"

@ -663,6 +663,18 @@ int msg_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len)
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_HELP_GAMEMODE_ENABLE), len);
break;
#endif
#ifdef ANDROID
case MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD:
snprintf(s, len,
"If RetroArch identifies a hardware keyboard as some kind of\n"
"gamepad, this setting can be used to force RetroArch to treat\n"
"the misidentified device as a keyboard.\n"
"This can be useful if you are trying to emulate a computer in some\n"
"Android TV device and also own a physical keyboard that can be\n"
"attached to the box.\n");
break;
#endif
default:
if (string_is_empty(s))
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len);

@ -2676,6 +2676,16 @@ MSG_HASH(
"Keep Win-key combinations inside the application."
)
#endif
#ifdef ANDROID
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_SELECT_PHYSICAL_KEYBOARD,
"Select physical keyboard"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_INPUT_SELECT_PHYSICAL_KEYBOARD,
"Use this device as a physical keyboard and not as a gamepad."
)
#endif
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_SENSORS_ENABLE,
"Auxiliary Sensor Input"

@ -644,6 +644,10 @@ GENERIC_DEFERRED_PUSH_GENERAL(deferred_push_dropdown_box_list_disk_index, PUSH_D
GENERIC_DEFERRED_PUSH_GENERAL(deferred_push_dropdown_box_list_input_device_type, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST_INPUT_DEVICE_TYPE)
GENERIC_DEFERRED_PUSH_GENERAL(deferred_push_dropdown_box_list_input_description, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST_INPUT_DESCRIPTION)
GENERIC_DEFERRED_PUSH_GENERAL(deferred_push_dropdown_box_list_input_description_kbd, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST_INPUT_DESCRIPTION_KBD)
#ifdef ANDROID
GENERIC_DEFERRED_PUSH_GENERAL(deferred_push_dropdown_box_list_input_select_physical_keyboard, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD)
#endif
#ifdef HAVE_NETWORKING
GENERIC_DEFERRED_PUSH_GENERAL(deferred_push_dropdown_box_list_netplay_mitm_server, PUSH_DEFAULT, DISPLAYLIST_DROPDOWN_LIST_NETPLAY_MITM_SERVER)
#endif
@ -681,6 +685,9 @@ static int menu_cbs_init_bind_deferred_push_compare_label(
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE, deferred_push_dropdown_box_list_input_device_type},
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION, deferred_push_dropdown_box_list_input_description},
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD, deferred_push_dropdown_box_list_input_description_kbd},
#ifdef ANDROID
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD, deferred_push_dropdown_box_list_input_select_physical_keyboard},
#endif
#ifdef HAVE_NETWORKING
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER, deferred_push_dropdown_box_list_netplay_mitm_server},
#endif

@ -301,6 +301,10 @@ static enum msg_hash_enums action_ok_dl_to_enum(unsigned lbl)
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION;
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD;
#ifdef ANDROID
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD;
#endif
#ifdef HAVE_NETWORKING
case ACTION_OK_DL_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER:
return MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER;
@ -796,6 +800,17 @@ int generic_action_ok_displaylist_push(const char *path,
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE;
dl_type = DISPLAYLIST_GENERIC;
break;
#ifdef ANDROID
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD:
info.type = type;
info.directory_ptr = idx;
info_path = path;
info_label = msg_hash_to_str(
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD);
info.enum_idx = MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD;
dl_type = DISPLAYLIST_GENERIC;
break;
#endif
case ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION:
info.type = type;
info.directory_ptr = idx;
@ -6779,6 +6794,63 @@ static int action_ok_push_dropdown_item_input_device_type(const char *path,
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#ifdef ANDROID
static int action_ok_push_dropdown_item_input_select_physical_keyboard(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
settings_t *settings = config_get_ptr();
const char *menu_path = NULL;
enum msg_hash_enums enum_idx;
rarch_setting_t *setting;
menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL);
enum_idx = (enum msg_hash_enums)atoi(menu_path);
setting = menu_setting_find_enum(enum_idx);
if (!setting)
return -1;
char* keyboard;
const char* keyboard_name = path;
const char* no_keyboard = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE);
if (string_is_equal(keyboard_name, no_keyboard))
settings->arrays.input_android_physical_keyboard[0] = '\0';
else
{
for (int i = 0; i < MAX_INPUT_DEVICES; i++)
{
const char* device_name = input_config_get_device_name(i);
if (string_is_equal(device_name, keyboard_name))
{
uint16_t vendor_id = input_config_get_device_vid(i);
uint16_t product_id = input_config_get_device_pid(i);
snprintf(settings->arrays.input_android_physical_keyboard,
sizeof(settings->arrays.input_android_physical_keyboard),
"%04x:%04x %s",
vendor_id, product_id, keyboard_name);
break;
}
}
/*
* if we did not find the selected device, do nothing, the user has chosen to keep
* the previous configuration, which is to use a device that is either not plugged right
* now or already working as the physical keyboard.
*/
}
settings->modified = true;
command_event(CMD_EVENT_REINIT, NULL);
/* Refresh menu */
bool refresh = false;
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
return action_cancel_pop_default(NULL, NULL, 0, 0);
}
#endif
static int action_ok_push_dropdown_item_input_description(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
@ -8614,6 +8686,11 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs,
case MENU_SETTING_DROPDOWN_ITEM_INPUT_DEVICE_TYPE:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_device_type);
break;
#ifdef ANDROID
case MENU_SETTING_DROPDOWN_ITEM_INPUT_SELECT_PHYSICAL_KEYBOARD:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_select_physical_keyboard);
break;
#endif
case MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION:
BIND_ACTION_OK(cbs, action_ok_push_dropdown_item_input_description);
break;

@ -711,6 +711,9 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_autodetect_enable, MENU_
#if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_nowinkey_enable, MENU_ENUM_SUBLABEL_INPUT_NOWINKEY_ENABLE)
#endif
#ifdef ANDROID
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_select_physical_keyboard, MENU_ENUM_SUBLABEL_INPUT_SELECT_PHYSICAL_KEYBOARD)
#endif
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_sensors_enable, MENU_ENUM_SUBLABEL_INPUT_SENSORS_ENABLE)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_auto_mouse_grab, MENU_ENUM_SUBLABEL_INPUT_AUTO_MOUSE_GRAB)
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_auto_game_focus, MENU_ENUM_SUBLABEL_INPUT_AUTO_GAME_FOCUS)
@ -3611,6 +3614,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_INPUT_NOWINKEY_ENABLE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_nowinkey_enable);
break;
#endif
#ifdef ANDROID
case MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_select_physical_keyboard);
break;
#endif
case MENU_ENUM_LABEL_INPUT_SENSORS_ENABLE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_sensors_enable);

@ -1813,6 +1813,9 @@ int menu_cbs_init_bind_title(menu_file_list_cbs_t *cbs,
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE, action_get_title_dropdown_item},
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION, action_get_title_dropdown_input_description},
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD, action_get_title_dropdown_input_description_kbd},
#ifdef ANDROID
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD, action_get_title_dropdown_item},
#endif
#ifdef HAVE_NETWORKING
{MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER, action_get_title_dropdown_item},
#endif

@ -53,6 +53,9 @@ enum
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE,
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION,
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD,
#ifdef ANDROID
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD,
#endif
#ifdef HAVE_NETWORKING
ACTION_OK_DL_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER,
#endif

@ -5160,6 +5160,131 @@ end:
return count;
}
#ifdef ANDROID
static int menu_displaylist_parse_input_select_physical_keyboard_list(
menu_displaylist_info_t *info, settings_t *settings)
{
char device_label[128];
const char *val_disabled = NULL;
rarch_system_info_t *system = &runloop_state_get_ptr()->system;
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info->path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
size_t menu_index = 0;
unsigned count = 0;
int i = 0;
char keyboard[sizeof(settings->arrays.input_android_physical_keyboard)];
bool keyboard_added = false;
input_driver_state_t *st = input_state_get_ptr();
input_driver_t *current_input = st->current_driver;
bool is_android_driver = string_is_equal(current_input->ident, "android");
device_label[0] = '\0';
if (!system || !settings || !setting || !is_android_driver)
goto end;
val_disabled = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE);
if (string_is_empty(settings->arrays.input_android_physical_keyboard))
strlcpy(keyboard, val_disabled, sizeof(keyboard));
else
{
unsigned int vendor_id;
unsigned int product_id;
if (sscanf(settings->arrays.input_android_physical_keyboard, "%04x:%04x ", &vendor_id, &product_id) != 2)
strlcpy(keyboard, settings->arrays.input_android_physical_keyboard, sizeof(keyboard));
else
/* If the vendor_id:product_id is encoded in the name, ignore them. */
strlcpy(keyboard, &settings->arrays.input_android_physical_keyboard[10], sizeof(keyboard));
}
for (i = MAX_INPUT_DEVICES; i >= -1; --i)
{
device_label[0] = '\0';
if (i < 0)
strlcpy(device_label, keyboard, sizeof(device_label));
else if (i == MAX_INPUT_DEVICES)
strlcpy(device_label, val_disabled, sizeof(device_label));
else if (i < MAX_INPUT_DEVICES)
{
/*
* Skip devices that do not look like keyboards
*/
if (!android_input_can_be_keyboard(st->current_data, i))
continue;
const char *device_name = input_config_get_device_display_name(i) ?
input_config_get_device_display_name(i) : input_config_get_device_name(i);
if (!string_is_empty(device_name))
{
unsigned idx = input_config_get_device_name_index(i);
size_t _len = strlcpy(device_label, device_name,
sizeof(device_label));
/*if idx is non-zero, it's part of a set*/
if (idx > 0)
snprintf(device_label + _len,
sizeof(device_label) - _len, " (#%u)", idx);
}
}
if (!string_is_empty(device_label))
{
size_t previous_position;
if (file_list_search(info->list, device_label, &previous_position))
continue;
/* Add menu entry */
if (menu_entries_append(info->list,
device_label,
device_label,
MSG_UNKNOWN,
MENU_SETTING_DROPDOWN_ITEM_INPUT_SELECT_PHYSICAL_KEYBOARD,
0, menu_index, NULL))
{
/* Add checkmark if input is currently
* mapped to this entry */
if (string_is_equal(device_label, keyboard))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_navigation_set_selection(menu_index);
keyboard_added = true;
}
count++;
menu_index++;
}
}
}
/* if nothing is configured, select None by default */
if (!keyboard_added)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[0].actiondata;
if (cbs)
cbs->checked = true;
menu_navigation_set_selection(0);
}
end:
/* Fallback */
if (count == 0)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
msg_hash_to_str(MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL))
count++;
return count;
}
#endif
static int menu_displaylist_parse_input_description_list(
menu_displaylist_info_t *info, settings_t *settings)
{
@ -7007,6 +7132,11 @@ unsigned menu_displaylist_build_list(
MENU_ENUM_LABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD,
PARSE_ACTION, true) == 0)
count++;
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SENSORS_ENABLE,
@ -12966,6 +13096,14 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
#ifdef ANDROID
case DISPLAYLIST_DROPDOWN_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD:
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
count = menu_displaylist_parse_input_select_physical_keyboard_list(info, settings);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
#endif
case DISPLAYLIST_DROPDOWN_LIST_INPUT_DESCRIPTION:
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
count = menu_displaylist_parse_input_description_list(info, settings);

@ -71,6 +71,9 @@ enum menu_displaylist_ctl_state
DISPLAYLIST_DROPDOWN_LIST_INPUT_DEVICE_TYPE,
DISPLAYLIST_DROPDOWN_LIST_INPUT_DESCRIPTION,
DISPLAYLIST_DROPDOWN_LIST_INPUT_DESCRIPTION_KBD,
#ifdef ANDROID
DISPLAYLIST_DROPDOWN_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD,
#endif
#ifdef HAVE_NETWORKING
DISPLAYLIST_DROPDOWN_LIST_NETPLAY_MITM_SERVER,
#endif

@ -108,6 +108,9 @@ enum menu_settings_type
MENU_SETTING_DROPDOWN_ITEM_DISK_INDEX,
MENU_SETTING_DROPDOWN_ITEM_INPUT_DEVICE_TYPE,
MENU_SETTING_DROPDOWN_ITEM_INPUT_DEVICE_INDEX,
#ifdef ANDROID
MENU_SETTING_DROPDOWN_ITEM_INPUT_SELECT_PHYSICAL_KEYBOARD,
#endif
MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION,
MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION_KBD,
#ifdef HAVE_NETWORKING

@ -2888,6 +2888,24 @@ static int setting_action_ok_libretro_device_type(
return 0;
}
#ifdef ANDROID
static int setting_action_ok_select_physical_keyboard(
rarch_setting_t *setting, size_t idx, bool wraparound)
{
char enum_idx[16];
if (!setting)
return -1;
snprintf(enum_idx, sizeof(enum_idx), "%d", setting->enum_idx);
generic_action_ok_displaylist_push(
enum_idx, /* we will pass the enumeration index of the string as a path */
NULL, NULL, 0, idx, 0,
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD);
return 0;
}
#endif
static int setting_string_action_left_string_options(
rarch_setting_t* setting, size_t idx, bool wraparound)
{
@ -6845,6 +6863,26 @@ static void setting_get_string_representation_input_touch_scale(rarch_setting_t
snprintf(s, len, "x%d", *setting->value.target.unsigned_integer);
}
#ifdef ANDROID
static void setting_get_string_representation_android_physical_keyboard(
rarch_setting_t *setting,
char *s, size_t len)
{
if (!setting)
return;
settings_t *settings = config_get_ptr();
int keyboard_vendor_id;
int keyboard_product_id;
if (sscanf(setting->value.target.string, "%04x:%04x ", &keyboard_vendor_id, &keyboard_product_id) != 2)
strlcpy(s, setting->value.target.string, len);
else
strlcpy(s, &setting->value.target.string[10], len);
}
#endif
#ifdef HAVE_LANGEXTRA
static void setting_get_string_representation_uint_user_language(
rarch_setting_t *setting,
@ -7850,6 +7888,11 @@ static void general_read_handler(rarch_setting_t *setting)
case MENU_ENUM_LABEL_INPUT_PLAYER5_JOYPAD_INDEX:
*setting->value.target.integer = settings->uints.input_joypad_index[setting->enum_idx - MENU_ENUM_LABEL_INPUT_PLAYER1_JOYPAD_INDEX];
break;
#ifdef ANDROID
case MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD:
setting->value.target.string = settings->arrays.input_android_physical_keyboard;
break;
#endif
default:
break;
}
@ -8170,6 +8213,15 @@ static void general_write_handler(rarch_setting_t *setting)
settings->uints.input_joypad_index[setting->enum_idx - MENU_ENUM_LABEL_INPUT_PLAYER1_JOYPAD_INDEX] = *setting->value.target.integer;
}
break;
#ifdef ANDROID
case MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD:
{
settings_t *settings = config_get_ptr();
settings->modified = true;
strlcpy(settings->arrays.input_android_physical_keyboard, setting->value.target.string, sizeof(settings->arrays.input_android_physical_keyboard));
}
break;
#endif
case MENU_ENUM_LABEL_LOG_TO_FILE:
if (verbosity_is_enabled())
{
@ -14064,6 +14116,24 @@ static bool setting_append_list(
general_read_handler,
SD_FLAG_NONE
);
input_driver_state_t *st = input_state_get_ptr();
input_driver_t *current_input = st->current_driver;
if (string_is_equal(current_input->ident, "android"))
{
CONFIG_ACTION(
list, list_info,
MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD,
MENU_ENUM_LABEL_VALUE_INPUT_SELECT_PHYSICAL_KEYBOARD,
&group_info,
&subgroup_info,
parent_group);
(*list)[list_info->index - 1].action_ok = &setting_action_ok_select_physical_keyboard;
(*list)[list_info->index - 1].read_handler = &general_read_handler;
(*list)[list_info->index - 1].change_handler = &general_write_handler;
(*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_android_physical_keyboard;
(*list)[list_info->index - 1].default_value.string = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE);
}
#endif
CONFIG_UINT(

@ -1080,6 +1080,11 @@ enum msg_hash_enums
#if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT)
MENU_LABEL(INPUT_NOWINKEY_ENABLE),
#endif
#ifdef ANDROID
MENU_LABEL(INPUT_SELECT_PHYSICAL_KEYBOARD),
#endif
MENU_LABEL(INPUT_SENSORS_ENABLE),
MENU_LABEL(INPUT_AUTO_MOUSE_GRAB),
@ -1710,6 +1715,9 @@ enum msg_hash_enums
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DEVICE_TYPE,
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION,
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION_KBD,
#ifdef ANDROID
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD,
#endif
MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_NETPLAY_MITM_SERVER,
MENU_ENUM_LABEL_DEFERRED_MIXER_STREAM_SETTINGS_LIST,
MENU_ENUM_LABEL_DEFERRED_CONFIGURATIONS_LIST,