nx-hbmenu/nx_main/main.c
GiantPluto 6e642e97a4 #98 : Support for scroll by holding direction pad keys.
Ideally this should have been supported with hid API. Since it is not available yet, adding the logic in the application itself.
2019-12-14 19:12:33 +05:30

341 lines
8.4 KiB
C

#include <switch.h>
#include <string.h>
#include <stdio.h>
#include "../common/common.h"
#include "nx_touch.h"
// Define the desired framebuffer resolution (here we set it to 720p).
#define FB_WIDTH 1280
#define FB_HEIGHT 720
Framebuffer g_framebufObj;
uint8_t* g_framebuf;
u32 g_framebuf_width;
bool menuUpdateErrorScreen(void);
u64 g_prev_keyheld = 0;
u64 g_curr_keyheld = 0;
u64 g_tick_prev_keyheld = 0;
u64 g_tick_keyheld_interval = 0;
u64 g_tick_keyheld_subsequent_interval = 0;
bool g_prev_elapsed = false;
void intializeKeyHeldInterval(u16, u16);
// These wait times are idenfied with trial and error
#define KEY_HELD_INITIAL_WAIT_TIME 400
#define KEY_HELD_SUBSEQUENT_WAIT_TIME 33
#ifdef PERF_LOG
u64 g_tickdiff_frame=0;
#endif
#ifdef ENABLE_AUDIO
void audio_initialize(void);
void audio_exit(void);
#endif
extern u32 __nx_applet_exit_mode;
int main(int argc, char **argv)
{
bool error_screen=0;
Result lastret=0;
Result rc=0;
char msg[256];
char errormsg[256];//Can't use StrId for these error messages since it would be unavailable if textInit fails.
#ifdef PERF_LOG
u64 start_tick=0;
#endif
memset(errormsg, 0, sizeof(errormsg));
appletLockExit();
appletSetScreenShotPermission(AppletScreenShotPermission_Enable);
ColorSetId theme;
rc = setsysInitialize();
if (R_FAILED(rc)) snprintf(errormsg, sizeof(errormsg)-1, "Error: setsysInitialize() failed: 0x%x.", rc);
if (R_SUCCEEDED(rc)) setsysGetColorSetId(&theme);
if (R_SUCCEEDED(rc)) {
rc = plInitialize();
if (R_FAILED(rc)) snprintf(errormsg, sizeof(errormsg)-1, "Error: plInitialize() failed: 0x%x.", rc);
}
if (R_SUCCEEDED(rc)) {
rc = textInit();
if (R_FAILED(rc)) {
snprintf(errormsg, sizeof(errormsg)-1, "Error: textInit() failed: 0x%x.", rc);
}
}
if (R_SUCCEEDED(rc)) menuStartupPath();
if (R_SUCCEEDED(rc)) {
rc = assetsInit();
if (R_FAILED(rc)) {
snprintf(errormsg, sizeof(errormsg)-1, "Error: assetsInit() failed: 0x%x.", rc);
}
}
if (R_SUCCEEDED(rc)) themeStartup((ThemePreset)theme);
if (R_SUCCEEDED(rc)) powerInit();
if (R_SUCCEEDED(rc)) {
rc = netloaderInit();
if (R_FAILED(rc)) {
snprintf(errormsg, sizeof(errormsg)-1, "Error: netloaderInit() failed: 0x%x.", rc);
}
}
if (R_SUCCEEDED(rc) && !workerInit()) {
rc = 1;
snprintf(errormsg, sizeof(errormsg)-1, "Error: workerInit() failed.");
}
if (R_SUCCEEDED(rc) && !statusInit()) {
rc = 1;
snprintf(errormsg, sizeof(errormsg)-1, "Error: statusInit() failed.");
}
if (R_SUCCEEDED(rc)) menuStartup();
if (R_SUCCEEDED(rc)) {
if (!launchInit()) {
rc = 2;
snprintf(errormsg, sizeof(errormsg)-1, "Error: launchInit() failed.");
}
}
if (R_SUCCEEDED(rc) && !fontInitialize()) {
rc = 3;
snprintf(errormsg, sizeof(errormsg)-1, "Error: fontInitialize() failed.");
}
#ifdef ENABLE_AUDIO
if (R_SUCCEEDED(rc)) audio_initialize();
#endif
if (R_SUCCEEDED(rc)) {
lastret = envGetLastLoadResult();
if (R_FAILED(lastret)) {
memset(msg, 0, sizeof(msg));
snprintf(msg, sizeof(msg)-1, "%s\n0x%x", textGetString(StrId_LastLoadResult), lastret);
menuCreateMsgBox(780, 300, msg);
}
}
if (errormsg[0]) error_screen = 1;
if (!error_screen) {
framebufferCreate(&g_framebufObj, nwindowGetDefault(), FB_WIDTH, FB_HEIGHT, PIXEL_FORMAT_RGBA_8888, 2);
framebufferMakeLinear(&g_framebufObj);
}
else {
consoleInit(NULL);
printf("%s\n", errormsg);
printf("Press the + button to exit.\n");
}
intializeKeyHeldInterval(KEY_HELD_INITIAL_WAIT_TIME, KEY_HELD_SUBSEQUENT_WAIT_TIME);
while (appletMainLoop())
{
//Scan all the inputs. This should be done once for each frame
hidScanInput();
if (!error_screen) {
if (!uiUpdate()) break;
g_framebuf = framebufferBegin(&g_framebufObj, &g_framebuf_width);
#ifdef PERF_LOG
start_tick = svcGetSystemTick();
#endif
memset(g_framebuf, 237, g_framebuf_width * FB_HEIGHT);
menuLoop();
}
else {
if (menuUpdateErrorScreen()) break;
}
if (!error_screen) {
framebufferEnd(&g_framebufObj);
#ifdef PERF_LOG
g_tickdiff_frame = svcGetSystemTick() - start_tick;
#endif
}
else {
consoleUpdate(NULL);
}
}
if (!error_screen) {
framebufferClose(&g_framebufObj);
}
else {
consoleExit(NULL);
__nx_applet_exit_mode = 1;
}
#ifdef ENABLE_AUDIO
audio_exit();
#endif
fontExit();
launchExit();
netloaderSignalExit();
statusExit();
workerExit();
netloaderExit();
powerExit();
assetsExit();
plExit();
setsysExit();
appletUnlockExit();
return 0;
}
u64 menuGetKeysDown(void) {
u64 down = 0;
for (u32 controller=0; controller<8; controller++) {
if (hidIsControllerConnected(controller)) down |= hidKeysDown(controller);
}
if (hidIsControllerConnected(CONTROLLER_HANDHELD)) down |= hidKeysDown(CONTROLLER_HANDHELD);
return down;
}
/**
Initializes the initial and susequent wait interval with which the keys is considered to be held for long
@param msInitialInterval : The interval after which the key is considered as held for long
@param msSubsequentInterval : Once the key is found to be held for long, this decides when the key held state
should be set for susequent calls to keyHeldTimeElapsed()
@return nothing
*/
void intializeKeyHeldInterval(u16 msInitialInterval, u16 msSubsequentInterval)
{
g_tick_keyheld_interval = armNsToTicks(msInitialInterval * 1000000);
g_tick_keyheld_subsequent_interval = armNsToTicks(msSubsequentInterval * 1000000);
}
/**
Initializes the initial and susequent wait interval after which continous key press will be set
@return true if the key is held for long, false if it is not held
bar and "," as the half bar.
*/
bool keyHeldTimeElapsed(void)
{
bool elapsed = false;
u64 tick_current = svcGetSystemTick();
if (g_tick_prev_keyheld == 0 || g_curr_keyheld == 0)
{
g_tick_prev_keyheld = tick_current;
}
else if (g_prev_keyheld != g_curr_keyheld)
{
g_tick_prev_keyheld = tick_current;
g_prev_keyheld = g_curr_keyheld;
}
else
{
u64 tickdiff_keyheld = tick_current - g_tick_prev_keyheld;
if (g_prev_elapsed && (tickdiff_keyheld > g_tick_keyheld_subsequent_interval))
{
elapsed = true;
}
else if (tickdiff_keyheld > g_tick_keyheld_interval)
{
g_tick_prev_keyheld = tick_current;
elapsed = true;
}
}
g_prev_elapsed = elapsed;
return elapsed;
}
//This is implemented here due to the hid code.
bool menuUpdate(void) {
bool exitflag = 0;
menu_s* menu = menuGetCurrent();
u64 down = menuGetKeysDown();
handleTouch(menu);
if (down & KEY_Y)
{
launchMenuNetloaderTask();
}
else if (down & KEY_X)
{
menuHandleXButton();
}
else if (down & KEY_A)
{
menuHandleAButton();
}
else if (down & KEY_B)
{
launchMenuBackTask();
}
else if(down & KEY_MINUS){
themeMenuStartup();
}
else if (down & KEY_PLUS)
{
exitflag = 1;
}
else if (menu->nEntries > 0)
{
int move = 0;
if (down & KEY_LEFT) move--;
if (down & KEY_RIGHT) move++;
if (down & KEY_DOWN) move-=7;
if (down & KEY_UP) move+=7;
u64 held = hidKeysHeld(CONTROLLER_P1_AUTO);
g_curr_keyheld = held;
if (keyHeldTimeElapsed())
{
if (held & KEY_LEFT) move--;
if (held & KEY_RIGHT) move++;
if (held & KEY_DOWN) move -= 7;
if (held & KEY_UP) move += 7;
}
int newEntry = menu->curEntry + move;
if (newEntry < 0) newEntry = 0;
if (newEntry >= menu->nEntries) newEntry = menu->nEntries-1;
menu->curEntry = newEntry;
}
return exitflag;
}
bool menuUpdateErrorScreen(void) {
bool exitflag = 0;
u64 down = menuGetKeysDown();
if (down & KEY_PLUS)
{
exitflag = 1;
}
return exitflag;
}