From ad5b8c019f3d6f8512aba9f657c4e2cb6faf360a Mon Sep 17 00:00:00 2001 From: exelix Date: Wed, 27 Feb 2019 16:17:03 +0100 Subject: [PATCH] Add some functions from IOverlayAppletProxy and hid:sys (#242) --- nx/include/switch.h | 1 + nx/include/switch/services/applet.h | 18 +++ nx/include/switch/services/hidsys.h | 23 ++++ nx/source/services/applet.c | 27 +++++ nx/source/services/hidsys.c | 181 ++++++++++++++++++++++++++++ 5 files changed, 250 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..4746691f 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -252,6 +252,24 @@ Result appletSetScreenShotPermission(s32 val); Result appletSetScreenShotImageOrientation(s32 val); +/** + * @brief Stops forwarding the input to the foreground app, works only in the Overlay applet context. + * @note You have to call this to receive inputs through the hid service when running as the overlay applet. + */ +Result appletBeginToWatchShortHomeButtonMessage(void); + +/** + * @brief Forwards input to the foreground app, works only in the Overlay applet context. + * @note After calling this the overlay applet won't receive any input until \ref appletBeginToWatchShortHomeButtonMessage is called again. + */ +Result appletEndToWatchShortHomeButtonMessage(void); + +/** + * @brief Get an event that fires when the home button is pressed, doesn't interfere with home menu. This event does not auto clear. + * @note Doesn't fire for long press. + */ +Result appletHomeButtonReaderLockAccessorGetEvent(Event *out_event); + /** * @brief Pushes a storage to the general channel. Used for sending requests to qlaunch. * @note This is not usable under an Application, however it is usable under a LibraryApplet. diff --git a/nx/include/switch/services/hidsys.h b/nx/include/switch/services/hidsys.h new file mode 100644 index 00000000..761c2ec5 --- /dev/null +++ b/nx/include/switch/services/hidsys.h @@ -0,0 +1,23 @@ +/** + * @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. This event does not auto clear. +**/ +Result hidsysAcquireHomeButtonEventHandle(Event* event_out); + +Result hidsysActivateHomeButton(void); +Result hidsysActivateSleepButton(void); +Result hidsysActivateCaptureButton(void); diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 62b24a9a..90d7718c 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -1378,8 +1378,35 @@ Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *sta return rc; } +// IOverlayFunctions + +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); +} + // ICommonStateGetter +Result appletHomeButtonReaderLockAccessorGetEvent(Event *out_event) { + Service ILockAccessor = {0}; + Result rc = _appletGetSession(&g_appletICommonStateGetter, &ILockAccessor, 30); + if (R_FAILED(rc)) + return rc; + + rc = _appletGetEvent(&ILockAccessor, out_event, 3, false); + serviceClose(&ILockAccessor); + return rc; +} + static Result _appletReceiveMessage(u32 *out) { IpcCommand c; ipcInitialize(&c); diff --git a/nx/source/services/hidsys.c b/nx/source/services/hidsys.c new file mode 100644 index 00000000..76e4dab9 --- /dev/null +++ b/nx/source/services/hidsys.c @@ -0,0 +1,181 @@ +#include +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.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 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) { + serviceClose(&g_hidsysSrv); + } +} + +Result hidsysEnableAppletToGetInput(bool enable) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmdid; + u8 permitInput; + u64 appletResourceUserId; + } *raw; + + raw = serviceIpcPrepareHeader(&g_hidsysSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmdid = 503; + raw->permitInput = enable != 0; + 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 _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) { + return _hidsysGetEvent(event_out, 101, false); +} + +//These functions don't seem to work in the overlaydisp applet context +Result hidsysAcquireCaptureButtonEventHandle(Event* event_out) { + return _hidsysGetEvent(event_out, 141, false); +} + +Result hidsysAcquireSleepButtonEventHandle(Event* event_out) { + return _hidsysGetEvent(event_out, 121, false); +} + +Result hidsysActivateHomeButton(void) { + return _hidsysCmdWithResIdAndPid(111); +} + +Result hidsysActivateSleepButton(void) { + return _hidsysCmdWithResIdAndPid(131); +} + +Result hidsysActivateCaptureButton(void) { + return _hidsysCmdWithResIdAndPid(151); +}