From 006959ca87eb1406a3d1f7021b6852b01600bcb0 Mon Sep 17 00:00:00 2001
From: ceski <[EMAIL REDACTED]>
Date: Wed, 13 May 2026 23:49:01 -0700
Subject: [PATCH] Add dual touchpad support to testcontroller (#15540)
---
test/CMakeLists.txt | 3 +-
test/gamepad_dual_touchpad.h | 57 +++++++++
test/gamepad_dual_touchpad.png | Bin 0 -> 643 bytes
test/gamepadutils.c | 215 +++++++++++++++++++++------------
test/gamepadutils.h | 2 +-
test/testcontroller.c | 68 +++++++----
test/testutils.c | 1 +
7 files changed, 241 insertions(+), 105 deletions(-)
create mode 100644 test/gamepad_dual_touchpad.h
create mode 100644 test/gamepad_dual_touchpad.png
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index b6e7b724bf228..895f885b13e0b 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -89,7 +89,7 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.20)
endif()
if(DOS)
- set(NAME83_LONG "unifont-15.1.05.hex;unifont-15.1.05-license.txt;physaudiodev.png;logaudiodev.png;audiofile.png;soundboard.png;soundboard_levels.png;trashcan.png;msdf_font.png;msdf_font.csv;gamepad_front.png;gamepad_back.png;gamepad_face_abxy.png;gamepad_face_axby.png;gamepad_face_bayx.png;gamepad_face_sony.png;gamepad_battery.png;gamepad_battery_unknown.png;gamepad_battery_wired.png;gamepad_touchpad.png;gamepad_button.png;gamepad_button_small.png;gamepad_button_background.png;gamepad_axis.png;gamepad_axis_arrow.png;gamepad_wired.png;gamepad_wireless.png;sdl-test_round.png")
+ set(NAME83_LONG "unifont-15.1.05.hex;unifont-15.1.05-license.txt;physaudiodev.png;logaudiodev.png;audiofile.png;soundboard.png;soundboard_levels.png;trashcan.png;msdf_font.png;msdf_font.csv;gamepad_front.png;gamepad_back.png;gamepad_face_abxy.png;gamepad_face_axby.png;gamepad_face_bayx.png;gamepad_face_sony.png;gamepad_battery.png;gamepad_battery_unknown.png;gamepad_battery_wired.png;gamepad_touchpad.png;gamepad_dual_touchpad.png;gamepad_button.png;gamepad_button_small.png;gamepad_button_background.png;gamepad_axis.png;gamepad_axis_arrow.png;gamepad_wired.png;gamepad_wireless.png;sdl-test_round.png")
set(DOS83_SHORT "UNIFONT.HEX;UNIFONTL.TXT;PHYSADEV.PNG;LOGADEV.PNG;AUDIOFIL.PNG;SNDBRD.PNG;SNDLVL.PNG;TRASHCAN.PNG;MSDFFONT.PNG;MSDFFONT.CSV;GP_FRONT.PNG;GP_BACK.PNG;GP_FABXY.PNG;GP_FAXBY.PNG;GP_FBAYX.PNG;GP_FSONY.PNG;GP_BATT.PNG;GP_BATTX.PNG;GP_BATTW.PNG;GP_TOUCH.PNG;GP_BTN.PNG;GP_BTNSM.PNG;GP_BTNBG.PNG;GP_AXIS.PNG;GP_AXARW.PNG;GP_WIRED.PNG;GP_WLESS.PNG;SDLROUND.PNG")
endif()
@@ -296,6 +296,7 @@ files2headers(gamepad_image_headers
gamepad_button_background.png
gamepad_button.png
gamepad_button_small.png
+ gamepad_dual_touchpad.png
gamepad_face_abxy.png
gamepad_face_axby.png
gamepad_face_bayx.png
diff --git a/test/gamepad_dual_touchpad.h b/test/gamepad_dual_touchpad.h
new file mode 100644
index 0000000000000..39909cc37398f
--- /dev/null
+++ b/test/gamepad_dual_touchpad.h
@@ -0,0 +1,57 @@
+unsigned char gamepad_dual_touchpad_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+ 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x9f,
+ 0x08, 0x03, 0x00, 0x00, 0x00, 0xb8, 0x09, 0x91, 0x77, 0x00, 0x00, 0x00,
+ 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72,
+ 0x65, 0x00, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67,
+ 0x65, 0x52, 0x65, 0x61, 0x64, 0x79, 0x71, 0xc9, 0x65, 0x3c, 0x00, 0x00,
+ 0x00, 0x1e, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17,
+ 0x25, 0x25, 0x25, 0x76, 0x76, 0x76, 0x86, 0x86, 0x86, 0xc3, 0xc3, 0xc3,
+ 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xff, 0xff, 0xff,
+ 0x6b, 0xf3, 0x50, 0x72, 0x00, 0x00, 0x01, 0xfb, 0x49, 0x44, 0x41, 0x54,
+ 0x78, 0xda, 0xec, 0xd5, 0x81, 0x71, 0x03, 0x21, 0x0c, 0x45, 0x41, 0x0e,
+ 0x01, 0x39, 0xf7, 0xdf, 0x70, 0xe2, 0x16, 0x32, 0x89, 0x2c, 0x5b, 0xfb,
+ 0x2a, 0xf8, 0xa3, 0x59, 0x86, 0xf1, 0x50, 0xeb, 0x86, 0x13, 0x00, 0x20,
+ 0x00, 0x04, 0x80, 0x00, 0x10, 0x00, 0x02, 0x40, 0x00, 0x08, 0x00, 0x01,
+ 0x20, 0x00, 0x04, 0x80, 0x00, 0x10, 0x00, 0x02, 0x40, 0x00, 0x08, 0x00,
+ 0x01, 0x20, 0x00, 0x04, 0xc0, 0x6f, 0xba, 0x63, 0x24, 0x16, 0x77, 0xe7,
+ 0xd5, 0x15, 0x01, 0xc4, 0x1c, 0xfb, 0xdc, 0x49, 0x9d, 0x3d, 0x66, 0xf4,
+ 0x5d, 0x5d, 0x11, 0x40, 0xcc, 0xfd, 0x95, 0xda, 0xfe, 0x8b, 0x5b, 0xbe,
+ 0xe7, 0xea, 0x8a, 0x00, 0x76, 0xf6, 0x25, 0x9f, 0xb7, 0xdc, 0x3d, 0x57,
+ 0x97, 0x04, 0x10, 0xeb, 0x64, 0x9f, 0xf2, 0xac, 0xe8, 0xb9, 0xba, 0x24,
+ 0x80, 0xfc, 0xa7, 0xf4, 0x7c, 0x4c, 0x3d, 0x57, 0x97, 0x04, 0x30, 0x5e,
+ 0x71, 0xca, 0xd1, 0x73, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xd9, 0x7c, 0xc5, 0x29, 0x67, 0xcf, 0xd5, 0x25, 0x01,
+ 0xc4, 0xca, 0x3f, 0xe5, 0x8a, 0x9e, 0xab, 0x4b, 0x02, 0x58, 0x91, 0xfe,
+ 0x98, 0x76, 0xac, 0x9e, 0xab, 0x4b, 0x02, 0x78, 0xcc, 0x75, 0x72, 0x2f,
+ 0x79, 0xd6, 0xec, 0xba, 0xba, 0x24, 0x80, 0x7d, 0xc5, 0xbe, 0xf3, 0x0e,
+ 0x79, 0xef, 0xb8, 0x76, 0xd7, 0xd5, 0x25, 0x01, 0xfc, 0x7c, 0xa8, 0xd7,
+ 0x48, 0xec, 0x8a, 0xce, 0xab, 0x4b, 0x02, 0x50, 0xb9, 0x00, 0x00, 0x40,
+ 0x00, 0x08, 0x00, 0x01, 0x20, 0x00, 0x04, 0x80, 0x00, 0x10, 0x00, 0x02,
+ 0x40, 0x00, 0x08, 0x00, 0x01, 0x20, 0x00, 0x04, 0x80, 0x00, 0x10, 0x00,
+ 0x02, 0x40, 0x00, 0x08, 0x00, 0x7d, 0x46, 0xdf, 0x02, 0x0c, 0x00, 0xeb,
+ 0x17, 0x39, 0xb7, 0x96, 0x32, 0x99, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+unsigned int gamepad_dual_touchpad_png_len = 643;
diff --git a/test/gamepad_dual_touchpad.png b/test/gamepad_dual_touchpad.png
new file mode 100644
index 0000000000000000000000000000000000000000..66cbc9da821c664c734644110377c83496822243
GIT binary patch
literal 643
zcmeAS@N?(olHy`uVBq!ia0y~yU;;83=5sIu$sL>%%Yl?+iEBhjaDG}zd16s2gJVj5
zQmTSyZen_BP-<dIW#P$G8=xY&0G|+7AT2H~uBxh9R#w*5)^_;t;bX^+9Y22j#EBFC
z|Nqba98ko-!1&wK#WAGf)|;!1h0KaPu8w?+mf!CeJQ6eN)QSGB^<!~l+sA;{ZNdx+
z3@i-{0t`$J3>*xM=$r%jyOLGJ%Aa2qWjrGD`;O;a+q5sSv4Rd~{!YF1uRD6*^H*IA
zW#3fiZ@*(3KAlD2b;|rtYhLW!rPA<c`Ij0WkeESS;i-$orVOKif#LtnnxmTO=dY?V
z9yw+Iv}@jKZ>ETe|7Mh}0kJC1losh%UVF0(7<#ow_kHH8e7~dYI#BJOnibbQ-gKP<
ostMT1z<@QL;4xV1cAtrd;kCHs_Gv~lK?#Pz)78&qol`;+02~XCo&W#<
literal 0
HcmV?d00001
diff --git a/test/gamepadutils.c b/test/gamepadutils.c
index 2f0fcc55ebd92..4da9522d16d41 100644
--- a/test/gamepadutils.c
+++ b/test/gamepadutils.c
@@ -22,6 +22,7 @@
#include "gamepad_battery.h"
#include "gamepad_battery_wired.h"
#include "gamepad_touchpad.h"
+#include "gamepad_dual_touchpad.h"
#include "gamepad_button.h"
#include "gamepad_button_small.h"
#include "gamepad_axis.h"
@@ -323,10 +324,18 @@ static const struct
{ 400, 5, 180.0 }, /* SDL_GAMEPAD_ELEMENT_AXIS_RIGHT_TRIGGER */
};
-static SDL_FRect touchpad_area = {
+#define MAX_TOUCHPADS 2
+#define MAX_FINGERS 2
+
+static const SDL_FRect touchpad_area = {
148.0f, 20.0f, 216.0f, 118.0f
};
+static const SDL_FRect dual_touchpad_area[MAX_TOUCHPADS] = {
+ {106.0f, 20.0f, 118.0f, 118.0f},
+ {288.0f, 20.0f, 118.0f, 118.0f},
+};
+
typedef struct
{
bool down;
@@ -335,6 +344,13 @@ typedef struct
float pressure;
} GamepadTouchpadFinger;
+typedef struct
+{
+ SDL_FRect area;
+ int num_fingers;
+ GamepadTouchpadFinger *fingers;
+} GamepadTouchpad;
+
struct GamepadImage
{
SDL_Renderer *renderer;
@@ -347,6 +363,7 @@ struct GamepadImage
SDL_Texture *connection_texture[2];
SDL_Texture *battery_texture[2];
SDL_Texture *touchpad_texture;
+ SDL_Texture *dual_touchpad_texture;
SDL_Texture *button_texture;
SDL_Texture *axis_texture;
float gamepad_width;
@@ -359,6 +376,8 @@ struct GamepadImage
float battery_height;
float touchpad_width;
float touchpad_height;
+ float dual_touchpad_width;
+ float dual_touchpad_height;
float button_width;
float button_height;
float axis_width;
@@ -378,8 +397,8 @@ struct GamepadImage
SDL_PowerState battery_state;
int battery_percent;
- int num_fingers;
- GamepadTouchpadFinger *fingers;
+ int num_touchpads;
+ GamepadTouchpad *touchpads;
};
static SDL_Texture *CreateTexture(SDL_Renderer *renderer, unsigned char *data, unsigned int len)
@@ -423,6 +442,9 @@ GamepadImage *CreateGamepadImage(SDL_Renderer *renderer)
ctx->touchpad_texture = CreateTexture(renderer, gamepad_touchpad_png, gamepad_touchpad_png_len);
SDL_GetTextureSize(ctx->touchpad_texture, &ctx->touchpad_width, &ctx->touchpad_height);
+ ctx->dual_touchpad_texture = CreateTexture(renderer, gamepad_dual_touchpad_png, gamepad_dual_touchpad_png_len);
+ SDL_GetTextureSize(ctx->dual_touchpad_texture, &ctx->dual_touchpad_width, &ctx->dual_touchpad_height);
+
ctx->button_texture = CreateTexture(renderer, gamepad_button_png, gamepad_button_png_len);
SDL_GetTextureSize(ctx->button_texture, &ctx->button_width, &ctx->button_height);
SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21);
@@ -462,17 +484,20 @@ void GetGamepadImageArea(GamepadImage *ctx, SDL_FRect *area)
}
}
-void GetGamepadTouchpadArea(GamepadImage *ctx, SDL_FRect *area)
+void GetGamepadTouchpadArea(GamepadImage *ctx, SDL_FRect *area, int touchpad)
{
+ int i;
+
if (!ctx) {
SDL_zerop(area);
return;
}
- area->x = ctx->x + (ctx->gamepad_width - ctx->touchpad_width) / 2 + touchpad_area.x;
- area->y = ctx->y + ctx->gamepad_height + touchpad_area.y;
- area->w = touchpad_area.w;
- area->h = touchpad_area.h;
+ i = SDL_clamp(touchpad, 0, MAX_TOUCHPADS - 1);
+ area->x = ctx->x + (ctx->gamepad_width - ctx->dual_touchpad_width) / 2 + dual_touchpad_area[i].x;
+ area->y = ctx->y + ctx->gamepad_height + dual_touchpad_area[i].y;
+ area->w = dual_touchpad_area[i].w;
+ area->h = dual_touchpad_area[i].h;
}
void SetGamepadImageShowingFront(GamepadImage *ctx, bool showing_front)
@@ -666,6 +691,18 @@ void SetGamepadImageElement(GamepadImage *ctx, int element, bool active)
ctx->elements[element] = active;
}
+static void FreeTouchpads(GamepadImage *ctx)
+{
+ if (ctx->touchpads) {
+ for (int i = 0; i < ctx->num_touchpads; ++i) {
+ SDL_free(ctx->touchpads[i].fingers);
+ }
+ SDL_free(ctx->touchpads);
+ ctx->touchpads = NULL;
+ ctx->num_touchpads = 0;
+ }
+}
+
void UpdateGamepadImageFromGamepad(GamepadImage *ctx, SDL_Gamepad *gamepad)
{
int i;
@@ -726,31 +763,39 @@ void UpdateGamepadImageFromGamepad(GamepadImage *ctx, SDL_Gamepad *gamepad)
ctx->connection_state = SDL_GetGamepadConnectionState(gamepad);
ctx->battery_state = SDL_GetGamepadPowerInfo(gamepad, &ctx->battery_percent);
- if (SDL_GetNumGamepadTouchpads(gamepad) > 0) {
- int num_fingers = SDL_GetNumGamepadTouchpadFingers(gamepad, 0);
- if (num_fingers != ctx->num_fingers) {
- GamepadTouchpadFinger *fingers = (GamepadTouchpadFinger *)SDL_realloc(ctx->fingers, num_fingers * sizeof(*fingers));
- if (fingers) {
- ctx->fingers = fingers;
- ctx->num_fingers = num_fingers;
+ FreeTouchpads(ctx);
+ ctx->num_touchpads = SDL_GetNumGamepadTouchpads(gamepad);
+ ctx->num_touchpads = SDL_min(ctx->num_touchpads, MAX_TOUCHPADS);
+ if (ctx->num_touchpads > 0) {
+ ctx->touchpads = (GamepadTouchpad *)SDL_malloc(sizeof(*ctx->touchpads) * ctx->num_touchpads);
+ if (ctx->touchpads) {
+ for (i = 0; i < ctx->num_touchpads; ++i) {
+ GamepadTouchpad *touchpad = &ctx->touchpads[i];
+ touchpad->num_fingers = SDL_GetNumGamepadTouchpadFingers(gamepad, i);
+ touchpad->num_fingers = SDL_min(touchpad->num_fingers, MAX_FINGERS);
+ if (touchpad->num_fingers > 0) {
+ touchpad->fingers = (GamepadTouchpadFinger *)SDL_malloc(sizeof(*touchpad->fingers) * touchpad->num_fingers);
+ if (touchpad->fingers) {
+ for (int j = 0; j < touchpad->num_fingers; ++j) {
+ GamepadTouchpadFinger *finger = &touchpad->fingers[j];
+ SDL_GetGamepadTouchpadFinger(gamepad, i, j, &finger->down, &finger->x, &finger->y, &finger->pressure);
+ }
+ } else {
+ touchpad->num_fingers = 0;
+ }
+ }
+ }
+ if (ctx->num_touchpads == 1) {
+ SDL_memcpy(&ctx->touchpads[0].area, &touchpad_area, sizeof(SDL_FRect));
} else {
- num_fingers = SDL_min(ctx->num_fingers, num_fingers);
+ SDL_memcpy(&ctx->touchpads[0].area, &dual_touchpad_area[0], sizeof(SDL_FRect));
+ SDL_memcpy(&ctx->touchpads[1].area, &dual_touchpad_area[1], sizeof(SDL_FRect));
}
+ } else {
+ ctx->num_touchpads = 0;
}
- for (i = 0; i < num_fingers; ++i) {
- GamepadTouchpadFinger *finger = &ctx->fingers[i];
-
- SDL_GetGamepadTouchpadFinger(gamepad, 0, i, &finger->down, &finger->x, &finger->y, &finger->pressure);
- }
- ctx->showing_touchpad = true;
- } else {
- if (ctx->fingers) {
- SDL_free(ctx->fingers);
- ctx->fingers = NULL;
- ctx->num_fingers = 0;
- }
- ctx->showing_touchpad = false;
}
+ ctx->showing_touchpad = (ctx->num_touchpads > 0);
}
void RenderGamepadImage(GamepadImage *ctx)
@@ -883,27 +928,39 @@ void RenderGamepadImage(GamepadImage *ctx)
}
if (ctx->display_mode == CONTROLLER_MODE_TESTING && ctx->showing_touchpad) {
- dst.x = ctx->x + (ctx->gamepad_width - ctx->touchpad_width) / 2;
- dst.y = ctx->y + ctx->gamepad_height;
- dst.w = ctx->touchpad_width;
- dst.h = ctx->touchpad_height;
- SDL_RenderTexture(ctx->renderer, ctx->touchpad_texture, NULL, &dst);
-
- for (i = 0; i < ctx->num_fingers; ++i) {
- GamepadTouchpadFinger *finger = &ctx->fingers[i];
-
- if (finger->down) {
- dst.x = ctx->x + (ctx->gamepad_width - ctx->touchpad_width) / 2;
- dst.x += touchpad_area.x + finger->x * touchpad_area.w;
- dst.x -= ctx->button_width / 2;
- dst.y = ctx->y + ctx->gamepad_height;
- dst.y += touchpad_area.y + finger->y * touchpad_area.h;
- dst.y -= ctx->button_height / 2;
- dst.w = ctx->button_width;
- dst.h = ctx->button_height;
- SDL_SetTextureAlphaMod(ctx->button_texture, (Uint8)(finger->pressure * SDL_ALPHA_OPAQUE));
- SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst);
- SDL_SetTextureAlphaMod(ctx->button_texture, SDL_ALPHA_OPAQUE);
+ float initial_dst_x;
+ if (ctx->num_touchpads == 1) {
+ dst.x = ctx->x + (ctx->gamepad_width - ctx->touchpad_width) / 2;
+ dst.y = ctx->y + ctx->gamepad_height;
+ dst.w = ctx->touchpad_width;
+ dst.h = ctx->touchpad_height;
+ SDL_RenderTexture(ctx->renderer, ctx->touchpad_texture, NULL, &dst);
+ } else {
+ dst.x = ctx->x + (ctx->gamepad_width - ctx->dual_touchpad_width) / 2;
+ dst.y = ctx->y + ctx->gamepad_height;
+ dst.w = ctx->dual_touchpad_width;
+ dst.h = ctx->dual_touchpad_height;
+ SDL_RenderTexture(ctx->renderer, ctx->dual_touchpad_texture, NULL, &dst);
+ }
+ initial_dst_x = dst.x;
+
+ for (i = 0; i < ctx->num_touchpads; ++i) {
+ GamepadTouchpad *touchpad = &ctx->touchpads[i];
+ for (int j = 0; j < touchpad->num_fingers; ++j) {
+ GamepadTouchpadFinger *finger = &touchpad->fingers[j];
+ if (finger->down) {
+ dst.x = initial_dst_x;
+ dst.x += touchpad->area.x + finger->x * touchpad->area.w;
+ dst.x -= ctx->button_width / 2;
+ dst.y = ctx->y + ctx->gamepad_height;
+ dst.y += touchpad->area.y + finger->y * touchpad->area.h;
+ dst.y -= ctx->button_height / 2;
+ dst.w = ctx->button_width;
+ dst.h = ctx->button_height;
+ SDL_SetTextureAlphaMod(ctx->button_texture, (Uint8)(finger->pressure * SDL_ALPHA_OPAQUE));
+ SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst);
+ SDL_SetTextureAlphaMod(ctx->button_texture, SDL_ALPHA_OPAQUE);
+ }
}
}
}
@@ -924,9 +981,10 @@ void DestroyGamepadImage(GamepadImage *ctx)
SDL_DestroyTexture(ctx->battery_texture[i]);
}
SDL_DestroyTexture(ctx->touchpad_texture);
+ SDL_DestroyTexture(ctx->dual_touchpad_texture);
SDL_DestroyTexture(ctx->button_texture);
SDL_DestroyTexture(ctx->axis_texture);
- SDL_free(ctx->fingers);
+ FreeTouchpads(ctx);
SDL_free(ctx);
}
}
@@ -1615,37 +1673,40 @@ void RenderGamepadDisplay(GamepadDisplay *ctx, SDL_Gamepad *gamepad)
}
if (ctx->display_mode == CONTROLLER_MODE_TESTING) {
- if (SDL_GetNumGamepadTouchpads(gamepad) > 0) {
- int num_fingers = SDL_GetNumGamepadTouchpadFingers(gamepad, 0);
- for (i = 0; i < num_fingers; ++i) {
- bool down;
- float finger_x, finger_y, finger_pressure;
-
- if (!SDL_GetGamepadTouchpadFinger(gamepad, 0, i, &down, &finger_x, &finger_y, &finger_pressure)) {
- continue;
- }
+ int num_touchpads = SDL_GetNumGamepadTouchpads(gamepad);
+ if (num_touchpads > 0) {
+ for (i = 0; i < num_touchpads; ++i) {
+ int num_fingers = SDL_GetNumGamepadTouchpadFingers(gamepad, i);
+ for (int j = 0; j < num_fingers; ++j) {
+ bool down;
+ float finger_x, finger_y, finger_pressure;
+
+ if (!SDL_GetGamepadTouchpadFinger(gamepad, i, j, &down, &finger_x, &finger_y, &finger_pressure)) {
+ continue;
+ }
- SDL_snprintf(text, sizeof(text), "Touch finger %d:", i);
- SDLTest_DrawString(ctx->renderer, x + center - SDL_strlen(text) * FONT_CHARACTER_SIZE, y, text);
+ SDL_snprintf(text, sizeof(text), "Pad %d Finger %d:", i, j);
+ SDLTest_DrawString(ctx->renderer, x + center - SDL_strlen(text) * FONT_CHARACTER_SIZE, y, text);
- if (down) {
- SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21);
- } else {
- SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255);
- }
+ if (down) {
+ SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21);
+ } else {
+ SDL_SetTextureColorMod(ctx->button_texture, 255, 255, 255);
+ }
- dst.x = x + center + 2.0f;
- dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2;
- dst.w = ctx->button_width;
- dst.h = ctx->button_height;
- SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst);
+ dst.x = x + center + 2.0f;
+ dst.y = y + FONT_CHARACTER_SIZE / 2 - ctx->button_height / 2;
+ dst.w = ctx->button_width;
+ dst.h = ctx->button_height;
+ SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst);
- if (down) {
- SDL_snprintf(text, sizeof(text), "(%.2f,%.2f)", finger_x, finger_y);
- SDLTest_DrawString(ctx->renderer, x + center + ctx->button_width + 4.0f, y, text);
- }
+ if (down) {
+ SDL_snprintf(text, sizeof(text), "(%.2f,%.2f)", finger_x, finger_y);
+ SDLTest_DrawString(ctx->renderer, x + center + ctx->button_width + 4.0f, y, text);
+ }
- y += ctx->button_height + 2.0f;
+ y += ctx->button_height + 2.0f;
+ }
}
}
diff --git a/test/gamepadutils.h b/test/gamepadutils.h
index d2ee1a7758d5e..503238afe14c0 100644
--- a/test/gamepadutils.h
+++ b/test/gamepadutils.h
@@ -69,7 +69,7 @@ enum
extern GamepadImage *CreateGamepadImage(SDL_Renderer *renderer);
extern void SetGamepadImagePosition(GamepadImage *ctx, float x, float y);
extern void GetGamepadImageArea(GamepadImage *ctx, SDL_FRect *area);
-extern void GetGamepadTouchpadArea(GamepadImage *ctx, SDL_FRect *area);
+extern void GetGamepadTouchpadArea(GamepadImage *ctx, SDL_FRect *area, int touchpad);
extern void SetGamepadImageShowingFront(GamepadImage *ctx, bool showing_front);
extern SDL_GamepadType GetGamepadImageType(GamepadImage *ctx);
extern void SetGamepadImageDisplayMode(GamepadImage *ctx, ControllerDisplayMode display_mode);
diff --git a/test/testcontroller.c b/test/testcontroller.c
index a0fee1c81149b..d6276d97e748b 100644
--- a/test/testcontroller.c
+++ b/test/testcontroller.c
@@ -33,7 +33,7 @@
#define PANEL_SPACING 25.0f
#define PANEL_WIDTH 250.0f
#define GAMEPAD_WIDTH 512.0f
-#define GAMEPAD_HEIGHT 560.0f
+#define GAMEPAD_HEIGHT 596.0f
#define BUTTON_MARGIN 16.0f
#define SCREEN_WIDTH (PANEL_WIDTH + PANEL_SPACING + GAMEPAD_WIDTH + PANEL_SPACING + PANEL_WIDTH)
#define SCREEN_HEIGHT (TITLE_HEIGHT + GAMEPAD_HEIGHT)
@@ -378,9 +378,16 @@ static SDL_GamepadAxis virtual_axis_active = SDL_GAMEPAD_AXIS_INVALID;
static float virtual_axis_start_x;
static float virtual_axis_start_y;
static SDL_GamepadButton virtual_button_active = SDL_GAMEPAD_BUTTON_INVALID;
-static bool virtual_touchpad_active = false;
-static float virtual_touchpad_x;
-static float virtual_touchpad_y;
+
+typedef struct
+{
+ bool active;
+ float x;
+ float y;
+} VirtualTouchpad;
+
+#define MAX_VIRTUAL_TOUCHPADS 2
+static VirtualTouchpad virtual_touchpad[MAX_VIRTUAL_TOUCHPADS];
static int s_arrBindingOrder[] = {
/* Standard sequence */
@@ -1585,7 +1592,10 @@ static bool SDLCALL VirtualGamepadSetLED(void *userdata, Uint8 red, Uint8 green,
static void OpenVirtualGamepad(void)
{
- SDL_VirtualJoystickTouchpadDesc virtual_touchpad = { 1, { 0, 0, 0 } };
+ SDL_VirtualJoystickTouchpadDesc virtual_touchpad_desc[MAX_VIRTUAL_TOUCHPADS] = {
+ { 1, { 0, 0, 0 } },
+ { 1, { 0, 0, 0 } }
+ };
SDL_VirtualJoystickSensorDesc virtual_sensors[] = {
{ SDL_SENSOR_ACCEL, 0.0f },
{ SDL_SENSOR_GYRO, 0.0f }
@@ -1601,8 +1611,8 @@ static void OpenVirtualGamepad(void)
desc.type = SDL_JOYSTICK_TYPE_GAMEPAD;
desc.naxes = SDL_GAMEPAD_AXIS_COUNT;
desc.nbuttons = SDL_GAMEPAD_BUTTON_COUNT;
- desc.ntouchpads = 1;
- desc.touchpads = &virtual_touchpad;
+ desc.ntouchpads = MAX_VIRTUAL_TOUCHPADS;
+ desc.touchpads = virtual_touchpad_desc;
desc.nsensors = SDL_arraysize(virtual_sensors);
desc.sensors = virtual_sensors;
desc.SetPlayerIndex = VirtualGamepadSetPlayerIndex;
@@ -1681,12 +1691,14 @@ static void VirtualGamepadMouseMotion(float x, float y)
}
}
- if (virtual_touchpad_active) {
- SDL_FRect touchpad;
- GetGamepadTouchpadArea(image, &touchpad);
- virtual_touchpad_x = (x - touchpad.x) / touchpad.w;
- virtual_touchpad_y = (y - touchpad.y) / touchpad.h;
- SDL_SetJoystickVirtualTouchpad(virtual_joystick, 0, 0, true, virtual_touchpad_x, virtual_touchpad_y, 1.0f);
+ for (int i = 0; i < MAX_VIRTUAL_TOUCHPADS; ++i) {
+ if (virtual_touchpad[i].active) {
+ SDL_FRect touchpad;
+ GetGamepadTouchpadArea(image, &touchpad, i);
+ virtual_touchpad[i].x = (x - touchpad.x) / touchpad.w;
+ virtual_touchpad[i].y = (y - touchpad.y) / touchpad.h;
+ SDL_SetJoystickVirtualTouchpad(virtual_joystick, i, 0, true, virtual_touchpad[i].x, virtual_touchpad[i].y, 1.0f);
+ }
}
}
@@ -1695,16 +1707,18 @@ static void VirtualGamepadMouseDown(float x, float y)
int element = GetGamepadImageElementAt(image, x, y);
if (element == SDL_GAMEPAD_ELEMENT_INVALID) {
- SDL_FPoint point;
- point.x = x;
- point.y = y;
- SDL_FRect touchpad;
- GetGamepadTouchpadArea(image, &touchpad);
- if (SDL_PointInRectFloat(&point, &touchpad)) {
- virtual_touchpad_active = true;
- virtual_touchpad_x = (x - touchpad.x) / touchpad.w;
- virtual_touchpad_y = (y - touchpad.y) / touchpad.h;
- SDL_SetJoystickVirtualTouchpad(virtual_joystick, 0, 0, true, virtual_touchpad_x, virtual_touchpad_y, 1.0f);
+ for (int i = 0; i < MAX_VIRTUAL_TOUCHPADS; ++i) {
+ SDL_FPoint point;
+ point.x = x;
+ point.y = y;
+ SDL_FRect touchpad;
+ GetGamepadTouchpadArea(image, &touchpad, i);
+ if (SDL_PointInRectFloat(&point, &touchpad)) {
+ virtual_touchpad[i].active = true;
+ virtual_touchpad[i].x = (x - touchpad.x) / touchpad.w;
+ virtual_touchpad[i].y = (y - touchpad.y) / touchpad.h;
+ SDL_SetJoystickVirtualTouchpad(virtual_joystick, i, 0, true, virtual_touchpad[i].x, virtual_touchpad[i].y, 1.0f);
+ }
}
return;
}
@@ -1756,9 +1770,11 @@ static void VirtualGamepadMouseUp(float x, float y)
virtual_axis_active = SDL_GAMEPAD_AXIS_INVALID;
}
- if (virtual_touchpad_active) {
- SDL_SetJoystickVirtualTouchpad(virtual_joystick, 0, 0, false, virtual_touchpad_x, virtual_touchpad_y, 0.0f);
- virtual_touchpad_active = false;
+ for (int i = 0; i < MAX_VIRTUAL_TOUCHPADS; ++i) {
+ if (virtual_touchpad[i].active) {
+ SDL_SetJoystickVirtualTouchpad(virtual_joystick, i, 0, false, virtual_touchpad[i].x, virtual_touchpad[i].y, 0.0f);
+ virtual_touchpad[i].active = false;
+ }
}
}
diff --git a/test/testutils.c b/test/testutils.c
index d828bb49a5683..99f18831e98e0 100644
--- a/test/testutils.c
+++ b/test/testutils.c
@@ -39,6 +39,7 @@ static const struct
{ "gamepad_battery_unknown.png", "GP_BATTX.PNG" },
{ "gamepad_battery_wired.png", "GP_BATTW.PNG" },
{ "gamepad_touchpad.png", "GP_TOUCH.PNG" },
+ { "gamepad_dual_touchpad.png", "GP_DUALT.PNG" },
{ "gamepad_button.png", "GP_BTN.PNG" },
{ "gamepad_button_small.png", "GP_BTNSM.PNG" },
{ "gamepad_button_background.png", "GP_BTNBG.PNG" },