Computer Science Canada

Turing Joystick Module PoC

Author:  ericfourfour [ Sat Nov 18, 2006 12:19 am ]
Post subject:  Turing Joystick Module PoC

This is simply a proof of concept showing that the Turing Joystick module actually has a lot of capabilities. I think it covers every button on my controller. The only problem is the Joystick module is very undocumented. All of the stuff used in the following program has no help or tutorials on it what-so-ever. I learned by analyzing the module and by using trial and error.

In the following program you control the two dots with the two analog stick. The left one controls the black dot and the right one controls the red dot. Buttons 1, 2, 3, 4 (that is what they are called on my controller) will make boxes appear at the side of the screen. The code is really messy and has no comments so don't expect to understand it.

code:
var pos : Joystick.PosRecord
var caps : Joystick.CapsRecord
Joystick.Capabilities (joystick1, caps)

loop
    Joystick.Read (joystick1, pos)
    put pos.xpos, " / ", caps.maxX
    put pos.ypos, " / ", caps.maxY
    put pos.zpos, " / ", caps.maxZ
    put pos.rpos, " / ", caps.maxR
    put pos.buttons
    if pos.buttons = 1 then
        Draw.FillBox (10, maxy div 2 - 5, 20, maxy div 2 + 5, blue)
    elsif pos.buttons = 2 then
        Draw.FillBox (maxx div 2 - 5, 10, maxx div 2 + 5, 20, green)
    elsif pos.buttons = 4 then
        Draw.FillBox (maxx - 20, maxy div 2 - 5, maxx - 10, maxy div 2 + 5,
            magenta)
    elsif pos.buttons = 8 then
        Draw.FillBox (maxx div 2 - 5, maxy - 20, maxx div 2 + 5, maxy - 10,
            yellow)
    end if
    Draw.FillOval (round (pos.xpos / caps.maxX * maxx),
        round (maxy - pos.ypos / caps.maxY * maxy), 10, 10, black)
    Draw.FillOval (round (pos.zpos / caps.maxZ * maxx),
        round (maxy - pos.rpos / caps.maxR * maxy), 10, 10, red)
    delay (10)
    cls
end loop


I'm thinking of making a joystick event handler to simplify use with the Joystick. I think it would really make games more interesting if they used controllers.

I've tested this using a logitech rumblepad2. If you could test it with other devices (like maybe a steering wheel or an actual joystick!) that would be cool.

Any feedback would be appreciated.

Author:  Wolf_Destiny [ Sat Nov 18, 2006 9:55 pm ]
Post subject: 

Actually I've been looking at the joystick module, (and I should probably make a tutorial for it or something) and it has a procedure which works much like Mouse.Where

Joystick Module wrote:
procedure GetInfo(jNum: int, var xpos: int, var ypos: int,
var btn1pressed: boolean, var btn2pressed: boolean)


"Yeah because that makes sense right?"

Yeah! Yeah it does! Lemme explain...

mousewhere uses x,y,button right?
Joystick.GetInfo uses id,x,y,btn1,btn2.

Piece by piece:
jNum :int --> The Joystick number or ID. Basically it'll either be 0 or 1 most of the time. Using "joyStick1" (or 2) works in it's place.
Quote:
Joystick.GetInfo (joyStick1

var xpos:int --> X position of the joystick. Actual values depend on your joystick, however it'll be +ve or -ve or 0 depending on position.
Quote:
var x : int := 0
Joystick.GetInfo (joyStick1,x

var ypos:int --> Y position of the joystick. Actual values depend on your joystick, however it'll be +ve or -ve or 0 depending on position.
Quote:
var x,y : int := 0
Joystick.GetInfo (joyStick1,x,y

var btn1pressed : boolean --> has button number 1 been pressed? True or false.
Quote:
var x,y : int := 0
var btn1 : boolean
Joystick.GetInfo (joyStick1,x,y,btn1

var btn2pressed : boolean --> has button number 2 been pressed? True or false.
Quote:
var x,y : int := 0
var btn1,btn2 : boolean
Joystick.GetInfo (joyStick1,x,y,btn1,btn2)


"Okay cool, that's great... really! But....what?"

If you were using mousewhere you would make a program to act based on the x and y position of the cursor right? Same thing with the joystick.

"But what about the buttons?"

if btn1 then
put "OMG you just pressed button 1 on the joystick"
end if

So how the heck do you actually use the joystick? Well that's for you to decide! *cough*flight sim in turing*cough* jk

...

Anyways...so say you want to position a dot at the x and y value of the joystick...
Turing:
var x,y : int := 0
var btn1,btn2 : boolean
loop
Joystick.GetInfo (joyStick1,x,y,btn1,btn2)
if btn1 then
drawdot (x,y,1)
elsif btn2 then
drawdot (x,y,2)
else
drawdot (x,y,3)
end if
end loop


Also here is the documentation that even Turing keeps saying doesn't exist:
Turing's Documentation wrote:
Joystick.GetInfo Part of Joystick module

Syntax Joystick.GetInfo (joystick : int, var xPos, yPos : int,
btn1Pressed, btn2Pressed : boolean)

Description Reads the position and button status of the joystick specified by the joystack parameter. The x and y parameter are returned in the xPos and yPos parameters. If button 1 or button 2 on the joystick are currently pressed, btn1Pressed and btn2Pressed will be set to true. The joystick parameter can be either joystick1 or joystick2.
The x and y positions vary from joyMin to joyMax. To use them with respect to a screen, the coordinates returned from Joystick.GetInfo must be translated into screen coordinates. The following formula can be used:


screenX = round (maxx * (xPos joyMin) / (joyMax joyMin))
screenY = round (maxy * (yPos joyMin) / (joyMax joyMin))

Details The Joystick module contains undocumented subprograms for those who need to access more than two buttons or axes on a joystick. Contact Holt Software if you need more information.

Example The following program outputs the current location of joystick #1 and draws a cursor on the screen to point out where it is showing.

var jx, jy, x, y, ox, oy : int := 1
var b1, b2, oB1, oB2 : boolean := false
loop
Joystick.GetInfo (joystick1, jx, jy, b1, b2)
% Convert joystick coordinates into screen coordinates.
x = round (maxx * (jx joyMin) / (joyMax joyMin))
y = round (maxy * (jy joyMin) / (joyMax joyMin))
if x not= ox or y not= oy or b1 not= oB1 or b2 not= oB2 then
Text.Locate (1, 1)
put "x = ", x, " y = ", y, " b1 = ", b1, " b2 = ", b2
View.Set ("xor")
Draw.Line (ox 10, oy, ox + 10, oy, brightred)
Draw.Line (ox , oy 10, ox , oy + 10, brightred)
Draw.Line (x 10, y, x + 10, y, brightred)
Draw.Line (x, y 10, x, y + 10, brightred)
ox := x
oy := y
oB1 := b1
oB2 := b2
end if
end loop

Status Exported qualified.
This means that you can only call the function by calling Joystick.GetInfo, not by calling GetInfo


~Wolf_Destiny
Making joystick modules available to the typeless typers (aka people who don't know what a type is or how it can enrich their lives)

Edit: I'll test yours with an actual joystick tommorrow when I've got access to my computer again and I'll post the results.

Edit: Also the Joystick module is VERY customizable. I suggest everyone look into it.

Author:  ericfourfour [ Sun Nov 19, 2006 1:13 am ]
Post subject: 

Actually, the one you just wrote about was the only part documented. There is way more abilities undocumented. You can get the status of up 32 different buttons. It supports 3 analog sticks and the D-Pad (POV).

It is however, difficult to work with the 32 buttons. The way it works is it adds the buttons value together. Each button value is a different power of 2. That means there is no combinations of buttons that can have the same sum as a different combination. It also can tell you how many buttons are pressed to simplify things.

Author:  ericfourfour [ Sun Nov 19, 2006 2:10 am ]
Post subject: 

I have made a new joystick program. This one tells you which button is being pressed. The ButtonEvent class uses 2 recursions to sort out which button is being pressed so don't expect to understand it easily.

code:
class ButtonEvent
    export setButtonAmount, displayButton, setButtonStates

    var button : flexible array 0 .. -1 of boolean

    proc displayButton
        for i : 0 .. upper (button)
            put i + 1, ": ", button (i)
        end for
    end displayButton

    proc resetButtons ()
        for i : 0 .. upper (button)
            button (i) := false
        end for
    end resetButtons

    proc setButtonAmount (amount : int)
        new button, amount - 1
        resetButtons ()
    end setButtonAmount

    fcn findPower (number, iteration : int) : int
        if number = 1 then
            result iteration
        end if
        result findPower (number div 2, iteration + 1)
    end findPower

    proc addButton (number : int)
        button (findPower (number, 0)) := true
    end addButton

    %Start from highest and go down
    proc convertStates (total : int, number : int)
        if total = 0 then
            return
        end if
        var newTotal := total
        if number <= total then
            addButton (number)
            newTotal -= number
        end if
        convertStates (newTotal, number div 2)
    end convertStates

    proc setButtonStates (pos : Joystick.PosRecord, caps : Joystick.CapsRecord)
        resetButtons ()
        convertStates (pos.buttons, 2 ** caps.numButtons)
    end setButtonStates
end ButtonEvent

var pos : Joystick.PosRecord
var caps : Joystick.CapsRecord
Joystick.Capabilities (joystick1, caps)

var event : ^ButtonEvent
new ButtonEvent, event
event -> setButtonAmount (caps.numButtons)

loop
    Joystick.Read (joystick1, pos)
    event -> setButtonStates (pos, caps)
    event -> displayButton ()
    delay (10)
    cls
end loop


: