From ec594bfbcf6e45520e09f83dc38669b3cc25059d Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 22 Dec 2017 03:26:26 -0500 Subject: [PATCH] Added _appletGetOperationMode() and _appletGetPerformanceMode(). In appletInitialize(), use _appletGetOperationMode and _appletGetPerformanceMode(). Also use _appletGetCurrentFocusState() in appletInitialize() with a global field even for non-application-type. Added _appletSetOperationModeChangedNotification/_appletSetPerformanceModeChangedNotification and use these in appletInitialize(). Added appletGetOperationMode(), appletGetPerformanceMode(), and appletGetFocusState(), which load from cached state fields. Handle notifications in appletMainLoop(). Added appletOperationMode enum. Imported applet hooking from libctru. --- nx/include/switch/services/applet.h | 46 ++++++ nx/source/services/applet.c | 236 +++++++++++++++++++++++++++- 2 files changed, 279 insertions(+), 3 deletions(-) diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index b467d03f..281d2160 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -9,6 +9,32 @@ typedef enum APPLET_TYPE_SystemApplication = 4, } appletType; +typedef enum +{ + APPLET_OperationMode_Handheld = 0, + APPLET_OperationMode_Docked = 1, +} appletOperationMode; + +/// applet hook types. +typedef enum { + APPLETHOOK_ONFOCUSSTATE = 0, ///< FocusState changed. + APPLETHOOK_ONOPERATIONMODE, ///< OperationMode changed. + APPLETHOOK_ONPERFORMANCEMODE, ///< PerformanceMode changed. + + APPLETHOOK_COUNT, ///< Number of applet hook types. +} applet_HookType; + +/// applet hook function. +typedef void (*appletHookFn)(applet_HookType hook, void* param); + +/// applet hook cookie. +typedef struct tag_appletHookCookie +{ + struct tag_appletHookCookie* next; ///< Next cookie. + appletHookFn callback; ///< Hook callback. + void* param; ///< Callback parameter. +} appletHookCookie; + Result appletInitialize(void); void appletExit(void); Result appletGetAppletResourceUserId(u64 *out); @@ -20,3 +46,23 @@ Result appletCreateManagedDisplayLayer(u64 *out); * @return Whether the application should continue running. */ bool appletMainLoop(void); + + +/** + * @brief Sets up an applet status hook. + * @param cookie Hook cookie to use. + * @param callback Function to call when applet's status changes. + * @param param User-defined parameter to pass to the callback. + */ +void appletHook(appletHookCookie* cookie, appletHookFn callback, void* param); + +/** + * @brief Removes an applet status hook. + * @param cookie Hook cookie to remove. + */ +void appletUnhook(appletHookCookie* cookie); + +/// These return state which is updated by appletMainLoop() when notifications are received. +u8 appletGetOperationMode(void); +u32 appletGetPerformanceMode(void); +u8 appletGetFocusState(void); diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 91788f6c..b57d1f19 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -22,6 +22,12 @@ static Handle g_appletMessageEventHandle = INVALID_HANDLE; static u64 g_appletResourceUserId = 0; +static u8 g_appletOperationMode; +static u32 g_appletPerformanceMode; +static u8 g_appletFocusState; + +static appletHookCookie appletFirstHook; + void appletExit(void); static Result _appletGetSession(Handle sessionhandle, Handle* handle_out, u64 cmd_id); @@ -38,6 +44,12 @@ static Result _appletAcquireForegroundRights(void); static Result _appletSetFocusHandlingMode(u8 inval0, u8 inval1, u8 inval2); static Result _appletSetOutOfFocusSuspendingEnabled(u8 inval); +static Result _appletGetOperationMode(u8 *out); +static Result _appletGetPerformanceMode(u32 *out); + +static Result _appletSetOperationModeChangedNotification(u8 flag); +static Result _appletSetPerformanceModeChangedNotification(u8 flag); + Result appletInitialize(void) { if (g_appletServiceSession != INVALID_HANDLE) return MAKERESULT(MODULE_LIBNX, LIBNX_ALREADYINITIALIZED); @@ -45,7 +57,6 @@ Result appletInitialize(void) { Handle prochandle = CUR_PROCESS_HANDLE; s32 tmpindex=0; u32 msg=0; - u8 tmp8=0; if (__nx_applet_type==APPLET_TYPE_None) return 0; @@ -120,9 +131,9 @@ Result appletInitialize(void) { if (msg==0 || msg!=0xF) continue; - rc = _appletGetCurrentFocusState(&tmp8); + rc = _appletGetCurrentFocusState(&g_appletFocusState); if (R_FAILED(rc)) break; - } while(tmp8!=1); + } while(g_appletFocusState!=1); } if (R_SUCCEEDED(rc)) rc = _appletAcquireForegroundRights(); @@ -132,6 +143,14 @@ Result appletInitialize(void) { if (R_SUCCEEDED(rc) && __nx_applet_auto_notifyrunning && __nx_applet_type==APPLET_TYPE_Application) rc = _appletNotifyRunning(NULL); + if (R_SUCCEEDED(rc)) rc = _appletGetOperationMode(&g_appletOperationMode); + if (R_SUCCEEDED(rc)) rc = _appletGetPerformanceMode(&g_appletPerformanceMode); + + if (R_SUCCEEDED(rc) && __nx_applet_type!=APPLET_TYPE_Application) rc = _appletGetCurrentFocusState(&g_appletFocusState); + + if (R_SUCCEEDED(rc)) rc = _appletSetOperationModeChangedNotification(1); + if (R_SUCCEEDED(rc)) rc = _appletSetPerformanceModeChangedNotification(1); + if (R_FAILED(rc)) appletExit(); return rc; @@ -199,6 +218,37 @@ void appletExit(void) g_appletResourceUserId = 0; } +static void appletCallHook(applet_HookType hookType) +{ + appletHookCookie* c; + for (c = &appletFirstHook; c && c->callback; c = c->next) + c->callback(hookType, c->param); +} + +void appletHook(appletHookCookie* cookie, appletHookFn callback, void* param) +{ + if (!callback) return; + + appletHookCookie* hook = &appletFirstHook; + *cookie = *hook; // Structure copy. + hook->next = cookie; + hook->callback = callback; + hook->param = param; +} + +void appletUnhook(appletHookCookie* cookie) +{ + appletHookCookie* hook; + for (hook = &appletFirstHook; hook; hook = hook->next) + { + if (hook->next == cookie) + { + *hook = *cookie; // Structure copy. + break; + } + } +} + static Result appletSetFocusHandlingMode(u32 mode) { Result rc=0; u8 invals[4]; @@ -461,6 +511,77 @@ static Result _appletReceiveMessage(u32 *out) { return rc; } +static Result _appletGetOperationMode(u8 *out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 5; + + Result rc = ipcDispatch(g_appletICommonStateGetter); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u8 out; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *out = resp->out; + } + } + + return rc; +} +static Result _appletGetPerformanceMode(u32 *out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 6; + + Result rc = ipcDispatch(g_appletICommonStateGetter); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u32 out; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *out = resp->out; + } + } + + return rc; +} + static Result _appletGetCurrentFocusState(u8 *out) { IpcCommand c; ipcInitialize(&c); @@ -497,6 +618,72 @@ static Result _appletGetCurrentFocusState(u8 *out) { return rc; } +static Result _appletSetOperationModeChangedNotification(u8 flag) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u8 flag; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 11; + raw->flag = flag; + + Result rc = ipcDispatch(g_appletISelfController); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _appletSetPerformanceModeChangedNotification(u8 flag) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u8 flag; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 12; + raw->flag = flag; + + Result rc = ipcDispatch(g_appletISelfController); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + static Result _appletSetFocusHandlingMode(u8 inval0, u8 inval1, u8 inval2) { IpcCommand c; ipcInitialize(&c); @@ -603,7 +790,50 @@ Result appletCreateManagedDisplayLayer(u64 *out) { return rc; } +u8 appletGetOperationMode(void) { + return g_appletOperationMode; +} + +u32 appletGetPerformanceMode(void) { + return g_appletPerformanceMode; +} + +u8 appletGetFocusState(void) { + return g_appletFocusState; +} + bool appletMainLoop(void) { + Result rc=0; + u32 msg=0; + s32 tmpindex=0; + + if (R_FAILED(svcWaitSynchronization(&tmpindex, &g_appletMessageEventHandle, 1, 0))) return true; + + rc = _appletReceiveMessage(&msg); + if (R_FAILED(rc)) { + if ((rc & 0x3fffff) == 0x680) return true; + fatalSimple(rc); + } + + switch(msg) { + case 0xF: + rc = _appletGetCurrentFocusState(&g_appletFocusState); + if (R_SUCCEEDED(rc)) appletCallHook(APPLETHOOK_ONFOCUSSTATE); + break; + + case 0x1E: + rc = _appletGetOperationMode(&g_appletOperationMode); + if (R_SUCCEEDED(rc)) appletCallHook(APPLETHOOK_ONOPERATIONMODE); + break; + + case 0x1F: + rc = _appletGetPerformanceMode(&g_appletPerformanceMode); + if (R_SUCCEEDED(rc)) appletCallHook(APPLETHOOK_ONPERFORMANCEMODE); + break; + } + + if (R_FAILED(rc)) fatalSimple(rc); + return true; }