From 9011f278b62c2fa419b537a8d832adb6bfed80a8 Mon Sep 17 00:00:00 2001 From: exelix Date: Sat, 23 Feb 2019 19:27:22 +0100 Subject: [PATCH] Add IOverlayAppletProxy-specific functions and hid:sys --- nx/include/switch.h | 1 + nx/include/switch/services/applet.h | 15 ++ nx/include/switch/services/hidsys.h | 20 +++ nx/source/services/applet.c | 39 +++++ nx/source/services/hidsys.c | 215 ++++++++++++++++++++++++++++ 5 files changed, 290 insertions(+) create mode 100644 nx/include/switch/services/hidsys.h create mode 100644 nx/source/services/hidsys.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 2521a092..3e83cb1d 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -67,6 +67,7 @@ extern "C" { #include "switch/services/usbds.h" #include "switch/services/usbhs.h" #include "switch/services/hid.h" +#include "switch/services/hidsys.h" #include "switch/services/irs.h" #include "switch/services/pl.h" #include "switch/services/vi.h" diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index 0b16df34..b43158e5 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -468,3 +468,18 @@ u32 appletGetPerformanceMode(void); AppletFocusState appletGetFocusState(void); Result appletSetFocusHandlingMode(AppletFocusHandlingMode mode); + +/** + * @brief Stops forwaring the input to the foreground app. Works only in the Overlay applet context + */ +Result appletBeginToWatchShortHomeButtonMessage(void); + +/** + * @brief Forwards input to the foreground app. Works only in the Overlay applet context + */ +Result appletEndToWatchShortHomeButtonMessage(void); + +/** + * @brief Get an event that fires when the home button is pressed, doesn't interfere with home menu + */ +Result appletHomeButtonReaderLockAccessorGetEvent(Event *out_event); \ No newline at end of file diff --git a/nx/include/switch/services/hidsys.h b/nx/include/switch/services/hidsys.h new file mode 100644 index 00000000..8fdc6d4c --- /dev/null +++ b/nx/include/switch/services/hidsys.h @@ -0,0 +1,20 @@ +/** + * @file hidsys.h + * @brief hid:sys service IPC wrapper. + * @author exelix + */ +#pragma once +#include "../types.h" +#include "../kernel/event.h" +#include "../services/sm.h" + +Result hidSysInitialize(void); + +void hidSysExit(void); + +Result hidSysEnableAppletToGetInput(bool enable); + +/** +* @brief Returns an event that fires when the home button is pressed, this will prevent the home menu from opening when the button is pressed. +**/ +Result hidSysAcquireHomeButtonEventHandle(Event* event_out); \ No newline at end of file diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 62b24a9a..7af4c644 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -83,6 +83,8 @@ static Result _appletSelfExit(void); static Result _appletExitProcessAndReturn(void); +static Event HomeButtonReaderLockAccessorEvent = {0}; + Result appletInitialize(void) { atomicIncrement64(&g_refCnt); @@ -314,6 +316,8 @@ void appletExit(void) } } } + + eventClose(&HomeButtonReaderLockAccessorEvent); eventClose(&g_appletLibraryAppletLaunchableEvent); @@ -2315,3 +2319,38 @@ bool appletMainLoop(void) { return true; } + +Result appletBeginToWatchShortHomeButtonMessage(void) { + if (__nx_applet_type != AppletType_OverlayApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletCmdNoIO(&g_appletIFunctions, 0); +} + +Result appletEndToWatchShortHomeButtonMessage(void) { + if (__nx_applet_type != AppletType_OverlayApplet) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _appletCmdNoIO(&g_appletIFunctions, 1); +} + +Result appletHomeButtonReaderLockAccessorGetEvent(Event *out_event) +{ + if (eventActive(&HomeButtonReaderLockAccessorEvent)) + { + *out_event = HomeButtonReaderLockAccessorEvent; + return 0; + } + + Service ILockAccessor = {0}; + Result rc = _appletGetSession(&g_appletICommonStateGetter, &ILockAccessor, 30); + if (!R_SUCCEEDED(rc)) + return rc; + + rc = _appletGetEvent(&ILockAccessor, &HomeButtonReaderLockAccessorEvent, 3,true); + if (R_SUCCEEDED(rc)) + *out_event = HomeButtonReaderLockAccessorEvent; + + serviceClose(&ILockAccessor); + return rc; +} diff --git a/nx/source/services/hidsys.c b/nx/source/services/hidsys.c new file mode 100644 index 00000000..11ac56b2 --- /dev/null +++ b/nx/source/services/hidsys.c @@ -0,0 +1,215 @@ +#include +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/shmem.h" +#include "kernel/rwlock.h" +#include "kernel/event.h" +#include "services/applet.h" +#include "services/hidsys.h" +#include "services/sm.h" + +static Service g_hidSysSrv; +static u64 g_hidSysRefCnt; + +static Event g_hidSysHomeEvent = {0}; +static Event g_hidSysCaptureEvent = {0}; +static Event g_hidSysSleeptEvent = {0}; + +static u64 g_hidSysAppletResourceUserId = 0; + +Result hidSysInitialize(void) { + atomicIncrement64(&g_hidSysRefCnt); + + if (serviceIsActive(&g_hidSysSrv)) + return 0; + + Result rc = smGetService(&g_hidSysSrv, "hid:sys"); + if (R_FAILED(rc)) + return rc; + + rc = appletGetAppletResourceUserId(&g_hidSysAppletResourceUserId); + if (R_FAILED(rc)) + g_hidSysAppletResourceUserId = 0; + + return 0; +} + +void hidSysExit(void) { + if (atomicDecrement64(&g_hidSysRefCnt) == 0) { + eventClose(&g_hidSysHomeEvent); + eventClose(&g_hidSysCaptureEvent); + eventClose(&g_hidSysSleeptEvent); + + serviceClose(&g_hidSysSrv); + } +} + +Result hidSysEnableAppletToGetInput(bool enable) { + IpcCommand c; + ipcInitialize(&c); + + struct CmdStruct{ + u64 magic; + u64 cmdid; + bool permitInput; + u64 appletResourceUserId; + } *cmdStruct; + + cmdStruct = (struct CmdStruct*) serviceIpcPrepareHeader(&g_hidSysSrv, &c, sizeof(*cmdStruct)); + + cmdStruct->magic = SFCI_MAGIC; + cmdStruct->cmdid = 503; + cmdStruct->permitInput = enable; + cmdStruct->appletResourceUserId = g_hidSysAppletResourceUserId; + + Result rc = serviceIpcDispatch(&g_hidSysSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hidSysSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _hidSysCmdWithResIdAndPid(u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 AppletResourceUserId; + } *raw; + + ipcSendPid(&c); + raw = serviceIpcPrepareHeader(&g_hidSysSrv,&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->AppletResourceUserId = g_hidSysAppletResourceUserId; + + Result rc = serviceIpcDispatch(&g_hidSysSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hidSysSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _hidSysGetHandle(Handle* handle_out, u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 AppletResourceUserId; + } *raw; + + ipcSendPid(&c); + raw = serviceIpcPrepareHeader(&g_hidSysSrv,&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->AppletResourceUserId = g_hidSysAppletResourceUserId; + + Result rc = serviceIpcDispatch(&g_hidSysSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_hidSysSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *handle_out = r.Handles[0]; + } + } + + return rc; +} + +static Result _hidSysGetEvent(Event* event_out, u64 cmd_id, bool autoclear) { + Handle tmp_handle=0; + Result rc = 0; + + rc = _hidSysGetHandle(&tmp_handle, cmd_id); + if (R_SUCCEEDED(rc)) eventLoadRemote(event_out, tmp_handle, autoclear); + return rc; +} + +Result hidSysAcquireHomeButtonEventHandle(Event* event_out) { + if (eventActive(&g_hidSysHomeEvent)) + { + *event_out = g_hidSysHomeEvent; + return 0; + } + Result rc = _hidSysGetEvent(&g_hidSysHomeEvent, 101, false); + if (R_SUCCEEDED(rc)) + *event_out = g_hidSysHomeEvent; + return rc; +} + +//These functions don't seem to work in the overlaydisp applet context +Result hidSysAcquireCaptureButtonEventHandle(Event* event_out) { + if (eventActive(&g_hidSysCaptureEvent)) + { + *event_out = g_hidSysCaptureEvent; + return 0; + } + Result rc = _hidSysGetEvent(&g_hidSysCaptureEvent, 141, false); + if (R_SUCCEEDED(rc)) + *event_out = g_hidSysCaptureEvent; + return rc; +} + +Result hidSysAcquireSleepButtonEventHandle(Event* event_out) { + if (eventActive(&g_hidSysSleeptEvent)) + { + *event_out = g_hidSysSleeptEvent; + return 0; + } + Result rc = _hidSysGetEvent(&g_hidSysSleeptEvent, 121, false); + if (R_SUCCEEDED(rc)) + *event_out = g_hidSysSleeptEvent; + return rc; +} + +Result hidSysActivateHomeButton(void) { + return _hidSysCmdWithResIdAndPid(111); +} + +Result hidSysActivateSleepButton(void) { + return _hidSysCmdWithResIdAndPid(131); +} + +Result hidSysActivateCaptureButton(void) { + return _hidSysCmdWithResIdAndPid(151); +} \ No newline at end of file