diff --git a/include/gint/keyboard.h b/include/gint/keyboard.h index 6347507..1289991 100644 --- a/include/gint/keyboard.h +++ b/include/gint/keyboard.h @@ -70,7 +70,7 @@ extern "C" { * keyreleased() checks if the specified key is currently up and was down at the time of the last cleareventflips(). - A typical game loop might look like. cleareventflisps() must be called + A typical game loop might look like. cleareventflips() must be called _before_ clearevents(). cleareventflips(); @@ -116,13 +116,13 @@ typedef struct { uint time :16; /* Time of event, unique over short periods */ - uint :3; /* Reserved for future use */ + uint :2; /* Reserved for future use */ uint mod :1; /* Whether modifiers are used */ uint shift :1; /* If mod=1, whether SHIFT was pressed */ uint alpha :1; /* If mod=1, whether ALPHA was pressed */ - uint type :2; /* Type of key event */ + uint type :3; /* Type of key event */ uint key :8; /* Hit key */ } GPACKED(4) key_event_t; @@ -130,10 +130,11 @@ typedef struct /* Keyboard event types, as in the [type] field of key_event_t */ enum { - KEYEV_NONE = 0, /* No event available (poll() only) */ - KEYEV_DOWN = 1, /* Key was pressed */ - KEYEV_UP = 2, /* Key was released */ - KEYEV_HOLD = 3, /* A key that was pressed has been held down */ + KEYEV_NONE = 0, /* No event available (poll() only) */ + KEYEV_DOWN = 1, /* Key was pressed */ + KEYEV_UP = 2, /* Key was released */ + KEYEV_HOLD = 3, /* A key that was pressed has been held down */ + KEYEV_OSMENU = 4, /* We went to the main menu and back */ }; /* Keyboard frequency analysis is a runtime setting since gint 2.4. This macro @@ -239,24 +240,29 @@ key_event_t getkey(void); /* The following are the option bits for getkey_opt(). */ enum { /* Enable modifiers keys */ - GETKEY_MOD_SHIFT = 0x01, - GETKEY_MOD_ALPHA = 0x02, + GETKEY_MOD_SHIFT = 0x0001, + GETKEY_MOD_ALPHA = 0x0002, /* SHIFT + OPTN (requires GETKEY_MOD_SHIFT) or LIGHT toggles backlight */ - GETKEY_BACKLIGHT = 0x04, + GETKEY_BACKLIGHT = 0x0004, /* MENU triggers a task switch and displays the main menu */ - GETKEY_MENU = 0x08, + GETKEY_MENU = 0x0008, /* Repeat arrow keys, or even all keys */ - GETKEY_REP_ARROWS = 0x10, - GETKEY_REP_ALL = 0x20, + GETKEY_REP_ARROWS = 0x0010, + GETKEY_REP_ALL = 0x0020, /* Enable custom repeat profiles; see getkey_set_repeat_profile() */ - GETKEY_REP_PROFILE = 0x40, + GETKEY_REP_PROFILE = 0x0040, /* Enable application shortcuts; see getkey_set_feature_function() */ - GETKEY_FEATURES = 0x80, + GETKEY_FEATURES = 0x0080, + /* After coming back from the main menu, redraw the screen with dupdate + (has an effect on fx-CG 50 only) */ + GETKEY_MENU_DUPDATE = 0x0100, + /* After coming back from the main menu, send a KEYEV_OSMENU event */ + GETKEY_MENU_EVENT = 0x0200, /* No modifiers */ - GETKEY_NONE = 0x00, + GETKEY_NONE = 0x0000, /* Default settings of getkey() */ - GETKEY_DEFAULT = 0xdf, + GETKEY_DEFAULT = 0x01df, }; /* getkey_feature_t: Custom feature function diff --git a/src/kernel/osmenu.c b/src/kernel/osmenu.c index 47b0d85..bd1351f 100644 --- a/src/kernel/osmenu.c +++ b/src/kernel/osmenu.c @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -28,6 +29,69 @@ static void __osmenu_handler(void) __Timer_Deinstall(__osmenu_id); } +#ifdef FXCG50 +typedef void (os_menu_function_t)(void); + +/* This method is possible thanks to reverse-engineering by Dr-Carlos. + */ +static os_menu_function_t *find_os_menu_function(void) +{ + /* Get syscall table address */ + uint32_t addr = *(uint32_t *)0x8002007c; + if(addr < 0x80020070 || addr >= 0x81000000 - 0x1e58 * 4) + return NULL; + + /* Get pointer to %1e58 SwitchToMainMenu() */ + uint16_t const *insns = *(uint16_t const **)(addr + 0x1e58 * 4); + if(addr < 0x80020070 || addr >= 0x81000000) + return NULL; + + /* Check up to 150 instructions to find the call to the internal function + SaveAndOpenMainMenu(). This call is in a widget of the shape + + mov.l GetkeyToMainFunctionReturnFlag, rX + mov #3, rY + bsr SaveAndOpenMainMenu + mov.b rY, @rX + bra + nop */ + for(int i = 0; i < 150; i++) { + /* Match: mov.l @(disp, pc), rX */ + if((insns[i] & 0xf000) != 0xd000) + continue; + int rX = (insns[i] >> 8) & 0x0f; + + /* Match: mov #3, rY */ + if((insns[i+1] & 0xf0ff) != 0xe003) + continue; + int rY = (insns[i+1] >> 8) & 0x0f; + + /* Match: bsr @(disp, pc) */ + if((insns[i+2] & 0xf000) != 0xb000) + continue; + int disp = (insns[i+2] & 0x0fff); + + /* Match: mov.b rX, @rY */ + if((insns[i+3] != 0x2000 + (rX << 8) + (rY << 4))) + continue; + + /* Match: bra @(_, pc) */ + if((insns[i+4] & 0xf000) != 0xa000) + continue; + + /* Match: nop */ + if(insns[i+5] != 0x0009) + continue; + + /* Return the target of the bsr instruction */ + uint32_t fun_addr = (uint32_t)&insns[i+2] + 4 + disp * 2; + return (os_menu_function_t *)fun_addr; + } + + return NULL; +} +#endif + void gint_osmenu_native(void) { __ClearKeyBuffer(); @@ -52,6 +116,22 @@ void gint_osmenu_native(void) { dst[x] = src[x]; } + + /* Try to use the internal function directly if we could figure out its + address by dynamically disassembling */ + os_menu_function_t *fun = find_os_menu_function(); + if(fun) { + fun(); + + /* Run an immediate keyboard update, and clear the events so that the + key pressed in order to re-enter the add-in is not also processed in + the application */ + extern int keysc_tick(void); + keysc_tick(); + clearevents(); + + return; + } #endif /* Mysteriously crashes when coming back; might be useful another time diff --git a/src/keysc/getkey.c b/src/keysc/getkey.c index c068f76..421dc12 100644 --- a/src/keysc/getkey.c +++ b/src/keysc/getkey.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -64,10 +65,17 @@ key_event_t getkey_opt(int opt, volatile int *timeout) e.key == KEY_MENU && !e.shift && !e.alpha) { gint_osmenu(); - continue; + #ifdef FXCG50 + if(opt & GETKEY_MENU_DUPDATE) + dupdate(); + #endif + + if(!(opt & GETKEY_MENU_EVENT)) + continue; + e.type = KEYEV_OSMENU; } - if(e.type == KEYEV_DOWN || e.type == KEYEV_HOLD) + if(e.type != KEYEV_NONE || e.type != KEYEV_UP) { /* Custom global features */ bool accepted = false; diff --git a/src/keysc/keysc.c b/src/keysc/keysc.c index 958b5ac..46b3bdb 100644 --- a/src/keysc/keysc.c +++ b/src/keysc/keysc.c @@ -56,7 +56,7 @@ static void keysc_scan(uint8_t *scan) } /* keysc_tick(): Update the keyboard to the next state */ -static int keysc_tick(void) +int keysc_tick(void) { uint8_t scan[12] = { 0 }; keysc_scan(scan);