From 089f9f18ac193f3d3977961bb57d1b7ab0050d3e Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 27 Nov 2020 14:22:16 -0500 Subject: [PATCH] hid: Added the following cmds: hidSendKeyboardLockKeyEvent, hidDisconnectNpad, hidGetPlayerLedPattern, hidSetNpadJoyAssignmentModeSingle, hidStartLrAssignmentMode, hidStopLrAssignmentMode, hidSwapNpadAssignment, hidEnableUnintendedHomeButtonInputProtection, hidSetNpadJoyAssignmentModeSingleWithDestination, hidSetNpadAnalogStickUseCenterClamp, hidSetNpadCaptureButtonAssignment, hidClearNpadCaptureButtonAssignment, hidIsUsbFullKeyControllerEnabled, hidEnableUsbFullKeyController, hidIsUsbFullKeyControllerConnected, hidGetNpadOfHighestBatteryLevel, hidSetNpadCommunicationMode, hidGetNpadCommunicationMode, hidSetTouchScreenConfiguration, hidIsFirmwareUpdateNeededForNotification. --- nx/include/switch/services/hid.h | 155 ++++++++++++++++- nx/source/services/hid.c | 289 +++++++++++++++++++++++++++---- 2 files changed, 406 insertions(+), 38 deletions(-) diff --git a/nx/include/switch/services/hid.h b/nx/include/switch/services/hid.h index 4e659666..f933797e 100644 --- a/nx/include/switch/services/hid.h +++ b/nx/include/switch/services/hid.h @@ -457,6 +457,14 @@ typedef enum { HidNpadJoyAssignmentMode_Single = 1, ///< Single (Set by hidSetNpadJoyAssignmentModeSingle*()) } HidNpadJoyAssignmentMode; +/// NpadCommunicationMode +typedef enum { + HidNpadCommunicationMode_Unknown0 = 0, ///< Unknown + HidNpadCommunicationMode_Unknown1 = 1, ///< Unknown + HidNpadCommunicationMode_Unknown2 = 2, ///< Unknown + HidNpadCommunicationMode_Unknown3 = 3, ///< Unknown +} HidNpadCommunicationMode; + /// DeviceType (system) typedef enum { HidDeviceTypeBits_FullKey = BIT(0), ///< Pro Controller and Gc controller. @@ -679,6 +687,11 @@ typedef struct HidTouchScreenSharedMemoryFormat { u8 padding[0x3c8]; } HidTouchScreenSharedMemoryFormat; +/// HidTouchScreenConfigurationForNx +typedef struct { + u8 config[0x10]; ///< Unknown +} HidTouchScreenConfigurationForNx; + // End HidTouchScreen // Begin HidMouse @@ -1456,6 +1469,13 @@ u32 hidSixAxisSensorValuesRead(SixAxisSensorValues *values, HidControllerID id, */ bool hidGetHandheldMode(void); +/** + * @brief SendKeyboardLockKeyEvent + * @note Only available on [6.0.0+]. + * @param[in] events Bitfield of KeyboardLockKeyEvent. + */ +Result hidSendKeyboardLockKeyEvent(u32 events); + /** * @brief Gets SixAxisSensorHandles. * @note Only ::HidNpadStyleTag_NpadJoyDual supports total_handles==2. @@ -1579,6 +1599,19 @@ Result hidSetSupportedNpadIdType(const HidNpadIdType *ids, size_t count); **/ Result hidAcquireNpadStyleSetUpdateEventHandle(HidNpadIdType id, Event* out_event, bool autoclear); +/** + * @brief DisconnectNpad + * @param[in] id \ref HidNpadIdType + */ +Result hidDisconnectNpad(HidNpadIdType id); + +/** + * @brief GetPlayerLedPattern + * @param[in] id \ref HidNpadIdType + * @param[out] out Output value. + */ +Result hidGetPlayerLedPattern(HidNpadIdType id, u8 *out); + /** * @brief Sets the \ref HidNpadJoyHoldType. * @note Used automatically by \ref hidScanInput when required. @@ -1593,11 +1626,18 @@ Result hidSetNpadJoyHoldType(HidNpadJoyHoldType type); Result hidGetNpadJoyHoldType(HidNpadJoyHoldType *type); /** - * @brief Use this if you want to use a single joy-con as a dedicated HidNpadIdType_No*. When used, both joy-cons in a pair should be used with this (HidNpadIdType_No1 and HidNpadIdType_No2 for example). + * @brief This is the same as \ref hidSetNpadJoyAssignmentModeSingle, except ::HidNpadJoyDeviceType_Left is used for the type. * @param[in] id \ref HidNpadIdType, must be HidNpadIdType_No*. */ Result hidSetNpadJoyAssignmentModeSingleByDefault(HidNpadIdType id); +/** + * @brief This is the same as \ref hidSetNpadJoyAssignmentModeSingleWithDestination, except without the output params. + * @param[in] id \ref HidNpadIdType, must be HidNpadIdType_No*. + * @param[in] type \ref HidNpadJoyDeviceType + */ +Result hidSetNpadJoyAssignmentModeSingle(HidNpadIdType id, HidNpadJoyDeviceType type); + /** * @brief Use this if you want to use a pair of joy-cons as a single HidNpadIdType_No*. When used, both joy-cons in a pair should be used with this (HidNpadIdType_No1 and HidNpadIdType_No2 for example). * @note Used automatically by \ref hidScanInput when required. @@ -1614,6 +1654,16 @@ Result hidSetNpadJoyAssignmentModeDual(HidNpadIdType id); */ Result hidMergeSingleJoyAsDualJoy(HidNpadIdType id0, HidNpadIdType id1); +/** + * @brief StartLrAssignmentMode + */ +Result hidStartLrAssignmentMode(void); + +/** + * @brief StopLrAssignmentMode + */ +Result hidStopLrAssignmentMode(void); + /** * @brief Sets the \ref HidNpadHandheldActivationMode. * @param[in] mode \ref HidNpadHandheldActivationMode @@ -1626,6 +1676,52 @@ Result hidSetNpadHandheldActivationMode(HidNpadHandheldActivationMode mode); */ Result hidGetNpadHandheldActivationMode(HidNpadHandheldActivationMode *out); +/** + * @brief SwapNpadAssignment + * @param[in] id0 \ref HidNpadIdType + * @param[in] id1 \ref HidNpadIdType + */ +Result hidSwapNpadAssignment(HidNpadIdType id0, HidNpadIdType id1); + +/** + * @brief EnableUnintendedHomeButtonInputProtection + * @note To get the state of this, use \ref hidGetNpadSystemButtonProperties to access HidNpadSystemButtonProperties::is_unintended_home_button_input_protection_enabled. + * @param[in] id \ref HidNpadIdType + * @param[in] flag Whether UnintendedHomeButtonInputProtection is enabled. + */ +Result hidEnableUnintendedHomeButtonInputProtection(HidNpadIdType id, bool flag); + +/** + * @brief Use this if you want to use a single joy-con as a dedicated HidNpadIdType_No*. When used, both joy-cons in a pair should be used with this (HidNpadIdType_No1 and HidNpadIdType_No2 for example). + * @note Only available on [5.0.0+]. + * @param[in] id \ref HidNpadIdType, must be HidNpadIdType_No*. + * @param[in] type \ref HidNpadJoyDeviceType + * @param[out] flag Whether the dest output is set. + * @param[out] dest \ref HidNpadIdType + */ +Result hidSetNpadJoyAssignmentModeSingleWithDestination(HidNpadIdType id, HidNpadJoyDeviceType type, bool *flag, HidNpadIdType *dest); + +/** + * @brief SetNpadAnalogStickUseCenterClamp + * @note Only available on [6.1.0+]. + * @param[in] flag Flag + */ +Result hidSetNpadAnalogStickUseCenterClamp(bool flag); + +/** + * @brief SetNpadCaptureButtonAssignment + * @note Only available on [8.0.0+]. + * @param[in] style_set Bitfield of \ref HidNpadStyleTag, exactly 1 bit must be set. + * @param[in] buttons Bitfield of \ref HidNpadButton. + */ +Result hidSetNpadCaptureButtonAssignment(u32 style_set, u64 buttons); + +/** + * @brief ClearNpadCaptureButtonAssignment + * @note Only available on [8.0.0+]. + */ +Result hidClearNpadCaptureButtonAssignment(void); + /** * @brief Gets and initializes vibration handles. * @note Only the following styles support total_handles 2: ::HidNpadStyleTag_NpadFullKey, ::HidNpadStyleTag_NpadHandheld, ::HidNpadStyleTag_NpadJoyDual, ::HidNpadStyleTag_NpadHandheldLark, ::HidNpadStyleTag_NpadSystem, ::HidNpadStyleTag_NpadSystemExt. @@ -1791,6 +1887,28 @@ Result hidGetSensorFusionError(float *out); */ Result hidGetGyroBias(UtilFloat3 *out); +/** + * @brief IsUsbFullKeyControllerEnabled + * @note Only available on [3.0.0+]. + * @param[out] out Output flag. + */ +Result hidIsUsbFullKeyControllerEnabled(bool *out); + +/** + * @brief EnableUsbFullKeyController + * @note Only available on [3.0.0+]. + * @param[in] flag Flag + */ +Result hidEnableUsbFullKeyController(bool flag); + +/** + * @brief IsUsbFullKeyControllerConnected + * @note Only available on [3.0.0+]. + * @param[in] id \ref HidNpadIdType + * @param[out] out Output flag. + */ +Result hidIsUsbFullKeyControllerConnected(HidNpadIdType id, bool *out); + /** * @brief Gets the \ref HidNpadInterfaceType for the specified controller. * @note Only available on [4.0.0+]. @@ -1799,3 +1917,38 @@ Result hidGetGyroBias(UtilFloat3 *out); */ Result hidGetNpadInterfaceType(HidNpadIdType id, u8 *out); +/** + * @brief GetNpadOfHighestBatteryLevel + * @note Only available on [10.0.0+]. + * @param[in] ids Input array of \ref HidNpadIdType, ::HidNpadIdType_Handheld is ignored. + * @param[in] count Total entries in the ids array. + * @param[out] out \ref HidNpadIdType + */ +Result hidGetNpadOfHighestBatteryLevel(const HidNpadIdType *ids, size_t count, HidNpadIdType *out); + +/** + * @brief SetNpadCommunicationMode + * @param[in] mode \ref HidNpadCommunicationMode + */ +Result hidSetNpadCommunicationMode(HidNpadCommunicationMode mode); + +/** + * @brief GetNpadCommunicationMode + * @param[out] out \ref HidNpadCommunicationMode + */ +Result hidGetNpadCommunicationMode(HidNpadCommunicationMode *out); + +/** + * @brief SetTouchScreenConfiguration + * @note Only available on [9.0.0+]. + * @param[in] config \ref HidTouchScreenConfigurationForNx + */ +Result hidSetTouchScreenConfiguration(const HidTouchScreenConfigurationForNx *config); + +/** + * @brief IsFirmwareUpdateNeededForNotification + * @note Only available on [9.0.0+]. + * @param[out] out Output flag. + */ +Result hidIsFirmwareUpdateNeededForNotification(bool *out); + diff --git a/nx/source/services/hid.c b/nx/source/services/hid.c index a80e2b7b..08d0d0ac 100644 --- a/nx/source/services/hid.c +++ b/nx/source/services/hid.c @@ -48,6 +48,12 @@ static Result _hidActivateGesture(void); static Result _hidSetDualModeAll(void); +static Result _hidGetVibrationDeviceHandles(HidVibrationDeviceHandle *handles, s32 total_handles, HidNpadIdType id, HidNpadStyleTag style); + +static Result _hidCreateActiveVibrationDeviceList(Service* srv_out); + +static Result _hidActivateVibrationDevice(Service* srv, HidVibrationDeviceHandle handle); + static u8 _hidGetSixAxisSensorHandleNpadStyleIndex(HidSixAxisSensorHandle handle); static Result _hidGetSixAxisSensorHandles(HidSixAxisSensorHandle *handles, s32 total_handles, HidNpadIdType id, HidNpadStyleTag style); @@ -998,6 +1004,22 @@ static Result _hidCmdInU64NoOut(Service* srv, u64 inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, inval); } +static Result _hidCmdInU8AruidNoOut(u8 inval, u32 cmd_id) { + const struct { + u8 inval; + u8 pad[7]; + u64 AppletResourceUserId; + } in = { inval, {0}, appletGetAppletResourceUserId() }; + + return serviceDispatchIn(&g_hidSrv, cmd_id, in, + .in_send_pid = true, + ); +} + +static Result _hidCmdInBoolAruidNoOut(bool flag, u32 cmd_id) { + return _hidCmdInU8AruidNoOut(flag!=0, cmd_id); +} + static Result _hidCmdInU32AruidNoOut(u32 inval, u32 cmd_id) { const struct { u32 inval; @@ -1021,6 +1043,19 @@ static Result _hidCmdInU64AruidNoOut(u64 inval, u32 cmd_id) { ); } +static Result _hidCmdInU32AruidU64NoOut(u32 in32, u64 in64, u32 cmd_id) { + const struct { + u32 in32; + u32 pad; + u64 AppletResourceUserId; + u64 in64; + } in = { in32, 0, appletGetAppletResourceUserId(), in64 }; + + return serviceDispatchIn(&g_hidSrv, cmd_id, in, + .in_send_pid = true, + ); +} + static Result _hidCmdInU8U32AruidNoOut(u8 in8, u32 in32, u32 cmd_id) { const struct { u8 in8; @@ -1038,6 +1073,17 @@ static Result _hidCmdInBoolU32AruidNoOut(bool flag, u32 in32, u32 cmd_id) { return _hidCmdInU8U32AruidNoOut(flag!=0, in32, cmd_id); } +static Result _hidCmdInU32U32AruidNoOut(u32 val0, u32 val1, u32 cmd_id) { + const struct { + u32 val0, val1; + u64 AppletResourceUserId; + } in = { val0, val1, appletGetAppletResourceUserId() }; + + return serviceDispatchIn(&g_hidSrv, cmd_id, in, + .in_send_pid = true, + ); +} + static Result _hidCmdInU32AruidOutU8(u32 inval, u8 *out, u32 cmd_id) { const struct { u32 inval; @@ -1084,6 +1130,10 @@ static Result _hidCmdNoInOutBool(bool *out, u32 cmd_id) { return rc; } +static Result _hidCmdNoInOutU64(u64 *out, u32 cmd_id) { + return serviceDispatchOut(&g_hidSrv, cmd_id, *out); +} + static Result _hidCreateAppletResource(Service* srv, Service* srv_out) { u64 AppletResourceUserId = appletGetAppletResourceUserId(); @@ -1110,6 +1160,13 @@ static Result _hidActivateKeyboard(void) { return _hidCmdInAruidNoOut(31); } +Result hidSendKeyboardLockKeyEvent(u32 events) { + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _hidCmdInU32AruidNoOut(events, 32); +} + Result hidGetSixAxisSensorHandles(HidSixAxisSensorHandle *handles, s32 total_handles, HidNpadIdType id, HidNpadStyleTag style) { if (id == (HidNpadIdType)CONTROLLER_HANDHELD) id = HidNpadIdType_Handheld; // Correct enum value for old users passing HidControllerID instead (avoids a hid sysmodule fatal later on) return _hidGetSixAxisSensorHandles(handles, total_handles, id, style); @@ -1280,6 +1337,18 @@ Result hidAcquireNpadStyleSetUpdateEventHandle(HidNpadIdType id, Event* out_even return rc; } +Result hidDisconnectNpad(HidNpadIdType id) { + return _hidCmdInU32AruidNoOut(id, 107); +} + +Result hidGetPlayerLedPattern(HidNpadIdType id, u8 *out) { + u32 in=id; + u64 tmp=0; + Result rc = serviceDispatchIn(&g_hidSrv, 108, in, tmp); + if (R_SUCCEEDED(rc) && out) *out = tmp; + return rc; +} + Result hidSetNpadJoyHoldType(HidNpadJoyHoldType type) { return _hidCmdInU64AruidNoOut(type, 120); } @@ -1295,19 +1364,24 @@ Result hidSetNpadJoyAssignmentModeSingleByDefault(HidNpadIdType id) { return _hidCmdInU32AruidNoOut(id, 122); } +Result hidSetNpadJoyAssignmentModeSingle(HidNpadIdType id, HidNpadJoyDeviceType type) { + return _hidCmdInU32AruidU64NoOut(id, type, 123); +} + Result hidSetNpadJoyAssignmentModeDual(HidNpadIdType id) { return _hidCmdInU32AruidNoOut(id, 124); } Result hidMergeSingleJoyAsDualJoy(HidNpadIdType id0, HidNpadIdType id1) { - const struct { - u32 id0, id1; - u64 AppletResourceUserId; - } in = { id0, id1, appletGetAppletResourceUserId() }; + return _hidCmdInU32U32AruidNoOut(id0, id1, 125); +} - return serviceDispatchIn(&g_hidSrv, 125, in, - .in_send_pid = true, - ); +Result hidStartLrAssignmentMode(void) { + return _hidCmdInAruidNoOut(126); +} + +Result hidStopLrAssignmentMode(void) { + return _hidCmdInAruidNoOut(127); } Result hidSetNpadHandheldActivationMode(HidNpadHandheldActivationMode mode) { @@ -1321,12 +1395,86 @@ Result hidGetNpadHandheldActivationMode(HidNpadHandheldActivationMode *out) { return rc; } -static Result _hidCreateActiveVibrationDeviceList(Service* srv_out) { - return _hidCmdGetSession(srv_out, 203); +Result hidSwapNpadAssignment(HidNpadIdType id0, HidNpadIdType id1) { + return _hidCmdInU32U32AruidNoOut(id0, id1, 130); } -static Result _hidActivateVibrationDevice(Service* srv, HidVibrationDeviceHandle handle) { - return _hidCmdInU32NoOut(srv, handle.type_value, 0); +Result hidEnableUnintendedHomeButtonInputProtection(HidNpadIdType id, bool flag) { + return _hidCmdInBoolU32AruidNoOut(flag, id, 132); +} + +Result hidSetNpadJoyAssignmentModeSingleWithDestination(HidNpadIdType id, HidNpadJoyDeviceType type, bool *flag, HidNpadIdType *dest) { + if (hosversionBefore(5,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + const struct { + u32 id; + u32 pad; + u64 AppletResourceUserId; + s64 type; + } in = { id, 0, appletGetAppletResourceUserId(), type }; + + struct { + u8 flag; + u8 pad[3]; + u32 id; + } out; + + Result rc = serviceDispatchInOut(&g_hidSrv, 133, in, out, + .in_send_pid = true, + ); + if (R_SUCCEEDED(rc)) { + if (flag) *flag = out.flag & 1; + if (dest) *dest = out.id; + } + return rc; +} + +Result hidSetNpadAnalogStickUseCenterClamp(bool flag) { + if (hosversionBefore(6,1,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _hidCmdInBoolAruidNoOut(flag, 134); +} + +Result hidSetNpadCaptureButtonAssignment(u32 style_set, u64 buttons) { + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _hidCmdInU32AruidU64NoOut(style_set, buttons, 135); +} + +Result hidClearNpadCaptureButtonAssignment(void) { + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _hidCmdInAruidNoOut(136); +} + +Result hidInitializeVibrationDevices(HidVibrationDeviceHandle *handles, s32 total_handles, HidNpadIdType id, HidNpadStyleTag style) { + Result rc=0; + s32 i; + + if (id == (HidNpadIdType)CONTROLLER_HANDHELD) id = HidNpadIdType_Handheld; // Correct enum value for old users passing HidControllerID instead (avoids a hid sysmodule fatal later on) + + rc = _hidGetVibrationDeviceHandles(handles, total_handles, id, style); + if (R_FAILED(rc)) return rc; + + mutexLock(&g_hidVibrationMutex); + if (!serviceIsActive(&g_hidIActiveVibrationDeviceList)) { + rc = _hidCreateActiveVibrationDeviceList(&g_hidIActiveVibrationDeviceList); + } + mutexUnlock(&g_hidVibrationMutex); + if (R_FAILED(rc)) return rc; + + for (i=0; i