Forum > Games

SDL2 — joystick tester program rewritten from C to Free Pascal


furious programming:
I was looking for information on joystick handling in SDL2 and came across a simple joystick testing program written in C by Sam Lantinga:

I rewrote it to Free Pascal and checked my gamepad, i.e. 8bitdo SN30 Pro. Everything works fine, buttons and axes are correctly recognized and operated, rumble (vibrations) works fine as well. If you need some code to learn joysticks handling in SDL2, the following code may be useful (there is a project for Lazarus in the attachment).

To run the program, the SDL2.dll file should be copied to the program directory. Just go to the GitHub reposity, download the archive and copy the dll file.

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{  Copyright (C) 2022 furious programming   This joystick tester is a translation to the Free Pascal language.  Original code is written in C language by Sam Lantinga:   <>    This tester program uses slightly modified Pascal headers ("SDL-for-Pascal")  developed by "PascalGameDevelopment" and others:   <>   Tested on Windows 10 64-bit, using "SDL2.dll' library version and  with the "8bitdo SN30 Pro" wired controller. Everything works perfectly.    This software is provided 'as-is', without any express or implied  warranty.  In no event will the authors be held liable for any damages  arising from the use of this software.   Permission is granted to anyone to use this software for any purpose,  including commercial applications, and to alter it and redistribute it  freely.} {$MODE OBJFPC}{$LONGSTRINGS ON} { Simple program to test the SDL joystick routines } uses  SDL2; const  SCREEN_WIDTH  = 640;  SCREEN_HEIGHT = 480; var  window: PSDL_Window = nil;  screen: PSDL_Renderer = nil;  joystick: PSDL_Joystick = nil;  done: TSDL_Bool = SDL_FALSE;   function IfThen(Condition: Boolean; IfTrue, IfFalse: PAnsiChar): PAnsiChar;  begin    if Condition then      Result := IfTrue    else      Result := IfFalse;  end;   procedure PrintJoystick(joy: PSDL_Joystick);  var    type_: PAnsiChar;    guid: array [0 .. 63] of AnsiChar;  begin    Assert(SDL_JoystickFromInstanceID(SDL_JoystickInstanceID(joy)) = joy);    SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy), guid, SizeOf(guid));     case SDL_JoystickGetType(joy) of      SDL_JOYSTICK_TYPE_GAMECONTROLLER: type_ := 'Game Controller';      SDL_JOYSTICK_TYPE_WHEEL:          type_ := 'Wheel';      SDL_JOYSTICK_TYPE_ARCADE_STICK:   type_ := 'Arcade Stick';      SDL_JOYSTICK_TYPE_FLIGHT_STICK:   type_ := 'Flight Stick';      SDL_JOYSTICK_TYPE_DANCE_PAD:      type_ := 'Dance Pad';      SDL_JOYSTICK_TYPE_GUITAR:         type_ := 'Guitar';      SDL_JOYSTICK_TYPE_DRUM_KIT:       type_ := 'Drum Kit';      SDL_JOYSTICK_TYPE_ARCADE_PAD:     type_ := 'Arcade Pad';      SDL_JOYSTICK_TYPE_THROTTLE:       type_ := 'Throttle';    otherwise      type_ := 'Unknown';    end;     SDL_Log('Joystick', []);    SDL_Log('          name: %s', [SDL_JoystickName(joy)]);    SDL_Log('          type: %s', [type_]);    SDL_Log('           LED: %s', [IfThen(SDL_JoystickHasLED(joy) = SDL_TRUE, 'yes', 'no')]);    SDL_Log('        rumble: %s', [IfThen(SDL_JoystickHasRumble(joy) = SDL_TRUE, 'yes', 'no')]);    SDL_Log('trigger rumble: %s', [IfThen(SDL_JoystickHasRumbleTriggers(joy) = SDL_TRUE, 'yes', 'no')]);    SDL_Log('          axes: %d', [SDL_JoystickNumAxes(joy)]);    SDL_Log('         balls: %d', [SDL_JoystickNumBalls(joy)]);    SDL_Log('          hats: %d', [SDL_JoystickNumHats(joy)]);    SDL_Log('       buttons: %d', [SDL_JoystickNumButtons(joy)]);    SDL_Log('   instance id: %d', [SDL_JoystickInstanceID(joy)]);    SDL_Log('          guid: %s', [guid]);    SDL_Log('       VID/PID: 0x%.4x/0x%.4x', [SDL_JoystickGetVendor(joy), SDL_JoystickGetProduct(joy)]);  end;   procedure DrawRect(r: PSDL_Renderer; x, y, w, h: Integer);  var    area: TSDL_Rect;  begin    area.x := x;    area.y := y;    area.w := w;    area.h := h;     SDL_RenderFillRect(r, @area);  end;   procedure Loop();  var    event: TSDL_Event;    i, x, y: Integer;    hat_pos: UInt8;  begin    { blank screen, set up for drawing this frame. }    SDL_SetRenderDrawColor(screen, $00, $00, $00, SDL_ALPHA_OPAQUE);    SDL_RenderClear(screen);     while SDL_PollEvent(@event) = 1 do    case event.type_ of       SDL_JOYDEVICEADDED:      begin        SDL_Log('Joystick device %d added.', [event.jdevice.which]);         if (joystick = nil) then        begin          joystick := SDL_JoystickOpen(event.jdevice.which);           if (joystick <> nil) then            PrintJoystick(joystick)          else            SDL_Log('Couldn''t open joystick: %s', [SDL_GetError()]);        end;      end;       SDL_JOYDEVICEREMOVED:      begin        SDL_Log('Joystick device %d removed.', [event.jdevice.which]);         if (event.jdevice.which = SDL_JoystickInstanceID(joystick)) then        begin          SDL_JoystickClose(joystick);          joystick := SDL_JoystickOpen(0);        end;      end;       SDL_JOYAXISMOTION:        SDL_Log(          'Joystick %d axis %d value: %d', [            event.jaxis.which,            event.jaxis.axis,            event.jaxis.value          ]        );       SDL_JOYHATMOTION:      begin        SDL_Log('Joystick %d hat %d value:', [event.jhat.which, event.jhat.hat]);         if (event.jhat.value = SDL_HAT_CENTERED)     then SDL_Log(' centered', []);        if (event.jhat.value and SDL_HAT_UP    <> 0) then SDL_Log(' up', []);        if (event.jhat.value and SDL_HAT_RIGHT <> 0) then SDL_Log(' right', []);        if (event.jhat.value and SDL_HAT_DOWN  <> 0) then SDL_Log(' down', []);        if (event.jhat.value and SDL_HAT_LEFT  <> 0) then SDL_Log(' left', []);         SDL_Log('', []);      end;       SDL_JOYBALLMOTION:        SDL_Log(          'Joystick %d ball %d delta: (%d,%d)', [            event.jball.which,            event.jball.ball,            event.jball.xrel,            event.jball.yrel          ]        );       SDL_JOYBUTTONDOWN:      begin        SDL_Log('Joystick %d button %d down', [event.jbutton.which, event.jbutton.button]);         { First button triggers a 0.5 second full strength rumble }        if (event.jbutton.button = 0) then            SDL_JoystickRumble(joystick, $FFFF, $FFFF, 500);      end;       SDL_JOYBUTTONUP:        SDL_Log('Joystick %d button %d up', [event.jbutton.which, event.jbutton.button]);       SDL_KEYDOWN:      begin        {          Press the L key to lag for 3 seconds, to see what happens          when SDL doesn't service the event loop quickly.        }        if (event.key.keysym.sym = SDLK_l) then        begin          SDL_Log('Lagging for 3 seconds...', []);          SDL_Delay(3000);        end        else        if ((event.key.keysym.sym = SDLK_ESCAPE) or (event.key.keysym.sym = SDLK_AC_BACK)) then          done := SDL_TRUE;      end;    end;     if joystick <> nil then    begin      { Update visual joystick state }      SDL_SetRenderDrawColor(screen, $00, $FF, $00, SDL_ALPHA_OPAQUE);       for i := 0 to SDL_JoystickNumButtons(joystick) - 1 do        if (SDL_JoystickGetButton(joystick, i) = SDL_PRESSED) then          DrawRect(screen, (i mod 20) * 34, SCREEN_HEIGHT - 68 + (i div 20) * 34, 32, 32);       SDL_SetRenderDrawColor(screen, $FF, $00, $00, SDL_ALPHA_OPAQUE);      i := 0;       while i < SDL_JoystickNumAxes(joystick) do      begin        { Draw the X/Y axis }        x := SDL_JoystickGetAxis(joystick, i) + 32768;        x *= SCREEN_WIDTH;        x := x div 65535;         if x < 0 then            x := 0        else            if x > SCREEN_WIDTH - 16 then              x := SCREEN_WIDTH - 16;         i += 1;         if i < SDL_JoystickNumAxes(joystick) then          y := SDL_JoystickGetAxis(joystick, i) + 32768        else          y := 32768;         y *= SCREEN_HEIGHT;        y := y div 65535;         if y < 0 then          y := 0        else          if y > SCREEN_HEIGHT - 16 then            y := SCREEN_HEIGHT - 16;         DrawRect(screen, x, y, 16, 16);        i += 1;      end;       SDL_SetRenderDrawColor(screen, $00, $00, $FF, SDL_ALPHA_OPAQUE);       for i := 0 to SDL_JoystickNumHats(joystick) - 1 do      begin        { Derive the new position }        x := SCREEN_WIDTH  div 2;        y := SCREEN_HEIGHT div 2;        hat_pos := SDL_JoystickGetHat(joystick, i);         if hat_pos and SDL_HAT_UP <> 0 then          y := 0        else          if hat_pos and SDL_HAT_DOWN <> 0 then            y := SCREEN_HEIGHT - 8;         if hat_pos and SDL_HAT_LEFT <> 0 then          x := 0        else          if hat_pos and SDL_HAT_RIGHT <> 0 then            x := SCREEN_WIDTH - 8;         DrawRect(screen, x, y, 8, 8);      end;    end;     SDL_RenderPresent(screen);  end; begin  SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, '0');   { Enable standard application logging }  SDL_LogSetPriority(Ord(SDL_LOG_CATEGORY_APPLICATION), SDL_LOG_PRIORITY_INFO);   { Initialize SDL (Note: video is required to start event loop) }  if SDL_Init(SDL_INIT_VIDEO or SDL_INIT_JOYSTICK) < 0 then  begin    SDL_LogError(Ord(SDL_LOG_CATEGORY_APPLICATION), 'Couldn''t initialize SDL: %s', [SDL_GetError()]);    Halt(1);  end;   { Create a window to display joystick axis position }  window := SDL_CreateWindow('Joystick Test', SDL_WINDOWPOS_CENTERED,                             SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,                             SCREEN_HEIGHT, 0);   if window = nil then  begin    SDL_LogError(Ord(SDL_LOG_CATEGORY_APPLICATION), 'Couldn''t create window: %s', [SDL_GetError()]);    Halt(0);  end;   screen := SDL_CreateRenderer(window, -1, 0);   if screen = nil then  begin    SDL_LogError(Ord(SDL_LOG_CATEGORY_APPLICATION), 'Couldn''t create renderer: %s', [SDL_GetError()]);    SDL_DestroyWindow(window);    Halt(0);  end;   SDL_SetRenderDrawColor(screen, $00, $00, $00, SDL_ALPHA_OPAQUE);  SDL_RenderClear(screen);  SDL_RenderPresent(screen);   { Loop, getting joystick events! }  while done = SDL_FALSE do    Loop();   SDL_DestroyRenderer(screen);  SDL_DestroyWindow(window);   SDL_QuitSubSystem(SDL_INIT_VIDEO or SDL_INIT_JOYSTICK);end.
Have fun.


[0] Message Index

Go to full version