Joysticks

Advanced game related topics
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Joysticks

Post by coco2 »

Thanks for showing the prototype code.

There are two devices when I connect the Xbox 360 controller, "HID-compliant game controller" and "USB Input Device" under Human Interface Devices.

I have found threads on the Steam forums where people are having two controllers appear when they connect one controller.

I could ask on the SDL forum.
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Joysticks

Post by coco2 »

Kenmo I have extended your code to include both controllers and joysticks. I have some USB SNES controllers which all seem to show up as unmanaged joysticks.

I'm having a problem with getting the GUID string, which would be needed for managing unrecognised joysticks so that button mappings can be saved. Have you gotten the GUID procedures working?

Code: Select all

SDL_Library.i = 0
SDL2_Library_Result = OpenLibrary(SDL_Library, "SDL2.dll")
If SDL2_Library_Result : Debug "SDL2 initialised" : Else : Debug "SDL2.dll not found" : End : EndIf

PrototypeC.i _SDL_Init(flags.l) : Global SDL_Init._SDL_Init = GetFunction(SDL_Library, "SDL_Init")
PrototypeC.i _SDL_InitSubSystem(flags.l) : Global SDL_InitSubSystem._SDL_InitSubSystem = GetFunction(SDL_Library, "SDL_InitSubSystem")
PrototypeC.i _SDL_NumJoysticks() : Global SDL_NumJoysticks._SDL_NumJoysticks = GetFunction(SDL_Library, "SDL_NumJoysticks")
PrototypeC.i _SDL_JoystickOpen(Device_Index.l) : Global SDL_JoystickOpen._SDL_JoystickOpen = GetFunction(SDL_Library, "SDL_JoystickOpen")
PrototypeC.i _SDL_IsGameController(Device_Index.l) : Global SDL_IsGameController._SDL_IsGameController = GetFunction(SDL_Library, "SDL_IsGameController")
PrototypeC.i _SDL_GameControllerOpen(Device_Index.l) : Global SDL_GameControllerOpen._SDL_GameControllerOpen = GetFunction(SDL_Library, "SDL_GameControllerOpen")
PrototypeC.i _SDL_JoystickNameForIndex(Device_Index.l) : Global SDL_JoystickNameForIndex._SDL_JoystickNameForIndex = GetFunction(SDL_Library, "SDL_JoystickNameForIndex")
PrototypeC.i _SDL_JoystickNumButtons(SDL_Joystick.l) : Global SDL_JoystickNumButtons._SDL_JoystickNumButtons = GetFunction(SDL_Library, "SDL_JoystickNumButtons")
PrototypeC.i _SDL_JoystickNumAxes(SDL_Joystick.l) : Global SDL_JoystickNumAxes._SDL_JoystickNumAxes = GetFunction(SDL_Library, "SDL_JoystickNumAxes")
PrototypeC.i _SDL_JoystickNumHats(SDL_Joystick.l) : Global SDL_JoystickNumHats._SDL_JoystickNumHats = GetFunction(SDL_Library, "SDL_JoystickNumHats")
PrototypeC.i _SDL_JoystickInstanceID(SDL_Joystick.l) : Global SDL_JoystickInstanceID._SDL_JoystickInstanceID = GetFunction(SDL_Library, "SDL_JoystickInstanceID")
PrototypeC.i _SDL_JoystickGetType(Device_Index.l) : Global SDL_JoystickGetType._SDL_JoystickGetType = GetFunction(SDL_Library, "SDL_JoystickGetType")
PrototypeC.i _SDL_GameControllerNameForIndex(Device_Index.l) : Global SDL_GameControllerNameForIndex._SDL_GameControllerNameForIndex = GetFunction(SDL_Library, "SDL_GameControllerNameForIndex")
PrototypeC.i _SDL_GameControllerGetType(SDL_GameController.l) : Global SDL_GameControllerGetType._SDL_GameControllerGetType = GetFunction(SDL_Library, "SDL_GameControllerGetType")
PrototypeC.i _SDL_GameControllerMapping(Game_Controller.l) : Global SDL_GameControllerMapping._SDL_GameControllerMapping = GetFunction(SDL_Library, "SDL_GameControllerMapping")
PrototypeC.a _SDL_GameControllerGetButton(SDL_GameController.l, SDL_GameControllerButton.l) : Global SDL_GameControllerGetButton._SDL_GameControllerGetButton = GetFunction(SDL_Library, "SDL_GameControllerGetButton")
PrototypeC.w _SDL_GameControllerGetAxis(SDL_GameController.l, SDL_GameControllerAxis.l) : Global SDL_GameControllerGetAxis._SDL_GameControllerGetAxis = GetFunction(SDL_Library, "SDL_GameControllerGetAxis")
PrototypeC.a _SDL_JoystickGetButton(SDL_Joystick.l, Button.l) : Global SDL_JoystickGetButton._SDL_JoystickGetButton = GetFunction(SDL_Library, "SDL_JoystickGetButton")
PrototypeC.w _SDL_JoystickGetAxis(SDL_Joystick.l, Axis.l) : Global SDL_JoystickGetAxis._SDL_JoystickGetAxis = GetFunction(SDL_Library, "SDL_JoystickGetAxis")
PrototypeC.a _SDL_JoystickGetHat(SDL_Joystick.l, Hat.l) : Global SDL_JoystickGetHat._SDL_JoystickGetHat = GetFunction(SDL_Library, "SDL_JoystickGetHat")
PrototypeC _SDL_PumpEvents() : Global SDL_PumpEvents._SDL_PumpEvents = GetFunction(SDL_Library, "SDL_PumpEvents")
PrototypeC.i _SDL_PollEvent(SDL_Event.l) : Global SDL_PollEvent._SDL_PollEvent = GetFunction(SDL_Library, "SDL_PollEvent")
PrototypeC.i _SDL_GameControllerEventState(State.i) : Global SDL_GameControllerEventState._SDL_GameControllerEventState = GetFunction(SDL_Library, "SDL_GameControllerEventState")
PrototypeC.i _SDL_JoystickEventState(State.i) : Global SDL_JoystickEventState._SDL_JoystickEventState = GetFunction(SDL_Library, "SDL_JoystickEventState")
PrototypeC _SDL_JoystickClose(SDL_Joystick.l) : Global SDL_JoystickClose._SDL_JoystickClose = GetFunction(SDL_Library, "SDL_JoystickClose")
PrototypeC _SDL_GameControllerClose(SDL_GameController.l) : Global SDL_GameControllerClose._SDL_GameControllerClose = GetFunction(SDL_Library, "SDL_GameControllerClose")
PrototypeC.i _SDL_GetError() : Global SDL_GetError._SDL_GetError = GetFunction(SDL_Library, "SDL_GetError")
PrototypeC _SDL_Quit() : Global SDL_Quit._SDL_Quit = GetFunction(SDL_Library, "SDL_Quit")
; Others: SDL_JoystickGetGUID, SDL_JoystickGetGUIDString, SDL_JoystickGetDeviceGUID, SDL_GameControllerAddMapping
; SDL_JoystickUpdate, SDL_GameControllerUpdate, SDL_GameControllerGetAttached

#MAX_JOYSTICKS            = $00000010
#MAX_BUTTONS_PER_JOYSTICK = $00000028
#MAX_AXES_PER_JOYSTICK    = $00000028
#MAX_HATS_PER_JOYSTICK    = $00000028

#SDL_ENABLE               = $00000001
#SDL_INIT_JOYSTICK        = $00000200
#SDL_JOYAXISMOTION        = $00000600
#SDL_JOYHATMOTION         = $00000602
#SDL_JOYBUTTONDOWN        = $00000603
#SDL_JOYBUTTONUP          = $00000604
#SDL_INIT_GAMECONTROLLER  = $00002000
#SDL_INIT_EVENTS          = $00004000

#SDL_JOYAXISMOTION        = $00000600
#SDL_JOYHATMOTION         = $00000602
#SDL_JOYDEVICEADDED       = $00000605
#SDL_JOYDEVICEREMOVED     = $00000606
#SDL_CONTROLLERAXISMOTION = $00000650
#SDL_CONTROLLERBUTTONDOWN = $00000651
#SDL_CONTROLLERBUTTONUP   = $00000652

Enumeration Joystick_Type_Enumeration
  #Type_Joystick
  #Type_Controller
EndEnumeration

Enumeration Controller_Buttons
  #SDL_CONTROLLER_BUTTON_INVALID = -1
  #SDL_CONTROLLER_BUTTON_A = 0
  #SDL_CONTROLLER_BUTTON_B = 1
  #SDL_CONTROLLER_BUTTON_X = 2
  #SDL_CONTROLLER_BUTTON_Y = 3
  #SDL_CONTROLLER_BUTTON_BACK = 4
  #SDL_CONTROLLER_BUTTON_GUIDE = 5
  #SDL_CONTROLLER_BUTTON_START = 6
  #SDL_CONTROLLER_BUTTON_LEFTSTICK = 7
  #SDL_CONTROLLER_BUTTON_RIGHTSTICK = 8
  #SDL_CONTROLLER_BUTTON_LEFTSHOULDER = 9
  #SDL_CONTROLLER_BUTTON_RIGHTSHOULDER = 10
  #SDL_CONTROLLER_BUTTON_DPAD_UP = 11
  #SDL_CONTROLLER_BUTTON_DPAD_DOWN = 12
  #SDL_CONTROLLER_BUTTON_DPAD_LEFT = 13
  #SDL_CONTROLLER_BUTTON_DPAD_RIGHT = 14
  #SDL_CONTROLLER_BUTTON_MAX = 15
EndEnumeration

Enumeration Controller_Axes
  #SDL_CONTROLLER_AXIS_INVALID = -1
  #SDL_CONTROLLER_AXIS_LEFTX = 0
  #SDL_CONTROLLER_AXIS_LEFTY = 1
  #SDL_CONTROLLER_AXIS_RIGHTX = 2
  #SDL_CONTROLLER_AXIS_RIGHTY = 3
  #SDL_CONTROLLER_AXIS_TRIGGERLEFT = 4
  #SDL_CONTROLLER_AXIS_TRIGGERRIGHT = 5
  #SDL_CONTROLLER_AXIS_MAX = 6
EndEnumeration

Structure SDL_JoyDeviceEvent_Structure
  Type.l
  Timestamp.l
  Which.l
EndStructure

Structure SDL_JoyButtonEvent_Structure
  Type.l
  Timestamp.l
  Which.l ; Joystick ID
  Button.b
  State.b
EndStructure

Structure SDL_JoyAxisEvent_Structure
  Type.l
  Timestamp.l
  Which.l ; Joystick ID
  Axis.b
  Padding1.b
  Padding2.b
  Padding3.b
  Value.w
EndStructure

Structure SDL_JoyHatEvent_Structure
  Type.l
  Timestamp.l
  Which.l ; Joystick ID
  Hat.b
  Value.w
EndStructure

Structure SDL_Event_Structure
  StructureUnion
    Type.l
    JoyDeviceEvent.SDL_JoyDeviceEvent_Structure
    JoyButtonEvent.SDL_JoyButtonEvent_Structure
    JoyAxisEvent.SDL_JoyAxisEvent_Structure
    JoyHatEvent.SDL_JoyHatEvent_Structure
  EndStructureUnion
EndStructure

Global SDL_Event.SDL_Event_Structure

Structure Button_Structure
  B.w[#MAX_BUTTONS_PER_JOYSTICK]
EndStructure

Structure Axis_Structure
  Axis.w[#MAX_AXES_PER_JOYSTICK]
EndStructure

Structure Hat_Structure
  Hat.w[#MAX_HATS_PER_JOYSTICK]
EndStructure

Structure Controller_Data_Structure
  Type.i ; 0 = Joystick, 1 = controller
  Joystick_ID.l
  Joystick_ID_From_Instance.l
  Controller_ID.l
  Controller_ID_From_Instance.l
  GUID.s
  Index_From_Instance.l
  Joystick_Type.l
  Controller_Type.l
  Joystick_Instance_ID.l
  Joystick_Name.s
  Joystick_GUID.s
  Num_Axes.i
  Num_Hats.i
  Num_Buttons.i
  Button_State.Button_Structure
  Axis_State.Axis_Structure
  Hat_State.Hat_Structure
EndStructure

Procedure.s NameForGCButton(btn)
  Select btn
    Case #SDL_CONTROLLER_BUTTON_A : ProcedureReturn "A"
    Case #SDL_CONTROLLER_BUTTON_B : ProcedureReturn "B"
    Case #SDL_CONTROLLER_BUTTON_X : ProcedureReturn "X"
    Case #SDL_CONTROLLER_BUTTON_Y : ProcedureReturn "Y"
    Case #SDL_CONTROLLER_BUTTON_BACK : ProcedureReturn "Bk"
    Case #SDL_CONTROLLER_BUTTON_DPAD_DOWN : ProcedureReturn "v"
    Case #SDL_CONTROLLER_BUTTON_DPAD_LEFT : ProcedureReturn "<"
    Case #SDL_CONTROLLER_BUTTON_DPAD_RIGHT : ProcedureReturn ">"
    Case #SDL_CONTROLLER_BUTTON_DPAD_UP : ProcedureReturn "^"
    Case #SDL_CONTROLLER_BUTTON_GUIDE : ProcedureReturn "Gd"
    Case #SDL_CONTROLLER_BUTTON_LEFTSHOULDER : ProcedureReturn "[L]"
    Case #SDL_CONTROLLER_BUTTON_LEFTSTICK : ProcedureReturn "(L)"
    Case #SDL_CONTROLLER_BUTTON_RIGHTSHOULDER : ProcedureReturn "[R]"
    Case #SDL_CONTROLLER_BUTTON_RIGHTSTICK : ProcedureReturn "(R)"
    Case #SDL_CONTROLLER_BUTTON_START : ProcedureReturn "St"
    Default : ProcedureReturn "?"
  EndSelect
EndProcedure

Procedure.s GetControllerType(ID.i)
  Select ID
    Case 1: ProcedureReturn "Xbox 360"
    Case 2: ProcedureReturn "Xbox One"
    Case 3: ProcedureReturn "PS3"
    Case 4: ProcedureReturn "PS4"
    Case 5: ProcedureReturn "Nintendo Switch Pro"
    Case 6: ProcedureReturn "Virtual"
    Case 7: ProcedureReturn "PS5"
    Case 8: ProcedureReturn "Amazon Luna"
    Case 9: ProcedureReturn "Google Stadia"
    Default: ProcedureReturn "Unknown"
  EndSelect     
EndProcedure  

Procedure.s GetJoystickType(ID.i)
  Select ID
    Case 1: ProcedureReturn "Game controller"
    Case 2: ProcedureReturn "Wheel"
    Case 3: ProcedureReturn "Arcade stick"
    Case 4: ProcedureReturn "Flight stick"
    Case 5: ProcedureReturn "Dance pad"
    Case 6:  ; GUITAR
    Case 7:  ; GUITAR_ALTERNATE
    Case 11: ; GUITAR_BASS
            ProcedureReturn "Guitar"
    Case 8: ProcedureReturn "Drum kit"
    Case 19: ProcedureReturn "Arcade pad"
    Default: ProcedureReturn "Unknown"
  EndSelect
EndProcedure
 
Dim Joysticks.Controller_Data_Structure(#MAX_JOYSTICKS)
Global Num_Joysticks.i
Global Use_Events.i, Use_Joystick_Events.i

Procedure DrawLists(Array Joysticks.Controller_Data_Structure(1))
  For c1 = 0 To Num_Joysticks-1
    If Joysticks(c1)\Type = #Type_Controller
      ; process controller
      RowText.s = Joysticks(c1)\Joystick_Name
      RowText + #LF$ + StrF(Joysticks(c1)\Axis_State\Axis[#SDL_CONTROLLER_AXIS_LEFTX]/32768.0,2)
      RowText + ", " + StrF(Joysticks(c1)\Axis_State\Axis[#SDL_CONTROLLER_AXIS_LEFTY]/32768.0,2)
      RowText + #LF$ + StrF(Joysticks(c1)\Axis_State\Axis[#SDL_CONTROLLER_AXIS_RIGHTX]/32768.0,2)
      RowText + ", " + StrF(Joysticks(c1)\Axis_State\Axis[#SDL_CONTROLLER_AXIS_RIGHTY]/32768.0,2)
      RowText + #LF$ + StrF(Joysticks(c1)\Axis_State\Axis[#SDL_CONTROLLER_AXIS_TRIGGERLEFT]/32768.0,2)
      RowText + ", " + StrF(Joysticks(c1)\Axis_State\Axis[#SDL_CONTROLLER_AXIS_TRIGGERRIGHT]/32768.0,2)
      Text.s = #LF$
      For c2 = 0 To #SDL_CONTROLLER_BUTTON_MAX-1
        If Joysticks(c1)\Button_State\B[c2]
          Text = Text + NameForGCButton(c2)
        Else
          Text = Text + "-"
        EndIf
      Next c2
      RowText + Text
      AddGadgetItem(0, c1, RowText)
    EndIf      
  Next c1
  For c1 = 0 To Num_Joysticks-1
    If Joysticks(c1)\Type = #Type_Joystick
      ; process joystick
      RowText.s = Joysticks(c1)\Joystick_Name
      For c2 = 0 To 5
        RowText + #LF$ + StrF(Joysticks(c1)\Axis_State\Axis[c2]/32768.0,2)
      Next
      For c2 = 0 To 3
        RowText + #LF$ + StrF(Joysticks(c1)\Hat_State\Hat[c2]/32768.0,2)
      Next      
      Text.s = #LF$
      For c2 = 0 To #SDL_CONTROLLER_BUTTON_MAX-1
        If Joysticks(c1)\Button_State\B[c2]
          Text = Text + "*"
        Else
          Text = Text + "-"
        EndIf
      Next c2
      RowText + Text
      AddGadgetItem(1, c1, RowText)
    EndIf
  Next c1  
EndProcedure

Procedure GetDeviceInformation(Array Joysticks.Controller_Data_Structure(1))
Debug "Number of joysticks connected: " + Num_Joysticks
Debug "----------"
For c = 0 To Num_Joysticks-1
  Is_Controller = SDL_IsGameController(c)
  If Is_Controller
    ; process controller
    Joysticks(c)\Type = #Type_Controller
    Joysticks(c)\Joystick_ID = SDL_JoystickOpen(c)
    If Not Joysticks(c)\Joystick_ID
      Debug "Failed to open controller"
      CallFunctionFast(SDL_Quit)
      CloseLibrary(0)
      End
    EndIf
    Num_Controllers = Num_Controllers + 1
    Joysticks(c)\Controller_ID = SDL_GameControllerOpen(c)
    Joysticks(c)\Joystick_Instance_ID = SDL_JoystickInstanceID(Joysticks(c)\Joystick_ID)
    Joysticks(Joysticks(c)\Joystick_Instance_ID)\Controller_ID_From_Instance = Joysticks(c)\Controller_ID
    Joysticks(Joysticks(c)\Joystick_Instance_ID)\Index_From_Instance = c
    Joysticks(c)\Joystick_Name = PeekS(SDL_GameControllerNameForIndex(c), -1, #PB_Ascii)
    Joysticks(c)\Controller_Type = SDL_GameControllerGetType(Joysticks(c)\Controller_ID)
    Debug "Joystick: " + Str(c) + " is a recognised game controller"
    Debug "Name: " + Joysticks(c)\Joystick_Name
    Debug "Type: " + GetControllerType(Joysticks(c)\Controller_Type)
    Debug "Controller ID: " + Joysticks(c)\Controller_ID
    Debug "Instance ID: " + Joysticks(c)\Joystick_Instance_ID
    If Joysticks(c)\Joystick_Instance_ID = -1
      Debug "Error: " + PeekS(CallFunctionFast(SDL_GetError), -1, #PB_Ascii)
      Debug "Failed to get instance of controller"
      SDL_Quit()
      CloseLibrary(0)
      End      
    EndIf    
    *Mapping_String = SDL_GameControllerMapping(Joysticks(c)\Controller_ID)
    If *Mapping_String <> #Null
      Debug "Mapping string: " + PeekS(*Mapping_String, -1, #PB_UTF8)
    EndIf  
  Else
    ; Process joystick
    Joysticks(c)\Type = #Type_Joystick
    Joysticks(c)\Joystick_ID = SDL_JoystickOpen(c)
    If Not Joysticks(c)\Joystick_ID
      Debug "Failed to open controller"
      SDL_Quit()
      CloseLibrary(0)
      End
    EndIf    
    Joysticks(c)\Joystick_Instance_ID = SDL_JoystickInstanceID(Joysticks(c)\Joystick_ID)
    Joysticks(Joysticks(c)\Joystick_Instance_ID)\Joystick_ID_From_Instance = Joysticks(c)\Joystick_ID
    Joysticks(Joysticks(c)\Joystick_Instance_ID)\Index_From_Instance = c
    Joysticks(c)\Joystick_Name = PeekS(SDL_JoystickNameForIndex(c), -1, #PB_Ascii)
    Joysticks(c)\Joystick_Type = SDL_JoystickGetType(Joysticks(c)\Joystick_ID)
    Debug "Joystick: " + c + " is not a recognised game controller"
    Debug "Name: " + Joysticks(c)\Joystick_Name
    Debug "Type: " + GetJoystickType(Joysticks(c)\Joystick_Type)
    Debug "Joystick ID: " + Joysticks(c)\Joystick_ID
    Debug "Instance ID: " + Joysticks(c)\Joystick_Instance_ID
    If Joysticks(c)\Joystick_Instance_ID = -1
      Debug "Error: " + PeekS(CallFunctionFast(SDL_GetError), -1, #PB_Ascii)
      Debug "Failed to get instance of controller"
      SDL_Quit()
      CloseLibrary(0)
      End      
    EndIf     
    Joysticks(c)\Num_Axes = SDL_JoystickNumAxes(Joysticks(c)\Joystick_ID)
    Debug "Joystick " + Str(c) + " has " + Str(Joysticks(c)\Num_Axes) + " axes"
    Joysticks(c)\Num_Hats = SDL_JoystickNumHats(Joysticks(c)\Joystick_ID)
    Debug "Joystick " + Str(c) + " has " + Str(Joysticks(c)\Num_Hats) + " hats"   
    Joysticks(c)\Num_Buttons = SDL_JoystickNumButtons(Joysticks(c)\Joystick_ID)
    Debug "Joystick " + Str(c) + " has " + Str(Joysticks(c)\Num_Buttons) + " buttons"   
  EndIf
  ; Get GUID
  Debug "----------"
Next c
EndProcedure

Procedure ProcessJoysticks(Array Joysticks.Controller_Data_Structure(1))
  If Use_Events
    While (SDL_PollEvent(@SDL_Event))
      Select SDL_Event\Type
        Case #SDL_JOYDEVICEADDED
          Debug "ProcessJoysticks: Joystick added"
          If SDL_Event\JoyDeviceEvent\Which > Num_Joysticks-1
            Num_Joysticks = SDL_NumJoysticks()
            GetDeviceInformation(Joysticks())
            DrawLists(Joysticks())
          EndIf
        Case #SDL_JOYDEVICEREMOVED
          Debug "ProcessJoysticks: Joystick removed"
            Num_Joysticks = SDL_NumJoysticks()
            GetDeviceInformation(Joysticks())
            DrawLists(Joysticks())        
      EndSelect
      If Use_Joystick_Events
        Select SDL_Event\Type
          Case #SDL_CONTROLLERBUTTONDOWN
            If Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Type = #Type_Controller
              Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Button_State\B[SDL_Event\JoyButtonEvent\Button] = 1
            EndIf
          Case #SDL_CONTROLLERBUTTONUP
            If Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Type = #Type_Controller      
              Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Button_State\B[SDL_Event\JoyButtonEvent\Button] = 0
            EndIf
          Case #SDL_CONTROLLERAXISMOTION
            If Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Type = #Type_Controller      
              Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Axis_State\Axis[SDL_Event\JoyAxisEvent\Axis] = SDL_Event\JoyAxisEvent\Value
            EndIf      
          Case #SDL_JOYBUTTONDOWN
            If Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Type = #Type_Joystick
              Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Button_State\B[SDL_Event\JoyButtonEvent\Button] = 1          
            EndIf
          Case #SDL_JOYBUTTONUP
            If Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Type = #Type_Joystick
              Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Button_State\B[SDL_Event\JoyButtonEvent\Button] = 0
            EndIf
          Case #SDL_JOYAXISMOTION
            If Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Type = #Type_Joystick    
              Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Axis_State\Axis[SDL_Event\JoyAxisEvent\Axis] = SDL_Event\JoyAxisEvent\Value
            EndIf      
          Case #SDL_JOYHATMOTION
            If Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Type = #Type_Joystick    
              Joysticks(Joysticks(SDL_Event\JoyButtonEvent\Which)\Index_From_Instance)\Hat_State\Hat[SDL_Event\JoyHatEvent\Hat] = SDL_Event\JoyHatEvent\Value
            EndIf       
        EndSelect
      Else
        ; don't use events, directly query the joysticks
        SDL_PumpEvents()
        For c1 = 0 To Num_Joysticks-1
          If Joysticks(c1)\Type = #Type_Controller
            For c2 = 0 To #SDL_CONTROLLER_BUTTON_MAX-1
              Joysticks(c1)\Button_State\B[c2] = SDL_GameControllerGetButton(Joysticks(c1)\Controller_ID, c2)
            Next c2
            For c2 = 0 To #SDL_CONTROLLER_AXIS_MAX-1
              Joysticks(c1)\Axis_State\Axis[c2] = SDL_GameControllerGetAxis(Joysticks(c1)\Controller_ID, c2)
            Next c2        
          Else
            For c2 = 0 To Joysticks(c1)\Num_Buttons-1
              Joysticks(c1)\Button_State\B[c2] = SDL_JoystickGetButton(Joysticks(c1)\Joystick_ID, c2)
            Next c2
            For c2 = 0 To Joysticks(c1)\Num_Axes-1
              Joysticks(c1)\Axis_State\Axis[c2] = SDL_JoystickGetAxis(Joysticks(c1)\Joystick_ID, c2)
            Next c2
            For c2 = 0 To Joysticks(c1)\Num_Hats-1
              Joysticks(c1)\Hat_State\Hat[c2] = SDL_JoystickGetHat(Joysticks(c1)\Joystick_ID, c2)
            Next   c2          
          EndIf
        Next c1
      EndIf
    Wend
  EndIf
EndProcedure

Use_Events.i = 1
Use_Joystick_Events.i = 0
Result = SDL_Init(#SDL_INIT_JOYSTICK | #SDL_INIT_GAMECONTROLLER | #SDL_INIT_EVENTS)
If Result = 0
  Debug "Success initialising the controller subsystem"
Else
  Debug "Failed trying to initialise the required subsystems"
  CallFunctionFast(SDL_Quit)
  CloseLibrary(0)  
EndIf
Num_Joysticks = SDL_NumJoysticks()
GetDeviceInformation(Joysticks())
OpenWindow(0, 0, 0, 800, 600, "SDL Controller Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ListIconGadget(0, 10, 30, 780, 250, "Name", 180, #PB_ListIcon_GridLines)
AddGadgetColumn(0, 1, "Left Stick", 80)
AddGadgetColumn(0, 2, "Right Stick", 80)
AddGadgetColumn(0, 3, "Triggers", 80)
AddGadgetColumn(0, 4, "Buttons", 160)
ListIconGadget(1, 10, 330, 780, 250, "Name", 180, #PB_ListIcon_GridLines)
AddGadgetColumn(1, 1, "Axis0", 40)
AddGadgetColumn(1, 2, "Axis1", 40)
AddGadgetColumn(1, 3, "Axis2", 40)
AddGadgetColumn(1, 4, "Axis3", 40)
AddGadgetColumn(1, 5, "Axis4", 40)
AddGadgetColumn(1, 6, "Axis5", 40)
AddGadgetColumn(1, 7, "Hat0", 40)
AddGadgetColumn(1, 8, "Hat1", 40)
AddGadgetColumn(1, 9, "Hat2", 40)
AddGadgetColumn(1, 10, "Hat3", 40)
AddGadgetColumn(1, 11, "Buttons", 160)
TextGadget    (2,  10,  10, 780, 20, "Game Controllers (fully mapped)", #PB_Text_Center)
TextGadget    (3,  10,  310, 780, 20, "Joysticks (unmapped)", #PB_Text_Center)
AddWindowTimer(0, 0, 100)
If Use_Events
  Debug "Enabling events"
  SDL_GameControllerEventState(#SDL_ENABLE)
  SDL_JoystickEventState(#SDL_ENABLE)
EndIf
Repeat
  Wait_Window_Event.i = WaitWindowEvent()
  Select Wait_Window_Event
    Case #PB_Event_Timer
      If EventTimer() = 0
        ProcessJoysticks(Joysticks())
        ClearGadgetItems(0)
        ClearGadgetItems(1)
        DrawLists(Joysticks())
      EndIf
	EndSelect
Until (Wait_Window_Event = #PB_Event_CloseWindow)
For c = 0 To Num_Joysticks-1
  If Joysticks(c)\Type = #Type_Controller
    SDL_GameControllerClose(Joysticks(c)\Controller_ID)
  Else 
    SDL_JoystickClose(Joysticks(c)\Joystick_ID)
  EndIf
Next c
SDL_Quit()
Debug "SDL_Quit"
CloseLibrary(0) 
Debug "Library closed"
End
Rinzwind
Enthusiast
Enthusiast
Posts: 690
Joined: Wed Mar 11, 2009 4:06 pm
Location: NL

Re: Joysticks

Post by Rinzwind »

PB uses SDL on Linux, but DirectInput on Windows. I hope Fred will make it SDL at both sides because it has much better general consistent out of the box gamepad support and make things equal in this regard. Also PB should offer a way to get the exact gamepad model number so any input mapping works across the board and it should hide non functional virtual gamepads (xbox controllers show another controller for directinput compatibility or whatever mysterious reasons). Of course there is XInput which Fred could also add as option which IS consistent, but only supports xbox compatible XInput controllers, of which PS4/5 for whatever silly reason is not one (without additional tooling). But anything of the last decade should function which is enough I guess.

Btw the newest iteration on Windows is Windows.Gaming.Input which supposedly offers a consistent layout for all kind of controllers.

Ps there really is not one complete decent PB open source game that shows full gamepad support and things like mapping buttons I found out. Or I missed it.

Anyway, SDL for all platforms please and add a dew needed missing functions.
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: Joysticks

Post by coco2 »

I had problems with the built in PB Windows one that's why I started using SDL. I would agree with you that a switch to SDL for Windows would be good.
Post Reply