diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index 2414eec409..639ed34831 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -56,27 +56,27 @@ static const char * const condnames[16] = { "al", // Always (unconditional) 14 }; -int SignExtend26(int x) { +static int SignExtend26(int x) { return (x & 0x02000000) ? (0xFC000000 | x) : (x & 0x3FFFFFF); } -int SignExtend19(int x) { +static int SignExtend19(int x) { return (x & 0x00040000) ? (0xFFF80000 | x) : (x & 0x7FFFF); } -int SignExtend9(int x) { +static int SignExtend9(int x) { return (x & 0x00000100) ? (0xFFFFFE00 | x) : (x & 0x1FF); } -int SignExtend7(int x) { +static int SignExtend7(int x) { return (x & 0x00000040) ? (0xFFFFFF80 | x) : (x & 0x7F); } -int SignExtend12(int x) { +static int SignExtend12(int x) { return (x & 0x00000800) ? (0xFFFFF000 | x) : (x & 0xFFF); } -int HighestSetBit(int value) { +static int HighestSetBit(int value) { int highest = 0; for (int i = 0; i < 32; i++) { if (value & (1 << i)) @@ -85,7 +85,7 @@ int HighestSetBit(int value) { return highest; } -int LowestSetBit(int value, int maximum = 32) { +static int LowestSetBit(int value, int maximum = 32) { for (int i = 0; i < maximum; i++) { if (value & (1 << i)) return i; diff --git a/Windows/HidInputDevice.cpp b/Windows/HidInputDevice.cpp index 7435a85e49..bf2270d18e 100644 --- a/Windows/HidInputDevice.cpp +++ b/Windows/HidInputDevice.cpp @@ -7,6 +7,7 @@ #include #include "Windows/HidInputDevice.h" +#include "Common/CommonTypes.h" #include "Common/TimeUtil.h" #include "Common/Log.h" #include "Common/Input/InputState.h" @@ -14,6 +15,10 @@ #include "Common/System/NativeApp.h" #include "Common/System/OSD.h" +constexpr u8 LED_R = 0x05; +constexpr u8 LED_G = 0x10; +constexpr u8 LED_B = 0x40; + enum PSButton : u32 { PS_DPAD_UP = 1, // These dpad ones are not real, we convert from hat switch format. PS_DPAD_DOWN = 2, @@ -135,41 +140,15 @@ static bool IsSupportedGamepad(HANDLE handle, USHORT *pidOut, PSSubType *subType return false; } -struct DualSenseOutputReport{ - uint8_t reportId; - uint8_t flags1; - uint8_t flags2; - uint8_t headphone[4]; - uint8_t muteLED; - uint8_t micMute; -}; - -// https://github.com/ds4windowsapp/DS4Windows/blob/65609b470f53a4f832fb07ac24085d3e28ec15bd/DS4Windows/DS4Library/InputDevices/DualSenseDevice.cs#L905 - -// Sends initialization packet to DualSense -static bool InitializeDualSense(HANDLE handle, int outReportSize) { - if (outReportSize != 48) { - return false; - } - - // Output report (0x05) – sets lightbar, enables full report mode - uint8_t reportData[48] = {0}; - - DualSenseOutputReport report; - report.reportId = 2; - report.flags1 = 0x0C; - report.flags2 = 0x15; - report.muteLED = 1; - - memcpy(reportData, &report, sizeof(report)); - +template +static bool WriteReport(HANDLE handle, const T &report) { DWORD written; - bool result = WriteFile(handle, reportData, sizeof(reportData), &written, NULL); + bool result = WriteFile(handle, &report, sizeof(report), &written, NULL); if (!result) { u32 errorCode = GetLastError(); if (errorCode == ERROR_INVALID_PARAMETER) { - if (!HidD_SetOutputReport(handle, reportData, outReportSize)) { + if (!HidD_SetOutputReport(handle, (PVOID)&report, sizeof(T))) { errorCode = GetLastError(); } } @@ -180,6 +159,67 @@ static bool InitializeDualSense(HANDLE handle, int outReportSize) { return true; } +struct DualSenseOutputReport { + u8 reportId; + u8 flags1; + u8 flags2; + u8 rumbleRight; + u8 rumbleLeft; + u8 pad[2]; + u8 muteLED; + u8 micMute; + u8 other[32]; + u8 enableBrightness; + u8 fade; + u8 brightness; + u8 playerLights; + u8 lightbarRed; + u8 lightbarGreen; + u8 lightbarBlue; +}; +static_assert(sizeof(DualSenseOutputReport) == 48); + +// https://github.com/ds4windowsapp/DS4Windows/blob/65609b470f53a4f832fb07ac24085d3e28ec15bd/DS4Windows/DS4Library/InputDevices/DualSenseDevice.cs#L905 + +// Sends initialization packet to DualSense +static bool InitializeDualSense(HANDLE handle, int outReportSize) { + if (outReportSize != sizeof(DualSenseOutputReport)) { + return false; + } + + DualSenseOutputReport report{}; + report.reportId = 2; + report.flags1 = 0x0C; + report.flags2 = 0x15; + report.muteLED = 1; + report.playerLights = 1; + report.enableBrightness = 1; + report.brightness = 0; // 0 = high, 1 = medium, 2 = low + report.lightbarRed = LED_R; + report.lightbarGreen = LED_G; + report.lightbarBlue = LED_B; + return WriteReport(handle, report); +} + +static bool ShutdownDualsense(HANDLE handle, int outReportSize) { + if (outReportSize != sizeof(DualSenseOutputReport)) { + return false; + } + + DualSenseOutputReport report{}; + report.reportId = 2; + report.flags1 = 0x0C; + report.flags2 = 0x15; + report.muteLED = 1; + report.playerLights = 0; + report.enableBrightness = 1; + report.brightness = 2; // 0 = high, 1 = medium, 2 = low + report.lightbarRed = 0; + report.lightbarGreen = 0; + report.lightbarBlue = 0; + return WriteReport(handle, report); +} + enum class DS4FeatureBits : u8 { VOL_L = 0x10, VOL_R = 0x20, @@ -191,33 +231,67 @@ enum class DS4FeatureBits : u8 { }; ENUM_CLASS_BITOPS(DS4FeatureBits); +struct DualshockOutputReport { + u8 reportID; + u8 featureBits; + u8 two; + u8 pad; + u8 rumbleRight; + u8 rumbleLeft; + u8 ledR; + u8 ledG; + u8 ledB; + u8 padding[23]; +}; +static_assert(sizeof(DualshockOutputReport) == 32); + static bool InitializeDualShock(HANDLE handle, int outReportSize) { - if (outReportSize != 32) { + if (outReportSize != sizeof(DualshockOutputReport)) { WARN_LOG(Log::UI, "DS4 unexpected report size %d", outReportSize); return false; } - // DS4 USB output report (report ID 0x05) - // Total size: 32 bytes (must match device buffer size) - uint8_t report[32] = {0}; + DualshockOutputReport report{}; + report.reportID = 0x05; // Report ID (DS4 output) + report.featureBits = (u8)(DS4FeatureBits::RUMBLE | DS4FeatureBits::LIGHTBAR | DS4FeatureBits::FLASH); // Flags: enable lightbar, rumble, etc. + report.two = 2; - report[0] = 0x05; // Report ID (DS4 output) - report[1] = (u8)(DS4FeatureBits::RUMBLE | DS4FeatureBits::LIGHTBAR | DS4FeatureBits::FLASH); // Flags: enable lightbar, rumble, etc. - report[2] = 0x02; // Rumble - report[4] = 0x00; // Right (weak) - report[5] = 0x00; // Left (strong) + report.rumbleRight = 0x00; // Right (weak) + report.rumbleLeft = 0x00; // Left (strong) // Lightbar (RGB) - report[6] = 0x00; // Red - report[7] = 0x10; // Green - report[8] = 0x40; // Blue (dim blue) + report.ledR = LED_R; + report.ledG = LED_G; + report.ledB = LED_B; - DWORD written; - return WriteFile(handle, report, sizeof(report), &written, NULL); + return WriteReport(handle, report); } -HANDLE OpenFirstDualShockOrSense(PSSubType *subType, int *reportSize) { +static bool ShutdownDualShock(HANDLE handle, int outReportSize) { + if (outReportSize != sizeof(DualshockOutputReport)) { + WARN_LOG(Log::UI, "DS4 unexpected report size %d", outReportSize); + return false; + } + + DualshockOutputReport report{}; + report.reportID = 0x05; // Report ID (DS4 output) + report.featureBits = (u8)(DS4FeatureBits::RUMBLE | DS4FeatureBits::LIGHTBAR | DS4FeatureBits::FLASH); // Flags: enable lightbar, rumble, etc. + report.two = 2; + + // Rumble + report.rumbleRight = 0x00; // Right (weak) + report.rumbleLeft = 0x00; // Left (strong) + + // Lightbar (RGB) + report.ledR = 0; + report.ledG = 0; + report.ledB = 0; + + return WriteReport(handle, report); +} + +HANDLE OpenFirstDualShockOrSense(PSSubType *subType, int *reportSize, int *outReportSize) { GUID hidGuid; HidD_GetHidGuid(&hidGuid); @@ -251,14 +325,14 @@ HANDLE OpenFirstDualShockOrSense(PSSubType *subType, int *reportSize) { HidD_FreePreparsedData(preparsedData); *reportSize = caps.InputReportByteLength; - int outReportSize = caps.OutputReportByteLength; + *outReportSize = caps.OutputReportByteLength; INFO_LOG(Log::UI, "Initializing gamepad. out report size=%d", outReportSize); bool result; if (*subType == PSSubType::DS5) { - result = InitializeDualSense(handle, outReportSize); + result = InitializeDualSense(handle, *outReportSize); } else { - result = InitializeDualShock(handle, outReportSize); + result = InitializeDualShock(handle, *outReportSize); } SetupDiDestroyDeviceInfoList(deviceInfoSet); @@ -428,6 +502,14 @@ bool HidInputDevice::ReadDualSenseInput(HANDLE handle, PSControllerState *state) void HidInputDevice::Init() {} void HidInputDevice::Shutdown() { if (controller_) { + switch (subType_) { + case PSSubType::DS4: + ShutdownDualShock(controller_, outReportSize_); + break; + case PSSubType::DS5: + ShutdownDualsense(controller_, outReportSize_); + break; + } CloseHandle(controller_); controller_ = nullptr; } @@ -452,7 +534,7 @@ int HidInputDevice::UpdateState() { // Poll for controllers from time to time. if (pollCount_ == 0) { pollCount_ = POLL_FREQ; - HANDLE newController = OpenFirstDualShockOrSense(&subType_, &reportSize_); + HANDLE newController = OpenFirstDualShockOrSense(&subType_, &reportSize_, &outReportSize_); if (newController) { controller_ = newController; } diff --git a/Windows/HidInputDevice.h b/Windows/HidInputDevice.h index f00500de74..877685728d 100644 --- a/Windows/HidInputDevice.h +++ b/Windows/HidInputDevice.h @@ -41,6 +41,7 @@ private: int pad_ = 0; int pollCount_ = 0; int reportSize_ = 0; + int outReportSize_ = 0; enum { POLL_FREQ = 283, // a prime number. }; diff --git a/android/src/org/ppsspp/ppsspp/TextRenderer.java b/android/src/org/ppsspp/ppsspp/TextRenderer.java index 6e017ad918..6345c1b64d 100644 --- a/android/src/org/ppsspp/ppsspp/TextRenderer.java +++ b/android/src/org/ppsspp/ppsspp/TextRenderer.java @@ -37,7 +37,6 @@ public class TextRenderer { } private static Point measureLine(String string, double textSize) { - textPaint.setTextSize((float) textSize); int w = (int) textPaint.measureText(string); // Round width up to even already here to avoid annoyances from odd-width 16-bit textures // which OpenGL does not like - each line must be 4-byte aligned @@ -73,11 +72,13 @@ public class TextRenderer { } public static int measureText(String string, double textSize) { + textPaint.setTextSize((float) textSize); Point s = measure(string, textSize); return (s.x << 16) | s.y; } public static int[] renderText(String string, double textSize) { + textPaint.setTextSize((float) textSize); Point s = measure(string, textSize); int w = s.x; @@ -87,7 +88,7 @@ public class TextRenderer { Canvas canvas = new Canvas(bmp); canvas.drawRect(0.0f, 0.0f, w, h, bg); - String lines[] = string.replaceAll("\\r", "").split("\n"); + String [] lines = string.replaceAll("\\r", "").split("\n"); float y = 1.0f; Path path = null;