Welcome, Guest
You have to register before you can post on our site.

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 308
» Latest member: Donaldvem
» Forum threads: 1,741
» Forum posts: 17,901

Full Statistics

Latest Threads
The QB64 IDE shell
Forum: Utilities
Last Post: JasonPag
09-16-2024, 05:37 PM
» Replies: 9
» Views: 762
Importance regarding Ches...
Forum: Utilities
Last Post: JasonPag
09-01-2024, 06:34 PM
» Replies: 0
» Views: 31
Chess and Analysis and En...
Forum: Utilities
Last Post: JasonPag
08-28-2024, 02:37 PM
» Replies: 0
» Views: 32
DAY 009:_PutImage
Forum: Keyword of the Day!
Last Post: grymmjack
09-02-2023, 02:57 PM
» Replies: 54
» Views: 2,033
Fall Banner Contest?
Forum: Site Suggestions
Last Post: grymmjack
08-31-2023, 11:50 PM
» Replies: 36
» Views: 1,261
ColorPicker - Function th...
Forum: Dav
Last Post: Dav
08-31-2023, 11:04 PM
» Replies: 3
» Views: 315
Goals(1) = New Tile()
Forum: Works in Progress
Last Post: RhoSigma
08-31-2023, 09:45 PM
» Replies: 3
» Views: 127
micro(A)v11
Forum: QBJS, BAM, and Other BASICs
Last Post: bplus
08-31-2023, 09:14 PM
» Replies: 90
» Views: 3,589
Updating The Single Most ...
Forum: QBJS, BAM, and Other BASICs
Last Post: bplus
08-31-2023, 09:13 PM
» Replies: 7
» Views: 254
QBJS Image Question
Forum: QBJS, BAM, and Other BASICs
Last Post: bplus
08-31-2023, 05:49 PM
» Replies: 5
» Views: 155

 
  Error in Wiki _limit page?
Posted by: PhilOfPerth - 04-13-2023, 01:00 AM - Forum: Wiki Discussion - Replies (3)

In the Wiki, on the _Limit page, point number 5 says we should not try to use _limit for less than once every 60 seconds.
I think this should be 60 times per second, unless I'm reading it incorrectly.  Huh

Print this item

  Is the f1 (help) function broken?
Posted by: PhilOfPerth - 04-13-2023, 12:44 AM - Forum: Help Me! - Replies (5)

Is the f1 (help) function broken?
When I focus a keyword and press f1, I normally get  Help for the word, but today, I'm constantly getting "The Help system is not yet initialised; Do it now?". Huh
Nothing happens when I say Yes to this. Is the function no longer available or is it broken?

Print this item

  Sorted Key Dictionary
Posted by: bplus - 04-12-2023, 06:52 PM - Forum: Utilities - Replies (9)

To turbo charge the speed of my Dictionary code, I am maintaining the Dictionary with a sorted and uppercase Key property. Now we only have to use a Binary search to lookup values to see if a Key already exists or not. This should save loads of time! Also added file Load and Save Dictionary abilities.

Code: (Select All)
Option _Explicit ' Dictionary 3
' b+ remake of TempodiBasic post 2021-04-06
' ref: https://www.qb64.org/forum/index.php?topic=3786.msg131448#msg131448
' 2021-04-07 add some bells and whistles
' 2023-04-11 add Find for faster actions,  add load and save to file

Type Dictionary
    K As String ' keys all caps for faster searches
    V As String
End Type

ReDim MyDict(1 To 1) As Dictionary ' use ubound of array to tell how many values we have

'                                  This code checks all the stuff Dictionary 2 did
' make some new pairs
Print "Show empty MyDict at start of this demo:"
ShowDict MyDict()
Print "Add a KV pair:"
AddModDictionary MyDict(), "mammals", "Cats"
ShowDict MyDict()
Print "Add a KV pair:"
AddModDictionary MyDict(), "trees", "Oak"
ShowDict MyDict()
Print "Add a KV pair:"
AddModDictionary MyDict(), "fish", "Bass"
ShowDict MyDict()
Print "Swap Dogs for Cats in mammals:"
AddModDictionary MyDict(), "mammals", "Dogs"
ShowDict MyDict()
Print "Check current mammals:"
Print "What is current mammal ? answer: "; GetValue$(MyDict(), "mammals")
Print "Remove mammals:"
RemoveKV MyDict(), "mammals"
ShowDict MyDict()
Print "Bring mammals back with Horses AND Dogs,Cats:"
AddAppendDictionary MyDict(), "Mammals", "Horses"
AddAppendDictionary MyDict(), "mammals", "Cats,Dogs"
ShowDict MyDict()
Print "Remove Cats from mammals:"
RemoveValue MyDict(), "mammals", "Cats"
ShowDict MyDict()
Print "Remove Horses from mammals:"
RemoveValue MyDict(), "mammals", "Horses"
ShowDict MyDict()
Print "Remove Unicorns from mammals:"
RemoveValue MyDict(), "mammals", "Unicorns"
ShowDict MyDict()
Print "And finally wipe out mammals again by removing dogs:"
RemoveValue MyDict(), "mammals", "Dogs"
ShowDict MyDict()

' all above seems to work how bout new subs?
Print "Test Save and Load of the Dictionary:"
SaveDictionary MyDict(), "My Dictionary.txt"
_Delay .25
LoadDictionary MyDict(), "My Dictionary.txt"
ShowDict MyDict()
' good

Sub SaveDictionary (Dict() As Dictionary, pathedFileName$)
    Dim As Long i
    Open pathedFileName$ For Output As #1 ' 2 line format key then value list
    For i = 1 To UBound(Dict)
        Print #1, Dict(i).K
        If _Trim$(Dict(i).V) = "" Then Print #1, " " Else Print #1, _Trim$(Dict(i).V)
    Next
    Close #1
End Sub

Sub LoadDictionary (Dict() As Dictionary, pathedFileName$)
    Dim As Long ub ' will track actual amout of items
    ReDim Dict(1 To 1) As Dictionary
    Dict(1).K = "": Dict(1).V = "" ' sometimes var string UDT's have to be zero'd
    If _FileExists(pathedFileName$) Then
        Open pathedFileName$ For Input As #1
        While Not EOF(1)
            ub = ub + 1
            If ub > UBound(Dict) Then ReDim _Preserve Dict(1 To ub + 1000) As Dictionary
            Line Input #1, Dict(ub).K
            Line Input #1, Dict(ub).V
        Wend
        ReDim _Preserve Dict(1 To ub) As Dictionary
    End If
End Sub

' replace 2 TempodiBasic Functions with 1 Sub, to handle both new and modified values for keys and dynamic Dict() dbl string array.
' Now just take ubound of dict() and have number of pairs it contains
Sub AddModDictionary (Dict() As Dictionary, K$, V$) ' mod with mod Find
    ReDim ub As Long, i As Long, ky$, f As Long, ip As Long
    ub = UBound(Dict)
    ky$ = UCase$(_Trim$(K$)) 'don't change k$ but make case insensitive?
    If ky$ <> "" Then ' bullet proof sub routine K$ must not be empty!
        If ub = 1 And Dict(1).K = "" Then 'our very first pair!
            Dict(1).K = ky$: Dict(1).V = V$: Exit Sub
        Else
            'For i = 1 To ub ' see if we have that name yet
            '    If ky$ = Dict(i).K Then Dict(i).V = V$: Exit Sub ' yes name is registered so change value
            'Next
            f = Find&(Dict(), ky$, ip)
            If f Then
                Dict(f).V = V$
            Else
                'still here? add var name and value to dictionary
                ReDim _Preserve Dict(1 To ub + 1) As Dictionary ' create one slot at a time such that ubound = number or pairs
                For i = ub To ip Step -1
                    Dict(i + 1) = Dict(i)
                Next
                Dict(ip).K = ky$: Dict(ip).V = V$ ' fill it with key and value
            End If
        End If
    End If
End Sub

Function GetValue$ (Dict() As Dictionary, K$) 'mod
    Dim f As Long, ip As Long
    f = Find&(Dict(), K$, ip)
    If f Then GetValue$ = Dict(f).V
End Function

Sub ShowDict (Dict() As Dictionary)
    Dim i As Long
    Print "Dictionary has "; _Trim$(Str$(UBound(Dict))); " items."
    For i = 1 To UBound(Dict)
        Print i, Dict(i).K, Dict(i).V
    Next
    Print
    Print "zzz... press any to continue"
    Sleep
    Print
End Sub

Sub RemoveKV (Dict() As Dictionary, K$) ' mod
    Dim As Long j, f, ip
    f = Find&(Dict(), K$, ip)
    If f Then
        If f <> UBound(Dict) Then
            For j = f + 1 To UBound(Dict)
                Swap Dict(j - 1), Dict(j)
            Next
        End If
        ReDim _Preserve Dict(1 To UBound(Dict) - 1) As Dictionary
    End If
End Sub

' instead or replacing a value with another we will add the new value delimited by a comma
Sub AddAppendDictionary (Dict() As Dictionary, K$, V$) ' mod
    Dim As Long ub, i, f, ip
    Dim ky$
    ub = UBound(Dict)
    ky$ = UCase$(_Trim$(K$)) 'don't change k$ but make case insensitive?
    If ky$ <> "" Then ' bullet proof sub routine K$ must not be empty!
        If ub = 1 And Dict(1).K = "" Then 'our very first pair!
            Dict(1).K = ky$: Dict(1).V = V$: Exit Sub
        Else
            f = Find&(Dict(), ky$, ip)
            If f Then
                Dict(f).V = Dict(f).V + "," + V$
            Else

                ReDim _Preserve Dict(1 To ub + 1) As Dictionary ' create one slot at a time such that ubound = number or pairs
                For i = ub To ip Step -1
                    Dict(i + 1) = Dict(i)
                Next
                Dict(ip).K = ky$: Dict(ip).V = V$ ' fill it with key and value
            End If
        End If
    End If
End Sub

Sub RemoveValue (Dict() As Dictionary, K$, RemoveV$) ' mod
    ReDim As Long ub, j, f, ip
    ReDim ky$, b$
    ub = UBound(Dict)
    ky$ = UCase$(_Trim$(K$)) 'don't change k$ but make case insensitive?
    If ky$ <> "" Then ' bullet proof sub routine K$ must not be empty!
        If ub = 1 And Dict(1).K = "" Then 'our very first pair!
            Exit Sub
        Else
            f = Find&(Dict(), ky$, ip)
            If f Then
                If InStr(Dict(f).V, ",") > 0 Then
                    ReDim t$(1 To 1)
                    Split Dict(f).V, ",", t$()
                    For j = 1 To UBound(t$)
                        If t$(j) <> RemoveV$ Then
                            If b$ = "" Then
                                b$ = t$(j)
                            Else
                                b$ = b$ + "," + t$(j)
                            End If
                        End If
                    Next
                    Dict(f).V = b$
                ElseIf Dict(f).V = RemoveV$ Then
                    Dict(f).V = ""
                End If
            End If
        End If
    End If
End Sub

' 2023-04-11 mod for Dictionary Type and inserting new words
Function Find& (SortedArr() As Dictionary, x$, insertPlace&)
    Dim As Long low, hi, test
    Dim xcap$
    xcap$ = UCase$(x$)
    low = LBound(SortedArr): hi = UBound(SortedArr)
    While low <= hi
        test = Int((low + hi) / 2)
        If SortedArr(hi).K < xcap$ Then insertPlace& = hi + 1 Else insertPlace& = low
        If SortedArr(test).K = xcap$ Then
            Find& = test: Exit Function
        Else
            If SortedArr(test).K <= xcap$ Then low = test + 1 Else hi = test - 1
        End If
    Wend
End Function

' note: I buggered this twice now, FOR base 1 array REDIM MyArray (1 to 1) AS ... the (1 to 1) is not same as (1) which was the Blunder!!!
'notes: REDIM the array(0) to be loaded before calling Split '<<<< IMPORTANT dynamic array and empty, can use any lbound though
'This SUB will take a given N delimited string, and delimiter$ and create an array of N+1 strings using the LBOUND of the given dynamic array to load.
'notes: the loadMeArray() needs to be dynamic string array and will not change the LBOUND of the array it is given.  rev 2019-08-27
Sub Split (SplitMeString As String, delim As String, loadMeArray() As String) ' from Handy library
    Dim curpos As Long, arrpos As Long, LD As Long, dpos As Long 'fix use the Lbound the array already has
    curpos = 1: arrpos = LBound(loadMeArray): LD = Len(delim)
    dpos = InStr(curpos, SplitMeString, delim)
    Do Until dpos = 0
        loadMeArray(arrpos) = Mid$(SplitMeString, curpos, dpos - curpos)
        arrpos = arrpos + 1
        If arrpos > UBound(loadMeArray) Then ReDim _Preserve loadMeArray(LBound(loadMeArray) To UBound(loadMeArray) + 1000) As String
        curpos = dpos + LD
        dpos = InStr(curpos, SplitMeString, delim)
    Loop
    loadMeArray(arrpos) = Mid$(SplitMeString, curpos)
    ReDim _Preserve loadMeArray(LBound(loadMeArray) To arrpos) As String 'get the ubound correct
End Sub

Would like to compare with @TempodiBasic and @madscijr but what data set are you testing?

Print this item

  Controller Library
Posted by: TerryRitchie - 04-12-2023, 03:29 PM - Forum: Terry Ritchie - Replies (10)

------------------------------------------------------

05/17/23 - UPDATE

Version 1.10 is now available (code below updated as well as attached ZIP file)


NOTE: This library will now require QB64PE version 3.7.0 and above.

This version now adds the following capabilities:

- Save and load user defined buttons ( __LOAD_BUTTONS, __SAVE_BUTTONS )
- The ability to detect new controllers plugged and existing controllers unplugged/plugged back in ( __NEW_CONTROLLER, __CONNECTED )
- Remove all controller associated user defined buttons ( __REMOVE_CONTROLLER )
- Prior versions automatically created buttons based on integer variables. A change was needed to facilitate the loading of saved button configurations.
  __MAKE_BUTTON is now required to initialize user defined buttons (see documentation in CONTROLLER.BI for more info).
------------------------------------------------------



I wrote a controller library for use with the keyboard, mouse, and joysticks / game pads.



The first code is CONTROLLER.BI to be placed at the top of your code. It also contains the library documentation.



The second code is CONTROLLER.BM to be placed at the bottom of your code.



The next three pieces of code are examples showing the use of the library. A ZIP file is also attached that contains all the code as well. A fourth demo named "Configure_Buttons.BAS" is also included that is a mini-game that highlights all the features of the library.



Give it a whirl and let me know if you find any bugs or changes that I should make to the library. I have not incorporated WHEEL routines yet. Having a bit of an issue getting WHEEL functions to work properly.



Code: (Select All)
'----------------------------
' Controller Library V1.10
' Terry Ritchie
' May 17th, 2023
' Written using QB64PE v3.7.0
'----------------------------
' CONTROLLER.BI
'----------------------------
'
' TODO: Add WHEEL routines
'       Create PDF instructions
'
'----------------------------
' 04/10/23 V1.0  - Initial Release
' 04/26/23 V1.01 - Corrected slot reassigning issues
' 05/17/23 V1.10 - Added __MAKE_BUTTON, __CONNECTED, __SAVE_BUTTONS, __LOAD_BUTTONS, __NEW_CONTROLLER, __REMOVE_CONTROLLER
'                - The library now has the ability to save and load controller user defined button configurations
'                - You can now detect when a controller has been plugged in or unplugged
'                - A controller's user defined button assignments can be removed when the controller has been unplugged
'----------------------------



' +---------------------------------------+
' |                                       |
' |     HOW QB64 HANDLES CONTROLLERS      |
' |                                       |
' +---------------------------------------+
'
' QB64's controller commands work by identifying the connected controllers at program start up using _DEVICES. This list of identified controllers can
' only be added to during program execution. If a controller is unplugged the controller's id number is not removed from the list. Instead, the
' controller will be listed as [DISCONNECTED] through _DEVICE$. When the controller is plugged back in the [DISCONNECTED] will be removed from the
' controller's identifying string returned by _DEVICE$.
'
' This library will support up to six controllers (see the list below in "INITIALIZING THE LIBRARY") connected at one time. The behavior above will only
' become an issue if your user, for whatever reason, has plugged in, and then unplugged, so many controllers that the device list contains all
' [DISCONNECTED] controllers and a new controller plugged in occupies id #7. That controller will not be detected, only the previous controllers the
' user plugged in. This scenario is highly unlikely but, users being users, it may happen. You can test for this condition by checking if _DEVICES is
' ever greater than 6.



' +---------------------------------------+
' |                                       |
' |       INITIALIZING THE LIBRARY        |
' |                                       |
' +---------------------------------------+
'
' The first subroutine that MUST be called is __INITIALIZE_CONTROLLERS. This subroutine initializes all the associated controller variables and
' identifies all connected controllers. Up to 6 total controllers can be detected and used:
'
' - 1 keyboard,  1 mouse,  and 4 joysticks/game pads
' - 1 leyboard,  no mouse, and 5 joysticks/game pads
' - no keyboard, 1 mouse,  and 5 joysticks/game pads
' - no keyboard, no mouse, and 6 joysticks/game pads
'
' Once the connected controllers have been identified the following shared integers will be set with controller ID numbers:
'
' __KEYBOARDCID      Always a value of 1 when a keyboard is detected
' __MOUSECID         Always a value of 2 if a keyboard is also present, 1 if no keyboard detected
' __JOYPAD1CID       The first joystick/game pad detected. Always a value of 3 if a keyboard and mouse present, 1 or 2 otherwise
' __JOYPAD2CID       The second joystick/game pad detected. Always a value of 4 if a keyboard and mouse present, 2 or 3 otherwise
' __JOYPAD3CID       The third joystick/game pad detected. Always a value of 5 if a keyboard and mouse present, 3 or 4 otherwise
' __JOYPAD4CID       The fourth joystick/game pad detected. Always a value of 6 if a keyboard and mouse present, 4 or 5 otherwise
' __JOYPAD5CID       The fifth joystick/game pad detected. ALWAYS A VALUE OF 5. Will only be detected if a keyboard or mouse is NOT present
' __JOYPAD6CID       The sixth joystick/game pad detected. ALWAYS A VALUE OF 6. Will only be detected if a keyboard and mouse are NOT present
'
' NOTE: If a certain controller is not found, for instance a mouse, then the corresponding variable will contain 0 (__MOUSECID = 0)
'
' These variables are now to be used to indentify the controller you wish to interact with. If a variable contains a value other than 0 the controller
' exists and will continue to exist until program termination.



' +---------------------------------------+
' |                                       |
' |        REDETECING CONTROLLERS         |
' |                                       |
' +---------------------------------------+
'
' If at any time you wish to rescan for currently connected controllers you can use this subroutine:
'
' __IDENTIFY_CONTROLLERS
'
' However, you'll more than likely never need to use this subroutine. The library is designed to automatically use __IDENTIFY_CONTROLLERS when a
' change in controller status occurs, such as a new controller plugged in, an existing controller unplugged, or an existing controller plugged back in.
' __INITIALIZE_CONTROLLERS automatically calls this subroutine as well.



' +---------------------------------------+
' |                                       |
' |       GET EXISTING CONTROLLERS        |
' |                                       |
' +---------------------------------------+
'
' The following functions can be used to determine the number and type of controllers found:
'
' __KEYBOARD_EXISTS         - determine if a keyboard controller was found, -1 (TRUE) or 0 (FALSE)
' __MOUSE_EXISTS            - determine if a mouse controller was found, -1 (TRUE) or 0 (FALSE)
' __JOYPAD_EXISTS(Number)   - determine if a joystick/game pad was found
'                             Number = the desired joystick/game pad to query (1 to 6)
'                             If the numbered game pad was found __JOYPAD_EXISTS returns the TOTAL NUMBER of joysticks/game pads found.
'
' Example:
'
' IF __KEYBOARD_EXISTS THEN PRINT "Found!" '                          was keyboard controller found?
' IF __MOUSE_EXISTS THEN PRINT "Found!" '                             was mouse controller found?
' NumberOfJoypads = __JOYPAD_EXISTS(__JOYPAD1CID) '                   query to determine if at least one joystick/game pad found
' IF NumberOfJoypads THEN '                                           at least 1 joystick found?
'     PRINT "Joystick 1 found!" '                                     yes, display result
'     PRINT "Total number of joysticks/game pads:"; NumberOfJoypads
' END IF



' +---------------------------------------+
' |                                       |
' |       GET CONTROLLER PROPERTIES       |
' |                                       |
' +---------------------------------------+
'
' The following functions can be used to query each controller for information:
'
' __CONTROLLER_NAME$(cid) - the descriptive name of the controller
' __BUTTON_TOTAL(cid)     - the number of buttons a controller has
' __AXIS_TOTAL(cid)       - the number of axes a controller has
'
' Example:
'
' IF __JOYPAD1CID THEN                                               ' or "IF __JOYPAD_EXISTS(1) THEN" would work as well
'     PRINT "Joystick 1 name  : "; __CONTROLLER_NAME$(__JOYPAD1CID)
'     PRINT "Buttons available:"; __BUTTON_TOTAL(__JOYPAD1CID)
'     PRINT "Axes available   :"; __AXIS_TOTAL(__JOYPAD1CID)
' END IF



' +---------------------------------------+
' |                                       |
' |       QUERY CONTROLLER DIRECTLY       |
' |                                       |
' +---------------------------------------+
'
' The following function can be used to determine if a controller is plugged in or unplugged:
'
' __CONNECTED(cid)
'
' The function will return a value of -1 (TRUE) if the controller is plugged in and 0 (FALSE) if the controller in unplugged.
'
' Example:
'
' IF __JOYPAD2CID THEN '                                      was joystick 2 detected at program startup?
'     IF __CONNECTED(__JOYPAD2CID) THEN '                     yes, is joystick 2 currently connected?
'         PRINT "Joystick 2 found and currently connected." ' yes, inform user
'     ELSE '                                                  no, joystick 2 has been unplugged
'         PRINT "Joystick 2 is currently unplugged." '        inform user
'     END IF
' END IF
'
' The following functions can be used to query buttons and axes directly from a controller:
'
' __CONTROLLER_BUTTON(cid, Button)
' __CONTROLLER_AXIS(cid, Axis)
'
' Example:
'
' IF __CONTROLLER_BUTTON(__JOYPAD1CID, 1) THEN '        is joystick button one down?
'     PRINT "Joystick button #1 pressed!" '             yes, report findings
' END IF
' IF __CONROLLER_BUTTON(__KEYBOARDCID, CLKEY_UP) THEN ' is keyboard UP ARROW key down?
'     PRINT "Keyboard UP ARROW key pressed!" '          yes, report findings
' END IF
' VerticalAxis = __CONTROLLER_AXIS(__JOYPAD1CID, 1) '   get current vertical axis of joystick/game pad 1



' +---------------------------------------+
' |                                       |
' |     RETRIEVING CONTROLLER EVENTS      |
' |                                       |
' +---------------------------------------+
'
' The __NEW_CONTROLLER function is used to identify when a new controller has been plugged in, and existing controller has been unplugged, or an
' existing controller has been plugged back in:
'
' Controller = __NEW_CONTROLLER(Event)
'
' Event will contain the controller event that was detected (if any):
'
'    0 - no events occurred
'    1 - an existing controller was unplugged       (the constant __UNPLUGGED     can be used to check for this event)
'    2 - an existing controller was plugged back in (the constant __PLUGGEDIN     can be used to check for this event)
'    3 - a new controller has been plugged in       (the constant __NEWCONTROLLER can be used to check for this event)
'
' The function will return the following values:
'
'      - a value of 0 (FALSE) if nothing has changed
'      - the value will contain the new controller id when a new controller is plugged in               (Event = 3     )
'      - the value will contain the controller id of a controller that was unplugged or plugged back in (Event = 1 or 2)
'
' Example:
'
' Controller = __NEW_CONTROLLER(Event) '                                                    check for a controller event
' IF Controller THEN '                                                                      has a controller event ocurred?
'     SELECT CASE Event '                                                                   yes, what happened?
'         CASE __NEW_CONTROLLER '                                                           a new controller was plugged in
'             PRINT "A new controller with the id of"; Controller; "has been plugged in."
'         CASE __PLUGGEDIN '                                                                an existing controller was plugged back in
'             PRINT "Controller id"; Controller; "has been plugged back in."
'         CASE __UNPLUGGED '                                                                an existing controller was unplugged
'             PRINT "Controller id"; Controller; "has been unplugged."
'     END SELECT
' END IF
'
' During game play there is no need to constantly check for controller events. Inside the main game loop during game play a check once per second
' will be more than enough. See the example program named "Configure_buttons.BAS" for a demonstration of this in action.



' +---------------------------------------+
' |                                       |
' |     CREATING USER DEFINED BUTTONS     |
' |                                       |
' +---------------------------------------+
'
' A user defined button can have up to 4 buttons or axes from various controllers associated with it. First, create an integer handle for each user
' defined button:
'
' DIM UP_Button AS INTEGER '    user defined button handles with up to four associated controller buttons and/or axes
' DIM DOWN_Button AS INTEGER
' DIM LEFT_Button AS INTEGER
' DIM RIGHT_Button AS INTEGER
'
' Next, the variables must be identified as user defined buttons using the __MAKE_BUTTON subroutine:
'
' __MAKE_BUTTON UP_Button '     __MAKE_BUTTON statement added with version 1.10
' __MAKE_BUTTON DOWN_Button '   __MAKE_BUTTON must be used with versions 1.10 and above
' __MAKE_BUTTOn LEFT_Button
' __MAKE_BUTTON RIGHT_Button
'
' The following subroutines allow for assigning a controller button and/or axes directly to a user defined button:
'
' __ASSIGN_BUTTON(Handle, cid, Button)
' __ASSIGN_AXIS(Handle, cid, Axis)
'
' Example:
'
' __ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_UP '       keyboard UP ARROW key assigned to UP_Button                     [SLOT1]
' __ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_W '        Keyboard W key also assigned to UP_Button                       [SLOT2]
' __ASSIGN_AXIS UP_Button, __JOYPAD1CID, -2 '                joystick vertical axis UP (-) also assigned to UP_Button        [SLOT3]
' __ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_DOWN '   keyboard DOWN ARROW key assigned to DOWN_Button                 [SLOT1]
' __ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_S '      keyboard S key also assigned to DOWN_Button                     [SLOT2]
' __ASSIGN_AXIS DOWN_Button, __JOYPAD1CID, 2 '               joystick vertical axis DOWN (+) also assigned to DOWN_Button    [SLOT3]
' __ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_LEFT '   keyboard LEFT ARROW key assigned to LEFT_Button                 [SLOT1]
' __ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_A '      keyboard A key also assigned to LEFT_Button                     [SLOT2]
' __ASSIGN_AXIS LEFT_Button, __JOYPAD1CID, -1 '              joystick horizontal axis LEFT (-) also assigned to LEFT_Button  [SLOT3]
' __ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_RIGHT ' keyboard RIGHT ARROW key assigned to RIGHT_Button               [SLOT1]
' __ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_D '     keyboard D key also assigned to RIGHT_Button                    [SLOT2]
' __ASSIGN_AXIS RIGHT_Button, __JOYPAD1CID, 1 '              joystick horizontal axis RIGHT (+) also asigned to RIGHT_Button [SLOT3]
'
' The above example now gives the player the option of using the keyboard ARROW keys, WASD keys, or the joystick to move in all four directions.
' Each of the above user defined buttons still have one slot remaining [SLOT4] and it could be populated with another joystick axis or perhaps
' the keyboard NUMBER PAD arrow keys if you wish.
'
' Joystick and game pad axis directions are defined with positive and negative values. A negative axis value either means UP or LEFT and a positive
' axis value either means DOWN or RIGHT depending on the axis being assigned. Axis deflections are detected when the axis is 50% or greater in
' deflection in a given direction. Top hats and D-Pads typically return a vale of -1 (-100%) or 1 (100%) while analog joystick inputs will change
' from -1 to 1 with a range of values in between. Analog joystick axes will register as a button press when they are deflected -.5 (-50%) to
' .5 (+50%) in either direction. (This .5 value can be changed using __SET_AXIS_THRESHOLD to suit your needs)




' +---------------------------------------+
' |                                       |
' |  SETTING AXIS THRESHOLD SENSITIVITY   |
' |                                       |
' +---------------------------------------+
'
' When using an axis as a button a certain axis deflection must be reached before the axis is considered "pressed". By default a joystick or game pad
' axis must be deflected at least 50% to reach this threshold. The following function can be used to change the threshold sensitivity amount:
'
' __SET_AXIS_THRESHOLD(Value)
'
' Example:
'
' __SET_AXIS_THRESHOLD .25 ' set axis button sensitivity to 25% deflection.
'
' Value can be any number from .01 (1%) to .99 (99%).



' +---------------------------------------+
' |                                       |
' | DETECTING A USER DEFINED BUTTON PRESS |
' |                                       |
' +---------------------------------------+
'
' The following function can be used to test if a user defined button is being pressed:
'
' __BUTTON_DOWN(Handle)
'
' Example:
'
' IF __BUTTON_DOWN(UP_Button) THEN
'     PRINT "Either the keyboard UP ARROW or W key was pressed or joystick 1 was pushed or pressed UP."
' END IF



' +---------------------------------------+
' |                                       |
' |  AUTO-ASSIGNING USER DEFINED BUTTONS  |
' |                                       |
' +---------------------------------------+
'
' Because of the wide variety of joytick and game pad controllers a user may connect it may be best to have the user define the keys, buttons, and
' axes they wish to use. The following subroutine can be used to have the user auto-assign user defined button assignments:
'
' __AUTOASSIGN_BUTTON(Handle)
'
' Example:
'
' __AUTOASSIGN_BUTTON UP_Button ' [SLOT1] wait for a button press or axis deflection
' __AUTOASSIGN_BUTTON UP_Button ' [SLOT2] wait for a button press or axis deflection
'
' __AUTOASSIGN_BUTTON will wait for a controller button press or axis deflection and then store that information into an available slot. Again,
' this can be done up to four times to fill the four available slots.
'
' NOTE: The mouse controller axes are ignored while __AUTOASSIGN_BUTTON waits for a controller button or axis. If you wish to assign mouse movements as
'       axes to a user defined button you'll need to do it manually with __ASSIGN_AXIS.



' +---------------------------------------+
' |                                       |
' |     REMOVING BUTTON ASSIGNMENTS       |
' |                                       |
' +---------------------------------------+
'
' The following subroutine can be used to clear button/axis assignments (slots) from a user defined button:
'
' __REMOVE_BUTTON(Handle, Slot)
'
' Example:
'
' __REMOVE_BUTTON UP_Button, 3   ' remove the assigned button/axis from slot 3
' __REMOVE_BUTTON DOWN_Button, 0 ' remove the assigned buttons/axes from all slots
'
' Slot can range from 1 to 4, or 0 if you wish to remove all user assigned buttons/axes.



' +---------------------------------------+
' |                                       |
' |    REMOVING A CONTROLLER'S BUTTONS    |
' |                                       |
' +---------------------------------------+
'
' The subroutine __REMOVE_CONTROLLER will remove all user assigned buttons associated with a controller. This is most useful when a controller has
' been detected as unplugged by __NEW_CONTROLLER and the associated assigned buttons need to be removed as well.
'
' __REMOVE_CONTROLLER cid
'
' Example:
'
' Controller = __NEW_CONTROLLER(Event) '                                                    check for a controller event
' IF Controller THEN '                                                                      has a controller event ocurred?
'     SELECT CASE Event '                                                                   yes, what happened?
'         CASE __NEW_CONTROLLER '                                                           a new controller was plugged in
'             PRINT "A new controller with the id of"; Controller; "has been plugged in."
'         CASE __PLUGGEDIN '                                                                an existing controller was plugged back in
'             PRINT "Controller id"; Controller; "has been plugged back in."
'             __LOAD_BUTTONS '                                                              load user defined buttons associated with controller (if they exist)
'         CASE __UNPLUGGED '                                                                an existing controller was unplugged
'             PRINT "Controller id"; Controller; "has been unplugged."
'             __REMOVE_CONTROLLER Controller '                                              remove controller's associated user defined buttons
'     END SELECT
' END IF



' +---------------------------------------+
' |                                       |
' | ENABLING/DISABLING BUTTON REASSIGNMENT|
' |                                       |
' +---------------------------------------+
'
' If an attempt is made to assign an axis or button that was previously assigned to a user defined button, the original assignment will be erased and
' replaced by the new assignment by default. This behavior can be changed using the following subroutines:
'
' __BUTTON_REASSIGN_ALLOWED
' __BUTTON_REASSIGN_NOT_ALLOWED
'
' Example:
'
' __BUTTON_REASSIGN_ALLOWED     ' allow previously assigned buttons/axes to be moved into a different user assigned button *DEFAULT*
' __BUTTON_REASSIGN_NOT_ALLOWED ' ignore requests to reassign buttons



' +---------------------------------------+
' |                                       |
' |       GETTING A BUTTON'S NAME         |
' |                                       |
' +---------------------------------------+
'
' When a user defined button is created a descriptive name is also generated and stored. You can use the following function to get a user defined button's
' name:
'
' __BUTTON_NAME$(Handle, Slot)
'
' Example:
'
' ButtonName$ = __BUTTON_NAME$(UP_Button, 1)
'
' Slot values range from 1 to 4.



' +---------------------------------------+
' |                                       |
' |  LOADING/SAVING USER DEFINED BUTTONS  |
' |                                       |
' +---------------------------------------+
'
' It's now possible to save and load user defined buttons associated to controller inputs. Use the __SAVE_BUTTONS subroutine to save the current
' set of user defined buttons and __LOAD_BUTTONS to load any user defined buttons that may be associated with a controller.
'
' __SAVE_BUTTONS ' save all currently configured user define buttons to configuration files
' __LOAD_BUTTONS ' load buttons that are associated with the currently connected controllers
'
' When __SAVED_BUTTONS is used a configration file for each attached controller is created. The name of the controller and the controller's id number
' ised used to create the file. For instance, if a system currently has a keyboard, mouse, Joystick, and game pad. The name of the joystick is
' "Saitek ST290 Pro" and the name of the game pad is "USB Game Pad". The joystick is using id#3 and the game pad is using id#4. The four configration
' files that will be created are:
'
'   - "Keyboard.ID1"
'   - "Mouse.ID2"
'   - "Saitek ST290 Pro.ID3"
'   - "USB Game Pad.ID4"
'
' All user assigned buttons will be saved in their assigned controller configuration file. It's possible to have multiple configration files for any
' given controller based on the id number it is using. For example, let's say the next time the program is started only the USB Game Pad is connected.
' It will be identified as using id number 3. Later on the user plugs in the Saitek ST290 Pro which will now be have an id of 4. When __SAVE_BUTTONS
' is used the four configration files will be as follows:
'
'   - "Keyboard.ID1"
'   - "Mouse.ID2"
'   - "USB Game Pad.ID3"
'   - "Saitek ST290 Pro.ID4"
'
' Therefore, depending on which id number a controller currently has will depend on which configuration file is used to load saved user defined
' buttons. This allows controllers to be set up with player 1-6 configurations with each player having a different preferred configuration.
'
' Also, controllers that have no user assigned buttons will still create a configuration file of zero bytes in size. This is normal.
'
' __LOAD_BUTTONS will look for configuration files associated with all currently connected controllers based on their id numbers. If a configration
' exists the user defined buttons wil be loaded.



' +---------------------------------------+
' |                                       |
' |   REMAPPING JOYSTICK/GAME PAD AXES    |
' |                                       |
' +---------------------------------------+
'
' As stated before, joystick and game pad axis are always returned as values between -1 and 1. The following function can be used to remap this range
' to a different value range:
'
' __MAP_AXIS(AxisValue, Lower, Upper)
'
' Example:
'
' J1Xaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 1), -128, 128) ' remap joystick 1 horizontal axis values from -128 to 128 (0 being center)
' J1Yaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 2), -128, 128) ' remap joystick 1 vertical axis values from -128 to 128   (0 being center)
' J2Xaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD2CID, 1), 0, 255) '    remap joystick 2 horizontal axis values from 0 to 255    (127 being center)
' J2Yaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD2CID, 2), 0, 255) '    remap joystick 2 vertical axis values from 0 to 255      (127 being center)
'
' The Lower and Upper range values can be any values you wish as long as the Lower value is less than the Upper value.



'
' +---------------------------------------+
' |                                       |
' |      LIBRARY CODE BEGINS HERE         |
' |                                       |
' +---------------------------------------+

'OPTION _EXPLICIT

' __________________________________________________________________________________________________________________________________________________
'/                                                                                                                   KEYBOARD KEY _BUTTON CONSTANTS \
CONST CLKEY_ESC = 2 '                                                                                                                               |
CONST CLKEY_F1 = 60 '              FUNCTION KEY ROW _BUTTON CONSTANTS                                                                               |
CONST CLKEY_F2 = 61 '               _____     _____ _____ _____ _____    _____ _____ _____ _____    _____ _____ _____ _____                         |
CONST CLKEY_F3 = 62 '              ||ESC||   ||F1 |||F2 |||F3 |||F4 ||  ||F5 |||F6 |||F7 |||F8 ||  ||F9 |||N/A|||F11|||F12||                        |
CONST CLKEY_F4 = 63 '              ||___||   ||___|||___|||___|||___||  ||___|||___|||___|||___||  ||___|||___|||___|||___||                        |
CONST CLKEY_F5 = 64 '              |/___\|   |/___\|/___\|/___\|/___\|  |/___\|/___\|/___\|/___\|  |/___\|/___\|/___\|/___\|                        |
CONST CLKEY_F6 = 65 '                                                                                                                               |
CONST CLKEY_F7 = 66 '              NOTE: F10 does not register as a _BUTTON. I know, strange but true.                                              |
CONST CLKEY_F8 = 67 '                    These _BUTTON contants were provided by gx.bi in dbox's Game Engine: https://github.com/boxgaming/gx       |
CONST CLKEY_F9 = 68 '                                                                                                                               |
CONST CLKEY_F11 = 88 '                                                                                                                              |
CONST CLKEY_F12 = 89 '                                                                                                                              |
CONST CLKEY_BACKQUOTE = 42 '       -----------------------------------------------------------------------------------------                        |
CONST CLKEY_1 = 3 '                FIRST KEY ROW _BUTTON CONSTANTS                                                                                  |
CONST CLKEY_2 = 4 '                                                                                                                                 |
CONST CLKEY_3 = 5 '                 _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _________                         |
CONST CLKEY_4 = 6 '                ||`~ |||1! |||2@ |||3# |||4$ |||5% |||6^ |||7& |||8* |||9( |||0) |||-_ |||=+ |||BACKSP ||                        |
CONST CLKEY_5 = 7 '                ||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||_______||                        |
CONST CLKEY_6 = 8 '                |/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/_______\|                        |
CONST CLKEY_7 = 9 '                                                                                                                                 |
CONST CLKEY_8 = 10 '                                                                                                                                |
CONST CLKEY_9 = 11 '                                                                                                                                |
CONST CLKEY_0 = 12 '                                                                                                                                |
CONST CLKEY_MINUS = 13 '                                                                                                                            |
CONST CLKEY_EQUALS = 14 '                                                                                                                           |
CONST CLKEY_BACKSPACE = 15 '                                                                                                                        |
CONST CLKEY_TAB = 16 '             -----------------------------------------------------------------------------------------                        |
CONST CLKEY_Q = 17 '               SECOND KEY ROW _BUTTON CONSTANTS                                                                                 |
CONST CLKEY_W = 18 '                                                                                                                                |
CONST CLKEY_E = 19 '                _______ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _______                         |
CONST CLKEY_R = 20 '               ||TAB  |||Q  |||W  |||E  |||R  |||T  |||Y  |||U  |||I  |||O  |||P  |||[{ |||]} |||\|   ||                        |
CONST CLKEY_T = 21 '               ||_____|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||_____||                        |
CONST CLKEY_Y = 22 '               |/_____\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/_____\|                        |
CONST CLKEY_U = 23 '                                                                                                                                |
CONST CLKEY_I = 24 '                                                                                                                                |
CONST CLKEY_O = 25 '                                                                                                                                |
CONST CLKEY_P = 26 '                                                                                                                                |
CONST CLKEY_LBRACKET = 27 '                                                                                                                         |
CONST CLKEY_RBRACKET = 28 '                                                                                                                         |
CONST CLKEY_BACKSLASH = 44 '                                                                                                                        |
CONST CLKEY_CAPSLOCK = 59 '        -----------------------------------------------------------------------------------------                        |
CONST CLKEY_A = 31 '               THIRD KEY ROW _BUTTON CONSTANTS                                                                                  |
CONST CLKEY_S = 32 '                                                                                                                                |
CONST CLKEY_D = 33 '                ________ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ ____________                         |
CONST CLKEY_F = 34 '               ||CAPS  |||A  |||S  |||D  |||F  |||G  |||H  |||J  |||K  |||L  |||;: |||'" |||ENTER     ||                        |
CONST CLKEY_G = 35 '               ||______|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||__________||                        |
CONST CLKEY_H = 36 '               |/______\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/__________\|                        |
CONST CLKEY_J = 37 '                                                                                                                                |
CONST CLKEY_K = 38 '                                                                                                                                |
CONST CLKEY_L = 39 '                                                                                                                                |
CONST CLKEY_SEMICOLON = 40 '                                                                                                                        |
CONST CLKEY_QUOTE = 41 '                                                                                                                            |
CONST CLKEY_ENTER = 29 '                                                                                                                            |
CONST CLKEY_LSHIFT = 43 '          -----------------------------------------------------------------------------------------                        |
CONST CLKEY_Z = 45 '               FOURTH KEY ROW _BUTTON CONSTANTS                                                                                 |
CONST CLKEY_X = 46 '                                                                                                                                |
CONST CLKEY_C = 47 '                _____________ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____________                         |
CONST CLKEY_V = 48 '               ||LEFT SHIFT |||Z  |||X  |||C  |||V  |||B  |||N  |||M  |||,< |||.> |||/? |||RIGHT SHIFT||                        |
CONST CLKEY_B = 49 '               ||___________|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___________||                        |
CONST CLKEY_N = 50 '               |/___________\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___________\|                        |
CONST CLKEY_M = 51 '                                                                                                                                |
CONST CLKEY_COMMA = 52 '                                                                                                                            |
CONST CLKEY_PERIOD = 53 '                                                                                                                           |
CONST CLKEY_SLASH = 54 '                                                                                                                            |
CONST CLKEY_RSHIFT = 55 '                                                                                                                           |
CONST CLKEY_LCTRL = 30 '           -----------------------------------------------------------------------------------------                        |
CONST CLKEY_LWIN = 348 '           FIFTH KEY ROW _BUTTON CONSTANTS                                                                                  |
CONST CLKEY_SPACEBAR = 58 '                                                                                                                         |
CONST CLKEY_RWIN = 349 '            ______ ______ ______ _____________________________________________ ______ ______ ______                         |
CONST CLKEY_RCTRL = 286 '          ||LCTL|||LWIN|||MENU|||SPACEBAR                                   |||N/A |||RWIN|||RCTL||                        |
CONST CLKEY_MENU = 350 '           ||____|||____|||____|||___________________________________________|||____|||____|||____||                        |
'                                  |/____\|/____\|/____\|/___________________________________________\|/____\|/____\|/____\|                        |
'                                                                                                                                                   |
CONST CLKEY_NUMLOCK = 326 '        -----------------------------------------------------------------------------------------                        |
CONST CLKEY_NUMPAD_DIVIDE = 310 '  NUMBER PAD _BUTTON CONSTANTS                                                                                     |
CONST CLKEY_NUMPAD_MULTIPLY = 56 '                                                                                                                  |
CONST CLKEY_NUMPAD_MINUS = 75 '     _____ _____ _____ _____                                                                                         |
CONST CLKEY_NUMPAD_7 = 72 '        ||NUM|||/  |||*  |||-  ||                                                                                        |
CONST CLKEY_NUMPAD_8 = 73 '        ||___|||___|||___|||___||                                                                                        |
CONST CLKEY_NUMPAD_9 = 74 '        |/___\|/___\|/___\|/___\|                                                                                        |
CONST CLKEY_NUMPAD_PLUS = 79 '      _____ _____ _____ _____                                                                                         |
CONST CLKEY_NUMPAD_4 = 76 '        ||7  |||8 |||9  |||+  ||                                                                                        |
CONST CLKEY_NUMPAD_5 = 77 '        ||___|||___|||___|||   ||                                                                                        |
CONST CLKEY_NUMPAD_6 = 78 '        |/___\|/___\|/___\||   ||                                                                                        |
CONST CLKEY_NUMPAD_1 = 80 '         _____ _____ _____||   ||                                                                                        |
CONST CLKEY_NUMPAD_2 = 81 '        ||4 |||5  |||6 |||   ||                                                                                        |
CONST CLKEY_NUMPAD_3 = 82 '        ||___|||___|||___|||___||                                                                                        |
CONST CLKEY_NUMPAD_ENTER = 285 '   |/___\|/___\|/___\|/___\|                                                                                        |
CONST CLKEY_NUMPAD_0 = 83 '         _____ _____ _____ _____                                                                                         |
CONST CLKEY_NUMPAD_PERIOD = 84 '   ||1  |||2 |||3  |||E  ||                                                                                        |
'                                  ||___|||___|||___|||N  ||                                                                                        |
'                                  |/___\|/___\|/___\||T  ||                                                                                        |
'                                   ___________ _____||E  ||                                                                                        |
'                                  ||0        |||.  |||R  ||                                                                                        |
'                                  ||_________|||___|||___||                                                                                        |
'                                  |/_________\|/___\|/___\|                                                                                        |
'                                                                                                                                                   |
CONST CLKEY_UP = 329 '             -----------------------------------------------------------------------------------------                        |
CONST CLKEY_LEFT = 332 '           ARROW KEY _BUTTON CONSTANTS                                                                                      |
CONST CLKEY_DOWN = 337 '                                                                                                                            |
CONST CLKEY_RIGHT = 334 '                 _____                                                                                                     |
'                                        ||  ||                                                                                                    |
'                                        ||___||                                                                                                    |
'                                        |/___\|                                                                                                    |
'                                   _____ _____ _____                                                                                               |
'                                  ||  |||  |||  ||                                                                                              |
'                                  ||___|||___|||___||                                                                                              |
'                                  |/___\|/___\|/___\|                                                                                              |
'                                                                                                                                                   |
CONST CLKEY_SCRLK = 71 '           -----------------------------------------------------------------------------------------                        |
CONST CLKEY_PAUSE = 70 '           POSITION KEY _BUTTON CONSTANTS                                                                                   |
CONST CLKEY_INSERT = 339 '                                                                                                                          |
CONST CLKEY_HOME = 328 '            _____ _____ _____                                                                                               |
CONST CLKEY_PAGEUP = 330 '         ||N/A|||SCR|||PAU||                                                                                              |
CONST CLKEY_DELETE = 340 '         ||___|||___|||___||               NOTE: Pause not working on my system?                                          |
CONST CLKEY_END = 336 '            |/___\|/___\|/___\|                                                                                              |
CONST CLKEY_PAGEDOWN = 338 '        _____ _____ _____|                                                                                              |
'                                  ||INS|||HOM|||PUP||                                                                                              |
'                                  ||___|||___|||___||                                                                                              |
'                                  |/___\|/___\|/___\|                                                                                              |
'                                   _____ _____ _____                                                                                               |
'                                  ||DEL|||END|||PDN||                                                                                              |
'                                  ||___|||___|||___||                                                                                              |
'                                  |/___\|/___\|/___\|                                                                                              |
'                                                                                                                                                   |
'\__________________________________________________________________________________________________________________________________________________/
'/                                                                                                                       __NEW_CONTROLLER CONSTANTS \
CONST __UNPLUGGED = 1 '                    existing controller unplugged        - use with __NEW_CONTROLLER                                         |
CONST __PLUGGEDIN = 2 '                    existing controller plugged back in  - use with __NEW_CONTROLLER                                         |
CONST __NEWCONTROLLER = 3 '                a new controller has been plugged in - use with __NEW_CONTROLLER                                         |
'\__________________________________________________________________________________________________________________________________________________/
'/                                                                                                                                       TYPE__SLOT \
TYPE TYPE__SLOT '                          USER DEFINED BUTTON SLOT PROPERTIES                                                                      |
    Cname AS STRING * 25 '                 controller name                                                                                          |
    cid AS INTEGER '                       controller id number (_DEVICES)                                                                          |
    Button AS INTEGER '                    button number (0 if using axis)                                                                          |
    Axis AS INTEGER '                      axis number (0 if using button) (- value for UP/LEFT or + value for DOWN/RIGHT)                          |
    Name AS STRING * 15 '                  button/axis name                                                                                         |
END TYPE '                                                                                                                                          |
'\__________________________________________________________________________________________________________________________________________________/
'/                                                                                                                                     TYPE__BUTTON \
TYPE TYPE__BUTTON '                        USER DEFINED BUTTON PROPERTIES                                                                           |
    Slot0 AS TYPE__SLOT '                  blank slot to clear others                                                                               |
    Slot1 AS TYPE__SLOT '                  user defined button slot 1                                                                               |
    Slot2 AS TYPE__SLOT '                  user defined button slot 2                                                                               |
    Slot3 AS TYPE__SLOT '                  user defined button slot 3                                                                               |
    Slot4 AS TYPE__SLOT '                  user defined button slot 4                                                                               |
END TYPE '                                                                                                                                          |
'\__________________________________________________________________________________________________________________________________________________/
'/                                                                                                                                 TYPE__CONTROLLER \
TYPE TYPE__CONTROLLER '                    DETECTED CONTROLLER PROPERTIES                                                                           |
    Found AS INTEGER '                     controller found (t/f)                                                                                   |
    Connected AS INTEGER '                 controller connected (t/f)                                                                               |
    Name AS STRING * 25 '                  description of controller                                                                                |
    Buttons AS INTEGER '                   number of buttons controller has ( _LASTBUTTON(Controller) )                                             |
    Axis AS INTEGER '                      number of axis controller has    ( _LASTAXIS(Controller)   )                                             |
    Wheels AS INTEGER '                    number of wheels controller has  ( _LASTWHEEL(Controller)  ) ** NOT IMPLEMENTED YET *                    |
END TYPE '                                                                                                                                          |
'\__________________________________________________________________________________________________________________________________________________/
'/                                                                                                                                   TYPE__SETTINGS \
TYPE TYPE__SETTINGS '                      LIBRARY SETTINGS                                                                                         |
    Reassign AS INTEGER '                  reassign (-1) or ignore (0) already used user defined buttons                                            |
    Threshold AS SINGLE '                  axis sensitivity when used as a user defined button (.01 to .99)                                         |
    FoundDevices AS INTEGER '              number of controllers found when program first started                                                   |
END TYPE '                                                                                                                                          |
'\__________________________________________________________________________________________________________________________________________________/
'/                                                                                                                             VARIABLE ASSIGNMENTS \
REDIM CL_BUTTON(1) AS TYPE__BUTTON '       user assigned button array                                                                               |
DIM CL_CONTROLLER(6) AS TYPE__CONTROLLER ' controller array (index number equals _DEVICES id number)                                                |
DIM CL_KEYNAME(350) AS STRING '            keyboard _BUTTON key names                                                                               |
DIM CL_SETTINGS AS TYPE__SETTINGS '        library settings                                                                                         |
DIM SHARED __CURRENT_ROUTINE AS STRING '   __ERROR use                                                                                              |
DIM SHARED __PREVIOUS_ROUTINE AS STRING '  __ERROR use                                                                                              |
DIM SHARED __KEYBOARDCID AS INTEGER '      these will contain the device ids (_DEVICES)                                                             |
DIM SHARED __MOUSECID AS INTEGER '                                                                                                                  |
DIM SHARED __JOYPAD1CID AS INTEGER '                                                                                                                |
DIM SHARED __JOYPAD2CID AS INTEGER '                                                                                                                |
DIM SHARED __JOYPAD3CID AS INTEGER '                                                                                                                |
DIM SHARED __JOYPAD4CID AS INTEGER '                                                                                                                |
DIM SHARED __JOYPAD5CID AS INTEGER '                                                                                                                |
DIM SHARED __JOYPAD6CID AS INTEGER '                                                                                                                |
'\__________________________________________________________________________________________________________________________________________________/


Code: (Select All)
'----------------------------
' Controller Library V1.10
' Terry Ritchie
' May 17th, 2023
' Written using QB64PE v3.7.0
'----------------------------
' CONTROLLER.BM
'----------------------------
'
' TODO: Add WHEEL routines
'       Create PDF instructions
'
'----------------------------
' 04/10/23 V1.0  - Initial Release
' 04/26/23 V1.01 - Corrected slot reassigning issues
' 05/17/23 V1.10 - Added __MAKE_BUTTON, __CONNECTED, __SAVE_BUTTONS, __LOAD_BUTTONS, __NEW_CONTROLLER, __REMOVE_CONTROLLER
'                - The library now has the ability to save and load controller user defined button configurations
'                - You can now detect when a controller has been plugged in or unplugged
'                - A controller's user defined button assignments can be removed when the controller has been unplugged
'----------------------------


' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __REMOVE_CONTROLLER (cid AS INTEGER) '                                                                                  __REMOVE_CONTROLLER |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Removes all user defined buttons associated with a controller.                                                                                |
    '|                                                                                                                                               |
    '| __REMOVE_CONTROLLER __JOYPAD3CID                                                                                                              |
    '|                                                                                                                                               |
    '| cid - the controller id                                                                                                                       |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_BUTTON() AS TYPE__BUTTON '         need access to button array
    DIM b AS INTEGER '                           button counter

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__REMOVE_CONTROLLER"
    IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-----------------------------------------------------------------------------+
    '| Cycle through each assigned button slot. If a button assignment matches the |
    '| controller name and controller id then remove the button from the array.    |
    '+-----------------------------------------------------------------------------+

    b = 0 '                                                                                           reset button counter
    DO '                                                                                              begin button search
        b = b + 1 '                                                                                   increment button counter
        IF CL_BUTTON(b).Slot1.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot1.cid = cid THEN ' does controller name and id match in slot 1?
            __REMOVE_BUTTON b, 1 '                                                                    yes, remove the button assignment in slot 1
        END IF
        IF CL_BUTTON(b).Slot2.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot2.cid = cid THEN ' does controller name and id match in slot 2?
            __REMOVE_BUTTON b, 2
        END IF
        IF CL_BUTTON(b).Slot3.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot3.cid = cid THEN ' does controller name and id match in slot 3?
            __REMOVE_BUTTON b, 3
        END IF
        IF CL_BUTTON(b).Slot4.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot4.cid = cid THEN ' does controller name and id match in slot 4?
            __REMOVE_BUTTON b, 4
        END IF
    LOOP UNTIL b = UBOUND(CL_BUTTON) '                                                                leave when all buttons checked

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __NEW_CONTROLLER (Action AS INTEGER) '                                                                                __NEW_CONTROLLER |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Checks for the addition of a new controller, a controller that has been unplugged, or a controller plugged back in.                           |
    '|                                                                                                                                               |
    '| Controller = __NEW_CONTROLLER(Action)                                                                                                         |
    '|                                                                                                                                               |
    '| Action - the returned action that occurred                                                                                                    |
    '|      0 - nothing changed                                                                                                                      |
    '|      1 - a controller was unplugged           (the constant __UNPLUGGED     has been created to check for this)                               |
    '|      2 - a controller was plugged back in     (the constant __PLUGGEDIN     has been created to check for this)                               |
    '|      3 - a new controller has been plugged in (the constant __NEWCONTROLLER has been created to check for this)                               |
    '|                                                                                                                                               |
    '| The function will return the following values:                                                                                                |
    '|                                                                                                                                               |
    '|        - the value will contain the new controller id when a new controller is plugged in               (Action = 3     )                     |
    '|        - the value will contain the controller id of a controller that was unplugged or plugged back in (Action = 1 or 2)                     |
    '|        - a value of 0 (FALSE) if nothing has changed                                                                                          |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_SETTINGS AS TYPE__SETTINGS '       need access to library settings
    DIM Rescan AS INTEGER '                      -1 (TRUE) if controllers need to be rescanned
    DIM Devices AS INTEGER '                     number of devices currently found
    DIM d AS INTEGER '                           device counter

    __NEW_CONTROLLER = 0 '                                                    assume no new or previous controller plugged in
    Action = 0 '                                                              assume no changes
    d = 0 '                                                                   reset device counter
    Rescan = 0 '                                                              reset rescan flag
    Devices = _DEVICES '                                                      get number of devices found
    IF Devices <> CL_SETTINGS.FoundDevices THEN '                             has a new controller been plugged in?
        Rescan = -1 '                                                         yes, controllers will need to be rescanned
        Action = __NEWCONTROLLER '                                            remember that a new controller was plugged in
    ELSE '                                                                    no, check for previous plugged/unplugged controllers
        DO '                                                                  begin controller search
            d = d + 1 '                                                       increment device counter
            IF __CONNECTED(d) <> CL_CONTROLLER(d).Connected THEN '            has controller connection status changed?
                Rescan = d '                                                  yes, remember which controller has changed and needs rescanned
                IF CL_CONTROLLER(d).Connected THEN '                          was the controller connected?
                    Action = __UNPLUGGED '                                    yes, remember that it was just unplugged
                ELSE '                                                        no, the controller was disconnected
                    Action = __PLUGGEDIN '                                    remember that it was just plugged back in
                END IF
                EXIT DO '                                                     no need to check any more controllers
            END IF
        LOOP UNTIL d = Devices '                                              leave when all controllers checked
    END IF
    IF Rescan THEN '                                                          need to scan for new/unplugged/plugged in controllers?
        __IDENTIFY_CONTROLLERS '                                              yes, identify connected controllers
        IF Rescan = -1 THEN '                                                 was a new controller found?
            __NEW_CONTROLLER = CL_SETTINGS.FoundDevices '                     yes, return the new controller id number
        ELSE '                                                                no, a controller was unplugged/plugged back in
            __NEW_CONTROLLER = Rescan '                                       return the controller that was unplugged/plugged back in
        END IF
    END IF

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __MAKE_BUTTON (Handle AS INTEGER) '                                                                                           __MAKE_BUTTON |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Assigns a value to a user generated integer button variable.                                                                                  |
    '|                                                                                                                                               |
    '| DIM UPButton AS INTEGER                                                                                                                       |
    '| __MAKE_BUTTON UPButton ' define the integer variable UPButton as a user defined button                                                        |
    '|                                                                                                                                               |
    '| Handle - the name of the variable the user wishes to use as a button reference.                                                               |
    '|          The variable's value will change to indicate the new handle value pointing to the button array index.                                |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__MAKE_BUTTON"
    IF Handle THEN __ERROR "This button has already been created"
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+----------------------------------------------+
    '| Create a new entry for the button assignment |
    '+----------------------------------------------+

    Handle = UBOUND(CL_BUTTON) + 1 '                    set handle to new size of button array
    REDIM _PRESERVE CL_BUTTON(Handle) AS TYPE__BUTTON ' increase size of button array to match new handle

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __SAVE_BUTTONS () '                                                                                                          __SAVE_BUTTONS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Saves all assigned buttons for all currently discovered and connected controllers.                                                            |
    '|                                                                                                                                               |
    '| __SAVE_BUTTONS                                                                                                                                |
    '|                                                                                                                                               |
    '| The config files created for the controllers will be in the form: [Controller Name].ID[Device ID#]                                            |
    '| For example, a joystick with the name Saitek ST290 Pro found as device number 4 will have the following config file: "Saitek ST290 Pro.ID4"   |
    '|                                                                                                                                               |
    '| It's possible for a controller to have multiple config files based on the device id number.                                                   |
    '|   - "Saitek ST290 Pro.ID3"                                                                                                                    |
    '|   - "Saitek ST290 Pro.ID4"                                                                                                                    |
    '|   - "Saitek ST290 Pro.ID5"                                                                                                                    |
    '|   - etc..                                                                                                                                     |
    '|                                                                                                                                               |
    '| This allows for multiple configurations based on which player is using which joystick/game pad in any order.                                  |
    '|                                                                                                                                               |
    '| Controllers with no assigned buttons will create config files that are zero bytes in length. This is normal.                                  |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_BUTTON() AS TYPE__BUTTON '         need access to button array
    DIM Fname AS STRING '                        controller config file name
    DIM b AS INTEGER '                           button counter
    DIM cid AS INTEGER '                         controller id counter
    DIM FF AS LONG '                             next available free file handle

    cid = 0 '                                                                                                     reset controller id counter
    DO '                                                                                                          begin controller search loop
        cid = cid + 1 '                                                                                           increment controller id counter
        IF CL_CONTROLLER(cid).Found THEN '                                                                        was this controller found initially?
            IF __CONNECTED(cid) THEN '                                                                            yes, is this controller still connected?

                '+---------------------------------------------------+
                '| This controller is in use and currently connected |
                '| Create and open a config file for this controller |
                '+---------------------------------------------------+

                Fname = _TRIM$(CL_CONTROLLER(cid).Name) + ".ID" + _TRIM$(STR$(cid)) '                             yes, build the name of controller's config file
                FF = FREEFILE '                                                                                   get a free file handle
                OPEN Fname FOR OUTPUT AS #FF '                                                                    open the config file for writing
                b = 0 '                                                                                           reset button counter

                '+-----------------------------------------------------------------------------+
                '| Cycle through each assigned button slot. If a button assignment matches the |
                '| controller name and controller id save the variable assignment value, the   |
                '| button value (0 if axis is used), and the axis value (0 if button is used). |
                '+-----------------------------------------------------------------------------+

                DO '                                                                                              begin assignment search and write loop
                    b = b + 1 '                                                                                   increment button counter
                    IF CL_BUTTON(b).Slot1.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot1.cid = cid THEN ' does controller name and id match in slot 1?
                        WRITE #FF, b, CL_BUTTON(b).Slot1.Button, CL_BUTTON(b).Slot1.Axis '                        yes, write assignment to file
                    END IF
                    IF CL_BUTTON(b).Slot2.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot2.cid = cid THEN ' does controller name and id match in slot 2?
                        WRITE #FF, b, CL_BUTTON(b).Slot2.Button, CL_BUTTON(b).Slot2.Axis '                        yes, write assignment to file
                    END IF
                    IF CL_BUTTON(b).Slot3.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot3.cid = cid THEN ' does controller name and id match in slot 3?
                        WRITE #FF, b, CL_BUTTON(b).Slot3.Button, CL_BUTTON(b).Slot3.Axis '                        yes, write assignment to file
                    END IF
                    IF CL_BUTTON(b).Slot4.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot4.cid = cid THEN ' does controller name and id match in slot 4?
                        WRITE #FF, b, CL_BUTTON(b).Slot4.Button, CL_BUTTON(b).Slot4.Axis '                        yes, write assignment to file
                    END IF
                LOOP UNTIL b = UBOUND(CL_BUTTON) '                                                                leave when all button assignments checked
                CLOSE #FF '                                                                                       close the file
            END IF
        END IF
    LOOP UNTIL cid = 6 '                                                                                          leave when all controllers checked
END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __LOAD_BUTTONS () '                                                                                                          __LOAD_BUTTONS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Loads assigned buttons for controllers from configuration files if they exist.                                                                |
    '|                                                                                                                                               |
    '| __LOAD_BUTTONS                                                                                                                                |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_BUTTON() AS TYPE__BUTTON '         need access to button array
    DIM Fname AS STRING '                        controller config file name
    DIM cid AS INTEGER '                         controller id counter
    DIM Handle AS INTEGER '                      user defined button handle
    DIM Button AS INTEGER '                      button to assign (0 if axis)
    DIM Axis AS INTEGER '                        axis to assign (0 if button)
    DIM FF AS LONG '                             next available free file handle

    cid = 0 '                                                                         reset controller id counter
    DO '                                                                              begin controller search loop
        cid = cid + 1 '                                                               increment controller id counter
        IF CL_CONTROLLER(cid).Found THEN '                                            was this controller found initially?
            IF __CONNECTED(cid) THEN '                                                yes, is this controller still connected?

                '+-----------------------------------------------------------------+
                '| This controller was initially found and is currently connected. |
                '| Create a config file name to check for.                         |
                '+-----------------------------------------------------------------+

                Fname = _TRIM$(CL_CONTROLLER(cid).Name) + ".ID" + _TRIM$(STR$(cid)) ' yes, build the name of the controller's config file
                IF _FILEEXISTS(Fname) THEN '                                          does a config file for this controller exist?

                    '+-------------------------------------------+
                    '| A config file exists for this controller  |
                    '| Open the file and assign the buttons/axes |
                    '+-------------------------------------------+

                    FF = FREEFILE '                                                   yes, get a free file handle
                    OPEN Fname FOR INPUT AS #FF '                                     open the config file for reading
                    WHILE NOT EOF(1) '                                                has the end of the file been reached?

                        '+---------------------------------------------------------------+
                        '| Config files that are zero bytes in length are simply ignored |
                        '+---------------------------------------------------------------+

                        INPUT #FF, Handle, Button, Axis '                             no, get the button handle, button, and axis settings
                        IF Button THEN '                                              has a button been assigned?
                            __ASSIGN_BUTTON Handle, cid, Button '                     yes, assign the button
                        ELSE '                                                        no, an axis is assigned
                            __ASSIGN_AXIS Handle, cid, Axis '                         assign the axis as a button
                        END IF
                    WEND '                                                            loop back and load next button assignment (if any)
                    CLOSE #FF '                                                       close the config file
                END IF
            END IF
        END IF
    LOOP UNTIL cid = 6 '                                                              leave when all controllers searched

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __CONNECTED (cid AS INTEGER) '                                                                                             __CONNECTED |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns 0 (FALSE) if a controller is disconnected, -1 (TRUE) otherwise                                                                        |
    '|                                                                                                                                               |
    '| Status = __CONNECTED(__JOYPAD1CID)                                                                                                            |
    '|                                                                                                                                               |
    '| cid - the id of the controller                                                                                                                |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__CONNECTED"
    IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-------------------------+
    '| Return connection state |
    '+-------------------------+

    WHILE _DEVICEINPUT(cid): WEND '                  get latest controller values
    IF INSTR(_DEVICE$(cid), "[DISCONNECTED]") THEN ' is controller disconnected?
        __CONNECTED = 0 '                            yes, return that controller is disconnected
    ELSE '                                           no
        __CONNECTED = -1 '                           return that controller is connected
    END IF

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __BUTTON_NAME$ (Handle AS INTEGER, Slot AS INTEGER) '                                                                   __BUTTON_NAME$ |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Retrieves the name of a user defined button.                                                                                                  |
    '|                                                                                                                                               |
    '| Description = __BUTTON_NAME$(Up_Button, 1) ' get name of button in slot 1                                                                     |
    '|                                                                                                                                               |
    '| Handle - the handle of the user defined button                                                                                                |
    '| Slot   - the slot number (1 to 4)                                                                                                             |
    '|          passing the value of 0 will clear all slot assignments and remove the user defined button completely.                                |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_BUTTON() AS TYPE__BUTTON '         need access to button array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__BUTTON_NAME$"
    IF Handle < 1 OR Handle > UBOUND(CL_BUTTON) THEN __ERROR "The specified button does not exist."
    IF Slot < 0 OR Slot > 4 THEN __ERROR "The requested slot assignment does not exist."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-----------------+
    '| Get button name |
    '+-----------------+

    SELECT CASE Slot
        CASE 1: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot1.Name
        CASE 2: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot2.Name
        CASE 3: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot3.Name
        CASE 4: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot4.Name
    END SELECT

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __SET_AXIS_THRESHOLD (Value AS SINGLE) '                                                                               __SET_AXIS_THRESHOLD |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Sets the value at which an axis set up as a user defined button is seen as being pressed.                                                     |
    '|                                                                                                                                               |
    '| __SET_AXIS_THRESHOLD .25 ' button activated when axis is deflected 25% either UP/DOWN or LEFT/RIGHT                                           |
    '|                                                                                                                                               |
    '| Value - .01 (1%) to .99 (99%) of axis deflection                                                                                              |
    '|                                                                                                                                               |
    '| NOTE: The default value set up by __INITIALIZE_CONTROLLERS is .5 (50%)                                                                        |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__SET_AXIS_THRESHOLD"
    IF Value <= 0 OR Value >= 1 THEN __ERROR "Threshold value must be between 0 and 1."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+---------------------+
    '| Set threshold value |
    '+---------------------+

    CL_SETTINGS.Threshold = Value ' set value of user defined button axis sensitivity

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __BUTTON_REASSIGN_ALLOWED () '                                                                                    __BUTTON_REASSIGN_ALLOWED |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Enables user defined button reassigning.                                                                                                      |
    '|                                                                                                                                               |
    '| __BUTTON_REASSIGN_ALLOWED                                                                                                                     |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings

    '+---------------------------+
    '| Enable button reassigning |
    '+---------------------------+

    CL_SETTINGS.Reassign = -1 ' enable button reassigning (TRUE)

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __BUTTON_REASSIGN_NOT_ALLOWED () '                                                                            __BUTTON_REASSIGN_NOT_ALLOWED |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Disables user defined button reassigning.                                                                                                     |
    '|                                                                                                                                               |
    '| __BUTTON_REASSIGN_NOT_ALLOWED                                                                                                                 |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings

    '+----------------------------+
    '| Disable button reassigning |
    '+----------------------------+

    CL_SETTINGS.Reassign = 0 ' disable button reassigning (FALSE)

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __REMOVE_BUTTON (Handle AS INTEGER, Slot AS INTEGER) '                                                                      __REMOVE_BUTTON |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Removes an assigned button or axis from a user defined button. Optionally the entire user defined button can be removed by supplying the      |
    '| value of 0 for slot.                                                                                                                          |
    '|                                                                                                                                               |
    '| __REMOVE_BUTTON UP_Button, 3 ' remove the button/axis assigned in the third slot                                                              |
    '|                                                                                                                                               |
    '| Handle - the handle of the user defined button                                                                                                |
    '| Slot   - the assigned slot to clear (0 to 4)                                                                                                  |
    '|          passing the value of 0 will clear all slot assignments and remove the user defined button completely.                                |
    '|                                                                                                                                               |
    '| When a defined button is removed from a slot the assignments in slots above are shifted down. For example, if the assignment in slot 1 is     |
    '| removed then the assignment in 2 is shifted to 1, 3 is shifted to 2, 4 is shifted to 3, and 4 is cleared.                                     |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__REMOVE_BUTTON"
    IF Handle < 1 OR Handle > UBOUND(CL_BUTTON) THEN __ERROR "The specified button does not exist."
    IF Slot < 0 OR Slot > 4 THEN __ERROR "The requested slot assignment does not exist."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+----------------------+
    '| Remove assignment(s) |
    '+----------------------+

    SELECT CASE Slot '                                          which slot?
        CASE 0 '                                                [ALL SLOTS]
            CL_BUTTON(Handle).Slot1 = CL_BUTTON(Handle).Slot0 ' clear slot 1
            CL_BUTTON(Handle).Slot2 = CL_BUTTON(Handle).Slot0 ' clear slot 2
            CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot0 ' clear slot 3
            CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
        CASE 1 '                                                [SLOT1]
            CL_BUTTON(Handle).Slot1 = CL_BUTTON(Handle).Slot2 ' move slot 2 up to slot 1
            CL_BUTTON(Handle).Slot2 = CL_BUTTON(Handle).Slot3 ' move slot 3 up to slot 2
            CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot4 ' move slot 4 up to slot 3
            CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
        CASE 2 '                                                [SLOT2]
            CL_BUTTON(Handle).Slot2 = CL_BUTTON(Handle).Slot3 ' move slot 3 up to slot 2
            CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot4 ' move slot 4 up to slot 3
            CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
        CASE 3 '                                                [SLOT3]
            CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot4 ' move slot 4 up to slot 3
            CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
        CASE 4 '                                                [SLOT4]
            CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
    END SELECT

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __JOYPAD_EXISTS (Number AS INTEGER) '                                                                                  __JOYPAD_EXISTS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns the total number of joysticks/game pads that exist (TREU) if the selected joystick/game pad exists, 0 (FALSE) otherwise.              |
    '|                                                                                                                                               |
    '| JoyPads = __JOYPAD_EXISTS(1) '                                     get total number of joysticks/game pads (if any)                           |
    '| IF JoyPads THEN '                                                  was the selected joypad found?                                             |
    '|     PRINT "Joystick 1 of"; STR$(JoyPads); " found!" '              yes, report findings                                                       |
    '|     Print "Joystick name    : ";__CONTROLLER_NAME$(__JOYPAD1CID)                                                                              |
    '|     PRINT "Number of buttons:"; __BUTTON_TOTAL(__JOYPAD1CID)                                                                                  |
    '|     PRINT "Number of axes   :"; __AXIS_TOTAL(__JOYPAD1CID)                                                                                    |
    '| END IF                                                                                                                                        |
    '|                                                                                                                                               |
    '| number - the joystick/game pad to query                                                                                                       |
    '\_______________________________________________________________________________________________________________________________________________/

    DIM Found AS INTEGER ' joypad found (t/f)

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__JOYPAD_EXISTS"
    IF Number < 1 OR Number > 6 THEN __ERROR "The requested joystick/game pad does not exist."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+---------------------------------------+
    '| Report existance of joystick/game pad |
    '+---------------------------------------+

    Found = 0 '                                   assume no joystick/game pad found
    __JOYPAD_EXISTS = 0 '                         assume there are no joypads
    SELECT CASE Number '                          which joypad are we looking for?
        CASE 1 '                                  joypad 1
            IF __JOYPAD1CID THEN Found = -1 '     record found if present
        CASE 2 '                                  etc..
            IF __JOYPAD2CID THEN Found = -1
        CASE 3
            IF __JOYPAD3CID THEN Found = -1
        CASE 4
            IF __JOYPAD4CID THEN Found = -1
        CASE 5
            IF __JOYPAD5CID THEN Found = -1
        CASE 6
            IF __JOYPAD6CID THEN Found = -1
    END SELECT
    IF Found THEN '                               was a joypad found?
        IF __JOYPAD6CID THEN '                    yes, are there 6 joypads?
            __JOYPAD_EXISTS = 6 '                 yes, return that 6 exist
        ELSEIF __JOYPAD5CID THEN '                no, are there 5 joypads?
            __JOYPAD_EXISTS = 5 '                 yes, return that 5 exist
        ELSEIF __JOYPAD4CID THEN '                etc..
            __JOYPAD_EXISTS = 4
        ELSEIF __JOYPAD3CID THEN
            __JOYPAD_EXISTS = 3
        ELSEIF __JOYPAD2CID THEN
            __JOYPAD_EXISTS = 2
        ELSEIF __JOYPAD1CID THEN
            __JOYPAD_EXISTS = 1
        END IF
    END IF

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __MOUSE_EXISTS () '                                                                                                     __MOUSE_EXISTS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns -1 (TRUE) if the mouse controller exists, 0 (FALSE) otherwise.                                                                        |
    '|                                                                                                                                               |
    '| IF __MOUSE_EXISTS THEN PRINT "Mouse found!"                                                                                                   |
    '|                                                                                                                                               |
    '| NOTE: It's highly unlikely that a mouse will not exist but for those instances where someone may have created a stand alone computer for      |
    '|       playing QB64 games without a mouse (and/or a keyboard) but just joysticks attached this function is available.                          |
    '\_______________________________________________________________________________________________________________________________________________/

    __MOUSE_EXISTS = 0 '                     assume no mouse
    IF __MOUSECID THEN __MOUSE_EXISTS = -1 ' report that mouse found

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __KEYBOARD_EXISTS () '                                                                                               __KEYBOARD_EXISTS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns -1 (TRUE) if the keyboard controller exists, 0 (FALSE) otherwise.                                                                     |
    '|                                                                                                                                               |
    '| IF __KEYBOARD_EXISTS THEN PRINT "Keyboard found!"                                                                                             |
    '|                                                                                                                                               |
    '| NOTE: It's highly unlikely that a keyboard will not exist but for those instances where someone may have created a stand alone computer for   |
    '|       playing QB64 games without a keyboard (and/or a mouse) but just joysticks attached this function is available.                          |
    '\_______________________________________________________________________________________________________________________________________________/

    __KEYBOARD_EXISTS = 0 '                        assume no keyboard
    IF __KEYBOARDCID THEN __KEYBOARD_EXISTS = -1 ' report that keyboard was found

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __MAP_AXIS (AxisValue AS SINGLE, Lower AS INTEGER, Upper AS INTEGER) '                                                      __MAP_AXIS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Maps a joypad or mouse axis value from -1 to 1 to another defined range.                                                                      |
    '|                                                                                                                                               |
    '| Xaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 1), 0, 255) ' map -1 to 1 as 0 to 255                                                      |
    '|                                                                                                                                               |
    '| AxisValue - current axis value (must be -1 to 1)                                                                                              |
    '| Lower     - the new lower value range                                                                                                         |
    '| Upper     - the new upper value range                                                                                                         |
    '|                                                                                                                                               |
    '| NOTE: This function will only work correctly when AxisValue is between -1 and 1.                                                              |
    '\_______________________________________________________________________________________________________________________________________________/

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__MAP_AXIS"
    IF AxisValue < -1 OR AxisValue > 1 THEN __ERROR "Axis value must be between -1 and 1."
    IF Lower >= Upper THEN __ERROR "The lower value must be less than the upper value."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-----------------------------------+
    '| Convert input to new output range |
    '+-----------------------------------+

    __MAP_AXIS = INT(Lower + (AxisValue + 1) * (Lower - Upper) / -2) ' convert input to adjusted output

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __AXIS_TOTAL (cid AS INTEGER) '                                                                                           __AXIS_TOTAL |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns the number of axes a controller has.                                                                                                  |
    '|                                                                                                                                               |
    '| Total = __AXIS_TOTAL(__JOYPAD1CID)                                                                                                            |
    '|                                                                                                                                               |
    '| cid - the controller id                                                                                                                       |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__AXIS_TOTAL"
    IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    IF CL_CONTROLLER(cid).Axis = 0 THEN __ERROR "The specified controller has no axes."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+----------------------------------+
    '| Return number of controller axis |
    '+----------------------------------+

    __AXIS_TOTAL = CL_CONTROLLER(cid).Axis ' return number of axes

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __BUTTON_TOTAL (cid AS INTEGER) '                                                                                       __BUTTON_TOTAL |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns the number of buttons a controller has.                                                                                               |
    '|                                                                                                                                               |
    '| Total = __BUTTON_TOTAL(__JOYPAD1CID)                                                                                                          |
    '|                                                                                                                                               |
    '| cid - the controller id                                                                                                                       |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__BUTTON_TOTAL"
    IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    IF CL_CONTROLLER(cid).Buttons = 0 THEN __ERROR "The specified controller has no buttons."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-------------------------------------+
    '| Return number of controller buttons |
    '+-------------------------------------+

    __BUTTON_TOTAL = CL_CONTROLLER(cid).Buttons ' return number of buttons

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __CONTROLLER_BUTTON (cid AS INTEGER, Button AS INTEGER) '                                                          __CONTROLLER_BUTTON |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns the state of a controller's button.                                                                                                   |
    '|                                                                                                                                               |
    '| Button = __CONTROLLER_BUTTON(__KEYBOARDCID, 329) ' keyboard UP arrow key                                                                      |
    '|                                                                                                                                               |
    '| cid    - the controller id                                                                                                                    |
    '| Button - the controller's button (or keyboard key)                                                                                            |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__CONTROLLER_BUTTON"
    IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    IF CL_CONTROLLER(cid).Buttons = 0 THEN __ERROR "The specified controller has no buttons."
    IF Button < 1 OR Button > CL_CONTROLLER(cid).Buttons THEN __ERROR "The specified controller does not have this button."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-----------------------------+
    '| Return current button state |
    '+-----------------------------+

    IF __CONNECTED(cid) THEN '                  is controller connected?
        WHILE _DEVICEINPUT(cid): WEND '         yes, get latest controller values
        __CONTROLLER_BUTTON = _BUTTON(Button) ' return controller button state
    END IF

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __CONTROLLER_AXIS (cid AS INTEGER, Axis AS INTEGER) '                                                                __CONTROLLER_AXIS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns the value of a controller's axis. (-1 to 1)                                                                                           |
    '|                                                                                                                                               |
    '| Xaxis = __CONTROLLER_AXIS(__JOYPAD1CID, 1) ' x axis of joypad 1                                                                               |
    '|                                                                                                                                               |
    '| cid  - the controller id                                                                                                                      |
    '| Axis - the controller's axis number                                                                                                           |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__CONTROLLER_AXIS"
    IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    IF CL_CONTROLLER(cid).Axis = 0 THEN __ERROR "The specified controller has no axes."
    IF Axis < 1 OR Axis > CL_CONTROLLER(cid).Axis THEN __ERROR "The specified controller does not have this axis."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+---------------------------+
    '| Return current axis value |
    '+---------------------------+

    IF __CONNECTED(cid) THEN '            is controller connected?
        WHILE _DEVICEINPUT(cid): WEND '   yes, get latest controller values
        __CONTROLLER_AXIS = _AXIS(Axis) ' return controller axis value
    END IF

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __CONTROLLER_NAME$ (cid AS INTEGER) '                                                                               __CONTROLLER_NAME$ |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns the descriptive name of the controller.                                                                                               |
    '|                                                                                                                                               |
    '| PRINT __CONTROLLER_NAME$(__JOYPAD1CID)                                                                                                        |
    '|                                                                                                                                               |
    '| cid - the id of the controller                                                                                                                |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__CONTROLLER_NAME$"
    IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist"
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+---------------------------+
    '| Return name of controller |
    '+---------------------------+

    __CONTROLLER_NAME$ = CL_CONTROLLER(cid).Name ' return the name of the controller

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION __BUTTON_DOWN (Handle AS INTEGER) '                                                                                      __BUTTON_DOWN |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns -1 (TRUE) if a button is pressed, 0 (FALSE) otherwise.                                                                                |
    '|                                                                                                                                               |
    '| State = __BUTTON_DOWN(UPButton)                                                                                                               |
    '|                                                                                                                                               |
    '| Handle - the handle of the button to check                                                                                                    |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_BUTTON() AS TYPE__BUTTON '   need access to button array
    SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
    DIM Slot AS INTEGER '                  button/axis slot counter
    DIM cid AS INTEGER '                   controller id
    DIM Button AS INTEGER '                controller button
    DIM Axis AS INTEGER '                  controller axis
    DIM AxisValue AS SINGLE '              controller current axis value
    DIM Down AS INTEGER '                  button is down (t/f)

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__BUTTON_DOWN"
    IF Handle < 1 OR Handle > UBOUND(CL_BUTTON) THEN __ERROR "The specified button does not exist."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-------------------------+
    '| Report status of button |
    '+-------------------------+

    Down = 0 '                                                         assume no button/axis pressed
    Slot = 0 '                                                         reset slot counter
    DO '                                                               begin button/axis down search
        Slot = Slot + 1 '                                              increment slot counter

        '+----------------------------------------------------------+
        '| Get the controller's id, button, and axis from each slot |
        '+----------------------------------------------------------+

        SELECT CASE Slot '                                             which button/axis slot?
            CASE 1 '                                                   slot 1
                cid = CL_BUTTON(Handle).Slot1.cid '                    get controller's id from slot 1
                Button = CL_BUTTON(Handle).Slot1.Button '              get controller's button from slot 1
                Axis = CL_BUTTON(Handle).Slot1.Axis '                  get controller's axis from slot 1
            CASE 2 '                                                   slot 2
                cid = CL_BUTTON(Handle).Slot2.cid
                Button = CL_BUTTON(Handle).Slot2.Button
                Axis = CL_BUTTON(Handle).Slot2.Axis
            CASE 3 '                                                   slot 3
                cid = CL_BUTTON(Handle).Slot3.cid
                Button = CL_BUTTON(Handle).Slot3.Button
                Axis = CL_BUTTON(Handle).Slot3.Axis
            CASE 4 '                                                   slot 4
                cid = CL_BUTTON(Handle).Slot4.cid
                Button = CL_BUTTON(Handle).Slot4.Button
                Axis = CL_BUTTON(Handle).Slot4.Axis
        END SELECT
        IF cid THEN '                                                  is there a controller id?

            '+---------------------------------------+
            '| A controller id was found in the slot |
            '+---------------------------------------+

            WHILE _DEVICEINPUT(cid): WEND '                            yes, get controller's latest values
            IF Button THEN '                                           does a controller button need checked?

                '+--------------------------------------------+
                '| This slot contained a button to be checked |
                '+--------------------------------------------+

                IF _BUTTON(Button) THEN Down = -1 '                    yes, get state of controller button
            ELSEIF Axis THEN '                                         no, does a controller axis need checked?

                '+-------------------------------------------+
                '| This slot contained an axis to be checked |
                '+-------------------------------------------+

                AxisValue = _AXIS(ABS(Axis)) '                         yes, get the current controller axis value
                IF ABS(AxisValue) >= CL_SETTINGS.Threshold THEN '      is axis deflected at least to sensitivity setting?
                    IF SGN(AxisValue) = SGN(Axis) THEN Down = -1 '     yes, get state of axis
                END IF
            END IF
        END IF
    LOOP UNTIL (Slot = 4) OR Down '                                    leave when all four slots checked or a button is down
    __BUTTON_DOWN = Down '                                             return state of button

END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __AUTOASSIGN_BUTTON (Handle AS INTEGER) '                                                                               __AUTOASSIGN_BUTTON |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Automatically assigns a button handle with up to a combination of four controller buttons or axis deflections. Simply call this subroutine up |
    '| to four times to associate each axis or button with the handle. This allows axis deflections to be treated as button presses. Good for top    |
    '| hats and Nintendo style "plus" directionals.                                                                                                  |
    '|                                                                                                                                               |
    '| __AUTOASSIGN_BUTTON UPButton ' player chooses the UP ARROW key for instance and that gets saved in SLOT 1                                     |
    '| __AUTOASSIGN_BUTTON UPButton ' player chooses the W key for instance and that gets saved in SLOT 2                                            |
    '| __AUTOASSIGN_BUTTON UPButton ' player chooses the UP direction on a "plus" pad for instance and that gets saved in SLOT 3                     |
    '| '                              the player now has three different methods of inputting a directional UP movement                              |
    '|                                                                                                                                               |
    '| Handle - button handle                                                                                                                        |
    '|                                                                                                                                               |
    '| The result of the scan is sent to either __ASSIGN_AXIS or __ASSIGN_BUTTON. See the documentation for these two subrotuines for more           |
    '| information on how the resulting values are stored and used.                                                                                  |
    '|                                                                                                                                               |
    '| NOTE: Once all four button slots are filled any attempt to associate a handle with more axis or buttons is ignored.                           |
    '|       Mouse axes are ignored during auto assign. Use __ASSIGN_AXIS if you wish to assign a mouse axis as a button (not recommended).          |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_SETTINGS AS TYPE__SETTINGS '       need access to library settings
    DIM cid AS INTEGER '                         controller id
    DIM Number AS INTEGER '                      axis/button number (or keyboard scan code) counter
    DIM Button AS INTEGER '                      button number (or keyboard scan code) that was pressed
    DIM Axis AS INTEGER '                        axis that was deflected
    DIM AxisValue AS SINGLE '                    value of axis that was deflected

    DO '                                                                  begin controller interaction search

        '+---------------------------------------------+
        '| Wait for a controller to be interacted with |
        '+---------------------------------------------+

        _LIMIT 60 '                                                       don't hog the CPU while waiting
        cid = _DEVICEINPUT '                                              check for a controller interaction
        IF cid THEN '                                                     was a controller interacted with?

            '+----------------------------------+
            '| A controller was interacted with |
            '+----------------------------------+

            WHILE _DEVICEINPUT(cid): WEND

            IF CL_CONTROLLER(cid).Buttons <> 0 THEN '                     yes, does this controler have buttons?

                '+---------------------------------------+
                '| This controller has buttons available |
                '+---------------------------------------+

                Number = 0 '                                              yes, reset button number counter
                Button = 0 '                                              reset button press number
                DO '                                                      begin button search

                    '+--------------------------------------+
                    '| Get button (if any) that was pressed |
                    '+--------------------------------------+

                    Number = Number + 1 '                                 increment button number counter
                    IF _BUTTON(Number) THEN Button = Number '             record this button number if it was pressed
                LOOP UNTIL Number = _LASTBUTTON(cid) OR Button '          leave when all buttons checked or a button weas pressed
            END IF

            '+--------------------------------------------------+
            '| A check for axis deflection will now be done.    |
            '| The mouse is purposely excluded from this check. |
            '+--------------------------------------------------+

            IF cid <> __MOUSECID THEN '                                   is this the mouse controller?
                IF CL_CONTROLLER(cid).Axis <> 0 THEN '                    no, does this controller have axis?

                    '+------------------------------------+
                    '| This controller has axis available |
                    '+------------------------------------+

                    Number = 0 '                                          yes, reset axis number counter
                    Axis = 0 '                                            reset axis deflection number
                    DO '                                                  begin axis search

                        '+--------------------------------------------------------------------------+
                        '| Get axis (if any) that was deflected at least 50% (or threshold setting) |
                        '+--------------------------------------------------------------------------+

                        Number = Number + 1 '                             increment axis number counter
                        AxisValue = _AXIS(Number) '                       get current value of axis
                        IF ABS(AxisValue) >= CL_SETTINGS.Threshold THEN ' was axis delfected at least to sensitivity setting?

                            '+----------------------------------------------------------------------------------------------------------+
                            '| The axis number is recorded as a negative value if the deflection was in a negative direction.           |
                            '| Likewise, the axis number is recorded as a positive value if the deflection was in a positive direction. |
                            '| This allows one axis to be recorded as two separate button actions (UP/DOWN or LEFT/RIGHT).              |
                            '+----------------------------------------------------------------------------------------------------------+

                            Axis = Number * SGN(AxisValue) '              yes, record axis with sign (+/-) of deflection
                        END IF
                    LOOP UNTIL Number = _LASTAXIS(cid) OR Axis '          leave when all axis checked or an axis was deflected
                END IF
            END IF
        END IF
    LOOP UNTIL cid <> 0 AND (Button <> 0 OR Axis <> 0) '                  leave when a controller interacted with and interaction was with a button or axis
    IF cid = __KEYBOARDCID THEN _KEYCLEAR '                               clear all keyboard buffers if the keyboard was interacted with
    IF Button THEN __ASSIGN_BUTTON Handle, cid, Button '                  assign the button to the handle
    IF Axis THEN __ASSIGN_AXIS Handle, cid, Axis '                        assign the axis to the handle

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __ASSIGN_AXIS (Handle AS INTEGER, cid AS INTEGER, Axis AS INTEGER) '                                                          __ASSIGN_AXIS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Associates a handle with up to four axis from the mouse or joypads. Simply call this subroutine up to four times to associate a new axis to   |
    '| the handle. This allows axis deflections to be treated as button presses. Good for top hats and Nintendo style "plus" directionals.           |
    '|                                                                                                                                               |
    '| __ASSIGN_AXIS UPButton, __JOYPAD1INPUT, -1 '   joystick/gamepad axis 1 UP                                                                     |
    '| __ASSIGN_AXIS DOWNButton, __JOYPAD1INPUT, 1 '  joystick/gamepad axis 1 DOWN                                                                   |
    '| __ASSIGN_AXIS LEFTButton, __JOYPAD1INPUT, -2 ' joystick/gamepad axis 2 LEFT                                                                   |
    '| __ASSIGN_AXIS RIGHTButton, __JOYPAD1INPUT, 2 ' joystick/gamepad axis 2 RIGHT                                                                  |
    '|                                                                                                                                               |
    '| Handle - button handle                                                                                                                        |
    '| cid    - controller id          (1-keyboard, 2-mouse, 3-joypad, etc..)                                                                        |
    '| Axis   - controller axis number ( 1 to _LASTAXIS(id) )                                                                                        |
    '|          the sign (+/-) of Axis determines which deflection direction will be used as a button press.                                         |
    '|          Negative typically means UP or LEFT and positive typically means DOWN or RIGHT.                                                      |
    '|                                                                                                                                               |
    '| NOTE: Once all four button slots are filled any attempt to associate a handle with more axis is ignored.                                      |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_BUTTON() AS TYPE__BUTTON '         need access to button array
    SHARED CL_SETTINGS AS TYPE__SETTINGS '       need access to library settings
    SHARED CL_KEYNAME() AS STRING '              need access to _BUTTON keyboard key names
    DIM Assigning AS TYPE__SLOT '                check slot UDT
    DIM AssignedHandle AS INTEGER '              previously assigned button handle
    DIM AssignedSlot AS INTEGER '                previously assigned button handle slot
    DIM Aname AS STRING '                        descriptive axis name
    DIM Jname AS STRING '                        joystick/game pad name

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__BUTTON_AXIS_ASSIGN"
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    IF ABS(Axis) < 1 OR ABS(Axis) > _LASTAXIS(cid) THEN __ERROR "The axis specified does not exist on controller."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-----------------------------------+
    '| Check if axis is already assigned |
    '+-----------------------------------+

    Assigning.cid = cid '                                                      set up check slot UDT
    Assigning.Button = 0
    Assigning.Axis = Axis

    IF IUO__ALREADY_ASSIGNED(Assigning, AssignedHandle, AssignedSlot) THEN '   is this axis button already assigned?

        '+-------------------------------------+
        '| This axis has already been assigned |
        '+-------------------------------------+

        IF Handle = AssignedHandle THEN '                                      is this axis already assigned to this handle?

            '+---------------------------------------------+
            '| This axis is aleady assigned to this handle |
            '+---------------------------------------------+

            EXIT SUB '                                                         yes, leave subroutine so duplicate is not made
        ELSE '                                                                 no, this is a new valid assignment
            IF CL_SETTINGS.Reassign THEN '                                     yes, is reassigning allowed?

                '+-----------------------------------+
                '| Reassigning of buttons is allowed |
                '+-----------------------------------+

                IF Handle = 0 OR CL_BUTTON(Handle).Slot1.cid = 0_
                              OR CL_BUTTON(Handle).Slot2.cid = 0_
                              OR CL_BUTTON(Handle).Slot3.cid = 0_
                              OR CL_BUTTON(Handle).Slot4.cid = 0 THEN '        yes, is there a slot available?

                    '+---------------------------------------------------------------+
                    '| This is either a new user assigned button or an existing user |
                    '| assigned button with a slot availabe so remove old assignment |
                    '+---------------------------------------------------------------+

                    __REMOVE_BUTTON AssignedHandle, AssignedSlot '             yes, remove previous button assignment
                END IF
            ELSE '                                                             no, reassigning not allowed

                '+---------------------------------------+
                '| Reassigning of buttons is not allowed |
                '+---------------------------------------+

                EXIT SUB '                                                     leave subroutine
            END IF
        END IF
    END IF

    '+----------------------------------------+
    '| Create a descriptive name for the axis |
    '+----------------------------------------+

    Jname = "" '                                                               clear joystick name
    SELECT CASE cid '                                                          which controller?
        CASE __MOUSECID '                                                      mouse
            IF ABS(Axis) = 1 THEN '                                            is this axis 1?
                IF SGN(Axis) = -1 THEN '                                       yes, up (negative)?
                    Aname = "Mouse Up" '                                       yes, create name
                ELSE '                                                         no, down (positive)
                    Aname = "Mouse Down" '                                     create name
                END IF
            ELSE '                                                             no, this must be axis 2
                IF SGN(Axis) = -1 THEN '                                       left (negative)?
                    Aname = "Mouse Left" '                                     yes, create name
                ELSE '                                                         no, right (positive)
                    Aname = "Mouse Right" '                                    create name
                END IF
            END IF
        CASE __JOYPAD1CID: Jname = "J1" '                                      joystick/game pad 1
        CASE __JOYPAD2CID: Jname = "J2" '                                      joystick/game pad 2
        CASE __JOYPAD3CID: Jname = "J3" '                                      joystick/game pad 3
        CASE __JOYPAD4CID: Jname = "J4" '                                      joystick/game pad 4
        CASE __JOYPAD5CID: Jname = "J5" '                                      joystick/game pad 5
        CASE __JOYPAD6CID: Jname = "J6" '                                      joystick/game pad 6
    END SELECT
    IF Jname <> "" THEN '                                                      was a joystick name given?

        '+-----------------------------------------+
        '| The axis belongs to a joystick/game pad |
        '+-----------------------------------------+

        SELECT CASE ABS(Axis) '                                                        yes, which axis?
            CASE 1: IF SGN(Axis) = -1 THEN Aname = "A1 Left" ELSE Aname = "A1 Right" ' axis 1, left or right
            CASE 2: IF SGN(Axis) = -1 THEN Aname = "A2 Up" ELSE Aname = "A2 Down" '    axis 2, up or down
            CASE 3: IF SGN(Axis) = -1 THEN Aname = "A3 Left" ELSE Aname = "A3 Right" ' axis 3, left or right
            CASE 4: IF SGN(Axis) = -1 THEN Aname = "A4 Up" ELSE Aname = "A4 Down" '    axis 4, up or down
        END SELECT
        Aname = Jname + Aname '                                                        complete joystick name
    END IF

    '+-------------------------+
    '| Save button information |
    '+-------------------------+

    Assigning.cid = cid '                                                      set up button to save
    Assigning.Button = 0
    Assigning.Axis = Axis
    Assigning.Name = Aname
    Assigning.Cname = __CONTROLLER_NAME$(cid)
    IF CL_BUTTON(Handle).Slot4.cid THEN '                                      4 buttons/axis already assigned?

        '+--------------------------------------------------------------------------+
        '| There are no more available slots to assign another axis to this handle. |
        '+--------------------------------------------------------------------------+

        EXIT SUB '                                                             yes, leave subroutine, no more room
    ELSEIF CL_BUTTON(Handle).Slot3.cid THEN '                                  no, 3 buttons/axis already assigned?
        CL_BUTTON(Handle).Slot4 = Assigning
    ELSEIF CL_BUTTON(Handle).Slot2.cid THEN '                                  no, 2 buttons/axis already assigned?
        CL_BUTTON(Handle).Slot3 = Assigning
    ELSEIF CL_BUTTON(Handle).Slot1.cid THEN '                                  no, 1 button/axis already assigned?
        CL_BUTTON(Handle).Slot2 = Assigning
    ELSE '                                                                     no buttons/axis have been assigned yet
        CL_BUTTON(Handle).Slot1 = Assigning
    END IF

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __ASSIGN_BUTTON (Handle AS INTEGER, cid AS INTEGER, Button AS INTEGER) '                                                    __ASSIGN_BUTTON |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Associates a handle with up to four buttons from the keyboard, mouse, or joypads. Simply call this subroutine up to four times to associate a |
    '| new button to the handle.                                                                                                                     |
    '|                                                                                                                                               |
    '| __ASSIGN_BUTTON FireButton, __KEYBOARDINPUT, CLKEY_SPACEBAR ' keyboard space bar          (in first slot)                                     |
    '| __ASSIGN_BUTTON FireButton, __JOYPAD1INPUT, 1 '               joystick trigger (button 1) (in second slot)                                    |
    '|                                                                                                                                               |
    '| Handle - button handle                                                                                                                        |
    '| cid    - controller id            (1-keyboard, 2-mouse, 3-joypad, etc..)                                                                      |
    '| Button - controller button number ( 1 to _LASTBUTTON(id) )                                                                                    |
    '|                                                                                                                                               |
    '| NOTE: Once all four button slots are filled any attempt to associate a handle with more buttons is ignored.                                   |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_BUTTON() AS TYPE__BUTTON '         need access to button array
    SHARED CL_SETTINGS AS TYPE__SETTINGS '       need access to library settings
    SHARED CL_KEYNAME() AS STRING '              need access to _BUTTON keyboard key names
    DIM Assigning AS TYPE__SLOT '                check slot UDT
    DIM AssignedHandle AS INTEGER '              previously assigned button handle
    DIM AssignedSlot AS INTEGER '                previously assigned button handle slot
    DIM Bname AS STRING '                        descriptive button name

    '+------------------+
    '| Check for errors |
    '+------------------+

    __CURRENT_ROUTINE = "__BUTTON_ASSIGN"
    IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
    IF Button < 1 OR Button > _LASTBUTTON(cid) THEN __ERROR "The button specified does not exist on controller."
    __PREVIOUS_ROUTINE = __CURRENT_ROUTINE

    '+-------------------------------------+
    '| Check if button is already assigned |
    '+-------------------------------------+

    Assigning.cid = cid '                                                      set up check slot UDT
    Assigning.Button = Button
    Assigning.Axis = 0

    IF IUO__ALREADY_ASSIGNED(Assigning, AssignedHandle, AssignedSlot) THEN '   is this button already assigned?

        '+---------------------------------------+
        '| This button has already been assigned |
        '+---------------------------------------+

        IF Handle = AssignedHandle THEN '                                      is this button already assigned to this handle?

            '+-----------------------------------------------+
            '| This button is aleady assigned to this handle |
            '+-----------------------------------------------+

            EXIT SUB '                                                         yes, leave subroutine so duplicate is not made
        ELSE '                                                                 no, this is a new valid assignment
            IF CL_SETTINGS.Reassign THEN '                                     is reassigning allowed?

                '+-----------------------------------+
                '| Reassigning of buttons is allowed |
                '+-----------------------------------+

                IF Handle = 0 OR CL_BUTTON(Handle).Slot1.cid = 0_
                              OR CL_BUTTON(Handle).Slot2.cid = 0_
                              OR CL_BUTTON(Handle).Slot3.cid = 0_
                              OR CL_BUTTON(Handle).Slot4.cid = 0 THEN '        yes, is there a slot available?

                    '+---------------------------------------------------------------+
                    '| This is either a new user assigned button or an existing user |
                    '| assigned button with a slot availabe so remove old assignment |
                    '+---------------------------------------------------------------+

                    __REMOVE_BUTTON AssignedHandle, AssignedSlot '             yes, remove previous button assignment
                END IF
            ELSE '                                                             no, reassigning not allowed

                '+---------------------------------------+
                '| Reassigning of buttons is not allowed |
                '+---------------------------------------+

                EXIT SUB '                                                     leave subroutine
            END IF
        END IF
    END IF

    '+------------------------------------------+
    '| Create a descriptive name for the button |
    '+------------------------------------------+

    SELECT CASE cid '                                                          which controller?
        CASE __KEYBOARDCID '                                                   keyboard
            Bname = CL_KEYNAME(Button) + " Key" '                              create descriptive keyboard key name
        CASE __MOUSECID '                                                      mouse
            IF Button = 1 THEN '                                               left button?
                Bname = "Left Mouse" '                                         yes, create name
            ELSEIF Button = 2 THEN '                                           no, middle button?
                Bname = "Center Mouse" '                                       yes, create name
            ELSE '                                                             no, must be right button
                Bname = "Right Mouse" '                                        create name
            END IF
        CASE __JOYPAD1CID: Bname = "J1B" + _TRIM$(STR$(Button)) '              joystick/game pad 1, create name
        CASE __JOYPAD2CID: Bname = "J2B" + _TRIM$(STR$(Button)) '              joystick/game pad 2, create name
        CASE __JOYPAD3CID: Bname = "J3B" + _TRIM$(STR$(Button)) '              joystick/game pad 3, create name
        CASE __JOYPAD4CID: Bname = "J4B" + _TRIM$(STR$(Button)) '              joystick/game pad 4, create name
        CASE __JOYPAD5CID: Bname = "J5B" + _TRIM$(STR$(Button)) '              joystick/game pad 5, create name
        CASE __JOYPAD6CID: Bname = "J6B" + _TRIM$(STR$(Button)) '              joystick/game pad 6, create name
    END SELECT

    '+-------------------------+
    '| Save button information |
    '+-------------------------+

    Assigning.cid = cid '                                                      set up button to save
    Assigning.Button = Button
    Assigning.Axis = 0
    Assigning.Name = Bname
    Assigning.Cname = __CONTROLLER_NAME$(cid)
    IF CL_BUTTON(Handle).Slot4.cid THEN '                                      4 buttons/axis already assigned?

        '+----------------------------------------------------------------------------+
        '| There are no more available slots to assign another button to this handle. |
        '+----------------------------------------------------------------------------+

        EXIT SUB '                                                             yes, leave subroutine, no more room
    ELSEIF CL_BUTTON(Handle).Slot3.cid THEN '                                  no, 3 buttons/axis already assigned?
        CL_BUTTON(Handle).Slot4 = Assigning
    ELSEIF CL_BUTTON(Handle).Slot2.cid THEN '                                  no, 2 buttons/axis already assigned?
        CL_BUTTON(Handle).Slot3 = Assigning
    ELSEIF CL_BUTTON(Handle).Slot1.cid THEN '                                  no, 1 button/axis already assigned?
        CL_BUTTON(Handle).Slot2 = Assigning
    ELSE '                                                                     no buttons/axis have been assigned yet
        CL_BUTTON(Handle).Slot1 = Assigning
    END IF

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __IDENTIFY_CONTROLLERS () '                                                                                          __IDENTIFY_CONTROLLERS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Finds all controllers (keyboard, mouse, gamepad, joystick) connected to the computer and polls them for information.                          |
    '|                                                                                                                                               |
    '| __IDENTIFY_CONTROLLERS                                                                                                                        |
    '|                                                                                                                                               |
    '| The following SHARED variables will be set with the controller's device id:                                                                   |
    '|   __KEYBOARDCID - usually 1 if found, 0 otherwise                                                                                             |
    '|   __MOUSECID    - usually 2 if found, 0 otherwise                                                                                             |
    '|   __JOYPAD1CID  - usually 3 if found (typical: 1st game pad, 1st joystick, 1st flight yoke, 1st steering wheel)                               |
    '|   __JOYPAD2CID  - usually 4 if found (typical: 2nd game pad, 2nd joystick, 2nd flight yoke, 1st rudder pedals, 1st gas/brake pedals)          |
    '|   __JOYPAD3CID  - usually 5 if found (typical: 3rd game pad, 3rd joystick, 3rd flight yoke, 2nd rudder pedals, 2nd steering wheel)            |
    '|   __JOYPAD4CID  - usually 6 if found (typical: 4th game pad, 4th joystick, 4th flight yoke, 2nd/3rd rudder pedals, 2nd/3rd gas/brake pedals)  |
    '|                                                                                                                                               |
    '| NOTE: The library will store the information for up to 6 controllers. This is typically 1 keyboard, 1 mouse, and up to four game pads and/or  |
    '|       joysticks. The "typical:" devices listed above are what I experienced when plugging these devices into my system. Your configuration    |
    '|       may vary wildly. If no keyboard or mouse is present it's possible to have up to six joysticks/game pads detected and stored.            |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    SHARED CL_SETTINGS AS TYPE__SETTINGS '       need access to library settings
    DIM Devices AS INTEGER '                     number of controller devices connected to computer
    DIM Device AS STRING '                       description and properties of controller device
    DIM cid AS INTEGER '                         controller id loop counter
    DIM Start AS INTEGER '                       beginning position of device name
    DIM Finish AS INTEGER '                      ending position of device name

    __KEYBOARDCID = 0 '                                                         reset input controller identifiers
    __MOUSECID = 0
    __JOYPAD1CID = 0
    __JOYPAD2CID = 0
    __JOYPAD3CID = 0
    __JOYPAD4CID = 0
    __JOYPAD5CID = 0
    __JOYPAD6CID = 0
    Devices = _DEVICES '                                                        get number of controllers connected to system
    CL_SETTINGS.FoundDevices = Devices '                                        record number of devices initially found
    cid = 0 '                                                                   reset controller counter
    DO '                                                                        begin controller identification loop
        cid = cid + 1 '                                                         increment controller counter
        IF cid <= Devices THEN '                                                was a controller found?
            Device = _DEVICE$(cid) '                                            yes, get controller properties
            CL_CONTROLLER(cid).Found = -1 '                                     mark this controller as found
            IF INSTR(Device, "[KEYBOARD]") THEN '                               is this a keyboard?
                CL_CONTROLLER(cid).Name = "KEYBOARD" '                          set a default descriptive name
                __KEYBOARDCID = cid '                                           set keyboard's input controller id
            END IF
            IF INSTR(Device, "[MOUSE]") THEN '                                  is this a mouse?
                CL_CONTROLLER(cid).Name = "MOUSE" '                             set a default descriptive name
                __MOUSECID = cid '                                              set mouse' input controller id
            END IF
            IF INSTR(Device, "[DISCONNECTED]") THEN '                           is this controller disconnected?
                CL_CONTROLLER(cid).Connected = 0 '                              yes, mark controller as disconnected
            ELSE '                                                              no, controller is connected
                CL_CONTROLLER(cid).Connected = -1 '                             mark controller as connected
            END IF
            IF INSTR(Device, "[CONTROLLER]") THEN '                             is this a game pad or joystick?

                '+---------------------------------------------------------+
                '| A generic name will be given to the joystick/game pad   |
                '| in the event the controller may not have a [NAME] field |
                '| Note: controllers 5 and/or 6 will only exist if the     |
                '|       keyboard and/or mouse are not connected           |
                '+---------------------------------------------------------+

                IF __JOYPAD5CID THEN '                                          has joypad5's id already been set?
                    __JOYPAD6CID = cid '                                        yes, set joypad6's input controller id
                    CL_CONTROLLER(cid).Name = "JOYPAD6" '                       set a default descriptive name
                ELSEIF __JOYPAD4CID THEN '                                      has joypad4's id already been set?
                    __JOYPAD5CID = cid '                                        yes, set joypad5's input controller id
                    CL_CONTROLLER(cid).Name = "JOYPAD5" '                       set a default descriptive name
                ELSEIF __JOYPAD3CID THEN '                                      has joypad3's id already been set?
                    __JOYPAD4CID = cid '                                        yes, set joypad4's input controller id
                    CL_CONTROLLER(cid).Name = "JOYPAD4" '                       set a default descriptive name
                ELSEIF __JOYPAD2CID THEN '                                      no, has joypad2's id already been set?
                    __JOYPAD3CID = cid '                                        yes, set joypad3's input controller id
                    CL_CONTROLLER(cid).Name = "JOYPAD3" '                       set a default descriptive name
                ELSEIF __JOYPAD1CID THEN '                                      no, has joypad1's id already been set?
                    __JOYPAD2CID = cid '                                        yes, set joypad2's input controller id
                    CL_CONTROLLER(cid).Name = "JOYPAD2" '                       set a default descriptive name
                ELSE '                                                          no joypad ids set yet
                    __JOYPAD1CID = cid '                                        set joypad1's input controller id
                    CL_CONTROLLER(cid).Name = "JOYPAD1" '                       set a default descriptive name
                END IF
            END IF
            IF INSTR(Device, "[BUTTON]") THEN '                                 does this controller have buttons?
                CL_CONTROLLER(cid).Buttons = _LASTBUTTON(cid) '                 yes, record number of buttons controller has
            ELSE '                                                              no
                CL_CONTROLLER(cid).Buttons = 0 '                                record no buttons
            END IF
            IF INSTR(Device, "[AXIS]") THEN '                                   does this controller have axis inputs?
                CL_CONTROLLER(cid).Axis = _LASTAXIS(cid) '                      yes, record number of axis controller has
            ELSE '                                                              no
                CL_CONTROLLER(cid).Axis = 0 '                                   record no axis
            END IF
            IF INSTR(Device, "[WHEEL]") THEN '                                  does this controller have wheels?
                CL_CONTROLLER(cid).Wheels = _LASTWHEEL(cid) '                   yes, record number of wheels controller has
            ELSE '                                                              no
                CL_CONTROLLER(cid).Wheels = 0 '                                 record no wheels
            END IF
            IF INSTR(Device, "[NAME]") THEN '                                   is there a more descriptive name for this controller?

                '+-------------------------------------------------------------+
                '| Replace the generic name given with the controller's [NAME] |
                '+-------------------------------------------------------------+

                Start = INSTR(Device, "[NAME]") + 7 '                           yes, get the start position of the name
                Finish = INSTR(Start, Device, "]") '                            get the end position of the name
                CL_CONTROLLER(cid).Name = MID$(Device, Start, Finish - Start) ' extract and only use the descriptive name of the controller
            END IF
        ELSE '                                                                  no controller here
            CL_CONTROLLER(cid) = CL_CONTROLLER(0) '                             reset all controller settings
        END IF
    LOOP UNTIL cid = Devices OR cid = 6 '                                       leave when all controllers polled

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __INITIALIZE_CONTROLLERS () '                                                                                      __INITIALIZE_CONTROLLERS |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Identify number and type of controllers and set initial variable values                                                                       |
    '|                                                                                                                                               |
    '| __INITIALIZE_CONTROLLERS                                                                                                                      |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_KEYNAME() AS STRING '              need access to _BUTTON keyboard key names
    SHARED CL_BUTTON() AS TYPE__BUTTON '         need access to user assigned buttons
    SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
    REDIM CL_BUTTON(1) AS TYPE__BUTTON '         clear user assigned buttons
    DIM k AS INTEGER '                           key counter

    __KEYBOARDCID = 0 '                      these will contain the device ids (_DEVICES)
    __MOUSECID = 0
    __JOYPAD1CID = 0
    __JOYPAD2CID = 0
    __JOYPAD3CID = 0
    __JOYPAD4CID = 0
    __JOYPAD5CID = 0
    __JOYPAD6CID = 0
    FOR k = 0 TO 6 '                         clear controller array
        CL_CONTROLLER(k).Found = 0
        CL_CONTROLLER(k).Name = ""
        CL_CONTROLLER(k).Buttons = 0
        CL_CONTROLLER(k).Axis = 0
        CL_CONTROLLER(k).Wheels = 0
    NEXT k
    __IDENTIFY_CONTROLLERS '                 identify controllers attached to system
    __SET_AXIS_THRESHOLD .5 '                set sensitivity of axis user defined button detection
    __BUTTON_REASSIGN_ALLOWED '              allow user defined button reassignments
    FOR k = 1 TO 350 '                       read in names of keyboard controller keys
        CL_KEYNAME(k) = "" '                 clear key name
        IF k < 90 THEN READ CL_KEYNAME(k) '  first 89 names are in data statements
        IF k = 285 THEN READ CL_KEYNAME(k) ' 285, 90 through 284 are skipped
        IF k = 286 THEN READ CL_KEYNAME(k) ' 286
        IF k = 310 THEN READ CL_KEYNAME(k) ' 310, 287 through 309 are skipped
        IF k > 325 THEN READ CL_KEYNAME(k) ' 326 through 350 are in data statements
    NEXT k

    'Keyboard _BUTTON   1 - 20
    DATA "","Escape","1","2","3","4","5","6","7","8","9","0","Minus","Equals","Backspace","Tab","Q","W","E","R"
    'Keyboard _BUTTON  21 - 40
    DATA "T","Y","U","I","O","P","Left Bracket","Right Bracket","Enter","Left CTRL","A","S","D","F","G","H","J","K","L","Semicolon"
    'Keyboard _BUTTON  41 - 50
    DATA "Quote","","Left Shift","Back Slash","Z","X","C","V","B","N"
    'Keyboard _BUTTON  51 - 60
    DATA "M","Comma","Period","Fore Slash","Right Shift","Numpad Multiply","","Space Bar","Caps Lock","F1"
    'Keyboard _BUTTON  61 - 70
    DATA "F2","F3","F4","F5","F6","F7","F8","F9","","Pause"
    'Keyboard _BUTTON  71 - 80
    DATA "Scroll Lock","Numpad 7","Numpad 8","Numpad 9","Numpad Minus","Numpad 4","Numpad 5","Numpad 6","Numpad Plus","Numpad 1"
    'Keyboard _BUTTON  81 - 89
    DATA "Numpad 2","Numpad 3","Numpad 0","Numpad Period","","","","F11","F12"
    'Keyboard _BUTTON 285 - 286
    DATA "Numpad Enter","Right CTRL"
    'Keyboard _BUTTON 310
    DATA "Numpad Divide"
    'Keyboard _BUTTON 326 - 340
    DATA "Number Lock","","Home","UP Arrow","Page UP","","LEFT Arrow","","RIGHT Arrow","","End","DOWN Arrow","Page Down","Insert","Delete"
    'Keyboard _BUTTON 341 - 350
    DATA "","","","","","","","Left Win","Right Win","Menu"

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
SUB __ERROR (Message AS STRING) '                                                                                                       __ERROR |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Set screen to text mode and display error information passed in.                                                                              |
    '|                                                                                                                                               |
    '| __ERROR "Message"                                                                                                                             |
    '|                                                                                                                                               |
    '| NOTE: Fatal error trap - halts program execution.                                                                                             |
    '\_______________________________________________________________________________________________________________________________________________/

    _FULLSCREEN _OFF '                                                    turn off full screen if active
    SCREEN 0, 0, 0, 0 '                                                   set screen to pure text mode
    CLS '                                                                 clear screen
    PLAY "l64o3ao2ao1ao3ao2ao1ao3ao2ao1a" '                               get developer's attention
    COLOR 12, 0
    PRINT '                                                               print error message
    PRINT " Controller Library has encountered the following error condition:"
    COLOR 15, 0
    PRINT
    PRINT " Error in routine: ";
    COLOR 14, 0
    PRINT __CURRENT_ROUTINE
    COLOR 15, 0
    PRINT " Previous routine: ";
    COLOR 14, 0
    PRINT __PREVIOUS_ROUTINE
    COLOR 11, 0
    PRINT
    PRINT " "; Message
    COLOR 7, 0
    _KEYCLEAR '                                                           clear all key buffers
    END '                                                                 terminate with "Press any key to continue..."

END SUB
' ______________________________________________________________________________________________________________________________________________
'/                                                                                                                                              \
FUNCTION IUO__ALREADY_ASSIGNED (Button AS TYPE__SLOT, Handle AS INTEGER, Slot AS INTEGER) '                               IUO__ALREADY_ASSIGNED |
    ' __________________________________________________________________________________________________________________________________________|____
    '/                                                                                                                                               \
    '| Returns -1 (TRUE) if a button is already assigned, 0 (FALSE) otherwise.                                                                       |
    '|                                                                                                                                               |
    '| IF IUO__ALREADY_ASSIGNED(Assigning, HandleFound, SlotFound)                                                                                   |
    '|                                                                                                                                               |
    '| Button - the new button being assigned                                                                                                        |
    '| Handle - the button handle that already contains this assignment                                                                              |
    '| Slot   - the slot number that already contains this assignment                                                                                |
    '|                                                                                                                                               |
    '| NOTE: IUO - Internal Use Only                                                                                                                 |
    '\_______________________________________________________________________________________________________________________________________________/

    SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array

    IUO__ALREADY_ASSIGNED = 0 '                                       assume button is not preassigned
    Handle = 0 '                                                      reset button handle
    Slot = 0 '                                                        reset slot number
    DO '                                                              begin assignment search
        Handle = Handle + 1 '                                         increment handle counter
        IF CL_BUTTON(Handle).Slot1.cid = Button.cid THEN '            do the controller ids match in slot 1?
            IF CL_BUTTON(Handle).Slot1.Button = Button.Button THEN '  yes, do the buttons match?
                IF CL_BUTTON(Handle).Slot1.Axis = Button.Axis THEN '  yes, do the axes match?
                    Slot = 1 '                                        yes, slot 1 already has this button assigned
                END IF
            END IF
        END IF
        IF CL_BUTTON(Handle).Slot2.cid = Button.cid THEN
            IF CL_BUTTON(Handle).Slot2.Button = Button.Button THEN
                IF CL_BUTTON(Handle).Slot2.Axis = Button.Axis THEN
                    Slot = 2 '                                        slot 2 already has this button assigned
                END IF
            END IF
        END IF
        IF CL_BUTTON(Handle).Slot3.cid = Button.cid THEN
            IF CL_BUTTON(Handle).Slot3.Button = Button.Button THEN
                IF CL_BUTTON(Handle).Slot3.Axis = Button.Axis THEN
                    Slot = 3 '                                        slot 3 already has this button assigned
                END IF
            END IF
        END IF
        IF CL_BUTTON(Handle).Slot4.cid = Button.cid THEN
            IF CL_BUTTON(Handle).Slot4.Button = Button.Button THEN
                IF CL_BUTTON(Handle).Slot4.Axis = Button.Axis THEN
                    Slot = 4 '                                        slot 4 already has this button assigned
                END IF
            END IF
        END IF
    LOOP UNTIL (Handle = UBOUND(CL_BUTTON)) OR Slot '                 leave when all checked or a slot contains assignment
    IF Slot THEN IUO__ALREADY_ASSIGNED = -1 '                         report button already assigned

END FUNCTION


Code: (Select All)
'$INCLUDE:'CONTROLLER.BI'
'----------------------------------------------------------------------------------------------------
' Controller Library Example 1
' Creating user defined buttons that include keyboard keys and joystick axes
'
' Use the keyboard ARROW keys, keyboard WASD keys, or Joystick 1 to move the circle around the screen
'
' Terry Ritchie
' April 11th, 2023 - initial release
' May 17th, 2023   - updated to use Controller Library v1.10
'----------------------------------------------------------------------------------------------------

DIM UP_Button AS INTEGER '    user defined button handles with up to four associated controller buttons and/or axes
DIM DOWN_Button AS INTEGER
DIM LEFT_Button AS INTEGER
DIM RIGHT_Button AS INTEGER
DIM x AS INTEGER '            circle x location
DIM y AS INTEGER '            circle y location

__INITIALIZE_CONTROLLERS '                                 initialize controller library
__MAKE_BUTTON UP_Button
__MAKE_BUTTON DOWN_Button
__MAKE_BUTTON LEFT_Button
__MAKE_BUTTON RIGHT_Button

'+----------------------------------------------------------------------------------+
'| Assign keyboard ARROW keys, WASD keys, and joystick 1 to the four button handles |
'+----------------------------------------------------------------------------------+

__ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_UP '       keyboard UP ARROW key assigned to UP_Button                     [SLOT1]
__ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_W '        Keyboard W key also assigned to UP_Button                       [SLOT2]
__ASSIGN_AXIS UP_Button, __JOYPAD1CID, -2 '                joystick vertical axis UP (-) also assigned to UP_Button        [SLOT3]
__ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_DOWN '   keyboard DOWN ARROW key assigned to DOWN_Button                 [SLOT1]
__ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_S '      keyboard S key also assigned to DOWN_Button                     [SLOT2]
__ASSIGN_AXIS DOWN_Button, __JOYPAD1CID, 2 '               joystick vertical axis DOWN (+) also assigned to DOWN_Button    [SLOT3]
__ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_LEFT '   keyboard LEFT ARROW key assigned to LEFT_Button                 [SLOT1]
__ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_A '      keyboard A key also assigned to LEFT_Button                     [SLOT2]
__ASSIGN_AXIS LEFT_Button, __JOYPAD1CID, -1 '              joystick horizontal axis LEFT (-) also assigned to LEFT_Button  [SLOT3]
__ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_RIGHT ' keyboard RIGHT ARROW key assigned to RIGHT_Button               [SLOT1]
__ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_D '     keyboard D key also assigned to RIGHT_Button                    [SLOT2]
__ASSIGN_AXIS RIGHT_Button, __JOYPAD1CID, 1 '              joystick horizontal axis RIGHT (+) also asigned to RIGHT_Button [SLOT3]
SCREEN _NEWIMAGE(640, 480, 32)
x = 319
y = 239
DO
    _LIMIT 30
    CLS
    LOCATE 2, 1
    PRINT " Controller Library Demo 1"
    PRINT " Use ARROW keys, WASD keys, or Joystick 1"
    PRINT " ESC to exit"
    IF __BUTTON_DOWN(UP_Button) THEN y = y - 5 '           press UP ARROW    key, W key, or move joystick UP
    IF __BUTTON_DOWN(DOWN_Button) THEN y = y + 5 '         press DOWN ARROW  key, S key, or move joystick DOWN
    IF __BUTTON_DOWN(LEFT_Button) THEN x = x - 5 '         press LEFT ARROW  key, A key, or move joystick LEFT
    IF __BUTTON_DOWN(RIGHT_Button) THEN x = x + 5 '        press RIGHT ARROW key, D key, or move joystick RIGHT
    CIRCLE (x, y), 30
    _DISPLAY
LOOP UNTIL _KEYDOWN(27) '                                  exit when ESC pressed
SYSTEM

'$INCLUDE:'CONTROLLER.BM'


Code: (Select All)
'$INCLUDE:'CONTROLLER.BI'
'----------------------------------------------------------------------------------------------------
' Controller Library Example 2
' Remapping joystick axes
'
' Use Joystick 1 to move the circle around the screen
'
' Terry Ritchie
' April 11th, 2023 - original release
' May 17th, 2023   - updated to use Controller Library v1.10
'----------------------------------------------------------------------------------------------------

__INITIALIZE_CONTROLLERS '                                       initialize controller library
SCREEN _NEWIMAGE(640, 480, 32)
DO
    _LIMIT 30
    CLS
    LOCATE 2, 1
    PRINT " Controller Library Demo 2"
    PRINT " Use Joystick 1"
    PRINT " ESC to exit"
    x = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 1), 0, 639) ' joystick 1 axis now 0 to 639
    y = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 2), 0, 479) ' joystick 2 axis now 0 to 479
    CIRCLE (x, y), 30
    _DISPLAY
LOOP UNTIL _KEYDOWN(27) '                                        exit when ESC pressed
SYSTEM

'$INCLUDE:'CONTROLLER.BM'


Code: (Select All)
'$INCLUDE:'CONTROLLER.BI'
'----------------------------------------------------------------------------------------------------
' Controller Library Example 3
' Polling controllers for information
'
' Reports information on all controllers found.
'
' Terry Ritchie
' April 11th, 2023 - original release
' May 17th, 2023   - updated to use Controller Library v1.10
'----------------------------------------------------------------------------------------------------

__INITIALIZE_CONTROLLERS ' initialize controller library
DIM Joysticks AS INTEGER
DIM Format AS STRING
DIM j AS INTEGER
DIM jid AS INTEGER

Joysticks = __JOYPAD_EXISTS(1)
Format = " |       #        | \                             \ |   ###   |  ##  |"
CLS
PRINT
PRINT "  ___________________________________________________________________"
PRINT " /           CONTROLLERS FOUND CONNECTED TO YOUR COMPUTER            \"
PRINT " |----------------+---------------------------------+---------+------|"
PRINT " |  CONTROLLER ID |         CONTROLLER NAME         | BUTTONS | AXES |"
PRINT " |----------------+---------------------------------+---------+------|"
IF __KEYBOARD_EXISTS THEN PRINT USING Format; __KEYBOARDCID; __CONTROLLER_NAME$(__KEYBOARDCID); __BUTTON_TOTAL(__KEYBOARDCID); 0
PRINT " |----------------+---------------------------------+---------+------|"
IF __MOUSE_EXISTS THEN PRINT USING Format; __MOUSECID; __CONTROLLER_NAME$(__MOUSECID); __BUTTON_TOTAL(__MOUSECID); __AXIS_TOTAL(__MOUSECID)
FOR j = 1 TO Joysticks
    SELECT CASE j
        CASE 1: jid = __JOYPAD1CID
        CASE 2: jid = __JOYPAD2CID
        CASE 3: jid = __JOYPAD3CID
        CASE 4: jid = __JOYPAD4CID
        CASE 5: jid = __JOYPAD5CID
        CASE 6: jid = __JOYPAD6CID
    END SELECT
    PRINT " |----------------+---------------------------------+---------+------|"
    PRINT USING Format; jid; __CONTROLLER_NAME$(jid); __BUTTON_TOTAL(jid); __AXIS_TOTAL(jid)
NEXT j
PRINT " \________________|_________________________________|_________|______/"
PRINT
PRINT " Press ESC to exit"
SLEEP
SYSTEM

'$INCLUDE:'CONTROLLER.BM'



Attached Files
.zip   ControllerLibV1.10.zip (Size: 2.53 MB / Downloads: 27)
Print this item

  REDIM, TYPE, and STRING Woes
Posted by: TerryRitchie - 04-12-2023, 05:57 AM - Forum: General Discussion - Replies (16)

Ok, been pulling my hair out for last 4 hours until I realized what was going on.

I have a TYPE with 3 integers and a string:

TYPE MYTYPE
    INT1 AS INTEGER
    INT2 AS INTEGER
    INT3 AS INTEGER
    INFO AS STRING
END TYPE

Then used it as so:

REDIM MYVARIABLE(1) AS MYTYPE

So far so good. As I start putting data into the array I need to resize it from time to time:

REDIM _PRESERVE MYVARIABLE(UBOUND(MYVARIABLE) + 1) AS MYTYPE

Still good right? Nope. The previous data gets completely garbled. The problem you ask?

INFO AS STRING

Change it to:

INFO AS STRING * 20

and all is good in QB64 land.

It seems variable length strings are a no-no when using REDIM _PRESERVE

If this is already a known issue then somehow I have missed it all these years. If it isn't then this is a warning letting others know this happens.

I was ready to throw my joystick through my screen until it finally dawned on me as to what may have been happening. The integers I was storing ranged from 1 to 6 but somehow they were changing to 16, 57, 3471, etc.. I thought maybe I was going nuts for a while, LOL.

Ugh.

Print this item

  Web-based paint app DPaint.js
Posted by: RhoSigma - 04-11-2023, 08:37 PM - Forum: QBJS, BAM, and Other BASICs - Replies (12)

Not strictly connected to QBJS, BAM or other BASICs, but seems the best place to point you to another stunning Web-based application, especially for the graphicans among us.

DPaint.js is inspired by the legendary Commodore Amiga Program "DeluxePaint". Just select "Documentation" from the "Help" menu, there you find some feature highlights and a introduction video.

Print this item

  Two or more finger on touchpad manager
Posted by: TempodiBasic - 04-11-2023, 08:19 PM - Forum: General Discussion - Replies (3)

CONST QB64 = QB64pe

Hi QB64 coders
QB64 developers
QB64 members of community

in what  manner do you manage modern input  mouse like touchpad of notebook?
Today new notebooks have customized input from touchpad with 2 or 3 or 4 fingers on it ....
how to catch and manage these new mouse input?
Where do you find and use the code for managing these modern mouse input?
In the old '80-'90 it was the new frontier managing mouse input (see call interrupt &H33, call absolute with binary code into an array), today the input with multiple fingers from a touchpad or another kind of input device is the new frontier.
I have get no good search result on stackoverflow.

Thanks for feedback boys and girls of QB64pe

Print this item

  how to pass parameters to H file?
Posted by: Petr - 04-11-2023, 03:30 PM - Forum: Help Me! - Replies (8)

I am confused. What is the compiler trying to do?

I try to pass a parameter of type INT or Float and it keeps telling me that the conversion from type INT* to INT and from Float to Float* cannot be performed - what does this mean? Here is a sample code to QB64PE and below that the contents of the H file. It should be fine (but it would have to work) - what did I do wrong?

QB64 code:

Code: (Select All)
Declare Library "plus"
    Function calc_plus% (a As Integer, b As Integer)
End Declare

c% = calc_plus(5, 6)
Print c%

plus.h file code:
Code: (Select All)
int calc_plus (int a, int b)
{
    int c = a + b;
    return c;
}


I'm not big friends with the C language...

Print this item

  QBJS - Fun Facts!
Posted by: dbox - 04-10-2023, 08:46 PM - Forum: QBJS, BAM, and Other BASICs - Replies (16)

Starting a thread here to post fun facts about QBJS that you might not know.

Fun Fact #1 - You can define optional parameters!

Code: (Select All)
PrintLines "First Test"
PrintLines "Second Test", 4
PrintLines "Third Test", , " -> "

Sub PrintLines (msg As String, lines As Integer, prefix As String)
    If lines = undefined  Then lines = 2   ' default to 2 lines
    If prefix = undefined Then prefix = "" ' default to blank prefix
   
    Dim i As Integer
    For i = 1 To lines
        Print prefix; msg
    Next i
End Sub

Output:
Code: (Select All)
First Test
First Test
Second Test
Second Test
Second Test
Second Test
-> Third Test
-> Third Test

Try it out on QBJS

Print this item

  Centering text inside char bax
Posted by: bplus - 04-08-2023, 05:05 PM - Forum: Utilities - Replies (14)

Code: (Select All)
_Title "Centering text inside a box of X's" ' b+ 2023-04-08
Screen _NewImage(800, 600, 32)
f& = _LoadFont("c:\WINDOWS\Fonts\arial.ttf", 24, "bold")
_Font f&
_PrintMode _KeepBackground

MessageBox "Centering text inside a box of X's, ...zzz", "X", &HFF0000FF, &HFFFFFFFF
Sleep
Cls
' OK generalize this for any meessage, character block and font size

f& = _LoadFont("c:\WINDOWS\Fonts\cambriab.ttf", 30, "Monospace")
f& = _LoadFont("c:\WINDOWS\Fonts\cambriab.ttf", 40)
_Font f&
MessageBox "bplus was here, ...zzz", "b", &HFFFF0000, &HFFBBBBFF

Sleep
Cls
f& = _LoadFont("c:\WINDOWS\Fonts\inkfree.ttf", 50)
_Font f&
MessageBox "bplus was here, ...zzz", "+", &HFFFF0000, &HFFBBBBFF
Sleep

' assuming font is loaded and _font handle activated   AND  _PrintMode _KeepBackground
' assuming message will fit on one line inside screen plus 4 extra Box characters
Sub MessageBox (message$, boxCharacter$, boxColor~&, PrintColor~&)
    ' note: "X" was the original Box Character used
    pwMessage = _PrintWidth(message$) ' print width of message$
    pwX = _PrintWidth(boxCharacter$) '  print width of 1 X
    addxs = pwMessage + 4 * pwX '       width of X box
    ' X + space + message + space + X  AND spaces same width as X = 4 * pwX

    fh = _FontHeight
    y = (_Height - 5 * fh) / 2 '        y start x's    top corner of box

    ' how many x's fit in add2x
    nx = (addxs + .5 * pwX) \ pwX '     round up to convert message line to a number of X's to print

    pwNX = _PrintWidth(String$(nx, boxCharacter$))
    x = (_Width - pwNX) / 2 '          x start x's    left side of box
    diff = pwNX - pwMessage '          what is difference between n printed X's and message line?

    Line (x, y)-Step(pwNX, 5 * fh), boxColor~&, BF
    Color PrintColor~&
    For i = 0 To 4
        If i = 0 Or i = 4 Then
            _PrintString (x, y + (i * fh)), String$(nx, boxCharacter$)
        Else
            _PrintString (x, y + (i * fh)), boxCharacter$
            _PrintString (x + pwNX - pwX, y + (i * fh)), boxCharacter$
        End If
    Next
    _PrintString (x + .5 * diff, y + 2 * fh), message$ ' for perfect center, add .5*difference

End Sub

       

Print this item