Simple AHK wrapper for SDL2 joystick Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
Hobby77
Posts: 31
Joined: 25 Jan 2021, 01:27

Simple AHK wrapper for SDL2 joystick

09 Apr 2023, 10:41

I am making a simple ahk wrapper for SDL2.dll to help me identify GUIDs, models, mapping keys, etc.
I received the SDL_PollEvent value using Buffer,
But I don't know how to get more specific values, such as jdevice.which
and how to be able to correctly receive the return value of the SDL_JoystickGetGUID

Sorry, my English is not good, here is the document I referenced:
https://wiki.libsdl.org/SDL2/CategoryAPI
https://wiki.libsdl.org/SDL2/SDL_PollEvent
https://wiki.libsdl.org/SDL2/SDL_Event
https://wiki.libsdl.org/SDL2/SDL_JoyDeviceEvent
https://wiki.libsdl.org/SDL2/SDL_JoystickGetGUID

0410: I solved the problem of accessing jdevice.which myself, because they are a union, so share some values.
Now the question is how to get the correct value of the GUID.

And my script(It can be identified including Xinput, PS4, Nintendo Switch Pro Controller...But the identification of GUIDs cannot be achieved):

Code: Select all

#Include <SDL2>
SDL2 := SDL2DLL()

windowRenderTest(SDL2) ;window test
joysticktest(SDL2) ;joystick test

SDL2.SDL_Quit()
; MsgBox("Test Finish")

return

windowRenderTest(SDL2)
{
   ; SDL2.SDL_Init(SDL_INIT_VIDEO := 0x20)
   ; SDL2.SDL_Init(SDL_INIT_JOYSTICK := 0x00000200)
   SDL2.SDL_Init(SDL_INIT_EVERYTHING := -1)

   window := SDL2.SDL_CreateWindow("SDL2 Window Test",0x2FFF0000,0x2FFF0000,"1000","500","0x00000002") ;0x2FFF0000 center
   renderer := SDL2.SDL_CreateRenderer(window,"-1","0x00000002")

   SDL2.SDL_SetRenderDrawColor(renderer, 200, 200, 100, 200) ;rgba
   SDL2.SDL_RenderClear(renderer)
   SDL2.SDL_RenderPresent(renderer)
}

joysticktest(SDL2)
{
   SDL2.SDL_SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1")
   SDL2.SDL_InitSubSystem(SDL_INIT_JOYSTICK := 0x00000200)
   SDL2.SDL_JoystickEventState(1)

   joystickUpdate(SDL2)
   
   ;AHK doesn't support union, need Buffer to receive SDL_Event
   evtBuffer := Buffer(56,0)
   NumPut("UInt", 56, evtBuffer, 0) 

   ;Deal the SDL_Event
   loop
   {
      PollEvent := SDL2.SDL_PollEvent(evtBuffer)
      evt := SDL2DLL.SDL_Event(evtBuffer)
      
      if (PollEvent != 0)
      {
         switch evt.type {
            case SDL_EventType.SDL_QUIT: ; close evt
            SDL2.SDL_Quit()
            break

            case SDL_EventType.SDL_MOUSEMOTION: ; mouse evt
               ToolTip("x: " evt.motion.x "`ny: " evt.motion.y)

            case SDL_EventType.SDL_JOYBUTTONDOWN,SDL_EventType.SDL_JOYBUTTONUP: ; joy button evt
               ToolTip(evt.jbutton.which . "#Joystick`nButton: " evt.jbutton.button "`nState:" evt.jbutton.state)

            case SDL_EventType.SDL_JOYDEVICEADDED,SDL_EventType.SDL_JOYDEVICEREMOVED: 
               joystickUpdate(SDL2)
         }
      }
      SDL2.SDL_Delay(1)
   }
}

joystickUpdate(SDL2)
{
   joyNum := SDL2.SDL_NumJoysticks()
   joyInfo := ""
   if (joyNum>0)
   loop joyNum{
      i := A_index-1
      joy := SDL2.SDL_JoystickOpen(i)

      ;;;;;;;;;;;;
      ; GUID := DllCall("SDL2.dll\SDL_JoystickGetGUID", "Int*", joy,"CDecl Ptr")
      ; pszGUID := Buffer(36,0)
      ; SDL2.SDL_GUIDToString(DllCall("SDL2.dll\SDL_JoystickGetGUID", "Int*", joy,"CDecl Ptr"),pszGUID,36)
      ; MsgBox(NumGet(pszGUID, 0, "char") NumGet(pszGUID, 2, "char") NumGet(pszGUID, 4, "char"))
      ;;;;;;;;;;;;
      name := SDL2.SDL_JoystickName(joy)
      joyInfo .= "port: " i " | name: " name "`n"
   }
      MsgBox(joyInfo, "Joystick Nums:" joyNum)
}
SDL2.AHK

Code: Select all


SDL_EventType := {
    SDL_FIRSTEVENT : 0,
    SDL_QUIT : 0x100,
    /* WinRT app events */
    SDL_APP_TERMINATING : 0x101,
    SDL_APP_LOWMEMORY : 0x102,
    SDL_APP_WILLENTERBACKGROUND : 0x103,
    SDL_APP_DIDENTERBACKGROUND : 0x104,
    SDL_APP_WILLENTERFOREGROUND : 0x105,
    SDL_APP_DIDENTERFOREGROUND : 0x106,

    /* Display events */
    /* Only available in SDL 2.0.9 or higher. */
    SDL_DISPLAYEVENT : 0x150,

    /* Window events */
    SDL_WINDOWEVENT : 0x200,
    SDL_SYSWMEVENT : 0x201,

    /* Keyboard events */
    SDL_KEYDOWN : 0x300,
    SDL_KEYUP : 0x301,
    SDL_TEXTEDITING : 0x302,
    SDL_TEXTINPUT : 0x303,
    SDL_KEYMAPCHANGED : 0x304,

    /* Mouse events */
    SDL_MOUSEMOTION : 0x400,
    SDL_MOUSEBUTTONDOWN : 0x401,
    SDL_MOUSEBUTTONUP : 0x402,
    SDL_MOUSEWHEEL : 0x403,

    /* Joystick events */
    SDL_JOYAXISMOTION : 0x600,
    SDL_JOYBALLMOTION : 0x601,
    SDL_JOYHATMOTION : 0x602,
    SDL_JOYBUTTONDOWN : 0x603,
    SDL_JOYBUTTONUP : 0x604,
    SDL_JOYDEVICEADDED : 0x605,
    SDL_JOYDEVICEREMOVED : 0x606,

    /* Game controller events */
    SDL_CONTROLLERAXISMOTION : 0x650,
    SDL_CONTROLLERBUTTONDOWN : 0x651,
    SDL_CONTROLLERBUTTONUP : 0x652,
    SDL_CONTROLLERDEVICEADDED : 0x653,
    SDL_CONTROLLERDEVICEREMOVED : 0x654,
    SDL_CONTROLLERDEVICEREMAPPED : 0x655,

    /* Touch events */
    SDL_FINGERDOWN : 0x700,
    SDL_FINGERUP : 0x701,
    SDL_FINGERMOTION : 0x702,

    /* Gesture events */
    SDL_DOLLARGESTURE : 0x800,
    SDL_DOLLARRECORD : 0x801,
    SDL_MULTIGESTURE : 0x802,

    /* Clipboard events */
    SDL_CLIPBOARDUPDATE : 0x900,

    /* Drag and drop events */
    SDL_DROPFILE : 0x1000,
    /* Only available in 2.0.4 or higher. */
    SDL_DROPTEXT : 0x1001,
    SDL_DROPBEGIN : 0x1002,
    SDL_DROPCOMPLETE : 0x1003,

    /* Audio hotplug events */
    /* Only available in SDL 2.0.4 or higher. */
    SDL_AUDIODEVICEADDED : 0x1100,
    SDL_AUDIODEVICEREMOVED : 0x1101,

    /* Sensor events */
    /* Only available in SDL 2.0.9 or higher. */
    SDL_SENSORUPDATE : 0x1200,

    /* Render events */
    /* Only available in SDL 2.0.2 or higher. */
    SDL_RENDER_TARGETS_RESET : 0x2000,
    /* Only available in SDL 2.0.4 or higher. */
    SDL_RENDER_DEVICE_RESET : 0x2001,

    /* Events SDL_USEREVENT through SDL_LASTEVENT are for
     * your use, and should be allocated with
     * SDL_RegisterEvents()
     */
    SDL_USEREVENT : 0x8000,

    /* The last event, used for bouding arrays. */
    SDL_LASTEVENT : 0xFFFF
}

; Class JoyInfo{
;     name := ""
;     index := 0
;     __New(name,index) {
;         this.name := name
;         this.index := index
;     }
; }

Class SDL2DLL{
    
    Class SDL_Event{
        type := ""
        motion := {}
        jbutton := {}
       __New(SDL_Event:="") {
            this.type := NumGet(SDL_Event, 0, "UInt")
            this.motion := {type: NumGet(SDL_Event, 0, "UInt")  
                        , timestamp: NumGet(SDL_Event, 4, "UInt")
                        , windowID: NumGet(SDL_Event, 8, "UInt")
                        , which: NumGet(SDL_Event, 12, "UInt")
                        , state: NumGet(SDL_Event, 16, "Char")
                        , padding1: NumGet(SDL_Event, 17, "Char")
                        , padding2: NumGet(SDL_Event, 18, "Char")
                        , padding3: NumGet(SDL_Event, 19, "Char")
                        , x: NumGet(SDL_Event, 20, "UInt")
                        , y: NumGet(SDL_Event, 24, "UInt")
                        , xrel: NumGet(SDL_Event, 28, "UInt")
                        , yrel: NumGet(SDL_Event, 32, "UInt")}

            this.jbutton := {type: NumGet(SDL_Event, 0, "UInt")
                        , timestamp: NumGet(SDL_Event, 4, "UInt")
                        , which: NumGet(SDL_Event, 8, "UInt")
                        , button: NumGet(SDL_Event, 12, "Char")
                        , state: NumGet(SDL_Event, 13, "Char")
                        , padding1: NumGet(SDL_Event, 14, "Char")
                        , padding2: NumGet(SDL_Event, 15, "Char")}
       }
     }

    dll => A_ScriptDir "\SDL2.dll"
    LibLoad => DllCall("LoadLibrary", "Str", this.dll, "Ptr")

    __New() {
       if !this.LibLoad
        MsgBox("Error while loading: " this.dll "`nPlease check the dll version")
    }

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;basic func
    SDL_Delay(millisecond) {
        DllCall(this.dll . "\SDL_Delay", "UInt", millisecond)
    }

    SDL_Init(flags) {
        Return DllCall(this.dll . "\SDL_Init", "UInt", flags,"CDecl")
    }

    SDL_InitSubSystem(flags)
    {
       return DllCall(this.dll . "\SDL_InitSubSystem", "UInt", flags,"CDecl")
    }

    SDL_Quit() {
        DllCall(this.dll . "\SDL_Quit")
        DllCall("FreeLibrary", "Ptr", this.LibLoad)
    }

    SDL_SetHint(name,value){
        return DllCall(this.dll . "\SDL_SetHint", "AStr", name, "AStr", value,"CDecl")
    }
    
    SDL_PollEvent(event){
        return DllCall(this.dll . "\SDL_PollEvent", "Ptr", event,"CDecl")
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;window control and render
    SDL_CreateWindow(title,x,y,w,h,flags) {
        return DllCall(this.dll . "\SDL_CreateWindow", "AStr", title, "Int",x,"Int",y,"Int",w,"Int",h, "UInt", flags,"CDecl")
    }
    
    SDL_CreateRenderer(window,index,flags) {
        return DllCall(this.dll . "\SDL_CreateRenderer", "Int", window, "Int",index, "UInt", flags,"CDecl")
    }
    
    SDL_SetRenderDrawColor(renderer,r,g,b,a) {
        return DllCall(this.dll . "\SDL_SetRenderDrawColor", "Int", renderer, "Short",r, "Short",g, "Short",b, "Short",a,"CDecl")
    }
    
    SDL_RenderClear(renderer) {
        return DllCall(this.dll . "\SDL_RenderClear", "Int", renderer,"CDecl")
    }
    SDL_RenderPresent(renderer) {
        return DllCall(this.dll . "\SDL_RenderPresent", "Int", renderer,"CDecl")
    }
    
    SDL_GetWindowTitle(window){
        return DllCall(this.dll . "\SDL_CreateRenderer", "Int", window,"Cdecl Str")
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;joystick
    SDL_JoystickEventState(state){
        return DllCall(this.dll . "\SDL_JoystickEventState", "Int", state,"CDecl")
    }

    SDL_NumJoysticks(){
        return DllCall(this.dll . "\SDL_NumJoysticks","CDecl")
    }

    SDL_JoystickOpen(index){
        return DllCall(this.dll . "\SDL_JoystickOpen", "Int", index,"CDecl Ptr")
    }

    SDL_JoystickGetGUID(joystick){
        return DllCall(this.dll . "\SDL_JoystickGetGUID", "Ptr", joystick,"CDecl Ptr")
    }

    SDL_JoystickGetDeviceGUID(device_index){
        DllCall(this.dll . "\SDL_JoystickGetDeviceGUID","Ptr",device_index,"Cdecl")
    }

    SDL_JoystickInstanceID(joystick){
        return DllCall(this.dll . "\SDL_JoystickInstanceID", "Ptr", &joystick,"CDecl Ptr")
    }

    SDL_JoystickNameForIndex(joystick){
        return DllCall(this.dll . "\SDL_JoystickNameForIndex", "Int", joystick,"CDecl AStr")
    }
    
    SDL_JoystickName(joystick){
        return DllCall(this.dll . "\SDL_JoystickName", "Ptr", joystick,"CDecl AStr")
    }
; void SDL_GUIDToString(SDL_GUID guid, char *pszGUID, int cbGUID);
;       guid	the ::SDL_GUID you wish to convert to string
;       pszGUID	buffer in which to write the ASCII string
;       cbGUID	the size of pszGUID
    SDL_GUIDToString(guid,pszGUID,cbGUID){
        DllCall(this.dll . "\SDL_GUIDToString", "Ptr", guid,"Ptr",pszGUID,"int",cbGUID)
    }
}
Last edited by Hobby77 on 10 Apr 2023, 01:12, edited 3 times in total.
Hobby77
Posts: 31
Joined: 25 Jan 2021, 01:27

Re: Simple AHK wrapper for SDL2 joystick

09 Apr 2023, 10:47

https://www.dll-files.com/sdl2.dll.html
This is the download URL of the SDL2.dll, if you are interested, thank you very much.
Hobby77
Posts: 31
Joined: 25 Jan 2021, 01:27

Re: Simple AHK wrapper for SDL2 joystick

09 Apr 2023, 12:04

Sorry I made a stupid mistake, it's a union, so they share some values, I think I need to rewrite the script
Hobby77
Posts: 31
Joined: 25 Jan 2021, 01:27

Re: Simple AHK wrapper for SDL2 joystick

10 Apr 2023, 01:21

now it can correctly recognizes the PS4, Nintendo Switch Pro Controller buttons, but the DLLCALL function does not correctly return the value of the GUID type, any good idea?

dll function:
https://wiki.libsdl.org/SDL2/SDL_JoystickGetGUID
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Simple AHK wrapper for SDL2 joystick

10 Apr 2023, 02:18

pass a pointer to a caller-allocated(ie by you) 16byte Buffer as the first hidden parameter
Hobby77
Posts: 31
Joined: 25 Jan 2021, 01:27

Re: Simple AHK wrapper for SDL2 joystick

10 Apr 2023, 08:12

swagfag wrote:
10 Apr 2023, 02:18
pass a pointer to a caller-allocated(ie by you) 16byte Buffer as the first hidden parameter
Is it like this? But still doesn't work

Code: Select all

      joystick := SDL2.SDL_JoystickOpen(0)      
      pguid := Buffer(16,0)
      pguid := DllCall("SDL2.dll\SDL_JoystickGetGUID", "Ptr", joystick,"CDecl Ptr")
      MsgBox(StrGet(pguid))
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Simple AHK wrapper for SDL2 joystick  Topic is solved

10 Apr 2023, 08:34

no, like this:

Code: Select all

joystick := SDL2.SDL_JoystickOpen(0)
guid := Buffer(16,0)
pguid := DllCall("SDL2.dll\SDL_JoystickGetGUID", 'Ptr', guid, "Ptr", joystick,"CDecl Ptr")
also a GUID is not a string, so trying to use StrGet on it makes no sense
Hobby77
Posts: 31
Joined: 25 Jan 2021, 01:27

Re: Simple AHK wrapper for SDL2 joystick

10 Apr 2023, 09:08

swagfag wrote:
10 Apr 2023, 08:34
no, like this:

Code: Select all

joystick := SDL2.SDL_JoystickOpen(0)
guid := Buffer(16,0)
pguid := DllCall("SDL2.dll\SDL_JoystickGetGUID", 'Ptr', guid, "Ptr", joystick,"CDecl Ptr")
also a GUID is not a string, so trying to use StrGet on it makes no sense
Thank you very much for your reply, it worked!!! I ended up using ole32.dll\StringFromGUID2 to get it to show. It's just that I'm curious, this function has only one parameter, why do we pass two parameters to it?

SDL_JoystickGUID SDL_JoystickGetGUID (SDL_Joystick *joystick)
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Simple AHK wrapper for SDL2 joystick

10 Apr 2023, 09:46

the function returns a large(ie larger than ptrsize) struct by value. the x86 and x64 calling conventions dictate that u should pass a pointer to a caller allocated piece of memory as the first parameter
Hobby77
Posts: 31
Joined: 25 Jan 2021, 01:27

Re: Simple AHK wrapper for SDL2 joystick

10 Apr 2023, 10:57

@swagfag
Thank you for your answer, maybe I need to learn more about it
s-ve-n
Posts: 5
Joined: 22 Sep 2018, 04:56

Re: Simple AHK wrapper for SDL2 joystick

30 Nov 2023, 06:21

i copied your code but get this error:
Line Text: SDL_FIRSTEVENT: 0,
Error: This line does not contain a recognized action

i only want to know the guids of the every connected controller. Can you help me?
My conding skills are very low.
s-ve-n
Posts: 5
Joined: 22 Sep 2018, 04:56

Re: Simple AHK wrapper for SDL2 joystick

02 Dec 2023, 05:49

s-ve-n wrote:
30 Nov 2023, 06:21
i copied your code but get this error:
Line Text: SDL_FIRSTEVENT: 0,
Error: This line does not contain a recognized action

i only want to know the guids of the every connected controller. Can you help me?
My conding skills are very low.
ok my first failure was to use ahk 1.x i tried ahk 2.x and got an output

Code: Select all

joystickUpdate(SDL2)
{
   joyNum := SDL2.SDL_NumJoysticks()
   joyInfo := ""
   if (joyNum>0)
   loop joyNum{
      i := A_index-1
      joy := SDL2.SDL_JoystickOpen(i)

      guid := Buffer(16,0)
	  pguid := DllCall("SDL2.dll\SDL_JoystickGetGUID", 'Ptr', guid, "Ptr", joy,"CDecl Ptr")
	  
      name := SDL2.SDL_JoystickName(joy)
      joyInfo .= "port: " i " | name: " name "`n" pguid
   }
      MsgBox(joyInfo, "Joystick Nums:" joyNum)
}
I changed the code like mentioned in the posts above but i do not understand how to get guid as string

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: songdg and 15 guests