!6 将sel/x/y对应的配置页移动到page.c

Merge pull request !6 from anod/dev_cheat
This commit is contained in:
anod 2023-05-11 01:03:47 +00:00 committed by Gitee
commit 8ecab438e0
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 1039 additions and 921 deletions

View File

@ -107,8 +107,8 @@ extern atp_error_t atp_select(
); );
extern atp_error_t atp_tips( extern atp_error_t atp_tips(
INPUT(atp_text_t) tips_at_bottom_left, INPUT(atp_text_t) tips_string,
INPUT(atp_text_t) tips_at_bottom_right OUTPUT(atp_text_t) tips_before
); );
#undef INPUT #undef INPUT

View File

@ -20,10 +20,42 @@
#include "error_codes.h" #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); Result oafParseConfigEarly(void);
u8 oafGetBacklightConfig(void); u8 oafGetBacklightConfig(void);
Result oafInitAndRun(void); Result oafInitAndRun(void);
void oafUpdate(void); void oafUpdate(void);
void oafFinish(void); void oafFinish(void);
int oafCheatMode(void);

29
include/arm11/pages.h Normal file
View File

@ -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__

View File

@ -7,8 +7,8 @@
#define TITLE_MAX 8 #define TITLE_MAX 8
#define TIPS_MAX 64 #define TIPS_MAX 64
static char ta[TIPS_MAX] = {'\0'}; static char dymt[TIPS_MAX] = {'\0'};
static char tb[TIPS_MAX] = {'\0'}; static atp_text_t stct = NULL;
#define ATP_COLOR_SIZE (ATP_COLOR_WHITE+1) #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() static void screen_clean()
{ {
memset(consoleGet()->frameBuffer, 0, WINDOW_WIDTH*WINDOW_HEIGHT*sizeof(uint16_t)); 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( dymt[0] ) acf_put_text( 5, 215, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH-10, ATP_COLOR_CYAN, ATP_PLACEMENT_LEFT, dymt );
if( tb[0] ) acf_put_text( 5, 215, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH-10, ATP_COLOR_CYAN, ATP_PLACEMENT_RIGHT, tb ); 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 ) static void screen_clean_zone( int x, int y, int w, int h )
@ -108,6 +108,13 @@ static uint32_t waitKey()
return down; 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( \ #define easy_put(text, align, color, row) acf_put_text( \
CONTAINER_LEFTTOP_X, \ CONTAINER_LEFTTOP_X, \
CONTAINER_LEFTTOP_Y+FONT_HEIGHT*(row), \ 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 ) atp_error_t atp_show( atp_counter_t cnt, atp_lineprovider_t provider, atp_callerdata_t data )
{ {
int idx_top = 0; int idx_top = 0;
dynamic_tips(" ");
screen_clean(); screen_clean();
container_paint( provider, data, cnt, idx_top ); 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; unsigned current = top / CONTAINER_MAX_LINES;
char buf[32]; char buf[32];
ee_snprintf( buf, sizeof(buf), "页码:%d/%d", current+1, total ); 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(); 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 ); if( strlen(tips) > TIPS_MAX-1 )
ta[TIPS_MAX-1] = 0; return ATP_INDEX_OUTOFRANGE;
}
if( tipsB != NULL ) stct = tips;
{
strncpy( tb, tipsB, TIPS_MAX-1 );
tb[TIPS_MAX-1] = 0;
} }
return ATP_SUCCESS; return ATP_SUCCESS;
} }

View File

@ -32,6 +32,7 @@
#include "arm11/atp.h" #include "arm11/atp.h"
#include "arm11/acl.h" #include "arm11/acl.h"
#include "arm11/cheat.h" #include "arm11/cheat.h"
#include "arm11/pages.h"
#include "arm11/keyremix.h" #include "arm11/keyremix.h"
#define screenClean() memset(consoleGet()->frameBuffer, 0, CWIDTH*CHEIGHT*sizeof(uint16_t)) #define screenClean() memset(consoleGet()->frameBuffer, 0, CWIDTH*CHEIGHT*sizeof(uint16_t))
@ -181,7 +182,7 @@ static atp_text_t folder_help[] = {
"A键      查看目录或启动游戏", "A键      查看目录或启动游戏",
"B键          上层文件夹", "B键          上层文件夹",
"X键            金手指", "X键            金手指",
"Y键           暂不使用", "Y键         配置游戏键位",
"START        查看说明", "START        查看说明",
"SELECT       系统设置" "SELECT       系统设置"
}; };
@ -204,46 +205,11 @@ static atp_error_t display_folder( atp_callerdata_t data, atp_counter_t index, a
return ATP_SUCCESS; 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_noserial, "提取游戏识别码失败" )
DECLARE_ERROR_PAGE( display_nocheat, "找不到对应的金手指配置" )
DECLARE_ERROR_PAGE( display_empty, "没有合适的文件" ) DECLARE_ERROR_PAGE( display_empty, "没有合适的文件" )
DECLARE_ERROR_PAGE( display_toolong, "路径过长,改名或移动文件后再试" ) DECLARE_ERROR_PAGE( display_toolong, "路径过长,改名或移动文件后再试" )
DECLARE_ERROR_PAGE( display_pathfull, "游戏或目录过量最多显示999个" ) DECLARE_ERROR_PAGE( display_pathfull, "游戏或目录过量最多显示999个" )
DECLARE_ERROR_PAGE( display_longname, "文件名总计过长,只显示前面的文件" ) 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, ... ) { /*void log( const char *fmt, ... ) {
char buf[512]; 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 ); }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(); extern atp_error_t oaf_config_page();
#define DIRBUFFSIZE 512 #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 ) 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 ) if( start )
{ {
atp_tips( "", NULL ); return WAIT_ON_ACT( use_help_page( folder_help ) );
return WAIT_ON_ACT( help_page( folder_help, sizeof(folder_help)/sizeof(atp_text_t) ) );
} }
else if( select ) 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 ) else if( x )
{ {
extern int get_cheat_mode(); if( CHEAT_MODE_DISABLED == oafCheatMode() )
if( CHEAT_MODE_DISABLED == get_cheat_mode() ) return WAIT_ON_ACT( use_help_page(cheat_off_help) );
{
return WAIT_ON_ACT( help_page( cheat_off_help, sizeof(cheat_off_help)/sizeof(atp_text_t) ) );
}
void* *dat = (void **)data; void* *dat = (void **)data;
DirList const *dList = (DirList*)dat[0]; DirList const *dList = (DirList*)dat[0];
char *path = (char*)dat[1]; 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; else RECOVER_PATH;
acl_count_t len; return WAIT_ON_ACT( use_cheat_page( serial ) );
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 );
} }
else if( y ) 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; void* *dat = (void **)data;
DirList const *dList = (DirList*)dat[0]; DirList const *dList = (DirList*)dat[0];
char *file = &dList->ptrs[index][1]; char *file = &dList->ptrs[index][1];
if( position < KEY_REMIX_LIMIT ) return WAIT_ON_ACT( use_keyremix_page(file) );
{
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;
}
}
return WAIT_ON_ACT(res);
} }
return ATP_PAGE_NOOPTION; return ATP_PAGE_NOOPTION;
@ -1022,7 +340,7 @@ Result browseFiles(const char *const basePath, char selected[512])
{ {
GFX_waitForVBlank0(); GFX_waitForVBlank0();
hidScanInput(); hidScanInput();
atp_tips( NULL, "指引按START" ); atp_tips( "指引按START", NULL );
void *cust[2] = {dList, curDir}; void *cust[2] = {dList, curDir};
error = atp_select( curDir, count, display_folder, serve_on_key, (atp_callerdata_t)cust, selecting, 0, &value ); 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 ) if( strcmp(curDir, FS_DRIVE_NAMES) == 0 )
{ {
atp_tips("没有上层目录", NULL); atp_show(1, disp_str, "没有上层目录");
help_page( folder_help, sizeof(folder_help)/sizeof(atp_text_t) );
atp_tips("", NULL);
} }
else DIRUP; else DIRUP;
} }

View File

@ -7,12 +7,13 @@
key_remix_t g_keyremixConfig[KEY_REMIX_LIMIT]; key_remix_t g_keyremixConfig[KEY_REMIX_LIMIT];
static key_remix_t *frozen_start, *frozen_end; 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 conkey_t blind_conkey;
static u16 flags_holding = 0; static u16 flags_holding = 0;
#define DIR_SEPARATOR "/" #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 VKEY_HOME (1u<<21)
#define now_release( now, prev, key ) ((~(now))&(prev)&(key)) #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) #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,9 +30,11 @@ uint16_t keyremix_cheatkey()
void keyremix_freeze() void keyremix_freeze()
{ {
// 空白选项忽略填充blind_conkey金手指放首位 // 空白选项忽略填充blind_conkey金手指放首位REMAP紧跟金手指HOLD在后面
key_remix_t temp[KEY_REMIX_LIMIT+1]; 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; blind_conkey = 0;
for( int i=0; i < KEY_REMIX_LIMIT; ++i ) for( int i=0; i < KEY_REMIX_LIMIT; ++i )
{ {
@ -43,41 +46,59 @@ void keyremix_freeze()
temp[0].game_keys = p->game_keys; temp[0].game_keys = p->game_keys;
has_cheat = 1; 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].remix_type = p->remix_type;
temp[j].device_keys = p->device_keys; temp[j].device_keys = p->device_keys;
temp[j].game_keys = p->game_keys; temp[j].game_keys = p->game_keys;
if( p->device_keys & CON_KEY_MASK )
blind_conkey |= p->device_keys;
++j; ++j;
} }
} else if( p->remix_type == REMIX_TYPE_HOLD
memset( g_keyremixConfig, 0, sizeof(g_keyremixConfig) ); && p->device_keys != 0
if( has_cheat ) && p->game_keys != 0 )
{ {
memcpy( g_keyremixConfig, temp, sizeof(key_remix_t)*j ); temp[k].remix_type = p->remix_type;
frozen_start = &g_keyremixConfig[1]; temp[k].device_keys = p->device_keys;
frozen_end = &g_keyremixConfig[j]; temp[k].game_keys = p->game_keys;
++k;
} }
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 ) void keyremix_update( uint16_t active_cheatkey )
{ {
phykey_t now = hidKeysHeld(); phykey_t now = hidKeysHeld();
conkey_t cur = 0;
u8 init_cur = 0;
vu16 *hid_set = (vu16*)0x10141112; vu16 *hid_set = (vu16*)0x10141112;
vu16 *hid_mode = (vu16*)0x10141110; vu16 *hid_mode = (vu16*)0x10141110;
if( hidGetExtraKeys(0) & KEY_HOME ) if( hidGetExtraKeys(0) & KEY_HOME )
now |= VKEY_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_mode = active_cheatkey;
*hid_set = ~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 ) else if( p->remix_type == REMIX_TYPE_HOLD )
{ {
if( init_cur == 0 )
{
init_cur = 1;
cur = res;
}
uint16_t flag = 1<<holding_pos++; uint16_t flag = 1<<holding_pos++;
uint16_t oldf = flags_holding; uint16_t oldf = flags_holding;
if( now_release(now, prev_status, p->device_keys) ) if( now_release(now, prev_phykey, p->device_keys) )
flags_holding ^= flag; flags_holding ^= flag;
if( flags_holding & flag ) if( flags_holding & flag )
{ {
// exclude console keys is up // 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 else if( oldf != flags_holding )// release
{ {
@ -128,7 +154,8 @@ void keyremix_update( uint16_t active_cheatkey )
*hid_mode = CON_KEY_MASK; *hid_mode = CON_KEY_MASK;
*hid_set = ~res; *hid_set = ~res;
} }
prev_status = now; prev_phykey = now;
prev_conkey = cur;
} }
const char* keyremix_load( const char *file ) const char* keyremix_load( const char *file )

View File

@ -40,6 +40,8 @@
#include "arm11/atp.h" #include "arm11/atp.h"
#include "arm11/cheat.h" #include "arm11/cheat.h"
#include "arm11/keyremix.h" #include "arm11/keyremix.h"
#include "arm11/pages.h"
#include "arm11/open_agb_firm.h"
#include "kernel.h" #include "kernel.h"
#include "kevent.h" #include "kevent.h"
#include "arm11/drivers/codec.h" #include "arm11/drivers/codec.h"
@ -61,40 +63,9 @@
"[advanced]\n" \ "[advanced]\n" \
"saveOverride=false\n" \ "saveOverride=false\n" \
"defaultSave=14" "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 #define CHEAT_INUSE_ADDR (0x3007FE0u) // see GBATek - Default memory usage at 03007FXX
typedef struct typedef struct global_oaf_config OafConfig;
{
// [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 typedef struct
{ {
@ -144,7 +115,7 @@ Result dump_rom( u32 size )
u8 *p = ROM_LOC; u8 *p = ROM_LOC;
u32 len; 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 ) for( u8 *p=ROM_LOC; size > 0; size-=len, p+=len )
{ {
res = fWrite( file, p, size < 256 ? size : 256, &len ); res = fWrite( file, p, size < 256 ? size : 256, &len );
@ -158,7 +129,7 @@ Result dump_rom( u32 size )
break; break;
if( ((u32)p-ROM_LOC) % (1024*64) == 0) 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 ); fClose( file );
@ -170,159 +141,14 @@ Result dump_rom( u32 size )
// -------------------------- // --------------------------
// code for oaf config page // code for oaf config page
// -------------------------- // --------------------------
atp_text_t config_help[] = int oafCheatMode()
{
"全局参数编辑操作指引",
"~ ~ ~ ~ ~ ~ ~",
"-修改后的全局参数保存在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()
{ {
return g_oafConfig.cheatMode; 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() atp_error_t oaf_config_page()
{ {
u8 base[sizeof(g_oafConfig)]; return use_config_page(&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;
} }
// cache the savetype // cache the savetype
@ -987,8 +813,8 @@ static Result showFileBrowser(char romAndSavePath[512])
if(cmpLen < strlen(lastDir) || strncmp(lastDir, romAndSavePath, cmpLen) != 0) if(cmpLen < strlen(lastDir) || strncmp(lastDir, romAndSavePath, cmpLen) != 0)
{ {
strncpy(lastDir, romAndSavePath, cmpLen); strncpy(lastDir, romAndSavePath, cmpLen);
lastDir[cmpLen] = '\0'; lastDir[cmpLen] = '\n';
res = fsQuickWrite("lastdir.txt", lastDir, cmpLen + 1); res = fsQuickWrite("lastdir.txt", lastDir, strlen(lastDir));
} }
} }
} while(0); } while(0);

878
source/arm11/pages.c Normal file
View File

@ -0,0 +1,878 @@
#include <string.h>
#include <stdlib.h>
#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", &current );
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", &current);
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;
}