2024-04-24 16:30:43 +08:00

938 lines
28 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "types.h"
#include "fsutil.h"
#include "arm11/pages.h"
#include "arm11/drivers/mcu.h"
#include "arm11/fmt.h"
#include "drivers/gfx.h"
#include "arm11/open_agb_firm.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=%s\n\n" \
"[video]\n" \
"scaler=%d\n" \
"gbaGamma=%s\n" \
"lcdGamma=%s\n" \
"contrast=%s\n" \
"brightness=%s\n\n" \
"[advanced]\n" \
"saveOverride=false\n" \
"defaultSave=%d\n\n" \
"[boost]\n" \
"cheatMode=%d\n"\
"haltMode=%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[] = {"关闭金手指", "全程激活", "组合键单次激活", "组合键激活/关闭"};
const char *haltmode_name[] = {"关闭3DS", "停止游戏"};
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];
}
else if( index == 5 )
{
cfg->text = "游戏中按住电源键";
cfg->extra_text = haltmode_name[g_oafConfig->haltMode];
}
cfg->value = index;
return ATP_SUCCESS;
}
static char* float2str( float f, char out[16] )
{
int s = (int)f;
if( f < 0 ) f = -f;
f = f - floor(f);
f *= 100;
int n = floor(f);
f = f - n;
if( f > 0.5) ++n;
if( n == 100 )
{
++s;
n = 0;
}
ee_snprintf(out, 16, "%d.%02d", s, n);
return out;
}
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( index == 5 ) {
size_t len = strlen( FIRMPATH_INCOME );
if( len < FIRMPATH_SIZELIMIT )
{
g_oafConfig->haltMode = ( HALT_MODE_SIZE + (g_oafConfig->haltMode+(l?-1:1) ) ) % HALT_MODE_SIZE;
}
else if( !oafRebootReady() )
{
return ATP_POWER_OFF == atp_show(1, disp_str, "请正确放置boot.firm文件")
? ATP_POWER_OFF : ATP_PAGE_REFRESH;
}
else
{
return ATP_POWER_OFF == atp_show(1, disp_str, "SD卡的open_agb_firm文件名太长")
? ATP_POWER_OFF : ATP_PAGE_REFRESH;
}
}
}
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) + 40;
char *data = malloc( len );
if( data == NULL ) return ATP_PAGE_DOSELECT; // only ignore this save
char gbaGamma[16];
char lcdGamma[16];
char contract[16];
char brightness[16];
len = ee_snprintf(
data, len, CONFIG_OUTPUT,
g_oafConfig->backlight,
g_oafConfig->directBoot ? "true":"false",
g_oafConfig->useGbaDb ? "true" : "false",
g_oafConfig->scaler,
float2str(g_oafConfig->gbaGamma, gbaGamma),
float2str(g_oafConfig->lcdGamma, lcdGamma),
float2str(g_oafConfig->contrast, contract),
float2str(g_oafConfig->brightness, brightness),
g_oafConfig->defaultSave,
g_oafConfig->cheatMode,
g_oafConfig->haltMode
);
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, 6, 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;
}