From c9f87272633be22f1ece8082838e471e71c1969e Mon Sep 17 00:00:00 2001
From: Lilis Iskandar <lilis@veand.co>
Date: Mon, 11 Dec 2023 11:32:57 +0800
Subject: [PATCH] sdl: add bindings up to SDL2 2.0.28 and some previously
 missing ones as well

Signed-off-by: Lilis Iskandar <lilis@veand.co>
---
 sdl/TODO.md           |  33 ++++++++++++++
 sdl/clipboard.go      |  58 +++++++++++++++++++++++-
 sdl/events.go         |  73 ++++++++++++++++++++++++++++--
 sdl/gamecontroller.go |  46 +++++++++++++++++--
 sdl/hints.go          |  84 +++++++++++++++++++++++++++++-----
 sdl/joystick.go       |  19 ++++++++
 sdl/sensor.go         | 102 +++++++++++++++---------------------------
 sdl/video.go          |  86 +++++++++++++++++++++++++++++++++++
 8 files changed, 417 insertions(+), 84 deletions(-)

diff --git a/sdl/TODO.md b/sdl/TODO.md
index 23603b56..2f138eb2 100644
--- a/sdl/TODO.md
+++ b/sdl/TODO.md
@@ -1,3 +1,36 @@
+## 2.28.0
+
+[x] SDL_HasWindowSurface, SDL_DestroyWindowSurface
+[x] SDL_DISPLAYEVENT_MOVED
+[x] SDL_HINT_ENABLE_SCREEN_KEYBOARD
+
+## 2.26.0
+
+[x] SDL_MouseWheelEvent: add mouseX and mouseY fields
+[x] SDL_GetWindowSizeInPixels()
+[x] SDL_ResetHints()
+[x] SDL_GetJoystickGUIDInfo()
+[x] SDL_HINT_JOYSTICK_HIDAPI_WII
+[x] SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED
+[x] SDL_HINT_JOYSTICK_HIDAPI_XBOX_360
+[x] SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED
+[x] SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS
+[x] SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE
+[x] SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED
+[x] SDL_HINT_JOYSTICK_HIDAPI_PS3
+[x] SDL_HINT_JOYSTICK_HIDAPI_PS4
+[x] SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE
+[x] SDL_HINT_JOYSTICK_HIDAPI_PS5
+[x] SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED
+[x] SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE
+[x] SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS
+[x] SDL_SensorEvent and SDL_ControllerSensorEvent: add timestamp_us field
+[x] SDL_SensorGetDataWithTimestamp() and SDL_GameControllerGetSensorDataWithTimestamp()
+[x] SDL_HINT_HIDAPI_IGNORE_DEVICES
+[x] SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE
+[x] SDL_SetPrimarySelectionText(), SDL_GetPrimarySelectionText(), and SDL_HasPrimarySelectionText()
+[x] SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP
+
 ## 2.24.0
 
 [x] SDL_GetPointDisplayIndex
diff --git a/sdl/clipboard.go b/sdl/clipboard.go
index 1b26bc8d..08a7a799 100644
--- a/sdl/clipboard.go
+++ b/sdl/clipboard.go
@@ -1,6 +1,33 @@
 package sdl
 
-// #include "sdl_wrapper.h"
+/*
+#include "sdl_wrapper.h"
+
+#if !(SDL_VERSION_ATLEAST(2,26,0))
+
+#if defined(WARN_OUTDATED)
+#pragma message("SDL_SetPrimarySelectionText is not supported before SDL 2.26.0")
+#pragma message("SDL_GetPrimarySelectionText is not supported before SDL 2.26.0")
+#pragma message("SDL_HasPrimarySelectionText is not supported before SDL 2.26.0")
+#endif
+
+static inline int SDL_SetPrimarySelectionText(const char *text)
+{
+    return -1;
+}
+
+static inline char * SDL_GetPrimarySelectionText(void)
+{
+    return NULL;
+}
+
+static inline SDL_bool SDL_HasPrimarySelectionText(void)
+{
+    return SDL_FALSE;
+}
+
+#endif
+*/
 import "C"
 import "unsafe"
 
@@ -32,3 +59,32 @@ func GetClipboardText() (string, error) {
 func HasClipboardText() bool {
 	return C.SDL_HasClipboardText() > 0
 }
+
+// SetPrimarySelectionText puts UTF-8 text into the primary selection.
+// (https://wiki.libsdl.org/SDL_SetPrimarySelectionText)
+func SetPrimarySelectionText(text string) error {
+	_text := C.CString(text)
+	defer C.free(unsafe.Pointer(_text))
+	if C.SDL_SetPrimarySelectionText(_text) < 0 {
+		return GetError()
+	}
+	return nil
+}
+
+// GetPrimarySelectionText gets UTF-8 text from the primary selection.
+// (https://wiki.libsdl.org/SDL_GetPrimarySelectionText)
+func GetPrimarySelectionText() (string, error) {
+	text := C.SDL_GetPrimarySelectionText()
+	if text == nil {
+		return "", GetError()
+	}
+	defer C.SDL_free(unsafe.Pointer(text))
+	_text := C.GoString(text)
+	return _text, nil
+}
+
+// HasPrimarySelectionText queries whether the primary selection exists and contains a non-empty text string.
+// (https://wiki.libsdl.org/SDL_HasPrimarySelectionText)
+func HasPrimarySelectionText() bool {
+	return C.SDL_HasPrimarySelectionText() == C.SDL_TRUE
+}
diff --git a/sdl/events.go b/sdl/events.go
index 25c53342..57de331d 100644
--- a/sdl/events.go
+++ b/sdl/events.go
@@ -83,6 +83,7 @@ typedef struct SDL_SensorEvent {
     Uint32 timestamp;
     Sint32 which;
     float data[6];
+    Uint64 timestamp_us;
 } SDL_SensorEvent;
 #endif
 
@@ -91,6 +92,22 @@ typedef struct SDL_SensorEvent {
 #pragma message("SDL_TEXTEDITING_EXT is not supported before SDL 2.0.22")
 #endif
 
+#if !SDL_VERSION_ATLEAST(2,0,14)
+#define SDL_CONTROLLERTOUCHPADDOWN (0x656)
+#define SDL_CONTROLLERTOUCHPADMOTION (0x657)
+#define SDL_CONTROLLERTOUCHPADUP (0x658)
+#define SDL_CONTROLLERSENSORUPDATE (0x659)
+
+typedef struct SDL_ControllerSensorEvent {
+    Uint32 type;
+    Uint32 timestamp;
+    SDL_JoystickID which;
+    Sint32 sensor;
+    float data[3];
+    Uint64 timestamp_us;
+} SDL_ControllerSensorEvent;
+
+#endif
 
 #define SDL_TEXTEDITING_EXT (0x305)
 #endif
@@ -130,6 +147,8 @@ typedef struct MouseWheelEvent
     Uint32 direction;   // Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back
     float preciseX;     // The amount scrolled horizontally, positive to the right and negative to the left, with float precision (added in 2.0.18)
     float preciseY;     // The amount scrolled vertically, positive away from the user and negative toward the user, with float precision (added in 2.0.18)
+    Sint32 mouseX;       // X coordinate, relative to window (added in 2.26.0) 
+    Sint32 mouseY;       // Y coordinate, relative to window (added in 2.26.0)
 } MouseWheelEvent;
 
 typedef struct TouchFingerEvent
@@ -257,6 +276,10 @@ const (
 	CONTROLLERDEVICEADDED    EventType = C.SDL_CONTROLLERDEVICEADDED    // controller connected
 	CONTROLLERDEVICEREMOVED  EventType = C.SDL_CONTROLLERDEVICEREMOVED  // controller disconnected
 	CONTROLLERDEVICEREMAPPED EventType = C.SDL_CONTROLLERDEVICEREMAPPED // controller mapping updated
+    CONTROLLERTOUCHPADDOWN   EventType = C.SDL_CONTROLLERTOUCHPADDOWN   // Game controller touchpad was touched
+    CONTROLLERTOUCHPADMOTION EventType = C.SDL_CONTROLLERTOUCHPADMOTION // Game controller touchpad finger was moved
+    CONTROLLERTOUCHPADUP     EventType = C.SDL_CONTROLLERTOUCHPADUP     // Game controller touchpad finger was lifted
+    CONTROLLERSENSORUPDATE   EventType = C.SDL_CONTROLLERSENSORUPDATE   // Game controller sensor was updated
 
 	// Touch events
 	FINGERDOWN   EventType = C.SDL_FINGERDOWN   // user has touched input device
@@ -527,6 +550,8 @@ type MouseWheelEvent struct {
 	Direction uint32    // MOUSEWHEEL_NORMAL, MOUSEWHEEL_FLIPPED (>= SDL 2.0.4)
 	PreciseX  float32   // The amount scrolled horizontally, positive to the right and negative to the left, with float precision (added in 2.0.18)
 	PreciseY  float32   // The amount scrolled vertically, positive away from the user and negative toward the user, with float precision (added in 2.0.18)
+	MouseX    int32     // X coordinate, relative to window (added in 2.26.0)
+	MouseY    int32     // Y coordinate, relative to window (added in 2.26.0)
 }
 type cMouseWheelEvent C.MouseWheelEvent
 
@@ -744,6 +769,28 @@ func (e ControllerDeviceEvent) GetTimestamp() uint32 {
 	return e.Timestamp
 }
 
+// ControllerSensorEvent contains data from sensors such as accelerometer and gyroscope
+// (TODO: https://wiki.libsdl.org/SDL_ControllerSensorEvent)
+type ControllerSensorEvent struct {
+	Type        EventType  // SDL_CONTROLLERSENSORUPDATE
+	Timestamp   uint32     // In milliseconds, populated using SDL_GetTicks()
+	Which       JoystickID // The joystick instance id
+    Sensor      int32      // The type of the sensor, one of the values of SensorType
+	Data        [3]float32 // Up to 3 values from the sensor - additional values can be queried using SDL_SensorGetData()
+    TimestampUs uint64     // The timestamp of the sensor reading in microseconds, if the hardware provides this information.
+}
+type cControllerSensorEvent C.SDL_ControllerSensorEvent
+
+// GetType returns the event type.
+func (e ControllerSensorEvent) GetType() EventType {
+	return e.Type
+}
+
+// GetTimestamp returns the timestamp of the event.
+func (e ControllerSensorEvent) GetTimestamp() uint32 {
+	return e.Timestamp
+}
+
 // AudioDeviceEvent contains audio device event information.
 // (https://wiki.libsdl.org/SDL_AudioDeviceEvent)
 type AudioDeviceEvent struct {
@@ -861,10 +908,11 @@ func (e DropEvent) GetTimestamp() uint32 {
 // SensorEvent contains data from sensors such as accelerometer and gyroscope
 // (https://wiki.libsdl.org/SDL_SensorEvent)
 type SensorEvent struct {
-	Type      EventType  // SDL_SENSORUPDATE
-	Timestamp uint32     // In milliseconds, populated using SDL_GetTicks()
-	Which     int32      // The instance ID of the sensor
-	Data      [6]float32 // Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData()
+	Type        EventType  // SDL_SENSORUPDATE
+	Timestamp   uint32     // In milliseconds, populated using SDL_GetTicks()
+	Which       int32      // The instance ID of the sensor
+	Data        [6]float32 // Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData()
+    TimestampUs uint64     // The timestamp of the sensor reading in microseconds, if the hardware provides this information.
 }
 type cSensorEvent C.SDL_SensorEvent
 
@@ -1175,6 +1223,8 @@ func goEvent(cevent *CEvent) Event {
 			Direction: uint32(e.direction),
 			PreciseX:  float32(e.preciseX),
 			PreciseY:  float32(e.preciseY),
+			MouseX:    int32(e.mouseX),
+			MouseY:    int32(e.mouseY),
 		}
 	case JOYAXISMOTION:
 		e := (*cJoyAxisEvent)(unsafe.Pointer(cevent))
@@ -1260,6 +1310,20 @@ func goEvent(cevent *CEvent) Event {
 			Timestamp: uint32(e.timestamp),
 			Which:     JoystickID(e.which),
 		}
+	case CONTROLLERSENSORUPDATE:
+		e := (*cControllerSensorEvent)(unsafe.Pointer(cevent))
+		return ControllerSensorEvent{
+			Type:      EventType(e._type),
+			Timestamp: uint32(e.timestamp),
+			Which:     JoystickID(e.which),
+            Sensor:    int32(e.sensor),
+			Data: [3]float32{
+				float32(e.data[0]),
+				float32(e.data[1]),
+				float32(e.data[2]),
+			},
+            TimestampUs: uint64(e.timestamp_us),
+		}
 	case AUDIODEVICEADDED, AUDIODEVICEREMOVED:
 		e := (*cAudioDeviceEvent)(unsafe.Pointer(cevent))
 		return AudioDeviceEvent{
@@ -1334,6 +1398,7 @@ func goEvent(cevent *CEvent) Event {
 				float32(e.data[4]),
 				float32(e.data[5]),
 			},
+            TimestampUs: uint64(e.timestamp_us),
 		}
 	case RENDER_TARGETS_RESET, RENDER_DEVICE_RESET:
 		// This is a CommonEvent as it doesn't currently (sdl-v2.0.22) have any additional fields
diff --git a/sdl/gamecontroller.go b/sdl/gamecontroller.go
index ebc49e9c..892a27d4 100644
--- a/sdl/gamecontroller.go
+++ b/sdl/gamecontroller.go
@@ -152,7 +152,7 @@ static void SDL_GameControllerSetPlayerIndex(SDL_GameController *gamecontroller,
 #pragma message("SDL_GameControllerSetLED is not supported before SDL 2.0.14")
 #endif
 
-static const char * SDLCALL SDL_GameControllerGetSerial(SDL_GameController *gamecontroller)
+static const char * SDL_GameControllerGetSerial(SDL_GameController *gamecontroller)
 {
 	return NULL;
 }
@@ -162,12 +162,12 @@ static SDL_bool SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SD
 	return SDL_FALSE;
 }
 
-static SDL_bool SDLCALL SDL_GameControllerHasButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
+static SDL_bool SDL_GameControllerHasButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button)
 {
 	return SDL_FALSE;
 }
 
-static int SDLCALL SDL_GameControllerGetNumTouchpads(SDL_GameController *gamecontroller)
+static int SDL_GameControllerGetNumTouchpads(SDL_GameController *gamecontroller)
 {
 	return 0;
 }
@@ -293,6 +293,15 @@ static Uint16 SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontr
 	return 0;
 }
 
+#endif
+
+#if !(SDL_VERSION_ATLEAST(2,26,0))
+#pragma message("SDL_GameControllerGetSensorDataWithTimestamp is not supported before SDL 2.26.0")
+
+static inline int SDL_GameControllerGetSensorDataWithTimestamp(SDL_GameController *gamecontroller, SDL_SensorType type, Uint64 *timestamp, float *data, int num_values)
+{
+    return -1;
+}
 #endif
 */
 import "C"
@@ -735,10 +744,39 @@ func (ctrl *GameController) SendEffect(data []byte) (err error) {
 
 // GetSensorDataRate gets the data rate (number of events per second) of a game controller sensor.
 // (https://wiki.libsdl.org/SDL_GameControllerGetSensorDataRate)
-func (ctrl *GameController) SensorDataRate(typ SensorType) (rate float32) {
+func (ctrl *GameController) GetSensorDataRate(typ SensorType) (rate float32) {
 	return float32(C.SDL_GameControllerGetSensorDataRate(ctrl.cptr(), C.SDL_SensorType(typ)))
 }
 
+// GameControllerGetSensorData gets the current state of a game controller sensor.
+//
+// The number of values and interpretation of the data is sensor dependent.
+// (https://wiki.libsdl.org/SDL_GameControllerGetSensorData)
+func (ctrl *GameController) GetSensorData(typ SensorType, data []float32) (err error) {
+	if data == nil {
+		return nil
+	}
+	_data := (*C.float)(unsafe.Pointer(&data[0]))
+	_numValues := C.int(len(data))
+	err = errorFromInt(int(C.SDL_GameControllerGetSensorData((*C.SDL_GameController)(ctrl), C.SDL_SensorType(typ), _data, _numValues)))
+	return
+}
+
+// GameeControllerGetSensorDataWithTimestamp gets current state of a game controller sensor with the timestamp of the last update.
+//
+// The number of values and interpretation of the data is sensor dependent.
+// (https://wiki.libsdl.org/SDL_GameControllerGetSensorDataWithTimestamp)
+func (ctrl *GameController) GetSensorDataWithTimestamp(typ SensorType, timestamp *uint64, data []float32) (err error) {
+	if data == nil {
+		return nil
+	}
+	_data := (*C.float)(unsafe.Pointer(&data[0]))
+	_numValues := C.int(len(data))
+	_timestamp := (*C.Uint64)(timestamp)
+	err = errorFromInt(int(C.SDL_GameControllerGetSensorDataWithTimestamp((*C.SDL_GameController)(ctrl), C.SDL_SensorType(typ), _timestamp, _data, _numValues)))
+	return
+}
+
 // HasRumble queries whether a game controller has rumble support.
 // (https://wiki.libsdl.org/SDL_GameControllerHasRumble)
 func (ctrl *GameController) HasRumble() bool {
diff --git a/sdl/hints.go b/sdl/hints.go
index f2603b7b..12525089 100644
--- a/sdl/hints.go
+++ b/sdl/hints.go
@@ -4,6 +4,38 @@ package sdl
 #include "sdl_wrapper.h"
 #include "hints.h"
 
+#if !(SDL_VERSION_ATLEAST(2,28,0))
+
+#define SDL_HINT_ENABLE_SCREEN_KEYBOARD ""
+
+#endif
+
+#if !(SDL_VERSION_ATLEAST(2,26,0))
+
+#if defined(WARN_OUTDATED)
+#pragma message("SDL_ResetHints is not supported before SDL 2.26.0")
+#endif
+
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360 ""
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED ""
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS ""
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE ""
+#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED ""
+#define SDL_HINT_JOYSTICK_HIDAPI_PS3 ""
+#define SDL_HINT_JOYSTICK_HIDAPI_WII ""
+#define SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED ""
+#define SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS ""
+#define SDL_HINT_HIDAPI_IGNORE_DEVICES ""
+#define SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE ""
+#define SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP ""
+
+static inline void SDLCALL SDL_ResetHints(void)
+{
+    // do nothing
+}
+
+#endif
+
 #if !(SDL_VERSION_ATLEAST(2,0,20))
 #define SDL_HINT_RENDER_LINE_METHOD ""
 #endif
@@ -13,11 +45,13 @@ package sdl
 #endif
 
 #if !(SDL_VERSION_ATLEAST(2,0,16))
+#define SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE ""
 #define SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT ""
 #define SDL_HINT_AUDIO_INCLUDE_MONITORS ""
 #define SDL_HINT_AUDIO_DEVICE_STREAM_ROLE ""
 #define SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS ""
 #define SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED ""
+#define SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED ""
 #endif
 
 #if !(SDL_VERSION_ATLEAST(2,0,14))
@@ -48,6 +82,8 @@ package sdl
 #define SDL_HINT_MOUSE_DOUBLE_CLICK_TIME ""
 #define SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS ""
 #define SDL_HINT_JOYSTICK_HIDAPI_STEAM ""
+#defien SDL_HINT_JOYSTICK_HIDAPI_PS4 ""
+#defien SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE ""
 #endif
 
 #if !(SDL_VERSION_ATLEAST(2,0,8))
@@ -259,7 +295,6 @@ const (
 	HINT_JOYSTICK_HIDAPI_GAMECUBE                 = C.SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE                 // A variable controlling whether the HIDAPI driver for Nintendo GameCube controllers should be used.
 	HINT_VIDEO_X11_WINDOW_VISUALID                = C.SDL_HINT_VIDEO_X11_WINDOW_VISUALID                // A variable forcing the visual ID chosen for new X11 windows.
 	HINT_VIDEO_X11_FORCE_EGL                      = C.SDL_HINT_VIDEO_X11_FORCE_EGL                      // A variable controlling whether X11 should use GLX or EGL by default.
-	HINT_JOYSTICK_HIDAPI_PS5                      = C.SDL_HINT_JOYSTICK_HIDAPI_PS5                      // A variable controlling whether the HIDAPI driver for PS5 controllers should be used.
 	HINT_MOUSE_RELATIVE_SCALING                   = C.SDL_HINT_MOUSE_RELATIVE_SCALING                   // A variable controlling whether relative mouse motion is affected by renderer scaling.
 	HINT_PREFERRED_LOCALES                        = C.SDL_HINT_PREFERRED_LOCALES                        // Override for SDL_GetPreferredLocales().
 	HINT_JOYSTICK_RAWINPUT                        = C.SDL_HINT_JOYSTICK_RAWINPUT                        // A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
@@ -291,15 +326,20 @@ const (
 	HINT_JOYSTICK_ROG_CHAKRAM                     = C.SDL_HINT_JOYSTICK_ROG_CHAKRAM                     // A variable controlling whether the ROG Chakram mice should show up as joysticks
 	HINT_X11_WINDOW_TYPE                          = C.SDL_HINT_X11_WINDOW_TYPE                          // A variable that forces X11 windows to create as a custom type
 	HINT_VIDEO_WAYLAND_PREFER_LIBDECOR            = C.SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR            // A variable controlling whether the libdecor Wayland backend is preferred over native decrations
-
-	// SDL2 2.0.24
-	HINT_MOUSE_RELATIVE_WARP_MOTION        = C.SDL_HINT_MOUSE_RELATIVE_WARP_MOTION        // A variable controlling whether a motion event should be generated for mouse warping in relative mode
-	HINT_TRACKPAD_IS_TOUCH_ONLY            = C.SDL_HINT_TRACKPAD_IS_TOUCH_ONLY            // A variable that treats trackpads as touch devices
-	HINT_JOYSTICK_HIDAPI_JOY_CONS          = C.SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS          // A variable controlling whether the HIDAPI driver for Nintendo Switch Joy-Cons should be used
-	HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS  = C.SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS  // A variable controlling whether Nintendo Switch Joy-Con controllers will be combined into a single Pro-like controller when using the HIDAPI driver
-	HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED   = C.SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED   // A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Pro controller is opened
-	HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED   = C.SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED   // A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Joy-Con controller is opened
-	HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED = C.SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED // A variable controlling whether the player LEDs should be lit to indicate which player is associated with a Nintendo Switch controller
+	HINT_JOYSTICK_HIDAPI_PS4                      = C.SDL_HINT_JOYSTICK_HIDAPI_PS4                 // A variable controlling whether the HIDAPI driver for PS4 controllers should be used
+	HINT_JOYSTICK_HIDAPI_PS4_RUMBLE               = C.SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE          // A variable controlling whether extended input reports should be used for PS4 controllers when using the HIDAPI driver
+	HINT_JOYSTICK_HIDAPI_PS5                      = C.SDL_HINT_JOYSTICK_HIDAPI_PS5                 // A variable controlling whether the HIDAPI driver for PS5 controllers should be used
+	HINT_JOYSTICK_HIDAPI_PS5_RUMBLE               = C.SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE          // A variable controlling whether extended input reports should be used for PS5 controllers when using the HIDAPI driver
+	HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED           = C.SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED      // A variable controlling whether the player LEDs should be lit to indicate which player is associated with a PS5 controller
+
+	// 2.24.0
+	HINT_MOUSE_RELATIVE_WARP_MOTION               = C.SDL_HINT_MOUSE_RELATIVE_WARP_MOTION        // A variable controlling whether a motion event should be generated for mouse warping in relative mode
+	HINT_TRACKPAD_IS_TOUCH_ONLY                   = C.SDL_HINT_TRACKPAD_IS_TOUCH_ONLY            // A variable that treats trackpads as touch devices
+	HINT_JOYSTICK_HIDAPI_JOY_CONS                 = C.SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS          // A variable controlling whether the HIDAPI driver for Nintendo Switch Joy-Cons should be used
+	HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS         = C.SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS  // A variable controlling whether Nintendo Switch Joy-Con controllers will be combined into a single Pro-like controller when using the HIDAPI driver
+	HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED          = C.SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED   // A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Pro controller is opened
+	HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED          = C.SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED   // A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Joy-Con controller is opened
+	HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED        = C.SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED // A variable controlling whether the player LEDs should be lit to indicate which player is associated with a Nintendo Switch controller
 	HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC  = C.SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC  // A variable controlling whether the HIDAPI driver for Nintendo Online classic controllers should be used
 	HINT_JOYSTICK_HIDAPI_SHIELD            = C.SDL_HINT_JOYSTICK_HIDAPI_SHIELD            // A variable controlling whether the HIDAPI driver for NVIDIA SHIELD controllers should be used
 	HINT_WINDOWS_DPI_AWARENESS             = C.SDL_HINT_WINDOWS_DPI_AWARENESS             // Controls whether SDL will declare the process to be DPI aware
@@ -310,6 +350,24 @@ const (
 	HINT_LINUX_DIGITAL_HATS                = C.SDL_HINT_LINUX_DIGITAL_HATS                // A variable controlling whether joysticks on Linux will always treat 'hat' axis inputs (ABS_HAT0X - ABS_HAT3Y) as 8-way digital hats without checking whether they may be analog
 	HINT_LINUX_HAT_DEADZONES               = C.SDL_HINT_LINUX_HAT_DEADZONES               // A variable controlling whether digital hats on Linux will apply deadzones to their underlying input axes or use unfiltered values
 	HINT_MAC_OPENGL_ASYNC_DISPATCH         = C.SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH         // A variable controlling whether dispatching OpenGL context updates should block the dispatching thread until the main thread finishes processing
+
+    // 2.26.0
+	HINT_JOYSTICK_HIDAPI_WII                 = C.SDL_HINT_JOYSTICK_HIDAPI_WII                 // A variable controlling whether the HIDAPI driver for Nintendo Wii and Wii U controllers should be used
+	HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED      = C.SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED      // A variable controlling whether the player LEDs should be lit to indicate which player is associated with a Wii controller
+	HINT_JOYSTICK_HIDAPI_XBOX                = C.SDL_HINT_JOYSTICK_HIDAPI_XBOX                // A variable controlling whether the HIDAPI driver for XBox controllers should be used
+	HINT_JOYSTICK_HIDAPI_XBOX_360            = C.SDL_HINT_JOYSTICK_HIDAPI_XBOX_360            // A variable controlling whether the HIDAPI driver for XBox 360 controllers should be used
+	HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED = C.SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED // A variable controlling whether the player LEDs should be lit to indicate which player is associated with an Xbox 360 controller
+	HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS   = C.SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_WIRELESS   // A variable controlling whether the HIDAPI driver for XBox 360 wireless controllers should be used
+	HINT_JOYSTICK_HIDAPI_XBOX_ONE            = C.SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE            // A variable controlling whether the HIDAPI driver for XBox One controllers should be used
+	HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED   = C.SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED   // A variable controlling whether the Home button LED should be turned on when an Xbox One controller is opened
+	HINT_JOYSTICK_HIDAPI_PS3                 = C.SDL_HINT_JOYSTICK_HIDAPI_PS3                 // A variable controlling whether the HIDAPI driver for PS3 controllers should be used
+	HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS   = C.SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS   // A variable controlling whether Nintendo Switch Joy-Con controllers will be in vertical mode when using the HIDAPI driver
+	HINT_HIDAPI_IGNORE_DEVICES               = C.SDL_HINT_HIDAPI_IGNORE_DEVICES               // A variable containing a list of devices to ignore in SDL_hid_enumerate()
+    HINT_MOUSE_RELATIVE_SYSTEM_SCALE         = C.SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE         // A variable controlling whether the system mouse acceleration curve is used for relative mouse motion
+    HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP    = C.SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP    // Enable or disable mouse pointer warp emulation, needed by some older games
+
+    // 2.28.0
+    HINT_ENABLE_SCREEN_KEYBOARD              = C.SDL_HINT_ENABLE_SCREEN_KEYBOARD              // A variable that controls whether the on-screen keyboard should be shown when text input is active
 )
 
 // An enumeration of hint priorities.
@@ -366,6 +424,12 @@ func ResetHint(name string) bool {
 	return C.SDL_ResetHint(_name) == C.SDL_TRUE
 }
 
+// ResetHints resets all hints to the default values.
+// (https://wiki.libsdl.org/SDL_ResetHints)
+func ResetHints() {
+	C.SDL_ResetHints()
+}
+
 // GetHint returns the value of a hint.
 // (https://wiki.libsdl.org/SDL_GetHint)
 func GetHint(name string) string {
diff --git a/sdl/joystick.go b/sdl/joystick.go
index 8d582b69..c5581f45 100644
--- a/sdl/joystick.go
+++ b/sdl/joystick.go
@@ -3,6 +3,14 @@ package sdl
 /*
 #include "sdl_wrapper.h"
 
+#if !(SDL_VERSION_ATLEAST(2,26,0))
+#if defined(WARN_OUTDATED)
+#pragma message("SDL_SDL_GetJoystickGUIDInfo is not supported before SDL 2.26.0")
+#endif
+
+void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version, Uint16 *crc16);
+#endif
+
 #if !(SDL_VERSION_ATLEAST(2,0,4))
 
 #if defined(WARN_OUTDATED)
@@ -445,6 +453,17 @@ func (joyid JoystickID) c() C.SDL_JoystickID {
 	return C.SDL_JoystickID(joyid)
 }
 
+// GetInfo returns the device information encoded in a JoystickGUID structure.
+// (https://wiki.libsdl.org/SDL_GetJoystickGUIDInfo)
+func (guid JoystickGUID) GetInfo() (vendor, product, version, crc16 uint16) {
+    _vendor := (*C.Uint16)(&vendor)
+    _product := (*C.Uint16)(&product)
+    _version := (*C.Uint16)(&version)
+    _crc16 := (*C.Uint16)(&crc16)
+    C.SDL_GetJoystickGUIDInfo(guid.c(), _vendor, _product, _version, _crc16)
+    return
+}
+
 // NumJoysticks returns the number of joysticks attached to the system.
 // (https://wiki.libsdl.org/SDL_NumJoysticks)
 func NumJoysticks() int {
diff --git a/sdl/sensor.go b/sdl/sensor.go
index b9303a3d..28c2aaba 100644
--- a/sdl/sensor.go
+++ b/sdl/sensor.go
@@ -3,6 +3,15 @@ package sdl
 /*
 #include "sdl_wrapper.h"
 
+#if !(SDL_VERSION_ATLEAST(2,26,0))
+#pragma message("SDL_SensorGetDataWithTimestamp is not supported before SDL 2.26.0")
+
+static inline int SDL_SensorGetDataWithTimestamp(SDL_Sensor *sensor, Uint64 *timestamp, float *data, int num_values)
+{
+    return -1;
+}
+#endif
+
 #if !(SDL_VERSION_ATLEAST(2,0,14))
 
 #if defined(WARN_OUTDATED)
@@ -37,6 +46,19 @@ typedef enum
 
 #if defined(WARN_OUTDATED)
 #pragma message("SDL_NumSensors is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetDeviceName is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetDeviceType is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetDeviceNonPortableType is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetDeviceInstanceID is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorOpen is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorFromInstanceID is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetName is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetType is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetNonPortableType is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetInstanceID is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorGetData is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorClose is not supported before SDL 2.0.9")
+#pragma message("SDL_SensorUpdate is not supported before SDL 2.0.9")
 #endif
 
 static inline int SDL_NumSensors()
@@ -44,130 +66,65 @@ static inline int SDL_NumSensors()
 	return 0;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetDeviceName is not supported before SDL 2.0.9")
-#endif
-
 static const char * SDL_SensorGetDeviceName(int device_index)
 {
 	return NULL;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetDeviceType is not supported before SDL 2.0.9")
-#endif
-
 static SDL_SensorType SDL_SensorGetDeviceType(int device_index)
 {
 	return SDL_SENSOR_INVALID;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetDeviceNonPortableType is not supported before SDL 2.0.9")
-#endif
-
 static int SDL_SensorGetDeviceNonPortableType(int device_index)
 {
 	return -1;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetDeviceInstanceID is not supported before SDL 2.0.9")
-#endif
-
 static SDL_SensorID SDL_SensorGetDeviceInstanceID(int device_index)
 {
 	return -1;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorOpen is not supported before SDL 2.0.9")
-#endif
-
 static SDL_Sensor * SDL_SensorOpen(int device_index)
 {
 	return NULL;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorFromInstanceID is not supported before SDL 2.0.9")
-#endif
-
 static SDL_Sensor * SDL_SensorFromInstanceID(SDL_SensorID instance_id)
 {
 	return NULL;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetName is not supported before SDL 2.0.9")
-#endif
-
 static const char * SDL_SensorGetName(SDL_Sensor *sensor)
 {
 	return NULL;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetType is not supported before SDL 2.0.9")
-#endif
-
 static SDL_SensorType SDL_SensorGetType(SDL_Sensor *sensor)
 {
 	return SDL_SENSOR_INVALID;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetNonPortableType is not supported before SDL 2.0.9")
-#endif
-
 static int SDL_SensorGetNonPortableType(SDL_Sensor *sensor)
 {
 	return -1;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetInstanceID is not supported before SDL 2.0.9")
-#endif
-
 static SDL_SensorID SDL_SensorGetInstanceID(SDL_Sensor *sensor)
 {
 	return -1;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorGetData is not supported before SDL 2.0.9")
-#endif
-
 static int SDL_SensorGetData(SDL_Sensor *sensor, float *data, int num_values)
 {
 	return -1;
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorClose is not supported before SDL 2.0.9")
-#endif
-
 static void SDL_SensorClose(SDL_Sensor *sensor)
 {
 }
 
-
-#if defined(WARN_OUTDATED)
-#pragma message("SDL_SensorUpdate is not supported before SDL 2.0.9")
-#endif
-
 static void SDL_SensorUpdate()
 {
 }
@@ -333,6 +290,21 @@ func (sensor *Sensor) GetData(data []float32) (err error) {
 	return
 }
 
+// GetDataWithTimestamp gets the current state of an opened sensor with the timestamp of the last update.
+//
+// The number of values and interpretation of the data is sensor dependent.
+// (https://wiki.libsdl.org/SDL_SensorGetDataWithTimestamp)
+func (sensor *Sensor) GetDataWithTimestamp(timestamp *uint64, data []float32) (err error) {
+	if data == nil {
+		return nil
+	}
+	_data := (*C.float)(unsafe.Pointer(&data[0]))
+	_numValues := C.int(len(data))
+	_timestamp := (*C.Uint64)(timestamp)
+	err = errorFromInt(int(C.SDL_SensorGetDataWithTimestamp((*C.SDL_Sensor)(sensor), _timestamp, _data, _numValues)))
+	return
+}
+
 // Close closes a sensor previously opened with SensorOpen()
 // (https://wiki.libsdl.org/SDL_SensorClose)
 func (sensor *Sensor) Close() {
diff --git a/sdl/video.go b/sdl/video.go
index bb8da7a2..e5b966da 100644
--- a/sdl/video.go
+++ b/sdl/video.go
@@ -9,6 +9,37 @@ static inline Sint32 ShowMessageBox(SDL_MessageBoxData data)
 	return buttonid;
 }
 
+#if !(SDL_VERSION_ATLEAST(2,28,0))
+
+#if defined(WARN_OUTDATED)
+#pragma message("SDL_HasWindowSurface is not supported before SDL 2.28.0")
+#pragma message("SDL_DestroyWindowSurface is not supported before SDL 2.28.0")
+#endif
+
+static inline SDL_bool SDL_HasWindowSurface(SDL_Window *window)
+{
+    return SDL_FALSE;
+}
+
+static inline int SDL_DestroyWindowSurface(SDL_Window *window)
+{
+    return -1;
+}
+
+#endif
+
+#if !(SDL_VERSION_ATLEAST(2,26,0))
+
+#if defined(WARN_OUTDATED)
+#pragma message("SDL_GetWindowSizeInPixels is not supported before SDL 2.26.0")
+#endif
+
+static inline void SDLCALL SDL_GetWindowSizeInPixels(SDL_Window * window, int *w, int *h)
+{
+    // do nothing
+}
+#endif
+
 #if !(SDL_VERSION_ATLEAST(2,0,14))
 
 #if defined(WARN_OUTDATED)
@@ -19,6 +50,25 @@ static inline Sint32 ShowMessageBox(SDL_MessageBoxData data)
 
 #endif
 
+#if (SDL_VERSION_ATLEAST(2,0,9))
+typedef SDL_DisplayOrientation DisplayOrientation;
+#else
+
+typedef enum {
+    SDL_ORIENTATION_UNKNOWN,            // The display orientation can't be determined
+    SDL_ORIENTATION_LANDSCAPE,          // The display is in landscape mode, with the right side up, relative to portrait mode
+    SDL_ORIENTATION_LANDSCAPE_FLIPPED,  // The display is in landscape mode, with the left side up, relative to portrait mode
+    SDL_ORIENTATION_PORTRAIT,           // The display is in portrait mode
+    SDL_ORIENTATION_PORTRAIT_FLIPPED    // The display is in portrait mode, upside down
+} DisplayOrientation;
+
+static inline SDL_DisplayOrientation SDL_GetDisplayOrientation(int displayIndex)
+{
+    return SDL_ORIENTATION_UNKNOWN;
+}
+
+#endif
+
 #if !(SDL_VERSION_ATLEAST(2,0,1))
 static void SDL_GL_GetDrawableSize(SDL_Window *window, int *w, int *h)
 {
@@ -411,6 +461,16 @@ const (
 
 type FlashOperation C.SDL_FlashOperation
 
+const (
+    ORIENTATION_UNKNOWN           DisplayOrientation = C.SDL_ORIENTATION_UNKNOWN           // The display orientation can't be determined
+    ORIENTATION_LANDSCAPE         DisplayOrientation = C.SDL_ORIENTATION_LANDSCAPE         // The display is in landscape mode, with the right side up, relative to portrait mode
+    ORIENTATION_LANDSCAPE_FLIPPED DisplayOrientation = C.SDL_ORIENTATION_LANDSCAPE_FLIPPED // The display is in landscape mode, with the left side up, relative to portrait mode
+    ORIENTATION_PORTRAIT          DisplayOrientation = C.SDL_ORIENTATION_PORTRAIT          // The display is in portrait mode
+    ORIENTATION_PORTRAIT_FLIPPED  DisplayOrientation = C.SDL_ORIENTATION_PORTRAIT_FLIPPED  // The display is in portrait mode, upside down
+)
+
+type DisplayOrientation C.DisplayOrientation
+
 // DisplayMode contains the description of a display mode.
 // (https://wiki.libsdl.org/SDL_DisplayMode)
 type DisplayMode struct {
@@ -545,6 +605,12 @@ func GetCurrentVideoDriver() (string, error) {
 	return C.GoString(name), nil
 }
 
+// GetDisplayOrientation returns the orientation of a display
+// ((https://wiki.libsdl.org/SDLL_GetDisplayOrientation)
+func GetDisplayOrientation(displayIndex int) DisplayOrientation {
+    return DisplayOrientation(C.SDL_GetDisplayOrientation(C.int(displayIndex)))
+}
+
 // GetNumDisplayModes returns the number of available display modes.
 // (https://wiki.libsdl.org/SDL_GetNumDisplayModes)
 func GetNumDisplayModes(displayIndex int) (int, error) {
@@ -791,6 +857,14 @@ func (window *Window) GetSize() (w, h int32) {
 	return int32(_w), int32(_h)
 }
 
+// GetSizeInPixels returns the size of a window in pixels.
+// (https://wiki.libsdl.org/SDL_GetWindowSizeInPixels)
+func (window *Window) GetSizeInPixels() (w, h int32) {
+	var _w, _h C.int
+	C.SDL_GetWindowSizeInPixels(window.cptr(), &_w, &_h)
+	return int32(_w), int32(_h)
+}
+
 // SetMinimumSize sets the minimum size of the window's client area.
 // (https://wiki.libsdl.org/SDL_SetWindowMinimumSize)
 func (window *Window) SetMinimumSize(minW, minH int32) {
@@ -868,6 +942,18 @@ func (window *Window) SetFullscreen(flags uint32) error {
 		C.SDL_SetWindowFullscreen(window.cptr(), C.Uint32(flags))))
 }
 
+// HasSurface returns whether the window has a surface associated with it.
+// (https://wiki.libsdl.org/SDL_HasWindowSurface)
+func (window *Window) HasSurface() bool {
+    return C.SDL_HasWindowSurface(window.cptr()) == C.SDL_TRUE
+}
+
+// DestroySurface destroys the surface associated with the window..
+// (https://wiki.libsdl.org/SDL_DestroyWindowSurface)
+func (window *Window) DestroySurface() error {
+    return errorFromInt(int(C.SDL_DestroyWindowSurface(window.cptr())))
+}
+
 // GetSurface returns the SDL surface associated with the window.
 // (https://wiki.libsdl.org/SDL_GetWindowSurface)
 func (window *Window) GetSurface() (*Surface, error) {