diff --git a/nx/include/switch.h b/nx/include/switch.h index e2ee6963..ba57091b 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -82,6 +82,7 @@ extern "C" { #include "switch/services/ncm.h" #include "switch/services/psc.h" #include "switch/services/caps.h" +#include "switch/services/capssc.h" #include "switch/services/capssu.h" #include "switch/services/nfc.h" diff --git a/nx/include/switch/services/capssc.h b/nx/include/switch/services/capssc.h new file mode 100644 index 00000000..df6c21ba --- /dev/null +++ b/nx/include/switch/services/capssc.h @@ -0,0 +1,30 @@ +/** + * @file capssc.h + * @brief Screenshot control (caps:sc) service IPC wrapper. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/sm.h" +#include "../services/caps.h" + +/// Initialize caps:sc. Only available on 2.0.0+. +Result capsscInitialize(void); +void capsscExit(void); + +/** + * @brief This takes a screenshot, with the screenshot being written into the output buffer. + * @note Not available with 5.0.0+ (stubbed). + * @note buffer_index and buffer_count correspond to buffers with size 0x384000(1280*720*4). These must not be negative. + * @param buf Output buffer containing the RGBA8 image. + * @param size Size of buf, should be 0x384000(1280*720*4) * buffer_count. + * @param inval Value 0 can be used for this. + * @param width Image width, must be 1280. + * @param height Image height, must be 720. + * @param buffer_count Total number of output image buffers. + * @param buffer_index Starting image buffer index. Must be < buffer_count. + * @param timeout Timeout in nanoseconds. A default value of 100000000 can be used. + */ +Result capsscCaptureScreenshot(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout); + diff --git a/nx/source/services/capssc.c b/nx/source/services/capssc.c new file mode 100644 index 00000000..fdeeb90b --- /dev/null +++ b/nx/source/services/capssc.c @@ -0,0 +1,81 @@ +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/detect.h" +#include "services/caps.h" +#include "services/capssc.h" +#include "services/sm.h" + +static Service g_capsscSrv; +static u64 g_capsscRefCnt; + +Result capsscInitialize(void) { + Result rc=0; + + atomicIncrement64(&g_capsscRefCnt); + + if (serviceIsActive(&g_capsscSrv)) + return 0; + + if (!kernelAbove200()) + rc = MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (R_SUCCEEDED(rc)) rc = smGetService(&g_capsscSrv, "caps:sc"); + + if (R_FAILED(rc)) capsscExit(); + + return rc; +} + +void capsscExit(void) { + if (atomicDecrement64(&g_capsscRefCnt) == 0) + serviceClose(&g_capsscSrv); +} + +Result capsscCaptureScreenshot(void* buf, size_t size, u32 inval, u64 width, u64 height, s64 buffer_count, s64 buffer_index, u64 timeout) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 inval; + u64 width; + u64 height; + s64 buffer_count; + s64 buffer_index; + u64 timeout; + } *raw; + + ipcAddRecvBuffer(&c, buf, size, 1); + + raw = serviceIpcPrepareHeader(&g_capsscSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2; + raw->inval = inval; + raw->width = width; + raw->height = height; + raw->buffer_count = buffer_count; + raw->buffer_index = buffer_index; + raw->timeout = timeout; + + Result rc = serviceIpcDispatch(&g_capsscSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_capsscSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} +