From 3ddbf2d5cc1735bb807d3f5b1210db5b09494352 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 24 Sep 2015 13:22:46 +0200 Subject: [PATCH] Refactor menu_input.c --- menu/drivers/glui.c | 31 +++-- menu/drivers/rgui.c | 34 ++--- menu/drivers/rmenu_xui.cpp | 6 +- menu/drivers/xmb.c | 25 ++-- menu/menu.c | 5 +- menu/menu_driver.h | 4 +- menu/menu_input.c | 251 ++++++++++++++++++++++++++++++++++++- menu/menu_input.h | 140 +++++++-------------- menu/menu_setting.c | 6 +- 9 files changed, 356 insertions(+), 146 deletions(-) diff --git a/menu/drivers/glui.c b/menu/drivers/glui.c index 5482f158cf..3746c14bef 100644 --- a/menu/drivers/glui.c +++ b/menu/drivers/glui.c @@ -28,6 +28,7 @@ #include "../menu.h" #include "../menu_driver.h" #include "../menu_hash.h" +#include "../menu_input.h" #include "../menu_display.h" #include "../menu_video.h" @@ -233,25 +234,26 @@ static void glui_render(void) if (settings->menu.pointer.enable) { - menu_input->pointer.ptr = - (menu_input->pointer.y - glui->line_height + menu->scroll_y - 16) + unsigned new_ptr = (menu_input_pressed(MENU_INPUT_POINTER_AXIS_Y) - glui->line_height + menu->scroll_y - 16) / glui->line_height; - menu->scroll_y -= menu_input->pointer.accel / 60.0; - menu_input->pointer.accel = menu_input->pointer.accel * 0.96; + menu_input_set_pointer(MENU_INPUT_PTR_TYPE_POINTER, new_ptr); + + menu->scroll_y -= menu_input_get_acceleration(MENU_INPUT_PTR_ACCELERATION) / 60.0; + menu_input_set_acceleration(MENU_INPUT_PTR_ACCELERATION, menu_input_get_acceleration(MENU_INPUT_PTR_ACCELERATION) * 0.96); } if (settings->menu.mouse.enable) { - if (menu_input->mouse.scrolldown) + if (menu_input_pressed(MENU_INPUT_MOUSE_SCROLL_DOWN)) menu->scroll_y += 10; - if (menu_input->mouse.scrollup) + if (menu_input_pressed(MENU_INPUT_MOUSE_SCROLL_UP)) menu->scroll_y -= 10; - menu_input->mouse.ptr = - (menu_input->mouse.y - glui->line_height + menu->scroll_y - 16) - / glui->line_height; + menu_input_set_pointer(MENU_INPUT_PTR_TYPE_MOUSE, + (menu_input_pressed(MENU_INPUT_MOUSE_AXIS_Y) - glui->line_height + menu->scroll_y - 16) + / glui->line_height); } if (menu->scroll_y < 0) @@ -474,16 +476,16 @@ static void glui_frame(void) TEXT_ALIGN_RIGHT); } - if (menu_input->keyboard.display) + if (menu_input_key_displayed()) { char msg[PATH_MAX_LENGTH]; - const char *str = *menu_input->keyboard.buffer; + const char *str = menu_input_key_get_buff(); msg[0] = '\0'; if (!str) str = ""; glui_render_quad(gl, 0, 0, width, height, width, height, &black_bg[0]); - snprintf(msg, sizeof(msg), "%s\n%s", menu_input->keyboard.label, str); + snprintf(msg, sizeof(msg), "%s\n%s", menu_input_key_get_label(), str); glui_render_messagebox(msg); } @@ -495,7 +497,10 @@ static void glui_frame(void) } if (settings->menu.mouse.enable) - glui_render_quad(gl, menu_input->mouse.x - 5, menu_input->mouse.y - 5, 10, 10, width, height, &white_bg[0]); + glui_render_quad(gl, + menu_input_pressed(MENU_INPUT_MOUSE_AXIS_X) - 5, + menu_input_pressed(MENU_INPUT_MOUSE_AXIS_Y) - 5, + 10, 10, width, height, &white_bg[0]); gl->shader->use(gl, GL_SHADER_STOCK_BLEND); diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 75813b915b..09e78e3081 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -372,10 +372,8 @@ end: static void rgui_blit_cursor(menu_handle_t *menu) { - menu_input_t *menu_input = menu_input_get_ptr(); - - int16_t x = menu_input->mouse.x; - int16_t y = menu_input->mouse.y; + int16_t x = menu_input_pressed(MENU_INPUT_MOUSE_AXIS_X); + int16_t y = menu_input_pressed(MENU_INPUT_MOUSE_AXIS_Y); color_rect(menu, x, y - 5, 1, 11, 0xFFFF); color_rect(menu, x - 5, y, 11, 1, 0xFFFF); @@ -443,11 +441,13 @@ static void rgui_render(void) if (settings->menu.pointer.enable) { - menu_input->pointer.ptr = menu_input->pointer.y / 11 - 2 + menu_entries_get_start(); + unsigned new_ptr = menu_input_pressed(MENU_INPUT_POINTER_AXIS_Y) / 11 - 2 + menu_entries_get_start(); - if (menu_input->pointer.dragging) + menu_input_set_pointer(MENU_INPUT_PTR_TYPE_POINTER, new_ptr); + + if (menu_input_pressed(MENU_INPUT_POINTER_DRAGGED)) { - menu->scroll_y += menu_input->pointer.dy; + menu->scroll_y += menu_input_pressed(MENU_INPUT_POINTER_DELTA_AXIS_Y); menu_entries_set_start(-menu->scroll_y / 11 + 2); if (menu->scroll_y > 0) menu->scroll_y = 0; @@ -456,14 +456,16 @@ static void rgui_render(void) if (settings->menu.mouse.enable) { - if (menu_input->mouse.scrolldown - && (menu_entries_get_start() < menu_entries_get_end() - RGUI_TERM_HEIGHT)) - menu_entries_set_start(menu_entries_get_start() + 1); + if (menu_input_pressed(MENU_INPUT_MOUSE_SCROLL_DOWN)) + if ((menu_entries_get_start() < menu_entries_get_end() - RGUI_TERM_HEIGHT)) + menu_entries_set_start(menu_entries_get_start() + 1); - if (menu_input->mouse.scrollup && (menu_entries_get_start() > 0)) - menu_entries_set_start(menu_entries_get_start() - 1); + if (menu_input_pressed(MENU_INPUT_MOUSE_SCROLL_UP)) + if (menu_entries_get_start() > 0) + menu_entries_set_start(menu_entries_get_start() - 1); - menu_input->mouse.ptr = menu_input->mouse.y / 11 - 2 + menu_entries_get_start(); + menu_input_set_pointer(MENU_INPUT_PTR_TYPE_MOUSE, + menu_input_pressed(MENU_INPUT_MOUSE_AXIS_Y) / 11 - 2 + menu_entries_get_start()); } /* Do not scroll if all items are visible. */ @@ -574,14 +576,14 @@ static void rgui_render(void) rgui_render_messagebox( message_queue); #endif - if (menu_input->keyboard.display) + if (menu_input_key_displayed()) { char msg[PATH_MAX_LENGTH] = {0}; - const char *str = *menu_input->keyboard.buffer; + const char *str = menu_input_key_get_buff(); if (!str) str = ""; - snprintf(msg, sizeof(msg), "%s\n%s", menu_input->keyboard.label, str); + snprintf(msg, sizeof(msg), "%s\n%s", menu_input_key_get_label(), str); rgui_render_messagebox(msg); } diff --git a/menu/drivers/rmenu_xui.cpp b/menu/drivers/rmenu_xui.cpp index c0b8f823b2..093972c515 100644 --- a/menu/drivers/rmenu_xui.cpp +++ b/menu/drivers/rmenu_xui.cpp @@ -590,14 +590,14 @@ static void rmenu_xui_render(void) } XuiListSetCurSelVisible(m_menulist, menu_navigation_get_selection(nav)); - if (menu->keyboard.display) + if (menu_input_key_displayed()) { char msg[1024] = {0}; - const char *str = *menu->keyboard.buffer; + const char *str = menu_input_key_get_ptr(); if (!str) str = ""; - snprintf(msg, sizeof(msg), "%s\n%s", menu->keyboard.label, str); + snprintf(msg, sizeof(msg), "%s\n%s", menu_input_key_get_label(), str); rmenu_xui_render_messagebox(msg); } } diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 9f13550f69..fd42fa8345 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1433,19 +1433,22 @@ static void xmb_render(void) { for (i = 0; i < end; i++) { - float item_y1 = xmb->margins.screen.top + xmb_item_y(xmb, i, current); - float item_y2 = item_y1 + xmb->icon.size; + float item_y1 = xmb->margins.screen.top + xmb_item_y(xmb, i, current); + float item_y2 = item_y1 + xmb->icon.size; + int16_t y_axis = menu_input_pressed(MENU_INPUT_POINTER_AXIS_Y); if (settings->menu.pointer.enable) { - if (menu_input->pointer.y > item_y1 && menu_input->pointer.y < item_y2) - menu_input->pointer.ptr = i; + if ((y_axis > item_y1) && (y_axis < item_y2)) + menu_input_set_pointer(MENU_INPUT_PTR_TYPE_POINTER, i); } if (settings->menu.mouse.enable) { - if (menu_input->mouse.y > item_y1 && menu_input->mouse.y < item_y2) - menu_input->mouse.ptr = i; + y_axis = menu_input_pressed(MENU_INPUT_MOUSE_AXIS_Y); + + if ((y_axis > item_y1) && (y_axis < item_y2)) + menu_input_set_pointer(MENU_INPUT_PTR_TYPE_MOUSE, i); } } } @@ -1630,14 +1633,14 @@ static void xmb_frame(void) menu_display_font_flush_block(menu, font_driver); - if (menu_input->keyboard.display) + if (menu_input_key_displayed()) { - const char *str = *menu_input->keyboard.buffer; + const char *str = menu_input_key_get_buff(); if (!str) str = ""; snprintf(msg, sizeof(msg), "%s\n%s", - menu_input->keyboard.label, str); + menu_input_key_get_label(), str); render_background = true; } @@ -1661,7 +1664,9 @@ static void xmb_frame(void) if (settings->menu.mouse.enable) xmb_draw_cursor(gl, xmb, &coord_color2[0], - menu_input->mouse.x, menu_input->mouse.y, width, height); + menu_input_pressed(MENU_INPUT_MOUSE_AXIS_X), + menu_input_pressed(MENU_INPUT_MOUSE_AXIS_Y), + width, height); menu_display_unset_viewport(); } diff --git a/menu/menu.c b/menu/menu.c index 110c1a0b9c..fd4c7b6804 100644 --- a/menu/menu.c +++ b/menu/menu.c @@ -196,7 +196,7 @@ void menu_free(menu_handle_t *menu) menu->playlist = NULL; menu_shader_free(menu); - + menu_input_free(menu); menu_driver_free(menu); #ifdef HAVE_DYNAMIC @@ -243,6 +243,9 @@ void *menu_init(const void *data) strlcpy(settings->menu.driver, menu_ctx->ident, sizeof(settings->menu.driver)); + if (!menu_input_init(menu)) + goto error; + if (!menu_entries_init(menu)) goto error; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 36825d49d7..a6944cd350 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -21,12 +21,12 @@ #include #include #include +#include "menu_input.h" #include "menu_animation.h" #include "menu_display.h" #include "menu_displaylist.h" #include "menu_entries.h" #include "menu_list.h" -#include "menu_input.h" #include "menu_navigation.h" #include "menu_setting.h" #include "../libretro.h" @@ -110,7 +110,7 @@ typedef struct char default_cgp[PATH_MAX_LENGTH]; struct video_shader *shader; - menu_input_t input; + menu_input_t *input; content_playlist_t *playlist; char db_playlist_file[PATH_MAX_LENGTH]; diff --git a/menu/menu_input.c b/menu/menu_input.c index 1b3ca75603..27c9a6d9d5 100644 --- a/menu/menu_input.c +++ b/menu/menu_input.c @@ -39,6 +39,100 @@ #include "../input/input_remapping.h" #include "../input/input_common.h" +struct menu_bind_state_port +{ + bool buttons[MENU_MAX_BUTTONS]; + int16_t axes[MENU_MAX_AXES]; + uint16_t hats[MENU_MAX_HATS]; +}; + +struct menu_bind_axis_state +{ + /* Default axis state. */ + int16_t rested_axes[MENU_MAX_AXES]; + /* Locked axis state. If we configured an axis, + * avoid having the same axis state trigger something again right away. */ + int16_t locked_axes[MENU_MAX_AXES]; +}; + +struct menu_bind_state +{ + struct retro_keybind *target; + /* For keyboard binding. */ + int64_t timeout_end; + unsigned begin; + unsigned last; + unsigned user; + struct menu_bind_state_port state[MAX_USERS]; + struct menu_bind_axis_state axis_state[MAX_USERS]; + bool skip; +}; + +typedef struct menu_input +{ + struct menu_bind_state binds; + + struct + { + int16_t dx; + int16_t dy; + int16_t x; + int16_t y; + int16_t screen_x; + int16_t screen_y; + bool left; + bool right; + bool oldleft; + bool oldright; + bool wheelup; + bool wheeldown; + bool hwheelup; + bool hwheeldown; + bool scrollup; + bool scrolldown; + unsigned ptr; + uint64_t state; + } mouse; + + struct + { + int16_t x; + int16_t y; + int16_t dx; + int16_t dy; + int16_t old_x; + int16_t old_y; + int16_t start_x; + int16_t start_y; + float accel; + float accel0; + float accel1; + bool pressed[2]; + bool oldpressed[2]; + bool dragging; + bool back; + bool oldback; + unsigned ptr; + } pointer; + + struct + { + const char **buffer; + const char *label; + const char *label_setting; + bool display; + unsigned type; + unsigned idx; + } keyboard; + + /* Used for key repeat */ + struct + { + float timer; + float count; + } delay; +} menu_input_t; + unsigned bind_port; menu_input_t *menu_input_get_ptr(void) @@ -46,7 +140,133 @@ menu_input_t *menu_input_get_ptr(void) menu_handle_t *menu = menu_driver_get_ptr(); if (!menu) return NULL; - return &menu->input; + return menu->input; +} + +void menu_input_set_binds(unsigned min, unsigned max) +{ + menu_input_t *ptr = menu_input_get_ptr(); + + if (!ptr) + return; + + ptr->binds.begin = min; + ptr->binds.last = max; +} + +void menu_input_set_pointer(enum menu_input_pointer_type type, unsigned val) +{ + menu_input_t *ptr = menu_input_get_ptr(); + + if (!ptr) + return; + + switch (type) + { + case MENU_INPUT_PTR_TYPE_POINTER: + ptr->pointer.ptr = val; + break; + case MENU_INPUT_PTR_TYPE_MOUSE: + ptr->mouse.ptr = val; + break; + } +} + +int16_t menu_input_pressed(enum menu_input_action axis) +{ + menu_input_t *ptr = menu_input_get_ptr(); + + switch (axis) + { + case MENU_INPUT_POINTER_AXIS_X: + return ptr->pointer.x; + case MENU_INPUT_POINTER_AXIS_Y: + return ptr->pointer.y; + case MENU_INPUT_POINTER_DELTA_AXIS_X: + return ptr->pointer.dx; + case MENU_INPUT_POINTER_DELTA_AXIS_Y: + return ptr->pointer.dy; + case MENU_INPUT_POINTER_DRAGGED: + return ptr->pointer.dragging; + case MENU_INPUT_MOUSE_AXIS_X: + return ptr->mouse.x; + case MENU_INPUT_MOUSE_AXIS_Y: + return ptr->mouse.y; + case MENU_INPUT_MOUSE_SCROLL_UP: + return ptr->mouse.scrollup; + case MENU_INPUT_MOUSE_SCROLL_DOWN: + return ptr->mouse.scrolldown; + } + + return 0; +} + +void menu_input_set_acceleration(enum menu_input_pointer_acceleration accel, float val) +{ + menu_input_t *ptr = menu_input_get_ptr(); + + if (!ptr) + return; + + switch (accel) + { + case MENU_INPUT_PTR_ACCELERATION: + ptr->pointer.accel = val; + break; + case MENU_INPUT_PTR_ACCELERATION_1: + ptr->pointer.accel0 = val; + break; + case MENU_INPUT_PTR_ACCELERATION_2: + ptr->pointer.accel1 = val; + break; + } +} + +float menu_input_get_acceleration(enum menu_input_pointer_acceleration accel) +{ + menu_input_t *ptr = menu_input_get_ptr(); + + if (!ptr) + return 0.0f; + + switch (accel) + { + case MENU_INPUT_PTR_ACCELERATION: + return ptr->pointer.accel; + case MENU_INPUT_PTR_ACCELERATION_1: + return ptr->pointer.accel0; + case MENU_INPUT_PTR_ACCELERATION_2: + return ptr->pointer.accel1; + } + + return 0.0f; +} + +bool menu_input_key_displayed(void) +{ + menu_input_t *menu_input = menu_input_get_ptr(); + if (!menu_input) + return false; + + return menu_input->keyboard.display; +} + +const char *menu_input_key_get_buff(void) +{ + menu_input_t *menu_input = menu_input_get_ptr(); + if (!menu_input) + return NULL; + + return *menu_input->keyboard.buffer; +} + +const char *menu_input_key_get_label(void) +{ + menu_input_t *menu_input = menu_input_get_ptr(); + if (!menu_input) + return NULL; + + return menu_input->keyboard.label; } void menu_input_key_start_line(const char *label, @@ -926,12 +1146,12 @@ void menu_input_post_iterate(int *ret, unsigned action) menu_entry_get(&entry, selected, NULL, false); - if (settings->menu.mouse.enable) + if (settings && settings->menu.mouse.enable) *ret = menu_input_mouse_post_iterate (&menu_input->mouse.state, cbs, action); *ret = menu_input_mouse_frame(cbs, &entry, menu_input->mouse.state); - if (settings->menu.pointer.enable) + if (settings && settings->menu.pointer.enable) *ret |= menu_input_pointer_post_iterate(cbs, &entry, action); } @@ -1034,3 +1254,28 @@ unsigned menu_input_frame(retro_input_t input, retro_input_t trigger_input) return ret; } + +void menu_input_free(void *data) +{ + menu_handle_t *menu = (menu_handle_t*)data; + if (!menu) + return; + + if (menu->input) + free(menu->input); + menu->input = NULL; +} + +bool menu_input_init(void *data) +{ + menu_handle_t *menu = (menu_handle_t*)data; + if (!menu) + return false; + + menu->input = (menu_input_t*)calloc(1, sizeof(*menu->input)); + + if (!menu->input) + return false; + + return true; +} diff --git a/menu/menu_input.h b/menu/menu_input.h index 00b4e2deb7..50b581df91 100644 --- a/menu/menu_input.h +++ b/menu/menu_input.h @@ -72,6 +72,32 @@ enum mouse_action MOUSE_ACTION_WHEEL_DOWN }; +enum menu_input_action +{ + MENU_INPUT_POINTER_AXIS_X = 0, + MENU_INPUT_POINTER_AXIS_Y, + MENU_INPUT_POINTER_DELTA_AXIS_X, + MENU_INPUT_POINTER_DELTA_AXIS_Y, + MENU_INPUT_POINTER_DRAGGED, + MENU_INPUT_MOUSE_AXIS_X, + MENU_INPUT_MOUSE_AXIS_Y, + MENU_INPUT_MOUSE_SCROLL_UP, + MENU_INPUT_MOUSE_SCROLL_DOWN +}; + +enum menu_input_pointer_acceleration +{ + MENU_INPUT_PTR_ACCELERATION = 0, + MENU_INPUT_PTR_ACCELERATION_1, + MENU_INPUT_PTR_ACCELERATION_2 +}; + +enum menu_input_pointer_type +{ + MENU_INPUT_PTR_TYPE_POINTER = 0, + MENU_INPUT_PTR_TYPE_MOUSE +}; + enum menu_input_bind_mode { MENU_INPUT_BIND_NONE, @@ -79,99 +105,7 @@ enum menu_input_bind_mode MENU_INPUT_BIND_ALL }; -struct menu_bind_state_port -{ - bool buttons[MENU_MAX_BUTTONS]; - int16_t axes[MENU_MAX_AXES]; - uint16_t hats[MENU_MAX_HATS]; -}; - -struct menu_bind_axis_state -{ - /* Default axis state. */ - int16_t rested_axes[MENU_MAX_AXES]; - /* Locked axis state. If we configured an axis, - * avoid having the same axis state trigger something again right away. */ - int16_t locked_axes[MENU_MAX_AXES]; -}; - -struct menu_bind_state -{ - struct retro_keybind *target; - /* For keyboard binding. */ - int64_t timeout_end; - unsigned begin; - unsigned last; - unsigned user; - struct menu_bind_state_port state[MAX_USERS]; - struct menu_bind_axis_state axis_state[MAX_USERS]; - bool skip; -}; - -typedef struct menu_input -{ - struct menu_bind_state binds; - - struct - { - int16_t dx; - int16_t dy; - int16_t x; - int16_t y; - int16_t screen_x; - int16_t screen_y; - bool left; - bool right; - bool oldleft; - bool oldright; - bool wheelup; - bool wheeldown; - bool hwheelup; - bool hwheeldown; - bool scrollup; - bool scrolldown; - unsigned ptr; - uint64_t state; - } mouse; - - struct - { - int16_t x; - int16_t y; - int16_t dx; - int16_t dy; - int16_t old_x; - int16_t old_y; - int16_t start_x; - int16_t start_y; - float accel; - float accel0; - float accel1; - bool pressed[2]; - bool oldpressed[2]; - bool dragging; - bool back; - bool oldback; - unsigned ptr; - } pointer; - - struct - { - const char **buffer; - const char *label; - const char *label_setting; - bool display; - unsigned type; - unsigned idx; - } keyboard; - - /* Used for key repeat */ - struct - { - float timer; - float count; - } delay; -} menu_input_t; +typedef struct menu_input menu_input_t; void menu_input_key_event(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); @@ -180,6 +114,12 @@ void menu_input_key_start_line(const char *label, const char *label_setting, unsigned type, unsigned idx, input_keyboard_line_complete_t cb); +bool menu_input_key_displayed(void); + +const char *menu_input_key_get_buff(void); + +const char *menu_input_key_get_label(void); + void menu_input_st_uint_callback(void *userdata, const char *str); void menu_input_st_hex_callback(void *userdata, const char *str); @@ -199,8 +139,22 @@ int menu_input_set_keyboard_bind_mode(void *data, enum menu_input_bind_mode type int menu_input_set_input_device_bind_mode(void *data, enum menu_input_bind_mode type); +void menu_input_set_binds(unsigned min, unsigned max); + +void menu_input_set_pointer(enum menu_input_pointer_type type, unsigned val); + +int16_t menu_input_pressed(enum menu_input_action axis); + +void menu_input_set_acceleration(enum menu_input_pointer_acceleration accel, float val); + +float menu_input_get_acceleration(enum menu_input_pointer_acceleration accel); + menu_input_t *menu_input_get_ptr(void); +void menu_input_free(void *data); + +bool menu_input_init(void *data); + #ifdef __cplusplus } #endif diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 89a0512638..4a1bccbfc3 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -996,14 +996,11 @@ static int setting_action_ok_bind_defaults(void *data, bool wraparound) struct retro_keybind *target = NULL; const struct retro_keybind *def_binds = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; - menu_input_t *menu_input = menu_input_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); (void)wraparound; - if (!menu_input) - return -1; if (!setting) return -1; @@ -1015,8 +1012,7 @@ static int setting_action_ok_bind_defaults(void *data, bool wraparound) if (!target) return -1; - menu_input->binds.begin = MENU_SETTINGS_BIND_BEGIN; - menu_input->binds.last = MENU_SETTINGS_BIND_LAST; + menu_input_set_binds(MENU_SETTINGS_BIND_BEGIN, MENU_SETTINGS_BIND_LAST); for (i = MENU_SETTINGS_BIND_BEGIN; i <= MENU_SETTINGS_BIND_LAST; i++, target++)