diff --git a/include/arm11/atp.h b/include/arm11/atp.h index 6734a70..8e03c77 100644 --- a/include/arm11/atp.h +++ b/include/arm11/atp.h @@ -107,8 +107,8 @@ extern atp_error_t atp_select( ); extern atp_error_t atp_tips( - INPUT(atp_text_t) tips_at_bottom_left, - INPUT(atp_text_t) tips_at_bottom_right + INPUT(atp_text_t) tips_string, + OUTPUT(atp_text_t) tips_before ); #undef INPUT diff --git a/include/arm11/open_agb_firm.h b/include/arm11/open_agb_firm.h index 88693d4..4a092f4 100644 --- a/include/arm11/open_agb_firm.h +++ b/include/arm11/open_agb_firm.h @@ -20,10 +20,42 @@ #include "error_codes.h" +struct global_oaf_config +{ + // [general] + u16 backlight; // Both LCDs. + bool directBoot; + bool useGbaDb; + // [video] + u8 scaler; // 0 = 1:1, 1 = bilinear (GPU) x1.5, 2 = matrix (hardware) x1.5. + float gbaGamma; + float lcdGamma; + float contrast; + float brightness; + + // [game] + u8 saveSlot; + // TODO: Per-game save type override. + + // [advanced] + bool saveOverride; + u16 defaultSave; + + // [boost] + u8 savePolicy; + u8 cheatMode; +}; + +#define SAVE_POLICY_GBADB 0 +#define SAVE_POLICY_FIRM 1 +#define SAVE_POLICY_SRAM 2 +#define SAVE_POLICY_POPUP 3 +#define SAVE_POLICY_SIZE 4 Result oafParseConfigEarly(void); u8 oafGetBacklightConfig(void); Result oafInitAndRun(void); void oafUpdate(void); void oafFinish(void); +int oafCheatMode(void); diff --git a/include/arm11/pages.h b/include/arm11/pages.h new file mode 100644 index 0000000..8f76941 --- /dev/null +++ b/include/arm11/pages.h @@ -0,0 +1,29 @@ +#ifndef __OAF_PAGES_H__ +#define __OAF_PAGES_H__ + +#include "arm11/atp.h" +#include "arm11/cheat.h" +#include "arm11/keyremix.h" +#include "arm11/open_agb_firm.h" + +extern atp_error_t disp_str( atp_callerdata_t , atp_counter_t, atp_linecfg_t * ); +extern atp_error_t use_config_page( struct global_oaf_config* ); +extern atp_error_t use_cheat_page( const char* ); +extern atp_error_t use_keyremix_page( char *file ); + +extern atp_error_t help_page( atp_text_t *wording, atp_counter_t length ); + +#define use_help_page(text) help_page((text), sizeof((text))/sizeof(atp_text_t)) +#define WAIT_ON_ACT( act ) ( ATP_POWER_OFF == (act) ) ? ATP_POWER_OFF : ATP_PAGE_REFRESH +#define WAIT_ON_ERRPAGE( page ) WAIT_ON_ACT( atp_show(1, (page), NULL) ) + +#define DECLARE_ERROR_PAGE(name, message) static atp_error_t name (atp_callerdata_t, atp_counter_t, atp_linecfg_t *c) \ + { \ + c->text = message; \ + c->text_align = ATP_PLACEMENT_CENTER; \ + c->text_color = ATP_COLOR_RED; \ + return ATP_SUCCESS; \ + } + + +#endif//__OAF_PAGES_H__ \ No newline at end of file diff --git a/source/arm11/atp.c b/source/arm11/atp.c index b70beec..0c3ebb3 100644 --- a/source/arm11/atp.c +++ b/source/arm11/atp.c @@ -7,8 +7,8 @@ #define TITLE_MAX 8 #define TIPS_MAX 64 -static char ta[TIPS_MAX] = {'\0'}; -static char tb[TIPS_MAX] = {'\0'}; +static char dymt[TIPS_MAX] = {'\0'}; +static atp_text_t stct = NULL; #define ATP_COLOR_SIZE (ATP_COLOR_WHITE+1) @@ -79,8 +79,8 @@ const char *acf_put_text(int x, int y, int width, int height, int maxwidth, u8 c static void screen_clean() { memset(consoleGet()->frameBuffer, 0, WINDOW_WIDTH*WINDOW_HEIGHT*sizeof(uint16_t)); - if( ta[0] ) acf_put_text( 5, 215, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH-10, ATP_COLOR_CYAN, ATP_PLACEMENT_LEFT, ta ); - if( tb[0] ) acf_put_text( 5, 215, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH-10, ATP_COLOR_CYAN, ATP_PLACEMENT_RIGHT, tb ); + if( dymt[0] ) acf_put_text( 5, 215, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH-10, ATP_COLOR_CYAN, ATP_PLACEMENT_LEFT, dymt ); + if( stct[0] ) acf_put_text( 5, 215, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH-10, ATP_COLOR_CYAN, ATP_PLACEMENT_RIGHT, stct ); } static void screen_clean_zone( int x, int y, int w, int h ) @@ -108,6 +108,13 @@ static uint32_t waitKey() return down; } +static atp_error_t dynamic_tips( atp_text_t tips ) +{ + if( strlen(tips) > TIPS_MAX-1 ) return ATP_INDEX_OUTOFRANGE; + strcpy( dymt, tips ); + return ATP_SUCCESS; +} + #define easy_put(text, align, color, row) acf_put_text( \ CONTAINER_LEFTTOP_X, \ CONTAINER_LEFTTOP_Y+FONT_HEIGHT*(row), \ @@ -144,6 +151,8 @@ static void container_paint( atp_lineprovider_t provider, atp_callerdata_t data, atp_error_t atp_show( atp_counter_t cnt, atp_lineprovider_t provider, atp_callerdata_t data ) { int idx_top = 0; + dynamic_tips(" "); + screen_clean(); container_paint( provider, data, cnt, idx_top ); @@ -197,7 +206,8 @@ static void set_paging( int top, int len ) unsigned current = top / CONTAINER_MAX_LINES; char buf[32]; ee_snprintf( buf, sizeof(buf), "页码:%d/%d", current+1, total ); - atp_tips( buf, NULL ); + if( total > 1 ) dynamic_tips( buf ); + else dynamic_tips(" "); screen_clean(); } @@ -384,17 +394,17 @@ atp_error_t atp_select( atp_text_t title, atp_counter_t cnt, atp_itemprovider_t } -atp_error_t atp_tips( atp_text_t tipsA, atp_text_t tipsB ) +atp_error_t atp_tips( atp_text_t tips, atp_text_t *old ) { - if( tipsA != NULL ) + if( old != NULL ) + *old = stct; + + if( tips != NULL ) { - strncpy( ta, tipsA, TIPS_MAX-1 ); - ta[TIPS_MAX-1] = 0; - } - if( tipsB != NULL ) - { - strncpy( tb, tipsB, TIPS_MAX-1 ); - tb[TIPS_MAX-1] = 0; + if( strlen(tips) > TIPS_MAX-1 ) + return ATP_INDEX_OUTOFRANGE; + + stct = tips; } return ATP_SUCCESS; } diff --git a/source/arm11/filebrowser.c b/source/arm11/filebrowser.c index c7a9edc..6beb75c 100644 --- a/source/arm11/filebrowser.c +++ b/source/arm11/filebrowser.c @@ -32,6 +32,7 @@ #include "arm11/atp.h" #include "arm11/acl.h" #include "arm11/cheat.h" +#include "arm11/pages.h" #include "arm11/keyremix.h" #define screenClean() memset(consoleGet()->frameBuffer, 0, CWIDTH*CHEIGHT*sizeof(uint16_t)) @@ -181,7 +182,7 @@ static atp_text_t folder_help[] = { "A键      查看目录或启动游戏", "B键          上层文件夹", "X键            金手指", - "Y键           暂不使用", + "Y键         配置游戏键位", "START        查看说明", "SELECT       系统设置" }; @@ -204,46 +205,11 @@ static atp_error_t display_folder( atp_callerdata_t data, atp_counter_t index, a return ATP_SUCCESS; } -#define DECLARE_ERROR_PAGE(name, message) static atp_error_t name (atp_callerdata_t, atp_counter_t, atp_linecfg_t *c) \ - { \ - c->text = message; \ - c->text_align = ATP_PLACEMENT_CENTER; \ - c->text_color = ATP_COLOR_RED; \ - return ATP_SUCCESS; \ - } - -DECLARE_ERROR_PAGE( display_openlib, "打开金手指文件出错" ) -DECLARE_ERROR_PAGE( display_selcht, "查找金手指配置出错" ) DECLARE_ERROR_PAGE( display_noserial, "提取游戏识别码失败" ) -DECLARE_ERROR_PAGE( display_nocheat, "找不到对应的金手指配置" ) DECLARE_ERROR_PAGE( display_empty, "没有合适的文件" ) DECLARE_ERROR_PAGE( display_toolong, "路径过长,改名或移动文件后再试" ) DECLARE_ERROR_PAGE( display_pathfull, "游戏或目录过量,最多显示999个" ) DECLARE_ERROR_PAGE( display_longname, "文件名总计过长,只显示前面的文件" ) -DECLARE_ERROR_PAGE( display_conflictkey, "和已有键位产生冲突" ) - -static atp_error_t display_help( atp_callerdata_t table, atp_counter_t index, atp_linecfg_t *config ) -{ - atp_text_t *list = (atp_text_t*)table; - config->text_align = ATP_PLACEMENT_CENTER; - config->text_color = index == 0 ? ATP_COLOR_MAGENTA : ATP_COLOR_LIGHT; - config->text = list[index]; - return ATP_SUCCESS; -} - -atp_error_t help_page( atp_text_t *wording, atp_counter_t length ) -{ - atp_tips( NULL, "返回:按A/B" ); - atp_error_t res = atp_show( length, display_help, (atp_callerdata_t)wording ); - atp_tips( NULL, "指引:按START" ); - return res; -} - -static atp_error_t disp_str( atp_callerdata_t data, atp_counter_t, atp_linecfg_t *cfg ) -{ - cfg->text = (atp_text_t)data; - return ATP_SUCCESS; -} /*void log( const char *fmt, ... ) { char buf[512]; @@ -263,403 +229,15 @@ static atp_error_t disp_str( atp_callerdata_t data, atp_counter_t, atp_linecfg_t }while ( down == 0 ); }*/ -static atp_error_t select_region( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *config ) -{ - static char text[16]; - - acl_region_t sreg; - acl_chtid_t sid, id; - if( ACHTLIB_SUCCESS != acl_query_cheat_set(index, &sid, &sreg) ) - { - config->text = "无效数据"; - config->value = index; - return ATP_SUCCESS; - } - char *t; - switch( sreg ) - { - case 'C': t = "官方中文"; break; - case 'J': t = "日文版"; break; - case 'E': t = "英文版"; break; - case 'F': t = "法语版"; break; - case 'S': t = "西班牙语"; break; - case 'I': t = "意大利语"; break; - case 'D': t = "德语版"; break; - case 'K': t = "韩文版"; break; - case 'X': case 'P': t = "欧洲语种"; break; - default: t = "其他语种"; break; - } - ee_sprintf(text, "%c-%s", 'A'+(char)index, t); - - if( CCHT_NOT_INIT == info_current_cheat( &id, NULL ) ) - id = 0; - - config->text = text; - config->value = index; - - // show saved information - if( sid == id ) - { - config->extra_text = "已启用"; - config->extra_text_color = ATP_COLOR_GREEN; - } - return ATP_SUCCESS; -} - -static atp_error_t select_holes( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - acl_text_t text; - acl_error_t res = acl_entry_get_label(index, &text); - if( res == ACHTLIB_SUCCESS ) - cfg->text = text; - else cfg->text = "无效数据"; - cfg->value = 1+index; - - // show saved information - acl_entryid_t id; - if( CCHT_OK == get_current_cheat( index, &id ) && ENT_USING(id) ) - { - cfg->extra_text = "开"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - - return ATP_SUCCESS; -} - -static atp_error_t select_onoff( atp_callerdata_t data, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - acl_entryid_t eid = (acl_entryid_t)data; - eid &= 0xffff; - if( index == 0 ) - { - cfg->text = "不开启"; - cfg->value = eid; - } - else if( index == 1 ) - { - cfg->text = "开启"; - cfg->value = 1<<16 | eid; - } - else - { - cfg->text = "调整数值开启[结果未知]"; - cfg->value = 0; - } - - // show saved information - if( CCHT_OK == include_current_cheat((acl_entryid_t)cfg->value) ) - { - cfg->extra_text = "选中"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - return ATP_SUCCESS; -} - -ALWAYS_INLINE u16 calc_step( u16 value ) -{ - u16 n = value / 50; - if( n == 0 ) return 1; - else - { - u16 base = 1; - while( n > 10 ) - { - n = n/10; - base *= 10; - } - if( n < 5 ) return base * 5; - else return base * 10; - } -} - -static atp_error_t step_provider( atp_callerdata_t mixid, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - static char number[8]; - u32 mix = (u32)mixid; - u16 max = mix & 0xffff; - u16 step = mix >> 16; - u16 res = step * (index+1); - ee_snprintf( number, 8, "%d", res < max ? res : max ); - cfg->text = number; - cfg->value = res < max ? res : max; - return ATP_SUCCESS; -} - -static atp_error_t handle_onoff_entry( acl_entryid_t id, acl_elemlen_t codelen, atp_itemval_t *item ) -{ -#define DEFAULT_ONOFF_HANDLER atp_select("选择此项目对应的设置", 2, select_onoff, NULL, (atp_callerdata_t)id, 0, 0, item); -#define ONOFF_SAFE_CALLACL( statement ) if( ACHTLIB_SUCCESS != statement ) return DEFAULT_ONOFF_HANDLER; - - if( codelen > 4 )// more than 2 address - return DEFAULT_ONOFF_HANDLER; - - u16 targetval = 0; - acl_armcode_t code; - - // one address - if( codelen == 2 ) - { - ONOFF_SAFE_CALLACL( acl_entry_get_armcode(1, &code) ); - targetval = code & 0xff; - } - // two addresses - else if( codelen == 4 ) - { - u32 addr0, addr1; - ONOFF_SAFE_CALLACL( acl_entry_get_armcode(0, &addr0) ); - ONOFF_SAFE_CALLACL( acl_entry_get_armcode(2, &addr1) ); - if( (addr0 & 1) || (addr0 | 1) != addr1 ) // valid u16 address - return DEFAULT_ONOFF_HANDLER; - - ONOFF_SAFE_CALLACL( acl_entry_get_armcode(1, &code) ); - targetval = code & 0xff; - ONOFF_SAFE_CALLACL( acl_entry_get_armcode(3, &code) ); - targetval |= (code & 0xff) << 8; - } - // more than two address, should not overwrite values - else return DEFAULT_ONOFF_HANDLER; - - atp_error_t res = atp_select( "选择此项目对应的设置", 3, select_onoff, NULL, targetval << 16 | id, 0, 0, item ); - if( res == ATP_SUCCESS && *item == 0 ) - { - char title[24]; - ee_snprintf( title, sizeof(title), "默认值:%d", targetval ); - u16 step = calc_step( targetval ); - atp_counter_t n = (targetval-1+step)/step; - res = atp_select(title, n, step_provider, NULL, (atp_callerdata_t)(step<<16|targetval), n, 0, item ); - if( res == ATP_SUCCESS && *item != targetval ) - overwrite_current_cheat( 1<<16|id, *item ); - - *item = 1<<16 | id; - } - return res; -} - -static atp_error_t select_keys( atp_callerdata_t data, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - acl_text_t text; - if( index == 0 ) - { - cfg->text = "不开启"; - } - else - { - acl_error_t res = acl_entry_get_label(index-1, &text); - if( res == ACHTLIB_SUCCESS ) - cfg->text = text; - else cfg->text = "无效数据"; - } - acl_entryid_t eid = (acl_entryid_t)data; - cfg->value = index<<16 | eid; - - if( CCHT_OK == include_current_cheat((acl_entryid_t)cfg->value) ) - { - cfg->extra_text = "选中"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - return ATP_SUCCESS; -} - -static inline void key_tips( key_remix_t *p, atp_boolean_t checking, atp_itemcfg_t *cfg ) -{ - if( p->remix_type == REMIX_TYPE_NONE ) - { - cfg->extra_text = "未添加"; - cfg->extra_text_color = ATP_COLOR_LIGHT; - } - else - { - if( p->remix_type == REMIX_TYPE_CHEAT ) - { - if( checking && p->game_keys == 0) - { - cfg->extra_text = "配置不齐"; - cfg->extra_text_color = ATP_COLOR_RED; - } - else - { - cfg->extra_text = "金手指键"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - } - else if( p->remix_type == REMIX_TYPE_REMAP ) - { - if( checking && (p->game_keys==0 || p->device_keys==0) ) - { - cfg->extra_text = "配置不齐"; - cfg->extra_text_color = ATP_COLOR_RED; - } - else - { - cfg->extra_text = "键位映射"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - } - else if( p->remix_type == REMIX_TYPE_HOLD ) - { - if( checking && (p->game_keys==0 || p->device_keys==0) ) - { - cfg->extra_text = "配置不齐"; - cfg->extra_text_color = ATP_COLOR_RED; - } - else - { - cfg->extra_text = "模拟长按"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - } - } -} - -#define KCP_OPTION_BASE 1000 -static atp_error_t select_krp( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - static char name[20]; - if( index < KEY_REMIX_LIMIT ) - { - ee_snprintf(name, sizeof(name), "键位配置项%ld", index+1); - cfg->text = name; - cfg->value = index; - key_remix_t *p = &g_keyremixConfig[index]; - key_tips(p, 1, cfg); - } - else - { - cfg->text = index == KEY_REMIX_LIMIT ? "保存当前配置到SD卡" : "从SD卡加载已保存的配置"; - cfg->value = KCP_OPTION_BASE + index-KEY_REMIX_LIMIT; - } - return ATP_SUCCESS; -} - - -#define KRFIELD_REMIX 0 -#define KRFIELD_DEVICE 1 -#define KRFIELD_GAME 2 - -const char *key_name[] = { - "上", "下", "左", "右", "A", "B", "L", "R", "SELECT", "START", "X", "Y", "ZL", "ZR" -}; -const u16 key_val[] = { - KEY_DUP, KEY_DDOWN, KEY_DLEFT, KEY_DRIGHT, KEY_A, KEY_B, KEY_L, KEY_R, KEY_SELECT, KEY_START, KEY_X, KEY_Y, KEY_ZL, KEY_ZR -}; -#define key_val_len (sizeof(key_val)/sizeof(u16)) -static atp_error_t select_kcf( atp_callerdata_t p, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - key_remix_t *kcfg = (key_remix_t*)p; - if( index == KRFIELD_REMIX ) - { - cfg->text = "选择键位功能"; - key_tips(kcfg, 0, cfg); - } - else if( index == KRFIELD_DEVICE ) - { - cfg->text = "选择实机键位"; - if( kcfg->device_keys ) - { - for( u8 i=0; i < key_val_len; ++i) - { - if( key_val[i] == kcfg->device_keys ) - { - cfg->extra_text = key_name[i]; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - } - } - else if( kcfg->remix_type == REMIX_TYPE_CHEAT ) - { - cfg->extra_text = "HOME"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - else - { - cfg->extra_text = "未设置"; - cfg->extra_text_color = ATP_COLOR_LIGHT; - } - } - else if( index == KRFIELD_GAME ) - { - cfg->text = "游戏中对应键位"; - if( kcfg->game_keys == 0 ) - { - cfg->extra_text = "未设置"; - cfg->extra_text_color = ATP_COLOR_LIGHT; - } - else - { - cfg->extra_text = "已设置"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - } - cfg->value = index; - return ATP_SUCCESS; -} - -static atp_error_t select_remixtype( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - if( index == REMIX_TYPE_NONE ) cfg->text = "停用设置"; - else if( index == REMIX_TYPE_REMAP ) cfg->text = "键位映射"; - else if( index == REMIX_TYPE_CHEAT ) cfg->text = "金手指键"; - else if( index == REMIX_TYPE_HOLD ) cfg->text = "模拟长按"; - cfg->value = index; - return ATP_SUCCESS; -} -static atp_error_t select_unikey( atp_callerdata_t str, atp_counter_t, atp_itemcfg_t *cfg ) -{ - cfg->text = (atp_text_t)str; - cfg->value = 0; - return ATP_SUCCESS; -} -static atp_error_t select_hostkey( atp_callerdata_t dat, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - phykey_t k = (phykey_t)dat; - cfg->text = key_name[index]; - cfg->value = key_val[index]; - if( k == key_val[index] ) - { - cfg->extra_text = "选中"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - return ATP_SUCCESS; -} - -static atp_error_t select_gbakey( atp_callerdata_t p_curkey, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - conkey_t key = *(conkey_t*)p_curkey; - cfg->text = key_name[index]; - cfg->value = key_val[index]; - if( key & key_val[index] ) - { - cfg->extra_text = "选中"; - cfg->extra_text_color = ATP_COLOR_GREEN; - } - return ATP_SUCCESS; -} - -static atp_error_t active_gbakey( atp_callerdata_t p_curkey, atp_counter_t index, atp_boolean_t x, atp_boolean_t y, atp_boolean_t l, atp_boolean_t r, atp_boolean_t start, atp_boolean_t select ) -{ - conkey_t *pkey = (conkey_t*)p_curkey; - if( l || r ) - { - conkey_t res = *pkey & key_val[index]; - if( res ) *pkey &= ~key_val[index]; - else *pkey |= key_val[index]; - return ATP_PAGE_UPDATE; - } - else return ATP_PAGE_NOOPTION; -} - extern atp_error_t oaf_config_page(); #define DIRBUFFSIZE 512 -#define WAIT_ON_ACT( act ) ( ATP_POWER_OFF == (act) ) ? ATP_POWER_OFF : ATP_PAGE_REFRESH -#define WAIT_ON_ERRPAGE( page ) WAIT_ON_ACT( atp_show(1, (page), NULL) ) static atp_pageopt_t serve_on_key( atp_callerdata_t data, atp_counter_t index, atp_boolean_t x, atp_boolean_t y, atp_boolean_t l, atp_boolean_t r, atp_boolean_t start, atp_boolean_t select ) { if( start ) { - atp_tips( "", NULL ); - return WAIT_ON_ACT( help_page( folder_help, sizeof(folder_help)/sizeof(atp_text_t) ) ); + return WAIT_ON_ACT( use_help_page( folder_help ) ); } else if( select ) { @@ -667,11 +245,9 @@ static atp_pageopt_t serve_on_key( atp_callerdata_t data, atp_counter_t index, a } else if( x ) { - extern int get_cheat_mode(); - if( CHEAT_MODE_DISABLED == get_cheat_mode() ) - { - return WAIT_ON_ACT( help_page( cheat_off_help, sizeof(cheat_off_help)/sizeof(atp_text_t) ) ); - } + if( CHEAT_MODE_DISABLED == oafCheatMode() ) + return WAIT_ON_ACT( use_help_page(cheat_off_help) ); + void* *dat = (void **)data; DirList const *dList = (DirList*)dat[0]; char *path = (char*)dat[1]; @@ -702,273 +278,15 @@ static atp_pageopt_t serve_on_key( atp_callerdata_t data, atp_counter_t index, a } else RECOVER_PATH; - acl_count_t len; - if( ACHTLIB_SUCCESS != acl_open_lib( "gba.acl" ) ) - { - return WAIT_ON_ERRPAGE( display_openlib ); - } - if( ACHTLIB_SUCCESS != acl_select_game( serial, 0, &len ) ) - { - acl_close_lib(); - return WAIT_ON_ERRPAGE( display_selcht ); - } - if( len == 0 ) - { - acl_close_lib(); - return WAIT_ON_ERRPAGE( display_nocheat ); - } - - // 显示配置页面 - atp_error_t res; - atp_itemval_t item; - acl_elemlen_t cnt; - -#define DISP_DONE 0 -#define DISP_REGION 1 -#define DISP_HOLES 2 -#define DISP_KEYS 3 -#define SAFE_CALLACL( r ) if( ACHTLIB_SUCCESS!=r ) \ - {\ - res = WAIT_ON_ERRPAGE( display_selcht );\ - break;\ - } - - uint8_t status = DISP_REGION; - atp_counter_t defi = 0; - acl_entryid_t eid = 0; - atp_tips(NULL, "确定A/取消B"); - - while( status != DISP_DONE ) - { - if( status == DISP_REGION ) - { - res = atp_select("请谨慎使用金手指!金手指可能会引起卡顿、死机、损坏存档等现象。           " - "选择一个金手指配置:", len, select_region, NULL, NULL, defi, 0, &item ); - if( res == ATP_SUCCESS ) - { - defi = item; - acl_chtid_t sid; - acl_elemlen_t len; - u32 ccid, cclen; - SAFE_CALLACL( acl_query_cheat_set((acl_index_t)item, &sid, NULL ) ); - SAFE_CALLACL( acl_select_cheat_set( sid ) ); - SAFE_CALLACL( acl_select_entry(0, &len) ); - - if( CCHT_OK == info_current_cheat(&ccid, &cclen) ) - { - // SKIP the init process when id and len is the same - if( ccid != sid || cclen != len ) - init_current_cheat( sid, len ); - } - else init_current_cheat( sid, len ); - - eid = 0; - status = DISP_HOLES; - } - else if( res == ATP_NO_ACTION) - { - status = DISP_DONE; - } - else break; - } - else if( status == DISP_HOLES ) - { - SAFE_CALLACL( acl_select_entry(0, &cnt) ); - res = atp_select("选择一个金手指项目", cnt, select_holes, NULL, NULL, eid > 0 ? (eid&0xffff)-1 : 0, 0, &item); - if( res == ATP_SUCCESS ) - { - eid = (acl_entryid_t)item; - status = DISP_KEYS; - } - else if( res == ATP_NO_ACTION ) - { - status = DISP_REGION; - } - else break; - } - else // DISP_KEYS - { - SAFE_CALLACL( acl_select_entry( eid, &cnt ) ); - if( cnt == 0 ) - { - SAFE_CALLACL( acl_select_entry( 1<<16 | eid, &cnt ) ); - res = handle_onoff_entry( eid, cnt, &item ); - } - else - { - res = atp_select("选择此项目对应的设置", cnt, select_keys, NULL, (atp_callerdata_t)eid, 0, 0, &item); - } - if( res == ATP_SUCCESS ) - { - put_current_cheat( (acl_entryid_t)item ); - status = DISP_HOLES; - } - else if( res == ATP_NO_ACTION ) - { - status = DISP_HOLES; - } - else break; - } - } - - acl_close_lib(); - atp_tips( NULL, "指引:按START" ); - return WAIT_ON_ACT( res ); + return WAIT_ON_ACT( use_cheat_page( serial ) ); } else if( y ) { -#ifndef NDEBUG - extern u8 dump_patched_rom; - dump_patched_rom = 0; -#endif - atp_itemval_t position=0, field=0, value; - atp_error_t res; - -#define DISP_KPOS 1 -#define DISP_SETK 2 // SET KEY -#define DISP_KMAP 3 // REMUX TYPE -#define DISP_3DSK 4 // 3DS KEY -#define DISP_GBAK 5 // GBA KEY - - uint8_t status = DISP_KPOS; - char tips[32]; - while ( status != DISP_DONE ) - { - if ( status == DISP_KPOS) - { - res = atp_select( "选择配置项后,按A进行键位配置", KEY_REMIX_LIMIT+2, select_krp, NULL, NULL, position, 0, &position ); - if( res == ATP_SUCCESS ) - { - void* *dat = (void **)data; - DirList const *dList = (DirList*)dat[0]; - char *file = &dList->ptrs[index][1]; - - if( position < KEY_REMIX_LIMIT ) - { - status = DISP_SETK; - field = 0; - } - else if( position == KCP_OPTION_BASE ) - { - const char *err = keyremix_dump( file ); - if( !err ) status = DISP_DONE; - else atp_show( 1, disp_str, err ); - } - else - { - const char *err = keyremix_load( file ); - if( !err ) position = 0; - else atp_show( 1, disp_str, err ); - } - } - else break; - } - else if( status == DISP_SETK ) - { - ee_snprintf(tips, sizeof(tips), "编辑配置项%ld", position+1); - key_remix_t *cur = &g_keyremixConfig[position]; - res = atp_select( tips, 3, select_kcf, NULL, cur, field, 0, &field ); - if( res == ATP_SUCCESS ) - { - status = field == KRFIELD_REMIX ? DISP_KMAP : (field == KRFIELD_DEVICE ? DISP_3DSK : DISP_GBAK); - } - else if( res == ATP_NO_ACTION ) - { - int fault = 0; - for( int i=0; i < KEY_REMIX_LIMIT; ++i ) - { - if( i!=position ) - { - if( g_keyremixConfig[i].remix_type == cur->remix_type - && g_keyremixConfig[i].device_keys == cur->device_keys ) - { - fault = 1; - break; - } - } - } - if( fault && cur->remix_type != REMIX_TYPE_NONE ) - atp_show(1, display_conflictkey, NULL); - else status = DISP_KPOS; - } - else break; - } - else if( status == DISP_KMAP ) - { - key_remix_t *cur = &g_keyremixConfig[position]; - res = atp_select( "配置键位功能", REMIX_TYPE_COUNT, select_remixtype, NULL, cur->remix_type, 0, 0, &value ); - if( res == ATP_SUCCESS ) - { - if( cur->remix_type != value ) - { - cur->remix_type = value; - cur->device_keys = 0; - cur->game_keys = value == REMIX_TYPE_CHEAT ? DEFAULT_CHEATKEY : 0; - } - status = DISP_SETK; - } - else if( res == ATP_NO_ACTION ) - { - status = DISP_SETK; - } - else break; - } - else if( status == DISP_3DSK ) - { - key_remix_t *cur = &g_keyremixConfig[position]; - atp_counter_t keys_count = 12; // old 3ds, old 3dsLL, 2ds - u8 host = MCU_getSystemModel();// 0=3ds 1=3dsll 2=n3ds 3=2ds 4=n3dsll 5=n2dsll - atp_text_t text; - if( cur->remix_type == REMIX_TYPE_CHEAT ) - { - keys_count = 1; - text = "HOME"; - } - else if( host > 1 && host != 3 ) // N3DS/N3DSLL/N2DSLL - { - keys_count = 14; - } - u8 selected = 31; - for( u8 i=0; i < key_val_len; ++i ) - { - if( key_val[i] == cur->device_keys ) - { - selected = i; - break; - } - } - if( keys_count == 1 ) res = atp_select("选择实机键位(单选)", 1, select_unikey, NULL, text, 0, 0, &value); - else res = atp_select( "选择实机键位(单选)", keys_count, select_hostkey, NULL, cur->device_keys, selected>keys_count?0:selected, 0, &value); - if( res == ATP_SUCCESS ) - { - cur->device_keys = value; - status = DISP_SETK; - } - else if( res == ATP_NO_ACTION ) - { - status = DISP_SETK; - } - else break; - } - else if( status == DISP_GBAK ) - { - key_remix_t *cur = &g_keyremixConfig[position]; - conkey_t key_editing = cur->game_keys; - res = atp_select( "选择游戏中对应键位[多选,按L/R键设置选中]", 10, select_gbakey, active_gbakey, &key_editing, 0, 0, &value); - if( res == ATP_SUCCESS ) - { - cur->game_keys = key_editing; - status = DISP_SETK; - } - else if( res == ATP_NO_ACTION ) - { - status = DISP_SETK; - } - else break; - } - } + void* *dat = (void **)data; + DirList const *dList = (DirList*)dat[0]; + char *file = &dList->ptrs[index][1]; - return WAIT_ON_ACT(res); + return WAIT_ON_ACT( use_keyremix_page(file) ); } return ATP_PAGE_NOOPTION; @@ -1022,7 +340,7 @@ Result browseFiles(const char *const basePath, char selected[512]) { GFX_waitForVBlank0(); hidScanInput(); - atp_tips( NULL, "指引:按START" ); + atp_tips( "指引:按START", NULL ); void *cust[2] = {dList, curDir}; error = atp_select( curDir, count, display_folder, serve_on_key, (atp_callerdata_t)cust, selecting, 0, &value ); } @@ -1067,9 +385,7 @@ Result browseFiles(const char *const basePath, char selected[512]) {// 上层目录 if( strcmp(curDir, FS_DRIVE_NAMES) == 0 ) { - atp_tips("没有上层目录", NULL); - help_page( folder_help, sizeof(folder_help)/sizeof(atp_text_t) ); - atp_tips("", NULL); + atp_show(1, disp_str, "没有上层目录"); } else DIRUP; } diff --git a/source/arm11/keyremix.c b/source/arm11/keyremix.c index ae8822d..931b827 100644 --- a/source/arm11/keyremix.c +++ b/source/arm11/keyremix.c @@ -7,12 +7,13 @@ key_remix_t g_keyremixConfig[KEY_REMIX_LIMIT]; static key_remix_t *frozen_start, *frozen_end; -static phykey_t prev_status = 0; +static phykey_t prev_phykey = 0; +static conkey_t prev_conkey = 0; static conkey_t blind_conkey; static u16 flags_holding = 0; #define DIR_SEPARATOR "/" -#define OUTPUT_DIR (KEYREMIX_OUTPUT_DIR##DIR_SEPARATOR) +#define OUTPUT_DIR (KEYREMIX_OUTPUT_DIR DIR_SEPARATOR) #define VKEY_HOME (1u<<21) #define now_release( now, prev, key ) ((~(now))&(prev)&(key)) #define CON_KEY_MASK (KEY_A|KEY_B|KEY_L|KEY_R|KEY_SELECT|KEY_START|KEY_DUP|KEY_DDOWN|KEY_DLEFT|KEY_DRIGHT) @@ -29,55 +30,75 @@ uint16_t keyremix_cheatkey() void keyremix_freeze() { - // 空白选项忽略,填充blind_conkey,金手指放首位 + // 空白选项忽略,填充blind_conkey,金手指放首位,REMAP紧跟金手指,HOLD在后面 key_remix_t temp[KEY_REMIX_LIMIT+1]; - int j=1, has_cheat=0; + + // 第一次循环:扫描得到各remix_type数量,用于定位在数组的位置 + int has_cheat=0, rem_count=0, valid_count=0; blind_conkey = 0; for( int i=0; i < KEY_REMIX_LIMIT; ++i ) { key_remix_t *p = &g_keyremixConfig[i]; - if( p->remix_type == REMIX_TYPE_CHEAT ) + if( p->remix_type == REMIX_TYPE_CHEAT ) { temp[0].remix_type = REMIX_TYPE_CHEAT; temp[0].device_keys = p->device_keys; temp[0].game_keys = p->game_keys; has_cheat = 1; } - else if( p->remix_type != REMIX_TYPE_NONE ) + else if( p->remix_type != REMIX_TYPE_NONE + && p->device_keys != 0 + && p->game_keys != 0 ) + { + valid_count++; + if( p->remix_type == REMIX_TYPE_REMAP ) rem_count++; + if( p->device_keys & CON_KEY_MASK ) + blind_conkey |= p->device_keys; + } + } + + // 第二次循环:根据remix_type放置到数组特定位置 + int j=has_cheat; + int k=j+rem_count; + for( int i=0; i < KEY_REMIX_LIMIT; ++i ) + { + key_remix_t *p = &g_keyremixConfig[i]; + if( p->remix_type == REMIX_TYPE_REMAP + && p->device_keys != 0 + && p->game_keys != 0 ) { temp[j].remix_type = p->remix_type; temp[j].device_keys = p->device_keys; temp[j].game_keys = p->game_keys; - if( p->device_keys & CON_KEY_MASK ) - blind_conkey |= p->device_keys; ++j; } + else if( p->remix_type == REMIX_TYPE_HOLD + && p->device_keys != 0 + && p->game_keys != 0 ) + { + temp[k].remix_type = p->remix_type; + temp[k].device_keys = p->device_keys; + temp[k].game_keys = p->game_keys; + ++k; + } } - memset( g_keyremixConfig, 0, sizeof(g_keyremixConfig) ); - if( has_cheat ) - { - memcpy( g_keyremixConfig, temp, sizeof(key_remix_t)*j ); - frozen_start = &g_keyremixConfig[1]; - frozen_end = &g_keyremixConfig[j]; - } - else - { - memcpy( g_keyremixConfig, &temp[1], sizeof(key_remix_t)*(j-1) ); - frozen_start = &g_keyremixConfig[0]; - frozen_end = &g_keyremixConfig[j-1]; - } + memcpy( g_keyremixConfig, temp, sizeof(g_keyremixConfig) ); + frozen_start = &g_keyremixConfig[has_cheat]; + frozen_end = &g_keyremixConfig[has_cheat+valid_count]; } void keyremix_update( uint16_t active_cheatkey ) { phykey_t now = hidKeysHeld(); + conkey_t cur = 0; + u8 init_cur = 0; vu16 *hid_set = (vu16*)0x10141112; vu16 *hid_mode = (vu16*)0x10141110; if( hidGetExtraKeys(0) & KEY_HOME ) now |= VKEY_HOME; - if( active_cheatkey && now_release(now, prev_status, VKEY_HOME) ) + if( active_cheatkey && now_release(now, prev_phykey, VKEY_HOME) ) { *hid_mode = active_cheatkey; *hid_set = ~active_cheatkey; @@ -109,15 +130,20 @@ void keyremix_update( uint16_t active_cheatkey ) } else if( p->remix_type == REMIX_TYPE_HOLD ) { + if( init_cur == 0 ) + { + init_cur = 1; + cur = res; + } uint16_t flag = 1<device_keys) ) + if( now_release(now, prev_phykey, p->device_keys) ) flags_holding ^= flag; if( flags_holding & flag ) { // exclude console keys is up - res |= now_release(now, prev_status, p->game_keys) ^ p->game_keys; + res |= now_release(cur, prev_conkey, p->game_keys) ^ p->game_keys; } else if( oldf != flags_holding )// release { @@ -128,7 +154,8 @@ void keyremix_update( uint16_t active_cheatkey ) *hid_mode = CON_KEY_MASK; *hid_set = ~res; } - prev_status = now; + prev_phykey = now; + prev_conkey = cur; } const char* keyremix_load( const char *file ) diff --git a/source/arm11/open_agb_firm.c b/source/arm11/open_agb_firm.c index 1719cd0..7b2633c 100644 --- a/source/arm11/open_agb_firm.c +++ b/source/arm11/open_agb_firm.c @@ -40,6 +40,8 @@ #include "arm11/atp.h" #include "arm11/cheat.h" #include "arm11/keyremix.h" +#include "arm11/pages.h" +#include "arm11/open_agb_firm.h" #include "kernel.h" #include "kevent.h" #include "arm11/drivers/codec.h" @@ -61,40 +63,9 @@ "[advanced]\n" \ "saveOverride=false\n" \ "defaultSave=14" - -#define SAVE_POLICY_GBADB 0 -#define SAVE_POLICY_FIRM 1 -#define SAVE_POLICY_SRAM 2 -#define SAVE_POLICY_POPUP 3 -#define SAVE_POLICY_SIZE 4 #define CHEAT_INUSE_ADDR (0x3007FE0u) // see GBATek - Default memory usage at 03007FXX -typedef struct -{ - // [general] - u16 backlight; // Both LCDs. - bool directBoot; - bool useGbaDb; - - // [video] - u8 scaler; // 0 = 1:1, 1 = bilinear (GPU) x1.5, 2 = matrix (hardware) x1.5. - float gbaGamma; - float lcdGamma; - float contrast; - float brightness; - - // [game] - u8 saveSlot; - // TODO: Per-game save type override. - - // [advanced] - bool saveOverride; - u16 defaultSave; - - // [boost] - u8 savePolicy; - u8 cheatMode; -} OafConfig; +typedef struct global_oaf_config OafConfig; typedef struct { @@ -144,7 +115,7 @@ Result dump_rom( u32 size ) u8 *p = ROM_LOC; u32 len; - ee_printf("dumping into dump.gba, file size %d\n", size); + ee_printf("dumping into dump.gba, file size %ld\n", size); for( u8 *p=ROM_LOC; size > 0; size-=len, p+=len ) { res = fWrite( file, p, size < 256 ? size : 256, &len ); @@ -158,7 +129,7 @@ Result dump_rom( u32 size ) break; if( ((u32)p-ROM_LOC) % (1024*64) == 0) - ee_printf("\x1b[3;1Hremaining %d bytes to dump.\n", size); + ee_printf("\x1b[3;1Hremaining %ld bytes to dump.\n", size); } } fClose( file ); @@ -170,159 +141,14 @@ Result dump_rom( u32 size ) // -------------------------- // code for oaf config page // -------------------------- -atp_text_t config_help[] = -{ - "全局参数编辑操作指引", - "~ ~ ~ ~ ~ ~ ~", - "-修改后的全局参数保存在config.ini ", - "保存修改时,存档方案的修改不会保存", - "-金手指组合键为下方向+L+R+SELECT", - " 也可以使用HOME键直接代替组合键 ", - "~ ~ ~ ~ ~ ~ ~", - "上下方向键      切换参数项目", - "左右方向键          翻页", - "L键和R键      调整当前参数", - "A键         应用修改退出", - "B键         放弃修改退出", - "X键       应用修改保存退出", // X做保存,选中后走A键流程 -}; -atp_text_t CONFIG_OUTPUT = "[general]\n" \ - "backlight=%d\n" \ - "directBoot=%s\n" \ - "useGbaDb=true\n\n" \ - "[video]\n" \ - "scaler=%d\n" \ - "gbaGamma=2.2\n" \ - "lcdGamma=1.54\n" \ - "contrast=1.0\n" \ - "brightness=0.0\n\n" \ - "[advanced]\n" \ - "saveOverride=false\n" \ - "defaultSave=14\n\n" \ - "[boost]\n" \ - "cheatMode=%d\n"; - -extern atp_error_t help_page( atp_text_t *wording, atp_counter_t length ); -int get_cheat_mode() +int oafCheatMode() { return g_oafConfig.cheatMode; } -#define LIGHT_MIN (MCU_getSystemModel() > 3 ? 50 : 20) -#define LIGHT_MAX (MCU_getSystemModel() > 3 ? 800 : 500) -#define SCALER_SIZE 4 -static atp_error_t config_item( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg ) -{ - const char *scaler_val[] = {"上屏无缩放", "上屏GPU放大", "上屏DMA放大", "下屏无缩放"}; - const char *savetype_name[] = {"和卡带序列号一致", "读取ROM的特定标记", "汉化带SRAM补丁", "自行决定"}; - const char *cheatmode_name[] = {"关闭金手指", "全程激活", "组合键单次激活", "组合键激活/关闭"}; - static char buf[16]; - cfg->extra_text_color = ATP_COLOR_GREEN; - if( index == 0 ) - { - ee_snprintf(buf, sizeof(buf), "%d", g_oafConfig.backlight); - cfg->text = "屏幕亮度"; - cfg->extra_text = buf; - if( g_oafConfig.backlight == LIGHT_MIN || g_oafConfig.backlight == LIGHT_MAX ) - cfg->extra_text_color = ATP_COLOR_RED; - } - else if( index == 1 ) - { - cfg->text = "GAME BOY画面"; - cfg->extra_text = g_oafConfig.directBoot ? "跳过" : "显示"; - } - else if( index == 2 ) - { - cfg->text = "画面输出"; - cfg->extra_text = scaler_val[g_oafConfig.scaler]; - } - else if( index == 3 ) - { - cfg->text = "存档方案"; - cfg->extra_text = savetype_name[g_oafConfig.savePolicy]; - } - else if( index == 4 ) - { - cfg->text = "激活金手指"; - cfg->extra_text = cheatmode_name[g_oafConfig.cheatMode]; - } - cfg->value = index; - return ATP_SUCCESS; -} - -static atp_pageopt_t config_adjust( atp_callerdata_t, atp_counter_t index, atp_boolean_t x, atp_boolean_t, atp_boolean_t l, atp_boolean_t r, atp_boolean_t start, atp_boolean_t ) -{ - if( l || r ) - { - if( index == 0 ) - { - u16 light = g_oafConfig.backlight; - if( l ) - { - light -= 10; - if( light % 10 ) light += 10 - light%10; - } - else if( r ) - { - light += 10; - if( light % 10 ) light -= light % 10; - } - if( light > LIGHT_MAX ) light = LIGHT_MAX; - else if( light < LIGHT_MIN ) light = LIGHT_MIN; - g_oafConfig.backlight = light; - } - else if( index == 1 ) g_oafConfig.directBoot = !g_oafConfig.directBoot; - else if( index == 2 ) g_oafConfig.scaler = ( SCALER_SIZE + ( g_oafConfig.scaler+(l?-1:1) ) ) % SCALER_SIZE; - else if( index == 3 ) g_oafConfig.savePolicy = ( SAVE_POLICY_SIZE + ( g_oafConfig.savePolicy+(l?-1:1) ) ) % SAVE_POLICY_SIZE; - else if( index == 4 ) g_oafConfig.cheatMode = ( CHEAT_MODE_SIZE + (g_oafConfig.cheatMode+(l?-1:1) ) ) % CHEAT_MODE_SIZE; - } - else if( start ) - { - atp_tips("", NULL); - return ATP_POWER_OFF == help_page( config_help, sizeof(config_help)/sizeof(atp_text_t) ) - ? ATP_POWER_OFF : ATP_PAGE_REFRESH; - } - else if( x ) - { - int len = strlen(CONFIG_OUTPUT) + 20; - char *data = malloc( len ); - if( data == NULL ) return ATP_PAGE_DOSELECT; // only ignore this save - - len = ee_snprintf( - data, len, CONFIG_OUTPUT, - g_oafConfig.backlight, g_oafConfig.directBoot ? "true":"false", g_oafConfig.scaler, g_oafConfig.cheatMode - ); - fsQuickWrite("config.ini", data, len); - free( data ); - return ATP_PAGE_DOSELECT; - } - return ATP_PAGE_UPDATE; -} - atp_error_t oaf_config_page() { - u8 base[sizeof(g_oafConfig)]; - static char title[210]; - memcpy( base, &g_oafConfig, sizeof(g_oafConfig) ); - OafConfig *prev = (OafConfig*)&base[0]; - - ee_snprintf( - title, sizeof(title), - "参数配置           当前电量:%3d%%" - "每次开机存档方案重置为“和卡带序列号一致”,这个方案会优先使用游戏最后一次启动时设置的存档类型", MCU_getBatteryLevel()); - atp_error_t res = atp_select( title, 5, config_item, config_adjust, NULL, 0, 0, NULL ); - if( res == ATP_NO_ACTION ) - { - memcpy( &g_oafConfig, prev, sizeof(g_oafConfig) ); - return ATP_SUCCESS; - } - else if( res == ATP_SUCCESS ) - { - if( prev->backlight != g_oafConfig.backlight ) - GFX_setBrightness(g_oafConfig.backlight, g_oafConfig.backlight); - } - - return res; + return use_config_page(&g_oafConfig); } // cache the savetype @@ -987,8 +813,8 @@ static Result showFileBrowser(char romAndSavePath[512]) if(cmpLen < strlen(lastDir) || strncmp(lastDir, romAndSavePath, cmpLen) != 0) { strncpy(lastDir, romAndSavePath, cmpLen); - lastDir[cmpLen] = '\0'; - res = fsQuickWrite("lastdir.txt", lastDir, cmpLen + 1); + lastDir[cmpLen] = '\n'; + res = fsQuickWrite("lastdir.txt", lastDir, strlen(lastDir)); } } } while(0); diff --git a/source/arm11/pages.c b/source/arm11/pages.c new file mode 100644 index 0000000..63ba1fe --- /dev/null +++ b/source/arm11/pages.c @@ -0,0 +1,878 @@ +#include +#include +#include "types.h" +#include "arm11/pages.h" +#include "arm11/drivers/mcu.h" + +atp_error_t disp_str( atp_callerdata_t data, atp_counter_t, atp_linecfg_t *cfg ) +{ + cfg->text = (atp_text_t)data; + cfg->text_color = ATP_COLOR_RED; + return ATP_SUCCESS; +} + +/// @brief base process for helping page +/// @param table +/// @param index +/// @param config +/// @return +static atp_error_t display_help( atp_callerdata_t table, atp_counter_t index, atp_linecfg_t *config ) +{ + atp_text_t *list = (atp_text_t*)table; + config->text_align = ATP_PLACEMENT_CENTER; + config->text_color = index == 0 ? ATP_COLOR_MAGENTA : ATP_COLOR_LIGHT; + config->text = list[index]; + return ATP_SUCCESS; +} + +/// @brief display a static page for help +/// @param wording static string array +/// @param length the size of array +/// @return +atp_error_t help_page( atp_text_t *wording, atp_counter_t length ) +{ + atp_text_t current; + atp_tips( "返回:按A/B", ¤t ); + atp_error_t res = atp_show( length, display_help, (atp_callerdata_t)wording ); + atp_tips( current, NULL ); + return res; +} + +// -------------------------- +// code for oaf config page +// -------------------------- +atp_text_t config_help[] = +{ + "全局参数编辑操作指引", + "~ ~ ~ ~ ~ ~ ~", + "-修改后的全局参数保存在config.ini ", + "保存修改时,存档方案的修改不会保存", + "-金手指组合键为下方向+L+R+SELECT", + " 也可以使用HOME键直接代替组合键 ", + "~ ~ ~ ~ ~ ~ ~", + "上下方向键      切换参数项目", + "左右方向键          翻页", + "L键和R键      调整当前参数", + "A键         应用修改退出", + "B键         放弃修改退出", + "X键       应用修改保存退出", // X做保存,选中后走A键流程 +}; +atp_text_t CONFIG_OUTPUT = "[general]\n" \ + "backlight=%d\n" \ + "directBoot=%s\n" \ + "useGbaDb=true\n\n" \ + "[video]\n" \ + "scaler=%d\n" \ + "gbaGamma=2.2\n" \ + "lcdGamma=1.54\n" \ + "contrast=1.0\n" \ + "brightness=0.0\n\n" \ + "[advanced]\n" \ + "saveOverride=false\n" \ + "defaultSave=14\n\n" \ + "[boost]\n" \ + "cheatMode=%d\n"; + +typedef struct global_oaf_config OafConfig; + +static char page_strbuf[512]; + +#define LIGHT_MIN (MCU_getSystemModel() > 3 ? 50 : 20) +#define LIGHT_MAX (MCU_getSystemModel() > 3 ? 800 : 500) +#define SCALER_SIZE 4 +static atp_error_t config_item( atp_callerdata_t gblcfg, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + //static char buf[16]; + OafConfig *g_oafConfig = (OafConfig*)gblcfg; + const char *scaler_val[] = {"上屏无缩放", "上屏GPU放大", "上屏DMA放大", "下屏无缩放"}; + const char *savetype_name[] = {"和卡带序列号一致", "读取ROM的特定标记", "汉化带SRAM补丁", "自行决定"}; + const char *cheatmode_name[] = {"关闭金手指", "全程激活", "组合键单次激活", "组合键激活/关闭"}; + cfg->extra_text_color = ATP_COLOR_GREEN; + if( index == 0 ) + { + ee_snprintf(page_strbuf, sizeof(page_strbuf), "%d", g_oafConfig->backlight); + cfg->text = "屏幕亮度"; + cfg->extra_text = page_strbuf; + if( g_oafConfig->backlight == LIGHT_MIN || g_oafConfig->backlight == LIGHT_MAX ) + cfg->extra_text_color = ATP_COLOR_RED; + } + else if( index == 1 ) + { + cfg->text = "GAME BOY画面"; + cfg->extra_text = g_oafConfig->directBoot ? "跳过" : "显示"; + } + else if( index == 2 ) + { + cfg->text = "画面输出"; + cfg->extra_text = scaler_val[g_oafConfig->scaler]; + } + else if( index == 3 ) + { + cfg->text = "存档方案"; + cfg->extra_text = savetype_name[g_oafConfig->savePolicy]; + } + else if( index == 4 ) + { + cfg->text = "激活金手指"; + cfg->extra_text = cheatmode_name[g_oafConfig->cheatMode]; + } + cfg->value = index; + return ATP_SUCCESS; +} + +static atp_pageopt_t config_adjust( atp_callerdata_t gblcfg, atp_counter_t index, atp_boolean_t x, atp_boolean_t, atp_boolean_t l, atp_boolean_t r, atp_boolean_t start, atp_boolean_t ) +{ + OafConfig *g_oafConfig = (OafConfig*)gblcfg; + if( l || r ) + { + if( index == 0 ) + { + u16 light = g_oafConfig->backlight; + if( l ) + { + light -= 10; + if( light % 10 ) light += 10 - light%10; + } + else if( r ) + { + light += 10; + if( light % 10 ) light -= light % 10; + } + if( light > LIGHT_MAX ) light = LIGHT_MAX; + else if( light < LIGHT_MIN ) light = LIGHT_MIN; + g_oafConfig->backlight = light; + } + else if( index == 1 ) g_oafConfig->directBoot = !g_oafConfig->directBoot; + else if( index == 2 ) g_oafConfig->scaler = ( SCALER_SIZE + ( g_oafConfig->scaler+(l?-1:1) ) ) % SCALER_SIZE; + else if( index == 3 ) g_oafConfig->savePolicy = ( SAVE_POLICY_SIZE + ( g_oafConfig->savePolicy+(l?-1:1) ) ) % SAVE_POLICY_SIZE; + else if( index == 4 ) g_oafConfig->cheatMode = ( CHEAT_MODE_SIZE + (g_oafConfig->cheatMode+(l?-1:1) ) ) % CHEAT_MODE_SIZE; + } + else if( start ) + { + return ATP_POWER_OFF == help_page( config_help, sizeof(config_help)/sizeof(atp_text_t) ) + ? ATP_POWER_OFF : ATP_PAGE_REFRESH; + } + else if( x ) + { + int len = strlen(CONFIG_OUTPUT) + 20; + char *data = malloc( len ); + if( data == NULL ) return ATP_PAGE_DOSELECT; // only ignore this save + + len = ee_snprintf( + data, len, CONFIG_OUTPUT, + g_oafConfig->backlight, g_oafConfig->directBoot ? "true":"false", g_oafConfig->scaler, g_oafConfig->cheatMode + ); + fsQuickWrite("config.ini", data, len); + free( data ); + return ATP_PAGE_DOSELECT; + } + return ATP_PAGE_UPDATE; +} + +atp_error_t use_config_page( OafConfig *g_oafConfig ) +{ + u8 base[sizeof(OafConfig)]; + memcpy( base, g_oafConfig, sizeof(OafConfig) ); + OafConfig *prev = (OafConfig*)&base[0]; + + atp_text_t oldtips; + atp_tips("保存X/确定A/返回B", &oldtips); + + ee_snprintf( + page_strbuf, sizeof(page_strbuf), + "参数配置           当前电量:%3d%%" + "每次开机存档方案重置为“和卡带序列号一致”,这个方案会优先使用游戏最后一次启动时设置的存档类型", MCU_getBatteryLevel()); + atp_error_t res = atp_select( page_strbuf, 5, config_item, config_adjust, g_oafConfig, 0, 0, NULL ); + atp_tips( oldtips, NULL ); + if( res == ATP_NO_ACTION ) + { + memcpy( g_oafConfig, prev, sizeof(OafConfig) ); + return ATP_SUCCESS; + } + else if( res == ATP_SUCCESS ) + { + if( prev->backlight != g_oafConfig->backlight ) + GFX_setBrightness(g_oafConfig->backlight, g_oafConfig->backlight); + } + + return res; +} + + +// -------------------------- +// code for oaf cheat page +// -------------------------- + +#define DISP_DONE 0 +#define DISP_REGION 1 +#define DISP_HOLES 2 +#define DISP_KEYS 3 +#define SAFE_CALLACL( r ) if( ACHTLIB_SUCCESS!=r ) \ + {\ + res = WAIT_ON_ERRPAGE( display_selcht );\ + break;\ + } + +DECLARE_ERROR_PAGE( display_selcht, "查找金手指配置出错" ) +DECLARE_ERROR_PAGE( display_openlib, "打开金手指文件出错" ) +DECLARE_ERROR_PAGE( display_nocheat, "找不到对应的金手指配置" ) + +static atp_error_t select_region( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *config ) +{ + acl_region_t sreg; + acl_chtid_t sid, id; + if( ACHTLIB_SUCCESS != acl_query_cheat_set(index, &sid, &sreg) ) + { + config->text = "导出文件"; + config->value = index; + return ATP_SUCCESS; + } + char *t; + switch( sreg ) + { + case 'C': t = "官方中文"; break; + case 'J': t = "日文版"; break; + case 'E': t = "英文版"; break; + case 'F': t = "法语版"; break; + case 'S': t = "西班牙语"; break; + case 'I': t = "意大利语"; break; + case 'D': t = "德语版"; break; + case 'K': t = "韩文版"; break; + case 'X': case 'P': t = "欧洲语种"; break; + default: t = "其他语种"; break; + } + ee_sprintf(page_strbuf, "%c-%s", 'A'+(char)index, t); + + if( CCHT_NOT_INIT == info_current_cheat( &id, NULL ) ) + id = 0; + + config->text = page_strbuf; + config->value = index; + + // show saved information + if( sid == id ) + { + config->extra_text = "已启用"; + config->extra_text_color = ATP_COLOR_GREEN; + } + return ATP_SUCCESS; +} + +static atp_error_t select_holes( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + acl_text_t text; + acl_error_t res = acl_entry_get_label(index, &text); + if( res == ACHTLIB_SUCCESS ) + cfg->text = text; + else cfg->text = "无效数据"; + cfg->value = 1+index; + + // show saved information + acl_entryid_t id; + if( CCHT_OK == get_current_cheat( index, &id ) && ENT_USING(id) ) + { + cfg->extra_text = "开"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + + return ATP_SUCCESS; +} + +static atp_error_t select_keys( atp_callerdata_t data, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + acl_text_t text; + if( index == 0 ) + { + cfg->text = "不开启"; + } + else + { + acl_error_t res = acl_entry_get_label(index-1, &text); + if( res == ACHTLIB_SUCCESS ) + cfg->text = text; + else cfg->text = "无效数据"; + } + acl_entryid_t eid = (acl_entryid_t)data; + cfg->value = index<<16 | eid; + + if( CCHT_OK == include_current_cheat((acl_entryid_t)cfg->value) ) + { + cfg->extra_text = "选中"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + return ATP_SUCCESS; +} + +static atp_error_t select_onoff( atp_callerdata_t data, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + acl_entryid_t eid = (acl_entryid_t)data; + eid &= 0xffff; + if( index == 0 ) + { + cfg->text = "不开启"; + cfg->value = eid; + } + else if( index == 1 ) + { + cfg->text = "开启"; + cfg->value = 1<<16 | eid; + } + else + { + cfg->text = "调整数值开启[结果未知]"; + cfg->value = 0; + } + + // show saved information + if( CCHT_OK == include_current_cheat((acl_entryid_t)cfg->value) ) + { + cfg->extra_text = "选中"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + return ATP_SUCCESS; +} + +ALWAYS_INLINE u16 calc_step( u16 value ) +{ + u16 n = value / 50; + if( n == 0 ) return 1; + else + { + u16 base = 1; + while( n > 10 ) + { + n = n/10; + base *= 10; + } + if( n < 5 ) return base * 5; + else return base * 10; + } +} + +static atp_error_t step_provider( atp_callerdata_t mixid, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + u32 mix = (u32)mixid; + u16 max = mix & 0xffff; + u16 step = mix >> 16; + u16 res = step * (index+1); + ee_snprintf( page_strbuf, 8, "%d", res < max ? res : max ); + cfg->text = page_strbuf; + cfg->value = res < max ? res : max; + return ATP_SUCCESS; +} + +static atp_error_t handle_onoff_entry( acl_entryid_t id, acl_elemlen_t codelen, atp_itemval_t *item ) +{ +#define DEFAULT_ONOFF_HANDLER atp_select("选择此项目对应的设置", 2, select_onoff, NULL, (atp_callerdata_t)id, 0, 0, item); +#define ONOFF_SAFE_CALLACL( statement ) if( ACHTLIB_SUCCESS != statement ) return DEFAULT_ONOFF_HANDLER; + + if( codelen > 4 )// more than 2 address + return DEFAULT_ONOFF_HANDLER; + + u16 targetval = 0; + acl_armcode_t code; + + // one address + if( codelen == 2 ) + { + ONOFF_SAFE_CALLACL( acl_entry_get_armcode(1, &code) ); + targetval = code & 0xff; + } + // two addresses + else if( codelen == 4 ) + { + u32 addr0, addr1; + ONOFF_SAFE_CALLACL( acl_entry_get_armcode(0, &addr0) ); + ONOFF_SAFE_CALLACL( acl_entry_get_armcode(2, &addr1) ); + if( (addr0 & 1) || (addr0 | 1) != addr1 ) // valid u16 address + return DEFAULT_ONOFF_HANDLER; + + ONOFF_SAFE_CALLACL( acl_entry_get_armcode(1, &code) ); + targetval = code & 0xff; + ONOFF_SAFE_CALLACL( acl_entry_get_armcode(3, &code) ); + targetval |= (code & 0xff) << 8; + } + // more than two address, should not overwrite values + else return DEFAULT_ONOFF_HANDLER; + + atp_error_t res = atp_select( "选择此项目对应的设置", 3, select_onoff, NULL, targetval << 16 | id, 0, 0, item ); + if( res == ATP_SUCCESS && *item == 0 ) + { + ee_snprintf( page_strbuf, sizeof(page_strbuf), "默认值:%d", targetval ); + u16 step = calc_step( targetval ); + atp_counter_t n = (targetval-1+step)/step; + res = atp_select(page_strbuf, n, step_provider, NULL, (atp_callerdata_t)(step<<16|targetval), n, 0, item ); + if( res == ATP_SUCCESS && *item != targetval ) + overwrite_current_cheat( 1<<16|id, *item ); + + *item = 1<<16 | id; + } + return res; +} + +atp_error_t use_cheat_page( const char *serial ) +{ + acl_count_t len; + if( ACHTLIB_SUCCESS != acl_open_lib( "gba.acl" ) ) + { + return WAIT_ON_ERRPAGE( display_openlib ); + } + if( ACHTLIB_SUCCESS != acl_select_game( serial, 0, &len ) ) + { + acl_close_lib(); + return WAIT_ON_ERRPAGE( display_selcht ); + } + if( len == 0 ) + { + acl_close_lib(); + return WAIT_ON_ERRPAGE( display_nocheat ); + } + + // 显示配置页面 + atp_error_t res; + atp_itemval_t item; + acl_elemlen_t cnt; + + uint8_t status = DISP_REGION; + atp_counter_t defi = 0; + acl_entryid_t eid = 0; + atp_text_t oldtips; + atp_tips("确定A/返回B", &oldtips); + + while( status != DISP_DONE ) + { + if( status == DISP_REGION ) + { +#ifdef NDEBUG + res = atp_select("请谨慎使用金手指!金手指可能会引起卡顿、死机、损坏存档等现象。           " + "选择一个金手指配置:", len, select_region, NULL, NULL, defi, 0, &item ); +#else + res = atp_select("请谨慎使用金手指!金手指可能会引起卡顿、死机、损坏存档等现象。           " + "选择一个金手指配置:", len+1, select_region, NULL, NULL, defi, 0, &item ); +#endif + if( res == ATP_SUCCESS ) + { +#ifndef NDEBUG + if( item == len ) + { + extern u8 dump_patched_rom; + dump_patched_rom = 1; + break; + } +#endif + defi = item; + acl_chtid_t sid; + acl_elemlen_t len; + u32 ccid, cclen; + SAFE_CALLACL( acl_query_cheat_set((acl_index_t)item, &sid, NULL ) ); + SAFE_CALLACL( acl_select_cheat_set( sid ) ); + SAFE_CALLACL( acl_select_entry(0, &len) ); + + if( CCHT_OK == info_current_cheat(&ccid, &cclen) ) + { + // SKIP the init process when id and len is the same + if( ccid != sid || cclen != len ) + init_current_cheat( sid, len ); + } + else init_current_cheat( sid, len ); + + eid = 0; + status = DISP_HOLES; + } + else if( res == ATP_NO_ACTION) + { + status = DISP_DONE; + } + else break; + } + else if( status == DISP_HOLES ) + { + SAFE_CALLACL( acl_select_entry(0, &cnt) ); + res = atp_select("选择一个金手指项目", cnt, select_holes, NULL, NULL, eid > 0 ? (eid&0xffff)-1 : 0, 0, &item); + if( res == ATP_SUCCESS ) + { + eid = (acl_entryid_t)item; + status = DISP_KEYS; + } + else if( res == ATP_NO_ACTION ) + { + status = DISP_REGION; + } + else break; + } + else // DISP_KEYS + { + SAFE_CALLACL( acl_select_entry( eid, &cnt ) ); + if( cnt == 0 ) + { + SAFE_CALLACL( acl_select_entry( 1<<16 | eid, &cnt ) ); + res = handle_onoff_entry( eid, cnt, &item ); + } + else + { + res = atp_select("选择此项目对应的设置", cnt, select_keys, NULL, (atp_callerdata_t)eid, 0, 0, &item); + } + if( res == ATP_SUCCESS ) + { + put_current_cheat( (acl_entryid_t)item ); + status = DISP_HOLES; + } + else if( res == ATP_NO_ACTION ) + { + status = DISP_HOLES; + } + else break; + } + } + + acl_close_lib(); + atp_tips( oldtips, NULL ); + return res; +} + +// -------------------------- +// code for oaf cheat page +// -------------------------- + +#define DISP_KPOS 1 +#define DISP_SETK 2 // SET KEY +#define DISP_KMAP 3 // REMUX TYPE +#define DISP_3DSK 4 // 3DS KEY +#define DISP_GBAK 5 // GBA KEY + +#define KCP_OPTION_BASE 1000 + +#define KRFIELD_REMIX 0 +#define KRFIELD_DEVICE 1 +#define KRFIELD_GAME 2 + +DECLARE_ERROR_PAGE( display_conflictkey, "和已有键位产生冲突" ) + +const char *key_name[] = { + "上", "下", "左", "右", "A", "B", "L", "R", "SELECT", "START", "X", "Y", "ZL", "ZR" +}; +const u16 key_val[] = { + KEY_DUP, KEY_DDOWN, KEY_DLEFT, KEY_DRIGHT, KEY_A, KEY_B, KEY_L, KEY_R, KEY_SELECT, KEY_START, KEY_X, KEY_Y, KEY_ZL, KEY_ZR +}; +#define key_val_len (sizeof(key_val)/sizeof(u16)) + +static inline void key_tips( key_remix_t *p, atp_boolean_t checking, atp_itemcfg_t *cfg ) +{ + if( p->remix_type == REMIX_TYPE_NONE ) + { + cfg->extra_text = "未添加"; + cfg->extra_text_color = ATP_COLOR_LIGHT; + } + else + { + if( p->remix_type == REMIX_TYPE_CHEAT ) + { + if( checking && p->game_keys == 0) + { + cfg->extra_text = "配置不齐"; + cfg->extra_text_color = ATP_COLOR_RED; + } + else + { + cfg->extra_text = "金手指键"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + } + else if( p->remix_type == REMIX_TYPE_REMAP ) + { + if( checking && (p->game_keys==0 || p->device_keys==0) ) + { + cfg->extra_text = "配置不齐"; + cfg->extra_text_color = ATP_COLOR_RED; + } + else + { + cfg->extra_text = "键位映射"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + } + else if( p->remix_type == REMIX_TYPE_HOLD ) + { + if( checking && (p->game_keys==0 || p->device_keys==0) ) + { + cfg->extra_text = "配置不齐"; + cfg->extra_text_color = ATP_COLOR_RED; + } + else + { + cfg->extra_text = "模拟长按"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + } + } +} + +static atp_error_t select_krp( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + if( index < KEY_REMIX_LIMIT ) + { + ee_snprintf(page_strbuf, sizeof(page_strbuf), "键位配置项%ld", index+1); + cfg->text = page_strbuf; + cfg->value = index; + key_remix_t *p = &g_keyremixConfig[index]; + key_tips(p, 1, cfg); + } + else + { + cfg->text = index == KEY_REMIX_LIMIT ? "保存当前配置到SD卡" : "从SD卡加载已保存的配置"; + cfg->value = KCP_OPTION_BASE + index-KEY_REMIX_LIMIT; + } + return ATP_SUCCESS; +} + +static atp_error_t select_kcf( atp_callerdata_t p, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + key_remix_t *kcfg = (key_remix_t*)p; + if( index == KRFIELD_REMIX ) + { + cfg->text = "选择键位功能"; + key_tips(kcfg, 0, cfg); + } + else if( index == KRFIELD_DEVICE ) + { + cfg->text = "选择实机键位"; + if( kcfg->device_keys ) + { + for( u8 i=0; i < key_val_len; ++i) + { + if( key_val[i] == kcfg->device_keys ) + { + cfg->extra_text = key_name[i]; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + } + } + else if( kcfg->remix_type == REMIX_TYPE_CHEAT ) + { + cfg->extra_text = "HOME"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + else + { + cfg->extra_text = "未设置"; + cfg->extra_text_color = ATP_COLOR_LIGHT; + } + } + else if( index == KRFIELD_GAME ) + { + cfg->text = "游戏中对应键位"; + if( kcfg->game_keys == 0 ) + { + cfg->extra_text = "未设置"; + cfg->extra_text_color = ATP_COLOR_LIGHT; + } + else + { + cfg->extra_text = "已设置"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + } + cfg->value = index; + return ATP_SUCCESS; +} +static atp_error_t select_remixtype( atp_callerdata_t, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + if( index == REMIX_TYPE_NONE ) cfg->text = "停用设置"; + else if( index == REMIX_TYPE_REMAP ) cfg->text = "键位映射"; + else if( index == REMIX_TYPE_CHEAT ) cfg->text = "金手指键"; + else if( index == REMIX_TYPE_HOLD ) cfg->text = "模拟长按"; + cfg->value = index; + return ATP_SUCCESS; +} +static atp_error_t select_unikey( atp_callerdata_t str, atp_counter_t, atp_itemcfg_t *cfg ) +{ + cfg->text = (atp_text_t)str; + cfg->value = 0; + return ATP_SUCCESS; +} +static atp_error_t select_hostkey( atp_callerdata_t dat, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + phykey_t k = (phykey_t)dat; + cfg->text = key_name[index]; + cfg->value = key_val[index]; + if( k == key_val[index] ) + { + cfg->extra_text = "选中"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + return ATP_SUCCESS; +} + +static atp_error_t select_gbakey( atp_callerdata_t p_curkey, atp_counter_t index, atp_itemcfg_t *cfg ) +{ + conkey_t key = *(conkey_t*)p_curkey; + cfg->text = key_name[index]; + cfg->value = key_val[index]; + if( key & key_val[index] ) + { + cfg->extra_text = "选中"; + cfg->extra_text_color = ATP_COLOR_GREEN; + } + return ATP_SUCCESS; +} + +static atp_error_t active_gbakey( atp_callerdata_t p_curkey, atp_counter_t index, atp_boolean_t x, atp_boolean_t y, atp_boolean_t l, atp_boolean_t r, atp_boolean_t start, atp_boolean_t select ) +{ + conkey_t *pkey = (conkey_t*)p_curkey; + if( x ) + { + conkey_t res = *pkey & key_val[index]; + if( res ) *pkey &= ~key_val[index]; + else *pkey |= key_val[index]; + return ATP_PAGE_UPDATE; + } + else return ATP_PAGE_NOOPTION; +} + +atp_error_t use_keyremix_page( char *file ) +{ + atp_itemval_t position=0, field=0, value; + atp_error_t res; + atp_text_t oldtips; + atp_tips( "确定A/返回B", &oldtips ); + + uint8_t status = DISP_KPOS; + while ( status != DISP_DONE ) + { + if ( status == DISP_KPOS) + { + res = atp_select( "选择配置项后,按A进行键位配置", KEY_REMIX_LIMIT+2, select_krp, NULL, NULL, position, 0, &position ); + if( res == ATP_SUCCESS ) + { + + if( position < KEY_REMIX_LIMIT ) + { + status = DISP_SETK; + field = 0; + } + else if( position == KCP_OPTION_BASE ) + { + const char *err = keyremix_dump( file ); + if( !err ) status = DISP_DONE; + else atp_show( 1, disp_str, err ); + } + else + { + const char *err = keyremix_load( file ); + if( !err ) position = 0; + else atp_show( 1, disp_str, err ); + } + } + else break; + } + else if( status == DISP_SETK ) + { + ee_snprintf(page_strbuf, sizeof(page_strbuf), "编辑配置项%ld", position+1); + key_remix_t *cur = &g_keyremixConfig[position]; + res = atp_select( page_strbuf, 3, select_kcf, NULL, cur, field, 0, &field ); + if( res == ATP_SUCCESS ) + { + status = field == KRFIELD_REMIX ? DISP_KMAP : (field == KRFIELD_DEVICE ? DISP_3DSK : DISP_GBAK); + } + else if( res == ATP_NO_ACTION ) + { + int fault = 0; + for( int i=0; i < KEY_REMIX_LIMIT; ++i ) + { + if( i!=position ) + { + if( g_keyremixConfig[i].remix_type == cur->remix_type + && g_keyremixConfig[i].device_keys == cur->device_keys ) + { + fault = 1; + break; + } + } + } + if( fault && cur->remix_type != REMIX_TYPE_NONE ) + atp_show(1, display_conflictkey, NULL); + else status = DISP_KPOS; + } + else break; + } + else if( status == DISP_KMAP ) + { + key_remix_t *cur = &g_keyremixConfig[position]; + res = atp_select( "配置键位功能", REMIX_TYPE_COUNT, select_remixtype, NULL, cur->remix_type, 0, 0, &value ); + if( res == ATP_SUCCESS ) + { + if( cur->remix_type != value ) + { + cur->remix_type = value; + cur->device_keys = 0; + cur->game_keys = value == REMIX_TYPE_CHEAT ? DEFAULT_CHEATKEY : 0; + } + status = DISP_SETK; + } + else if( res == ATP_NO_ACTION ) + { + status = DISP_SETK; + } + else break; + } + else if( status == DISP_3DSK ) + { + key_remix_t *cur = &g_keyremixConfig[position]; + atp_counter_t keys_count = 12; // old 3ds, old 3dsLL, 2ds + u8 host = MCU_getSystemModel();// 0=3ds 1=3dsll 2=n3ds 3=2ds 4=n3dsll 5=n2dsll + atp_text_t text; + if( cur->remix_type == REMIX_TYPE_CHEAT ) + { + keys_count = 1; + text = "HOME"; + } + else if( host > 1 && host != 3 ) // N3DS/N3DSLL/N2DSLL + { + keys_count = 14; + } + u8 selected = 31; + for( u8 i=0; i < key_val_len; ++i ) + { + if( key_val[i] == cur->device_keys ) + { + selected = i; + break; + } + } + if( keys_count == 1 ) res = atp_select("选择实机键位(单选)", 1, select_unikey, NULL, text, 0, 0, &value); + else res = atp_select( "选择实机键位(单选)", keys_count, select_hostkey, NULL, cur->device_keys, selected>keys_count?0:selected, 0, &value); + if( res == ATP_SUCCESS ) + { + cur->device_keys = value; + status = DISP_SETK; + } + else if( res == ATP_NO_ACTION ) + { + status = DISP_SETK; + } + else break; + } + else if( status == DISP_GBAK ) + { + key_remix_t *cur = &g_keyremixConfig[position]; + conkey_t key_editing = cur->game_keys; + atp_text_t current; + atp_tips("选择X/确定A/返回B", ¤t); + res = atp_select( "选择游戏中对应键位[多选,按X键设置选中]", 10, select_gbakey, active_gbakey, &key_editing, 0, 0, &value); + atp_tips( current, NULL ); + if( res == ATP_SUCCESS ) + { + cur->game_keys = key_editing; + status = DISP_SETK; + } + else if( res == ATP_NO_ACTION ) + { + status = DISP_SETK; + } + else break; + } + } + + atp_tips( oldtips, NULL ); + return res; +} \ No newline at end of file