Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
kind of works? reading multiple mice: any c programmers want to look at this?
#41
If you want to see good examples of event-driven programs, take a look at anything made with Fellippe's InForm. InForm basically does that same stuff but all from scratch. However, we can't use it for this purpose.
Tread on those who tread on you

Reply
#42
(09-12-2022, 07:19 PM)Spriggsy Wrote: If you want to see good examples of event-driven programs, take a look at anything made with Fellippe's InForm. InForm basically does that same stuff but all from scratch. However, we can't use it for this purpose.

Thanks... I think this will work fine. I'll give it a try a little later. 

One question I have is, can it be made to work with _FullScreen? 
I'm not sure if QB64 has a valid window handle in that mode.
Reply
#43
All programs have window handles so you'll definitely have one even when full screen. InForm probably won't look very nice in full screen, though. Scaling issues and whatnot. All controls in InForm are created with BMPs, I think. With Win32, the resources scale with the client. We could make a Win32 version that goes full screen. I'm not sure about what you're wanting to do, however.
Tread on those who tread on you

Reply
#44
(09-12-2022, 08:07 PM)Spriggsy Wrote: All programs have window handles so you'll definitely have one even when full screen. InForm probably won't look very nice in full screen, though. Scaling issues and whatnot. All controls in InForm are created with BMPs, I think. With Win32, the resources scale with the client. We could make a Win32 version that goes full screen. I'm not sure about what you're wanting to do, however.

If it's okay with you, for now I'm not going to jump into InForm, which I have no experience with yet. 
I think I understand how the events are working the way you have it set up. 
The problem I'm having is controlling the display, screen resolution and window size. 

I tweaked the code so that it still has all the events, but in Sub MouseRawInputTest 
there is a main loop that runs concurrently with the events, and updates the screen 
(with old fashioned CLS and PRINT statements). 

However when it runs, the program just displays a blank white window. 
I remembered there was some manual screen updating going on in 
Function MainWndProc%&
at Case WM_PAINT, 
so I tried disabling the lines there, 
so QB64 could just do the screen updating itself, 
but the screen is still blank. 

I think if we can get the display stuff working, then we're possibly done! 
Any ideas how to give control of the display back to QB64? 

Here is the latest code:

Code: (Select All)
' ################################################################################################################################################################
' Multimouse
' ################################################################################################################################################################
' Working proof of concept! (Windows only so far)
' Plug in 2 or more USB mice and try moving them around


' -------------------------------------------------------------------------------
' TO DO
' -------------------------------------------------------------------------------
' DONE:
' * detect mouse button clicks (left, middle, right buttons)

' Some issues and things to fix:
' * rework code from event-driven to linear (ie call a routine to get the
'   latest coordinates / button states / scroll wheel for mouse n)
' * detect moving the scroll wheel
' * hide the real mouse cursor
' * get this working with _FullScreen _SquarePixels
' * scale the dx and dy of each mouse to 80x25 (or whatever target range is)
' * read the absolute position rather than dx and dy & fix scaling mouse
'   coordinates to 80x25 (or whatever our target range is)
' * the code is seeing an extra (phantom) mouse - might be the disabled
'   trackpad on my laptop. Is there a way to determine which mice or devices
'   are disabled or can be ignored?
' * (later) Figure out how to do this for reading multiple keyboards.
' * (later) Figure out how to get the same functionality for Mac & Linux

' -------------------------------------------------------------------------------
' CHANGES
' -------------------------------------------------------------------------------
' DATE         WHO        WHAT
' 2004-04-22   jstookey   added the ability to detect whether RawMouse is
'                         available or not so the application can either use a
'                         different multi-mouse system, or exit gracefully
'                         (thanks to Mark Healey).
' 2005-04-24   jstookey   Modified the code work with the latest version of
'                         MinGW. The new MinGW incorporates rawinput, so my
'                         winuser header and library is obsolete.
' 2006-03-05   jstookey   Initialized is_absolute and is_virtual_desktop to
'                         work better with newer versions of VStudio.
' 2022-09-07   madscijr   Turned into a command line EXE that is called from
'                         QB64 with SpriggsySpriggs' pipecom from
'                         https://github.com/SpriggsySpriggs/Spriggsys-API-Collection/blob/master/Cross-Platform%20(Windows%2C%20Macintosh%2C%20Linux)/pipecomqb64.bas
'                         This version doesn't work.
' 2022-09-08   Spriggsy   Converted C to pure QB64 code.
' 2022-09-09   madscijr   Added demo code to move multiple objects on screen
'                         with separate mice independently.
' 2022-09-09   Spriggsy   Added a screen refresh.
' 2022-09-10   madscijr   Added detecting mouse buttons.

Option Explicit
_Title "multimouse"
$NoPrefix
$Console:Only
Console Off

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN CONSTANTS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Const FALSE = 0
Const TRUE = Not FALSE

Const CS_HREDRAW = &H0002
Const CS_VREDRAW = &H0001

Const IDI_APPLICATION = 32512
Const IDC_ARROW = 32512
Const COLOR_WINDOW = 5

Const WS_OVERLAPPED = &H00000000
Const WS_CAPTION = &H00C00000
Const WS_SYSMENU = &H00080000
Const WS_THICKFRAME = &H00040000
Const WS_MINIMIZEBOX = &H00020000
Const WS_MAXIMIZEBOX = &H00010000
Const WS_CHILD = &H40000000
Const WS_VISIBLE = &H10000000
Const WS_OVERLAPPEDWINDOW = WS_OVERLAPPED Or WS_CAPTION Or WS_SYSMENU Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX
Const CW_USEDEFAULT = &H80000000

Const WM_DESTROY = &H0002
Const WM_INPUT = &H00FF

Const SW_SHOW = 5

Const RID_INPUT = &H10000003
Const RIM_TYPEMOUSE = 0

Const MOUSE_MOVE_RELATIVE = &H00
Const MOUSE_MOVE_ABSOLUTE = &H01
Const MOUSE_VIRTUAL_DESKTOP = &H02
Const MOUSE_ATTRIBUTES_CHANGED = &H04
Const MOUSE_MOVE_NOCOALESCE = &H08

Const WM_MOUSEMOVE = &H0200

Const WM_PAINT = &H000F

Const DT_CENTER = &H00000001

' MIN/MAX VALUES FOR MOUSE TEST
Const cMinX = 2
Const cMaxX = 79
Const cMinY = 16
Const cMaxY = 24
Const cMinWheel = 0
Const cMaxWheel = 255
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END CONSTANTS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN UDTs
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Type RAWINPUTDEVICE
    As Unsigned Integer usUsagePage, usUsage
    As Unsigned Long dwFlags
    As Offset hwndTarget
End Type

Type RAWINPUTDEVICELIST
    As Offset hDevice
    As Unsigned Long dwType
    $If 64BIT Then
        As String * 4 alignment
    $End If
End Type

Type POINT
    As Long x, y
End Type

Type MSG
    As Offset hwnd
    As Unsigned Long message
    As Unsigned Offset wParam
    As Offset lParam
    As Long time
    As POINT pt
    As Long lPrivate
End Type

Type WNDCLASSEX
    As Unsigned Long cbSize, style
    As Offset lpfnWndProc
    As Long cbClsExtra, cbWndExtra
    As Offset hInstance, hIcon, hCursor, hbrBackground, lpszMenuName, lpszClassName, hIconSm
End Type

Type RECT
    As Long left, top, right, bottom
End Type

Type PAINTSTRUCT
    As Offset hdc
    As Long fErase
    $If 64BIT Then
        As String * 4 alignment
    $End If
    As RECT rcPaint
    As Long fRestore, fIncUpdate
    As String * 32 rgbReserved
End Type

Type RAWINPUTHEADER
    As Unsigned Long dwType, dwSize
    As Offset hDevice
    As Unsigned Offset wParam
End Type

Type RAWMOUSE
    As Unsigned Integer usFlags
    $If 64BIT Then
        As String * 2 alignment
    $End If
    'As Unsigned Long ulButtons  'commented out because I'm creating this value using MAKELONG
    As Unsigned Integer usButtonFlags, usButtonData
    As Unsigned Long ulRawButtons
    As Long lLastX, lLastY
    As Unsigned Long ulExtraInformation
End Type

Type RAWINPUT
    As RAWINPUTHEADER header
    As RAWMOUSE mouse
End Type

' UDT TO HOLD THE INFO FOR EACH MOUSE
Type MouseInfoType
    ID As String ' mouse device ID
   
    c As String ' text cursor character
    x As Integer ' text x position
    y As Integer ' text y position
   
    xPos As Long ' hires x position
    yPos As Long ' hires y position
   
    dx As Long ' dx
    dy As Long ' dy
   
    wheel As Integer ' mouse wheel value
    LeftDown As Integer ' tracks left mouse button state, TRUE=down
    MiddleDown As Integer ' tracks middle mouse button state, TRUE=down
    RightDown As Integer ' tracks right mouse button state, TRUE=down
   
    'OldLeftDown As Integer ' tracks left mouse button state, TRUE=down
    'OldMiddleDown As Integer ' tracks middle mouse button state, TRUE=down
    'OldRightDown As Integer ' tracks right mouse button state, TRUE=down
   
    LeftCount As Integer ' counts left clicks
    MiddleCount As Integer ' counts middle clicks
    RightCount As Integer ' counts right clicks
End Type ' MouseInfoType

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END UDTs
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN API DECLARATIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Declare CustomType Library
    Function GetRawInputDeviceList~& (ByVal pRawInputDeviceList As Offset, Byval puiNumDevices As Offset, Byval cbSize As Unsigned Long)
    Sub GetRawInputDeviceList (ByVal pRawInputDeviceList As Offset, Byval puiNumDevices As Offset, Byval cbSize As Unsigned Long)
    Function RegisterRawInputDevices& (ByVal pRawInputDevices As Offset, Byval uiNumDevices As Unsigned Long, Byval cbSize As Unsigned Long)
    Function GetModuleHandle%& (ByVal lpModulename As Offset)
    Function LoadIcon%& (ByVal hInstance As Offset, Byval lpIconName As Offset)
    Function LoadCursor%& (ByVal hInstance As Offset, Byval lpCursorName As Offset)
    Function RegisterClassEx~% (ByVal wndclassex As Offset)
    Function CreateWindowEx%& (ByVal dwExStyle As Unsigned Long, Byval lpClassName As Offset, Byval lpWindowName As Offset, Byval dwStyle As Unsigned Long, Byval x As Long, Byval y As Long, Byval nWidth As Long, Byval nHeight As Long, Byval hWndParent As Offset, Byval hMenu As Offset, Byval hInstance As Offset, Byval lpParam As Offset)
    Sub ShowWindow (ByVal hWnd As Offset, Byval nCmdShow As Long)
    Sub UpdateWindow (ByVal hWnd As Offset)
    Function GetMessage& (ByVal lpMsg As Offset, Byval hWnd As Offset, Byval wMsgFilterMin As Unsigned Long, Byval wMsgFilterMax As Unsigned Long)
    Sub TranslateMessage (ByVal lpMsg As Offset)
    Sub DispatchMessage (ByVal lpMsg As Offset)
    Sub PostQuitMessage (ByVal nExitCode As Long)
    Function DefWindowProc%& (ByVal hWnd As Offset, Byval Msg As Unsigned Long, Byval wParam As Unsigned Offset, Byval lParam As Offset)
    Sub GetRawInputData (ByVal hRawInput As Offset, Byval uiCommand As Unsigned Long, Byval pData As Offset, Byval pcbSize As Offset, Byval cbSizeHeader As Unsigned Long)
    Function GetRawInputData~& (ByVal hRawInput As Offset, Byval uiCommand As Unsigned Long, Byval pData As Offset, Byval pcbSize As Offset, Byval cbSizeHeader As Unsigned Long)
    Sub InvalidateRect (ByVal hWnd As Offset, Byval lpRect As Offset, Byval bErase As Long)
    Sub SendMessage (ByVal hWnd As Offset, Byval Msg As Unsigned Long, Byval wParam As Unsigned Offset, Byval lParam As Offset)
    Function BeginPaint%& (ByVal hWnd As Offset, Byval lpPaint As Offset)
    Sub GetClientRect (ByVal hWnd As Offset, Byval lpRect As Offset)
    Sub DrawText (ByVal hdc As Offset, Byval lpchText As Offset, Byval cchText As Long, Byval lprc As Offset, Byval format As Unsigned Long)
    Sub OffsetRect (ByVal lprc As Offset, Byval dx As Long, Byval dy As Long)
    Sub EndPaint (ByVal hWnd As Offset, Byval lpPaint As Offset)
End Declare

' Header file "makeint.h" must be in same folder as this program.
Declare CustomType Library ".\makeint"
    Function MAKEINTRESOURCE%& Alias "MAKEINTRSC" (ByVal i As _Offset)
End Declare

Declare Library
    Function MAKELPARAM%& (ByVal l As Integer, Byval h As Integer)
    Function MAKELONG~& (ByVal l As Unsigned Integer, Byval h As Unsigned Integer)
End Declare

$If 64BIT Then
    Declare Library ".\internal\c\c_compiler\x86_64-w64-mingw32\include\windowsx"
    $Else
    Declare Library ".\internal\c\c_compiler\i686-w64-mingw32\include\windowsx"
    $End If
    Function GET_Y_LPARAM& (ByVal lp As Offset)
    Function GET_X_LPARAM& (ByVal lp As Offset)
End Declare

' Header file "winproc.h" must be in same folder as this program.
Declare Library ".\winproc"
    Function WindowProc%& ()
End Declare
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END API DECLARATIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GLOBAL VARIABLES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ENABLE / DISABLE DEBUG CONSOLE
Dim Shared m_bDebug As Integer: m_bDebug = FALSE

' BASIC PROGRAM METADATA
Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)

' HOLDS STATUS MESSAGES SAVED INSIDE EVENTS
Dim Shared m_EventMessage As String

' RAW INPUT VARIABLES
Dim Shared m_MouseMessage As String
Dim Shared m_RawInputMessage As String

' MOUSE TEST VARIABLES
Dim Shared m_arrMouseInfo(8) As MouseInfoType ' STORES INFO FOR EACH MOUSE
Dim Shared m_iMouseCount As Integer ' # OF MICE ATTACHED
Dim Shared m_iMinX As Long
Dim Shared m_iMaxX As Long
Dim Shared m_iMinY As Long
Dim Shared m_iMaxY As Long

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GLOBAL VARIABLES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ****************************************************************************************************************************************************************
' BEGIN ACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************
'If m_bDebug = TRUE Then
'    $Console
'    _Delay 4
'    _Console On
'    _Echo "Started " + m_ProgramName$
'    _Echo "Debugging on..."
'End If
' ****************************************************************************************************************************************************************
' END ACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' EXECUTION STARTS HERE!
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main

' ****************************************************************************************************************************************************************
' BEGIN DEACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************
'If m_bDebug = TRUE Then
'    _Console Off
'End If
' ****************************************************************************************************************************************************************
' END DEACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN CLEANUP + FINISH
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
System ' return control to the operating system
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END CLEANUP + FINISH
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' MOUSE CURSORS (JUST SOME LETTERS)
CData:
Data A,b,C,D,E,f,G,H

' DEFAULT/INTIAL X COORDINATE OF EACH CURSOR ON SCREEN
XData:
Data 5,15,25,35,45,55,65,75

' DEFAULT/INTIAL Y COORDINATE OF EACH CURSOR ON SCREEN
YData:
Data 17,17,19,19,21,21,23,23

' DEFAULT/INITIAL VALUE OF EACH SCROLL WHEEL
WData:
Data 224,192,160,128,96,64,32,0
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN MAIN PROGRAM
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Sub main
    ' INITIALIZE NON-EVENT VALUES
    InitMouseVars
   
    ' SETUP WINDOW EVENTS AND RAWINPUT
    System Val(Str$(WinMain))
   
    ' TEST READING MULTIPLE MICE
    MouseRawInputTest
End Sub ' main

' /////////////////////////////////////////////////////////////////////////////

Sub InitMouseVars
    Dim iIndex As Integer
    Dim iLoop As Integer
   
    ' INITIALIZE
    m_iMinX = 0
    m_iMaxX = 3583
    m_iMinY = 0
    m_iMaxY = 8202
   
    ' INITIALIZE CURSORS, MOUSE STATE, ETC.
    Restore CData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).c
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).x = 0
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).y = 0
       
        m_arrMouseInfo(iIndex).xPos = 0
        m_arrMouseInfo(iIndex).yPos = 0
        m_arrMouseInfo(iIndex).dx = 0
        m_arrMouseInfo(iIndex).dy = 0
       
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).wheel = 127
        m_arrMouseInfo(iIndex).LeftDown = FALSE
        m_arrMouseInfo(iIndex).MiddleDown = FALSE
        m_arrMouseInfo(iIndex).RightDown = FALSE
       
        'm_arrMouseInfo(iIndex).OldLeftDown = FALSE
        'm_arrMouseInfo(iIndex).OldMiddleDown = FALSE
        'm_arrMouseInfo(iIndex).OldRightDown = FALSE
       
        m_arrMouseInfo(iIndex).LeftCount = 0
        m_arrMouseInfo(iIndex).MiddleCount = 0
        m_arrMouseInfo(iIndex).RightCount = 0
    Next iLoop
   
    ' INITIALIZE X COORDINATES
    Restore XData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).x
    Next iLoop
   
    ' INITIALIZE Y COORDINATES
    Restore YData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).y
    Next iLoop
   
    ' INITIALIZE SCROLL WHEEL
    Restore WData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).wheel
    Next iLoop
End Sub ' InitMouseVars

' /////////////////////////////////////////////////////////////////////////////
' Gets mouse input using RawInput API

Sub MouseRawInputTest
    ' MIN/MAX VALUES
    Const cMinX = 2
    Const cMaxX = 79
    Const cMinY = 16
    Const cMaxY = 24
    Const cMinWheel = 0
    Const cMaxWheel = 255
   
    ' MAIN VARIABLES
    Dim left%, middle%, right% ' temp mouse variables
    Dim iLoop As Integer
    Dim iIndex As Integer
   
    ' TEMP VARIABLES FOR DISPLAYING FORMATTED VALUES TO SCREEN
    Dim iLen As Integer
    Dim sCount As String
    Dim sX As String
    Dim sY As String
    Dim sWheel As String
    Dim sLeftDown As String
    Dim sMiddleDown As String
    Dim sRightDown As String
    Dim sLeftCount As String
    Dim sMiddleCount As String
    Dim sRightCount As String
    Dim iRowOffset As Integer
   
    ' DRAW PLAYING FIELD
    _ScreenMove _Middle
    Cls ' clear screen
    Locate 1, 1: Print "1. PLUG 1-8 MICE INTO THE COMPUTER"
    Locate 2, 1: Print "2. USE MICE TO POSITION LETTERS ON SCREEN"
    Locate 3, 1: Print "3. PRESS <ESC> TO QUIT"
    Locate 4, 1: Print "--------------------------------------------------------------------------------";
    Locate 5, 1: Print "#  X  Y  Wheel LeftDown MiddleDown RightDown LeftCount MiddleCount RightCount   "
    Locate 6, 1: Print "--------------------------------------------------------------------------------";
   
    ' NOTE: LEAVE THE NEXT 8 LINES FREE (ROWS 8-15)
    '       TO DISPLAY TEST VALUES FOR UPTO 8 MICE
   
    ' DRAW BORDER AROUND PLAYING FIELD
    DrawTextLine cMinX - 1, cMinY - 1, cMinX - 1, cMaxY + 1, "#"
    DrawTextLine cMinX - 1, cMinY - 1, cMaxX + 1, cMinY - 1, "#"
    DrawTextLine cMaxX + 1, cMaxY + 1, cMaxX + 1, cMinY - 1, "#"
    DrawTextLine cMaxX + 1, cMaxY + 1, cMinX - 1, cMaxY + 1, "#"
   
    ' GET INPUT AND MOVE PLAYERS
    Do
        iRowOffset = 0
        For iIndex = LBound(m_arrMouseInfo) To UBound(m_arrMouseInfo)
           
            ' ERASE CURSORS AT CURRENT POSITION
            Locate m_arrMouseInfo(iIndex).y, m_arrMouseInfo(iIndex).x: Print " ";
           
            ' HANDLE LEFT MOUSE BUTTON
            If m_arrMouseInfo(iIndex).LeftDown = TRUE Then
                ' (DO SOMETHING)
            End If
           
            ' HANDLE MIDDLE MOUSE BUTTON (SCROLL WHEEL BUTTON)
            If m_arrMouseInfo(iIndex).MiddleDown = TRUE Then
                ' (DO SOMETHING)
            End If
           
            ' HANDLE RIGHT MOUSE BUTTON
            If m_arrMouseInfo(iIndex).RightDown = TRUE Then
                ' (DO SOMETHING)
            End If
           
           
           
           
           
           
            ' ****************************************************************************************************************************************************************
            ' HANDLE MOUSE MOVEMENT
           
            '' UPDATE ABSOLUTE POSITION
            'm_arrMouseInfo(iIndex).xPos = GET_X_LPARAM(lParam)
            'm_arrMouseInfo(iIndex).yPos = GET_Y_LPARAM(lParam)
            'iNewX = ( (GET_X_LPARAM(lParam) + 1) * 80) \ (iMaxX+1)
            'iNewY = ( (GET_Y_LPARAM(lParam) + 1) * 25) \ (iMaxY+1)
           
            ' UPDATE DELTA
            'm_arrMouseInfo(iIndex).dx = raw.mouse.lLastX
            'm_arrMouseInfo(iIndex).dy = raw.mouse.lLastY
            If m_arrMouseInfo(iIndex).dx < 0 Then
                m_arrMouseInfo(iIndex).x = m_arrMouseInfo(iIndex).x - 1
            ElseIf m_arrMouseInfo(iIndex).dx > 0 Then
                m_arrMouseInfo(iIndex).x = m_arrMouseInfo(iIndex).x + 1
            End If
            If m_arrMouseInfo(iIndex).dy < 0 Then
                m_arrMouseInfo(iIndex).y = m_arrMouseInfo(iIndex).y - 1
            ElseIf m_arrMouseInfo(iIndex).dy > 0 Then
                m_arrMouseInfo(iIndex).y = m_arrMouseInfo(iIndex).y + 1
            End If
            ' ****************************************************************************************************************************************************************
           
           
           
           
            ' CHECK BOUNDARIES
            If m_arrMouseInfo(iIndex).x < cMinX Then m_arrMouseInfo(iIndex).x = cMinX
            If m_arrMouseInfo(iIndex).x > cMaxX Then m_arrMouseInfo(iIndex).x = cMaxX
            If m_arrMouseInfo(iIndex).y < cMinY Then m_arrMouseInfo(iIndex).y = cMinY
            If m_arrMouseInfo(iIndex).y > cMaxY Then m_arrMouseInfo(iIndex).y = cMaxY
           
            ' PLOT CURSOR
            Locate m_arrMouseInfo(iIndex).y, m_arrMouseInfo(iIndex).x: Print m_arrMouseInfo(iIndex).c;
           
            ' DISPLAY VARIABLES
            iLen = 3: sCount = Left$(LTrim$(RTrim$(Str$(iLoop))) + String$(iLen, " "), iLen)
            iLen = 3: sX = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).x))) + String$(iLen, " "), iLen)
            iLen = 3: sY = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).y))) + String$(iLen, " "), iLen)
            iLen = 6: sWheel = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).wheel))) + String$(iLen, " "), iLen)
            iLen = 9: sLeftDown = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).LeftDown))) + String$(iLen, " "), iLen)
            iLen = 11: sMiddleDown = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).MiddleDown))) + String$(iLen, " "), iLen)
            iLen = 10: sRightDown = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).RightDown))) + String$(iLen, " "), iLen)
            iLen = 10: sLeftCount = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).LeftCount))) + String$(iLen, " "), iLen)
            iLen = 12: sMiddleCount = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).MiddleCount))) + String$(iLen, " "), iLen)
            iLen = 11: sRightCount = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).RightCount))) + String$(iLen, " "), iLen)
           
            'LOCATE 5,       1: PRINT "#  X  Y  Wheel LeftDown MiddleDown RightDown LeftCount MiddleCount RightCount   "
            Locate 6 + iLoop, 1: Print sCount + sX + sY + sWheel + sLeftDown + sMiddleDown + sRightDown + sLeftCount + sMiddleCount + sRightCount
        Next iIndex
       
        _Limit 100 ' keep loop at 100 frames per second
    Loop Until _KeyDown(27) ' escape key exit
    _KeyClear: '_DELAY 1
End Sub ' MouseRawInputTest

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END MAIN PROGRAM
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN RAW INPUT FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Runs first, initializes the RawMouse stuff and events.

Function WinMain~%& ()
    Dim As Offset hwndMain, hInst
    Dim As MSG msg
    Dim As WNDCLASSEX wndclass
    Dim As String szMainWndClass
    Dim As String szWinTitle
    Dim As Unsigned Integer reg
   
    'DEBUG: TRY FULL SCREEN <- PROGRAM CRASHES!
    '_FullScreen _SquarePixels
   
    hInst = GetModuleHandle(0)
    szMainWndClass = "WinTestWin" + Chr$(0)
    szWinTitle = "Hello" + Chr$(0)
   
    wndclass.lpszClassName = Offset(szMainWndClass)
    wndclass.cbSize = Len(wndclass)
    wndclass.style = CS_HREDRAW Or CS_VREDRAW
    wndclass.lpfnWndProc = WindowProc
    wndclass.hInstance = hInst 'GetModuleHandle(0) will return the hInstance of this EXE
    wndclass.hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION))
    wndclass.hIconSm = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION))
    wndclass.hCursor = LoadCursor(0, MAKEINTRESOURCE(IDC_ARROW))
    wndclass.hbrBackground = COLOR_WINDOW + 1
   
    reg = RegisterClassEx(Offset(wndclass)) 'I prefer to use the output of RegisterClassEx rather than the window name
   
    'DEBUG: SUBSTITUTE _WindowHandle
    hwndMain = CreateWindowEx(0, MAKELPARAM(reg, 0), Offset(szWinTitle), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInst, 0)
    'hwndMain = _WindowHandle
   
    'DEBUG: SUBSTITUTE _WindowHandle
    ShowWindow hwndMain, SW_SHOW
    'ShowWindow _WindowHandle, SW_SHOW
   
    'DEBUG: SUBSTITUTE _WindowHandle
    UpdateWindow hwndMain
    'UpdateWindow _WindowHandle
   
    InitRawInput
    InitMouseTest 'TODO: SAVE_MOUSE_INFO
   
    While GetMessage(Offset(msg), 0, 0, 0)
        TranslateMessage Offset(msg)
        DispatchMessage Offset(msg)
    Wend
   
    WinMain = msg.wParam
End Function ' WinMain

' /////////////////////////////////////////////////////////////////////////////
' Handles main window events.

Function MainWndProc%& (hwnd As Offset, nMsg As Unsigned Long, wParam As Unsigned Offset, lParam As Offset)
    Static As Offset hwndButton
    Static As Long cx, cy
    Dim As Offset hdc
    Dim As PAINTSTRUCT ps
    Dim As RECT rc
    Dim As MEM lpb
    Dim As Unsigned Long dwSize
    Dim As RAWINPUT raw
    Dim As Long tmpx, tmpy
    Static As Long maxx
    Dim As RAWINPUTHEADER rih
   
    ' TEMP VARIABLES FOR DISPLAYING FORMATTED VALUES TO SCREEN
    Dim strNextID As String
    Dim iIndex As Integer
    Dim iLen As Integer
    Dim sCount As String
    Dim sX As String
    Dim sY As String
    Dim sWheel As String
    Dim sLeftDown As String
    Dim sMiddleDown As String
    Dim sRightDown As String
    Dim sLeftCount As String
    Dim sMiddleCount As String
    Dim sRightCount As String
    Dim sNext As String
    Dim iNewX As Integer
    Dim iNewY As Integer
    Dim iDX As Integer
    Dim iDY As Integer
   
    ' HANDLE EVENTS
    Select Case nMsg
        Case WM_DESTROY
            PostQuitMessage 0
            MainWndProc = 0
            Exit Function
           
        Case WM_INPUT
            GetRawInputData lParam, RID_INPUT, 0, Offset(dwSize), Len(rih)
            lpb = MemNew(dwSize)
            If lpb.SIZE = 0 Then
                MainWndProc = 0
                Exit Function
            End If
            If GetRawInputData(lParam, RID_INPUT, lpb.OFFSET, Offset(dwSize), Len(rih)) <> dwSize Then
                m_EventMessage = "GetRawInputData doesn't return correct size!"
            End If
            MemGet lpb, lpb.OFFSET, raw
           
            If raw.header.dwType = RIM_TYPEMOUSE Then
                ' GET MOUSE INFO
                tmpx = raw.mouse.lLastX
                tmpy = raw.mouse.lLastY
                maxx = tmpx
               
                ' UPDATE RANGE OF MOUSE COORDINATES
                If GET_X_LPARAM(lParam) < m_iMinX Then m_iMinX = GET_X_LPARAM(lParam)
                If GET_X_LPARAM(lParam) > m_iMaxX Then m_iMaxX = GET_X_LPARAM(lParam)
                If GET_Y_LPARAM(lParam) < m_iMinY Then m_iMinY = GET_Y_LPARAM(lParam)
                If GET_Y_LPARAM(lParam) > m_iMaxY Then m_iMaxY = GET_Y_LPARAM(lParam)
               
                ' IDENTIFY WHICH MOUSE IT IS
                strNextID = _Trim$(Str$(raw.header.hDevice))
                iIndex = GetMouseIndex%(strNextID)
                If iIndex >= LBound(m_arrMouseInfo) Then
                    If iIndex <= UBound(m_arrMouseInfo) Then
                       
                        ' =============================================================================
                        ' SAVE MOUSE POINTER POSITION
                       
                        ' UPDATE ABSOLUTE POSITION
                        m_arrMouseInfo(iIndex).xPos = GET_X_LPARAM(lParam)
                        m_arrMouseInfo(iIndex).yPos = GET_Y_LPARAM(lParam)
                       
                        ' UPDATE DELTA
                        m_arrMouseInfo(iIndex).dx = raw.mouse.lLastX
                        m_arrMouseInfo(iIndex).dy = raw.mouse.lLastY
                       
                        ' =============================================================================
                        ' SAVE SCROLL WHEEL
                        ' (TBD)
                       
                        ' usButtonData changes value when scroll wheel moved (just stays at one value):
                        ' "usButtonData=" + Hex$(raw.mouse.usButtonData)
                         
                        ' SAVE SCROLL WHEEL POSITION TO:
                        ' m_arrMouseInfo(iIndex).wheel
                       
                        ' =============================================================================
                        ' DETECT BUTTON PRESS / RELEASE
                       
                        ' left button = 1 when down, 2 when released
                        If ((raw.mouse.usButtonFlags And 1) = 1) Then
                            m_arrMouseInfo(iIndex).LeftDown = TRUE
                            m_arrMouseInfo(iIndex).LeftCount = m_arrMouseInfo(iIndex).LeftCount + 1
                        ElseIf ((raw.mouse.usButtonFlags And 2) = 2) Then
                            m_arrMouseInfo(iIndex).LeftDown = FALSE
                        End If
                       
                        ' middle button = 16 when down, 32 when released
                        If ((raw.mouse.usButtonFlags And 16) = 16) Then
                            m_arrMouseInfo(iIndex).MiddleDown = TRUE
                            m_arrMouseInfo(iIndex).MiddleCount = m_arrMouseInfo(iIndex).MiddleCount + 1
                        ElseIf ((raw.mouse.usButtonFlags And 32) = 32) Then
                            m_arrMouseInfo(iIndex).MiddleDown = FALSE
                        End If
                       
                        ' right button = 4 when down, 8 when released
                        If ((raw.mouse.usButtonFlags And 4) = 4) Then
                            m_arrMouseInfo(iIndex).RightDown = TRUE
                            m_arrMouseInfo(iIndex).RightCount = m_arrMouseInfo(iIndex).RightCount + 1
                        ElseIf ((raw.mouse.usButtonFlags And 8) = 8) Then
                            m_arrMouseInfo(iIndex).RightDown = FALSE
                        End If
                       
                    End If
                End If
               
                InvalidateRect hwnd, 0, -1
                SendMessage hwnd, WM_PAINT, 0, 0
                MainWndProc = 0
            End If
            MemFree lpb
            MainWndProc = 0
            Exit Function
           
        Case WM_MOUSEMOVE
            ' SAVE RANGE OF MOUSE COORDINATES
            If GET_X_LPARAM(lParam) < m_iMinX Then m_iMinX = GET_X_LPARAM(lParam)
            If GET_X_LPARAM(lParam) > m_iMaxX Then m_iMaxX = GET_X_LPARAM(lParam)
            If GET_Y_LPARAM(lParam) < m_iMinY Then m_iMinY = GET_Y_LPARAM(lParam)
            If GET_Y_LPARAM(lParam) > m_iMaxY Then m_iMaxY = GET_Y_LPARAM(lParam)
           
            ' IDENTIFY WHICH MOUSE IT IS
            strNextID = _Trim$(Str$(raw.header.hDevice))
            iIndex = GetMouseIndex%(strNextID)
            If iIndex >= LBound(m_arrMouseInfo) Then
                If iIndex <= UBound(m_arrMouseInfo) Then
                    ' (DO NOTHING)
                End If
            End If
           
            InvalidateRect hwnd, 0, -1
            SendMessage hwnd, WM_PAINT, 0, 0
            MainWndProc = 0
            Exit Function
           
        Case WM_PAINT
            hdc = BeginPaint(hwnd, Offset(ps))
            GetClientRect hwnd, Offset(rc)
            DrawText hdc, Offset(m_MouseMessage), Len(m_MouseMessage), Offset(rc), DT_CENTER
            OffsetRect Offset(rc), 0, 200
           
            ' PRINT LIST OF RawInput DEVICES
            'DrawText hdc, Offset(m_RawInputMessage), Len(m_RawInputMessage), Offset(rc), DT_CENTER
           
            EndPaint hwnd, Offset(ps)
            MainWndProc = 0
            Exit Function
           
        Case Else
            MainWndProc = DefWindowProc(hwnd, nMsg, wParam, lParam)
    End Select
End Function ' MainWndProc

' /////////////////////////////////////////////////////////////////////////////
' Initializes raw input stuff

Sub InitRawInput ()
    Dim As RAWINPUTDEVICE Rid(0 To 49)
    Dim As Unsigned Long nDevices
    Dim As RAWINPUTDEVICELIST RawInputDeviceList
    Dim As MEM pRawInputDeviceList
    ReDim As RAWINPUTDEVICELIST rawdevs(-1)
    Dim As Unsigned Long x
    Dim strNextID As String
    'dim lngNextID as long
   
    If GetRawInputDeviceList(0, Offset(nDevices), Len(RawInputDeviceList)) <> 0 Then
        Exit Sub
    End If
   
    pRawInputDeviceList = MemNew(Len(RawInputDeviceList) * nDevices)
    GetRawInputDeviceList pRawInputDeviceList.OFFSET, Offset(nDevices), Len(RawInputDeviceList)
   
    ' This small block of commented code proves that we've got the device list
    ReDim As RAWINPUTDEVICELIST rawdevs(0 To nDevices - 1)
    MemGet pRawInputDeviceList, pRawInputDeviceList.OFFSET, rawdevs()
   
    ' GET MOUSE INFO
    m_iMouseCount = 0
    m_RawInputMessage = "Number of raw input devices:" + Str$(nDevices) + Chr$(13)
    For x = 0 To UBound(rawdevs)
        m_RawInputMessage = m_RawInputMessage + Str$(rawdevs(x).hDevice) + ":" + Str$(rawdevs(x).dwType) + Chr$(13)
       
        ' Is it a mouse?
        'TODO: SAVE_MOUSE_INFO
        If rawdevs(x).dwType = 0 Then
            m_iMouseCount = m_iMouseCount + 1
            strNextID = _Trim$(Str$(rawdevs(x).hDevice))
            'lngNextID = Val(strNextID)
            'm_arrMouseInfo(m_iMouseCount-1).ID = lngNextID
            m_arrMouseInfo(m_iMouseCount - 1).ID = strNextID
        End If
       
    Next x
    m_RawInputMessage = m_RawInputMessage + Chr$(0)
   
    MemFree pRawInputDeviceList
   
    Rid(0).usUsagePage = &H01
    Rid(0).usUsage = &H02
    Rid(0).dwFlags = 0
   
    'DEBUG: SUBSTITUTE _WindowHandle
    Rid(0).hwndTarget = 0
    'Rid(0).hwndTarget = _WindowHandle
   
    If RegisterRawInputDevices(Offset(Rid()), 1, Len(Rid(0))) = 0 Then
        m_MouseMessage = "RawInput init failed" + Chr$(0)
    End If
End Sub ' InitRawInput

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END RAW INPUT FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN MOUSE TEST FUNCTIONS #1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Initialize mouse test stuff

'TODO: SAVE_MOUSE_INFO

Sub InitMouseTest
    Dim iIndex As Integer
    Dim iLoop As Integer
   
    ' FOR NOW ONLY SUPPORT UPTO 8 MICE
    If (m_iMouseCount > 8) Then m_iMouseCount = 8
   
    ' INITIALIZE CURSORS, MOUSE STATE, ETC.
    Restore CData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).c
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).x = 0
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).y = 0
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).wheel = 127
        m_arrMouseInfo(iIndex).LeftDown = FALSE
        m_arrMouseInfo(iIndex).MiddleDown = FALSE
        m_arrMouseInfo(iIndex).RightDown = FALSE
        m_arrMouseInfo(iIndex).LeftCount = 0
        m_arrMouseInfo(iIndex).MiddleCount = 0
        m_arrMouseInfo(iIndex).RightCount = 0
    Next iLoop
   
    ' INITIALIZE X COORDINATES
    Restore XData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).x
    Next iLoop
   
    ' INITIALIZE Y COORDINATES
    Restore YData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).y
    Next iLoop
   
    ' INITIALIZE SCROLL WHEEL
    Restore WData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).wheel
    Next iLoop
   
End Sub ' InitMouseTest

' /////////////////////////////////////////////////////////////////////////////
' Finds position in array m_arrMouseInfo where .ID = MouseID

Function GetMouseIndex% (MouseID As String)
    Dim iLoop As Integer
    Dim iIndex%
    iIndex% = LBound(m_arrMouseInfo) - 1
    For iLoop = LBound(m_arrMouseInfo) To UBound(m_arrMouseInfo)
        If m_arrMouseInfo(iLoop).ID = MouseID Then
            iIndex% = iLoop
            Exit For
        Else
            ' not it
        End If
    Next iLoop
    GetMouseIndex% = iIndex%
End Function ' GetMouseIndex%

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END MOUSE TEST FUNCTIONS #1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' based on code from:
' Qbasic Programs - Download free bas source code
' http://www.thedubber.altervista.org/qbsrc.htm

Sub DrawTextLine (y%, x%, y2%, x2%, c$)
    Dim i%
    Dim steep%
    Dim e%
    Dim sx%
    Dim dx%
    Dim sy%
    Dim dy%
    i% = 0: steep% = 0: e% = 0
    If (x2% - x%) > 0 Then sx% = 1: Else sx% = -1
    dx% = Abs(x2% - x%)
    If (y2% - y%) > 0 Then sy% = 1: Else sy% = -1
    dy% = Abs(y2% - y%)
    If (dy% > dx%) Then
        steep% = 1
        Swap x%, y%
        Swap dx%, dy%
        Swap sx%, sy%
    End If
    e% = 2 * dy% - dx%
    For i% = 0 To dx% - 1
        If steep% = 1 Then
            Locate y%, x%
            Print c$;
        Else
            Locate x%, y%
            Print c$;
        End If

        While e% >= 0
            y% = y% + sy%: e% = e% - 2 * dx%
        Wend
        x% = x% + sx%: e% = e% + 2 * dy%
    Next
    Locate x2%, y2%
    Print c$;
End Sub ' DrawTextLine

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END TEST OUTPUT FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GENERAL PURPOSE FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' FOR BITWISE OPERATIONS

Function HasBit% (iByte As Integer, iBit As Integer)
    Dim iBitValue As Integer
    iBitValue = 2 ^ (iBit - 1)
    HasBit% = ((iByte And iBitValue) = iBitValue)
End Function ' HasBit%

' /////////////////////////////////////////////////////////////////////////////
' Split and join strings
' https://www.qb64.org/forum/index.php?topic=1073.0
'
' FROM luke, QB64 Developer
' Date: February 15, 2019, 04:11:07 AM
'
' Given a string of words separated by spaces (or any other character),
' splits it into an array of the words. I've no doubt many people have
' written a version of this over the years and no doubt there's a million
' ways to do it, but I thought I'd put mine here so we have at least one
' version. There's also a join function that does the opposite
' array -> single string.
'
' Code is hopefully reasonably self explanatory with comments and a little demo.
' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.

'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
'
'delimiter$ must be one character long.
'result$() must have been REDIMmed previously.

' Modified to handle multi-character delimiters

Sub split (in$, delimiter$, result$())
    Dim start As Integer
    Dim finish As Integer
    Dim iDelimLen As Integer
    ReDim result$(-1)

    iDelimLen = Len(delimiter$)

    start = 1
    Do
        'While Mid$(in$, start, 1) = delimiter$
        While Mid$(in$, start, iDelimLen) = delimiter$
            'start = start + 1
            start = start + iDelimLen
            If start > Len(in$) Then
                Exit Sub
            End If
        Wend
        finish = InStr(start, in$, delimiter$)
        If finish = 0 Then
            finish = Len(in$) + 1
        End If

        ReDim _Preserve result$(0 To UBound(result$) + 1)

        result$(UBound(result$)) = Mid$(in$, start, finish - start)
        start = finish + 1
    Loop While start <= Len(in$)
End Sub ' split

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GENERAL PURPOSE FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DEBUGGING ROUTINES #DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

'' /////////////////////////////////////////////////////////////////////////////
'
'Sub DebugPrint (MyString As String)
'    If m_bDebug = TRUE Then
'        '_Echo MyString
'        ReDim arrLines(-1) As String
'        Dim iLoop As Integer
'        split MyString, Chr$(13), arrLines()
'        For iLoop = LBound(arrLines) To UBound(arrLines)
'            _Echo arrLines(iLoop)
'        Next iLoop
'    End If
'End Sub ' DebugPrint

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DEBUGGING ROUTINES @DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ################################################################################################################################################################
' #REFERENCE

' =============================================================================
' SOME USEFUL STUFF FOR REFERENCE:

' Type Name               Type suffix symbol   Minimum value                  Maximum value                Size in Bytes
' ---------------------   ------------------   ----------------------------   --------------------------   -------------
' _BIT                    `                    -1                             0                            1/8
' _BIT * n                `n                   -128                           127                          n/8
' _UNSIGNED _BIT          ~`                   0                              1                            1/8
' _BYTE                   %%                   -128                           127                          1
' _UNSIGNED _BYTE         ~%%                  0                              255                          1
' INTEGER                 %                    -32,768                        32,767                       2
' _UNSIGNED INTEGER       ~%                   0                              65,535                       2
' LONG                    &                    -2,147,483,648                 2,147,483,647                4
' _UNSIGNED LONG          ~&                   0                              4,294,967,295                4
' _INTEGER64              &&                   -9,223,372,036,854,775,808     9,223,372,036,854,775,807    8
' _UNSIGNED _INTEGER64    ~&&                  0                              18,446,744,073,709,551,615   8
' SINGLE                  ! or none            -2.802597E-45                  +3.402823E+38                4
' DOUBLE                  #                    -4.490656458412465E-324        +1.797693134862310E+308      8
' _FLOAT                  ##                   -1.18E-4932                    +1.18E+4932                  32(10 used)
' _OFFSET                 %&                   -9,223,372,036,854,775,808     9,223,372,036,854,775,807    Use LEN
' _UNSIGNED _OFFSET       ~%&                  0                              18,446,744,073,709,551,615   Use LEN
' _MEM                    none                 combined memory variable type  N/A                          Use LEN

' div: int1% = num1% \ den1%
' mod: rem1% = num1% MOD den1%

' @END
Reply
#45
(09-12-2022, 08:07 PM)Spriggsy Wrote: All programs have window handles so you'll definitely have one even when full screen. InForm probably won't look very nice in full screen, though. Scaling issues and whatnot. All controls in InForm are created with BMPs, I think. With Win32, the resources scale with the client. We could make a Win32 version that goes full screen. I'm not sure about what you're wanting to do, however.

Well, I tried turning on the debug console, and am not seeing any output from the loop at line 579, 
so it seems that once it hits line 378:

System Val(Str$(WinMain))

which I _thought_ would just get the events firing, 
the flow of the program isn't progressing. 
I would expect the events to get set up and then line 301 fires MouseRawInputTest, 
which runs a loop until the user presses ESC, 
checking for changes in shared array m_arrMouseInfo 
(which the mouse events update when mouse movement + buttons are detected). 

Any idea how, when we call WinMain, to get it to just set up the events and then return control back to the main program? 


Code: (Select All)
' ################################################################################################################################################################
' Multimouse
' ################################################################################################################################################################
' Working proof of concept! (Windows only so far)
' Plug in 2 or more USB mice and try moving them around


' -------------------------------------------------------------------------------
' TO DO
' -------------------------------------------------------------------------------
' DONE:
' * detect mouse button clicks (left, middle, right buttons)

' Some issues and things to fix:
' * rework code from event-driven to linear (ie call a routine to get the
'   latest coordinates / button states / scroll wheel for mouse n)
' * detect moving the scroll wheel
' * hide the real mouse cursor
' * get this working with _FullScreen _SquarePixels
' * scale the dx and dy of each mouse to 80x25 (or whatever target range is)
' * read the absolute position rather than dx and dy & fix scaling mouse
'   coordinates to 80x25 (or whatever our target range is)
' * the code is seeing an extra (phantom) mouse - might be the disabled
'   trackpad on my laptop. Is there a way to determine which mice or devices
'   are disabled or can be ignored?
' * (later) Figure out how to do this for reading multiple keyboards.
' * (later) Figure out how to get the same functionality for Mac & Linux

' -------------------------------------------------------------------------------
' CHANGES
' -------------------------------------------------------------------------------
' DATE         WHO        WHAT
' 2004-04-22   jstookey   added the ability to detect whether RawMouse is
'                         available or not so the application can either use a
'                         different multi-mouse system, or exit gracefully
'                         (thanks to Mark Healey).
' 2005-04-24   jstookey   Modified the code work with the latest version of
'                         MinGW. The new MinGW incorporates rawinput, so my
'                         winuser header and library is obsolete.
' 2006-03-05   jstookey   Initialized is_absolute and is_virtual_desktop to
'                         work better with newer versions of VStudio.
' 2022-09-07   madscijr   Turned into a command line EXE that is called from
'                         QB64 with SpriggsySpriggs' pipecom from
'                         https://github.com/SpriggsySpriggs/Spriggsys-API-Collection/blob/master/Cross-Platform%20(Windows%2C%20Macintosh%2C%20Linux)/pipecomqb64.bas
'                         This version doesn't work.
' 2022-09-08   Spriggsy   Converted C to pure QB64 code.
' 2022-09-09   madscijr   Added demo code to move multiple objects on screen
'                         with separate mice independently.
' 2022-09-09   Spriggsy   Added a screen refresh.
' 2022-09-10   madscijr   Added detecting mouse buttons.

Option Explicit
_Title "multimouse"
$NoPrefix
$Console:Only
Console Off

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN CONSTANTS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Const FALSE = 0
Const TRUE = Not FALSE

Const CS_HREDRAW = &H0002
Const CS_VREDRAW = &H0001

Const IDI_APPLICATION = 32512
Const IDC_ARROW = 32512
Const COLOR_WINDOW = 5

Const WS_OVERLAPPED = &H00000000
Const WS_CAPTION = &H00C00000
Const WS_SYSMENU = &H00080000
Const WS_THICKFRAME = &H00040000
Const WS_MINIMIZEBOX = &H00020000
Const WS_MAXIMIZEBOX = &H00010000
Const WS_CHILD = &H40000000
Const WS_VISIBLE = &H10000000
Const WS_OVERLAPPEDWINDOW = WS_OVERLAPPED Or WS_CAPTION Or WS_SYSMENU Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX
Const CW_USEDEFAULT = &H80000000

Const WM_DESTROY = &H0002
Const WM_INPUT = &H00FF

Const SW_SHOW = 5

Const RID_INPUT = &H10000003
Const RIM_TYPEMOUSE = 0

Const MOUSE_MOVE_RELATIVE = &H00
Const MOUSE_MOVE_ABSOLUTE = &H01
Const MOUSE_VIRTUAL_DESKTOP = &H02
Const MOUSE_ATTRIBUTES_CHANGED = &H04
Const MOUSE_MOVE_NOCOALESCE = &H08

Const WM_MOUSEMOVE = &H0200

Const WM_PAINT = &H000F

Const DT_CENTER = &H00000001

' MIN/MAX VALUES FOR MOUSE TEST
Const cMinX = 2
Const cMaxX = 79
Const cMinY = 16
Const cMaxY = 24
Const cMinWheel = 0
Const cMaxWheel = 255
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END CONSTANTS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN UDTs
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Type RAWINPUTDEVICE
    As Unsigned Integer usUsagePage, usUsage
    As Unsigned Long dwFlags
    As Offset hwndTarget
End Type

Type RAWINPUTDEVICELIST
    As Offset hDevice
    As Unsigned Long dwType
    $If 64BIT Then
        As String * 4 alignment
    $End If
End Type

Type POINT
    As Long x, y
End Type

Type MSG
    As Offset hwnd
    As Unsigned Long message
    As Unsigned Offset wParam
    As Offset lParam
    As Long time
    As POINT pt
    As Long lPrivate
End Type

Type WNDCLASSEX
    As Unsigned Long cbSize, style
    As Offset lpfnWndProc
    As Long cbClsExtra, cbWndExtra
    As Offset hInstance, hIcon, hCursor, hbrBackground, lpszMenuName, lpszClassName, hIconSm
End Type

Type RECT
    As Long left, top, right, bottom
End Type

Type PAINTSTRUCT
    As Offset hdc
    As Long fErase
    $If 64BIT Then
        As String * 4 alignment
    $End If
    As RECT rcPaint
    As Long fRestore, fIncUpdate
    As String * 32 rgbReserved
End Type

Type RAWINPUTHEADER
    As Unsigned Long dwType, dwSize
    As Offset hDevice
    As Unsigned Offset wParam
End Type

Type RAWMOUSE
    As Unsigned Integer usFlags
    $If 64BIT Then
        As String * 2 alignment
    $End If
    'As Unsigned Long ulButtons  'commented out because I'm creating this value using MAKELONG
    As Unsigned Integer usButtonFlags, usButtonData
    As Unsigned Long ulRawButtons
    As Long lLastX, lLastY
    As Unsigned Long ulExtraInformation
End Type

Type RAWINPUT
    As RAWINPUTHEADER header
    As RAWMOUSE mouse
End Type

' UDT TO HOLD THE INFO FOR EACH MOUSE
Type MouseInfoType
    ID As String ' mouse device ID
   
    c As String ' text cursor character
    x As Integer ' text x position
    y As Integer ' text y position
    
    xPos As Long ' hires x position
    yPos As Long ' hires y position
    
    dx As Long ' dx
    dy As Long ' dy
    
    wheel As Integer ' mouse wheel value
    LeftDown As Integer ' tracks left mouse button state, TRUE=down
    MiddleDown As Integer ' tracks middle mouse button state, TRUE=down
    RightDown As Integer ' tracks right mouse button state, TRUE=down
   
    'OldLeftDown As Integer ' tracks left mouse button state, TRUE=down
    'OldMiddleDown As Integer ' tracks middle mouse button state, TRUE=down
    'OldRightDown As Integer ' tracks right mouse button state, TRUE=down
   
    LeftCount As Integer ' counts left clicks
    MiddleCount As Integer ' counts middle clicks
    RightCount As Integer ' counts right clicks
End Type ' MouseInfoType

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END UDTs
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN API DECLARATIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Declare CustomType Library
    Function GetRawInputDeviceList~& (ByVal pRawInputDeviceList As Offset, Byval puiNumDevices As Offset, Byval cbSize As Unsigned Long)
    Sub GetRawInputDeviceList (ByVal pRawInputDeviceList As Offset, Byval puiNumDevices As Offset, Byval cbSize As Unsigned Long)
    Function RegisterRawInputDevices& (ByVal pRawInputDevices As Offset, Byval uiNumDevices As Unsigned Long, Byval cbSize As Unsigned Long)
    Function GetModuleHandle%& (ByVal lpModulename As Offset)
    Function LoadIcon%& (ByVal hInstance As Offset, Byval lpIconName As Offset)
    Function LoadCursor%& (ByVal hInstance As Offset, Byval lpCursorName As Offset)
    Function RegisterClassEx~% (ByVal wndclassex As Offset)
    Function CreateWindowEx%& (ByVal dwExStyle As Unsigned Long, Byval lpClassName As Offset, Byval lpWindowName As Offset, Byval dwStyle As Unsigned Long, Byval x As Long, Byval y As Long, Byval nWidth As Long, Byval nHeight As Long, Byval hWndParent As Offset, Byval hMenu As Offset, Byval hInstance As Offset, Byval lpParam As Offset)
    Sub ShowWindow (ByVal hWnd As Offset, Byval nCmdShow As Long)
    Sub UpdateWindow (ByVal hWnd As Offset)
    Function GetMessage& (ByVal lpMsg As Offset, Byval hWnd As Offset, Byval wMsgFilterMin As Unsigned Long, Byval wMsgFilterMax As Unsigned Long)
    Sub TranslateMessage (ByVal lpMsg As Offset)
    Sub DispatchMessage (ByVal lpMsg As Offset)
    Sub PostQuitMessage (ByVal nExitCode As Long)
    Function DefWindowProc%& (ByVal hWnd As Offset, Byval Msg As Unsigned Long, Byval wParam As Unsigned Offset, Byval lParam As Offset)
    Sub GetRawInputData (ByVal hRawInput As Offset, Byval uiCommand As Unsigned Long, Byval pData As Offset, Byval pcbSize As Offset, Byval cbSizeHeader As Unsigned Long)
    Function GetRawInputData~& (ByVal hRawInput As Offset, Byval uiCommand As Unsigned Long, Byval pData As Offset, Byval pcbSize As Offset, Byval cbSizeHeader As Unsigned Long)
    Sub InvalidateRect (ByVal hWnd As Offset, Byval lpRect As Offset, Byval bErase As Long)
    Sub SendMessage (ByVal hWnd As Offset, Byval Msg As Unsigned Long, Byval wParam As Unsigned Offset, Byval lParam As Offset)
    Function BeginPaint%& (ByVal hWnd As Offset, Byval lpPaint As Offset)
    Sub GetClientRect (ByVal hWnd As Offset, Byval lpRect As Offset)
    Sub DrawText (ByVal hdc As Offset, Byval lpchText As Offset, Byval cchText As Long, Byval lprc As Offset, Byval format As Unsigned Long)
    Sub OffsetRect (ByVal lprc As Offset, Byval dx As Long, Byval dy As Long)
    Sub EndPaint (ByVal hWnd As Offset, Byval lpPaint As Offset)
End Declare

' Header file "makeint.h" must be in same folder as this program.
Declare CustomType Library ".\makeint"
    Function MAKEINTRESOURCE%& Alias "MAKEINTRSC" (ByVal i As _Offset)
End Declare

Declare Library
    Function MAKELPARAM%& (ByVal l As Integer, Byval h As Integer)
    Function MAKELONG~& (ByVal l As Unsigned Integer, Byval h As Unsigned Integer)
End Declare

$If 64BIT Then
    Declare Library ".\internal\c\c_compiler\x86_64-w64-mingw32\include\windowsx"
    $Else
    Declare Library ".\internal\c\c_compiler\i686-w64-mingw32\include\windowsx"
    $End If
    Function GET_Y_LPARAM& (ByVal lp As Offset)
    Function GET_X_LPARAM& (ByVal lp As Offset)
End Declare

' Header file "winproc.h" must be in same folder as this program.
Declare Library ".\winproc"
    Function WindowProc%& ()
End Declare
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END API DECLARATIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GLOBAL VARIABLES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ENABLE / DISABLE DEBUG CONSOLE
Dim Shared m_bDebug As Integer: m_bDebug = TRUE

' BASIC PROGRAM METADATA
Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)

' HOLDS STATUS MESSAGES SAVED INSIDE EVENTS
Dim Shared m_EventMessage As String

' RAW INPUT VARIABLES
Dim Shared m_MouseMessage As String
Dim Shared m_RawInputMessage As String

' MOUSE TEST VARIABLES
Dim Shared m_arrMouseInfo(8) As MouseInfoType ' STORES INFO FOR EACH MOUSE
Dim Shared m_iMouseCount As Integer ' # OF MICE ATTACHED
Dim Shared m_iMinX As Long
Dim Shared m_iMaxX As Long
Dim Shared m_iMinY As Long
Dim Shared m_iMaxY As Long

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GLOBAL VARIABLES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ****************************************************************************************************************************************************************
' BEGIN ACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************
If m_bDebug = TRUE Then
    $Console
    _Delay 4
    _Console On
    _Echo "Started " + m_ProgramName$
    _Echo "Debugging on..."
End If
' ****************************************************************************************************************************************************************
' END ACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' EXECUTION STARTS HERE!
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main

' ****************************************************************************************************************************************************************
' BEGIN DEACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************
If m_bDebug = TRUE Then
    _Console Off
End If
' ****************************************************************************************************************************************************************
' END DEACTIVATE DEBUGGING WINDOW
' ****************************************************************************************************************************************************************

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN CLEANUP + FINISH
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
System ' return control to the operating system
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END CLEANUP + FINISH
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' MOUSE CURSORS (JUST SOME LETTERS)
CData:
Data A,b,C,D,E,f,G,H

' DEFAULT/INTIAL X COORDINATE OF EACH CURSOR ON SCREEN
XData:
Data 5,15,25,35,45,55,65,75

' DEFAULT/INTIAL Y COORDINATE OF EACH CURSOR ON SCREEN
YData:
Data 17,17,19,19,21,21,23,23

' DEFAULT/INITIAL VALUE OF EACH SCROLL WHEEL
WData:
Data 224,192,160,128,96,64,32,0
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN MAIN PROGRAM
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

sub main
    ' INITIALIZE NON-EVENT VALUES
    InitMouseVars
    
    ' SETUP WINDOW EVENTS AND RAWINPUT
    System Val(Str$(WinMain))
    
    ' TEST READING MULTIPLE MICE
    MouseRawInputTest
end sub ' main

' /////////////////////////////////////////////////////////////////////////////

sub InitMouseVars
    Dim iIndex As Integer
    Dim iLoop As Integer
   
    ' INITIALIZE
    m_iMinX = 0
    m_iMaxX = 3583
    m_iMinY = 0
    m_iMaxY = 8202
    
    ' INITIALIZE CURSORS, MOUSE STATE, ETC.
    Restore CData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).c
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).x = 0
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).y = 0
        
        m_arrMouseInfo(iIndex).xPos = 0
        m_arrMouseInfo(iIndex).yPos = 0
        m_arrMouseInfo(iIndex).dx = 0
        m_arrMouseInfo(iIndex).dy = 0
        
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).wheel = 127
        m_arrMouseInfo(iIndex).LeftDown = FALSE
        m_arrMouseInfo(iIndex).MiddleDown = FALSE
        m_arrMouseInfo(iIndex).RightDown = FALSE
        
        'm_arrMouseInfo(iIndex).OldLeftDown = FALSE
        'm_arrMouseInfo(iIndex).OldMiddleDown = FALSE
        'm_arrMouseInfo(iIndex).OldRightDown = FALSE
        
        m_arrMouseInfo(iIndex).LeftCount = 0
        m_arrMouseInfo(iIndex).MiddleCount = 0
        m_arrMouseInfo(iIndex).RightCount = 0
    Next iLoop
    
    ' INITIALIZE X COORDINATES
    Restore XData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).x
    Next iLoop
   
    ' INITIALIZE Y COORDINATES
    Restore YData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).y
    Next iLoop
   
    ' INITIALIZE SCROLL WHEEL
    Restore WData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).wheel
    Next iLoop
end sub ' InitMouseVars

' /////////////////////////////////////////////////////////////////////////////
' Gets mouse input using RawInput API

Sub MouseRawInputTest
    ' MIN/MAX VALUES
    Const cMinX = 2
    Const cMaxX = 79
    Const cMinY = 16
    Const cMaxY = 24
    Const cMinWheel = 0
    Const cMaxWheel = 255
    
    ' MAIN VARIABLES
    Dim left%, middle%, right% ' temp mouse variables
    Dim iLoop As Integer
    Dim iIndex As Integer
    
    ' TEMP VARIABLES FOR DISPLAYING FORMATTED VALUES TO SCREEN
    Dim iLen As Integer
    Dim sCount As String
    Dim sX As String
    Dim sY As String
    Dim sWheel As String
    Dim sLeftDown As String
    Dim sMiddleDown As String
    Dim sRightDown As String
    Dim sLeftCount As String
    Dim sMiddleCount As String
    Dim sRightCount As String
    Dim iRowOffset As Integer
    
    ' DRAW PLAYING FIELD
    _ScreenMove _Middle
    Cls ' clear screen
    Locate 1, 1: Print "1. PLUG 1-8 MICE INTO THE COMPUTER"
    Locate 2, 1: Print "2. USE MICE TO POSITION LETTERS ON SCREEN"
    Locate 3, 1: Print "3. PRESS <ESC> TO QUIT"
    Locate 4, 1: Print "--------------------------------------------------------------------------------";
    Locate 5, 1: Print "#  X  Y  Wheel LeftDown MiddleDown RightDown LeftCount MiddleCount RightCount   "
    Locate 6, 1: Print "--------------------------------------------------------------------------------";
   
    ' NOTE: LEAVE THE NEXT 8 LINES FREE (ROWS 8-15)
    '       TO DISPLAY TEST VALUES FOR UPTO 8 MICE
   
    ' DRAW BORDER AROUND PLAYING FIELD
    DrawTextLine cMinX - 1, cMinY - 1, cMinX - 1, cMaxY + 1, "#"
    DrawTextLine cMinX - 1, cMinY - 1, cMaxX + 1, cMinY - 1, "#"
    DrawTextLine cMaxX + 1, cMaxY + 1, cMaxX + 1, cMinY - 1, "#"
    DrawTextLine cMaxX + 1, cMaxY + 1, cMinX - 1, cMaxY + 1, "#"
   
    ' GET INPUT AND MOVE PLAYERS
    Do
        iRowOffset = 0
        For iIndex = LBound(m_arrMouseInfo) To UBound(m_arrMouseInfo)
           
            ' ERASE CURSORS AT CURRENT POSITION
            Locate m_arrMouseInfo(iIndex).y, m_arrMouseInfo(iIndex).x: Print " ";
           
            ' HANDLE LEFT MOUSE BUTTON
            If m_arrMouseInfo(iIndex).LeftDown = TRUE Then
                ' (DO SOMETHING)
            End If
           
            ' HANDLE MIDDLE MOUSE BUTTON (SCROLL WHEEL BUTTON)
            If m_arrMouseInfo(iIndex).MiddleDown = TRUE Then
                ' (DO SOMETHING)
            End If
           
            ' HANDLE RIGHT MOUSE BUTTON
            If m_arrMouseInfo(iIndex).RightDown = TRUE Then
                ' (DO SOMETHING)
            End If
           
            
            
            
            
            
            ' ****************************************************************************************************************************************************************
            ' HANDLE MOUSE MOVEMENT
            
            '' UPDATE ABSOLUTE POSITION
            'm_arrMouseInfo(iIndex).xPos = GET_X_LPARAM(lParam)
            'm_arrMouseInfo(iIndex).yPos = GET_Y_LPARAM(lParam)
            'iNewX = ( (GET_X_LPARAM(lParam) + 1) * 80) \ (iMaxX+1)
            'iNewY = ( (GET_Y_LPARAM(lParam) + 1) * 25) \ (iMaxY+1)
            
            ' UPDATE DELTA
            'm_arrMouseInfo(iIndex).dx = raw.mouse.lLastX
            'm_arrMouseInfo(iIndex).dy = raw.mouse.lLastY
            If m_arrMouseInfo(iIndex).dx < 0 Then
                m_arrMouseInfo(iIndex).x = m_arrMouseInfo(iIndex).x - 1
            ElseIf m_arrMouseInfo(iIndex).dx > 0 Then
                m_arrMouseInfo(iIndex).x = m_arrMouseInfo(iIndex).x + 1
            End If
            If m_arrMouseInfo(iIndex).dy < 0 Then
                m_arrMouseInfo(iIndex).y = m_arrMouseInfo(iIndex).y - 1
            ElseIf m_arrMouseInfo(iIndex).dy > 0 Then
                m_arrMouseInfo(iIndex).y = m_arrMouseInfo(iIndex).y + 1
            End If
            ' ****************************************************************************************************************************************************************
            
            
            
            
            ' CHECK BOUNDARIES
            If m_arrMouseInfo(iIndex).x < cMinX Then m_arrMouseInfo(iIndex).x = cMinX
            If m_arrMouseInfo(iIndex).x > cMaxX Then m_arrMouseInfo(iIndex).x = cMaxX
            If m_arrMouseInfo(iIndex).y < cMinY Then m_arrMouseInfo(iIndex).y = cMinY
            If m_arrMouseInfo(iIndex).y > cMaxY Then m_arrMouseInfo(iIndex).y = cMaxY
           
            ' PLOT CURSOR
            Locate m_arrMouseInfo(iIndex).y, m_arrMouseInfo(iIndex).x: Print m_arrMouseInfo(iIndex).c;
           
            ' DISPLAY VARIABLES
            iLen = 3: sCount = Left$(LTrim$(RTrim$(Str$(iLoop))) + String$(iLen, " "), iLen)
            iLen = 3: sX = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).x))) + String$(iLen, " "), iLen)
            iLen = 3: sY = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).y))) + String$(iLen, " "), iLen)
            iLen = 6: sWheel = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).wheel))) + String$(iLen, " "), iLen)
            iLen = 9: sLeftDown = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).LeftDown))) + String$(iLen, " "), iLen)
            iLen = 11: sMiddleDown = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).MiddleDown))) + String$(iLen, " "), iLen)
            iLen = 10: sRightDown = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).RightDown))) + String$(iLen, " "), iLen)
            iLen = 10: sLeftCount = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).LeftCount))) + String$(iLen, " "), iLen)
            iLen = 12: sMiddleCount = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).MiddleCount))) + String$(iLen, " "), iLen)
            iLen = 11: sRightCount = Left$(LTrim$(RTrim$(Str$(m_arrMouseInfo(iIndex).RightCount))) + String$(iLen, " "), iLen)
           
            'LOCATE 5,       1: PRINT "#  X  Y  Wheel LeftDown MiddleDown RightDown LeftCount MiddleCount RightCount   "
            Locate 6 + iLoop, 1: Print sCount + sX + sY + sWheel + sLeftDown + sMiddleDown + sRightDown + sLeftCount + sMiddleCount + sRightCount
            
            
            DebugPrint "" + _
                "Mouse " + _TRIM$(STR$(iIndex)) + _
                " .x=" + _TRIM$(STR$(m_arrMouseInfo(iIndex).x)) + _
                " .y=" + _TRIM$(STR$(m_arrMouseInfo(iIndex).y))
            
        Next iIndex
       
        
        _DISPLAY
        
        
        
        _Limit 100 ' keep loop at 100 frames per second
    Loop Until _KeyDown(27) ' escape key exit
    _KeyClear: '_DELAY 1
    
    _AUTODISPLAY
End Sub ' MouseRawInputTest

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END MAIN PROGRAM
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN RAW INPUT FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Runs first, initializes the RawMouse stuff and events.

Function WinMain~%& ()
    Dim As Offset hwndMain, hInst
    Dim As MSG msg
    Dim As WNDCLASSEX wndclass
    Dim As String szMainWndClass
    Dim As String szWinTitle
    Dim As Unsigned Integer reg
   
    'DEBUG: TRY FULL SCREEN <- PROGRAM CRASHES!
    '_FullScreen _SquarePixels
   
    hInst = GetModuleHandle(0)
    szMainWndClass = "WinTestWin" + Chr$(0)
    szWinTitle = "Hello" + Chr$(0)
   
    wndclass.lpszClassName = Offset(szMainWndClass)
    wndclass.cbSize = Len(wndclass)
    wndclass.style = CS_HREDRAW Or CS_VREDRAW
    wndclass.lpfnWndProc = WindowProc
    wndclass.hInstance = hInst 'GetModuleHandle(0) will return the hInstance of this EXE
    wndclass.hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION))
    wndclass.hIconSm = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION))
    wndclass.hCursor = LoadCursor(0, MAKEINTRESOURCE(IDC_ARROW))
    wndclass.hbrBackground = COLOR_WINDOW + 1
   
    reg = RegisterClassEx(Offset(wndclass)) 'I prefer to use the output of RegisterClassEx rather than the window name
   
    'DEBUG: SUBSTITUTE _WindowHandle
    hwndMain = CreateWindowEx(0, MAKELPARAM(reg, 0), Offset(szWinTitle), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInst, 0)
    'hwndMain = _WindowHandle
   
    'DEBUG: SUBSTITUTE _WindowHandle
    ShowWindow hwndMain, SW_SHOW
    'ShowWindow _WindowHandle, SW_SHOW
   
    'DEBUG: SUBSTITUTE _WindowHandle
    UpdateWindow hwndMain
    'UpdateWindow _WindowHandle
   
    InitRawInput
    InitMouseTest 'TODO: SAVE_MOUSE_INFO
   
    While GetMessage(Offset(msg), 0, 0, 0)
        TranslateMessage Offset(msg)
        DispatchMessage Offset(msg)
    Wend
   
    WinMain = msg.wParam
End Function ' WinMain

' /////////////////////////////////////////////////////////////////////////////
' Handles main window events.

Function MainWndProc%& (hwnd As Offset, nMsg As Unsigned Long, wParam As Unsigned Offset, lParam As Offset)
    Static As Offset hwndButton
    Static As Long cx, cy
    Dim As Offset hdc
    Dim As PAINTSTRUCT ps
    Dim As RECT rc
    Dim As MEM lpb
    Dim As Unsigned Long dwSize
    Dim As RAWINPUT raw
    Dim As Long tmpx, tmpy
    Static As Long maxx
    Dim As RAWINPUTHEADER rih
   
    ' TEMP VARIABLES FOR DISPLAYING FORMATTED VALUES TO SCREEN
    Dim strNextID As String
    Dim iIndex As Integer
    Dim iLen As Integer
    Dim sCount As String
    Dim sX As String
    Dim sY As String
    Dim sWheel As String
    Dim sLeftDown As String
    Dim sMiddleDown As String
    Dim sRightDown As String
    Dim sLeftCount As String
    Dim sMiddleCount As String
    Dim sRightCount As String
    Dim sNext As String
    Dim iNewX As Integer
    Dim iNewY As Integer
    Dim iDX As Integer
    Dim iDY As Integer
   
    ' HANDLE EVENTS
    Select Case nMsg
        Case WM_DESTROY
            PostQuitMessage 0
            MainWndProc = 0
            Exit Function
           
        Case WM_INPUT
            GetRawInputData lParam, RID_INPUT, 0, Offset(dwSize), Len(rih)
            lpb = MemNew(dwSize)
            If lpb.SIZE = 0 Then
                MainWndProc = 0
                Exit Function
            End If
            If GetRawInputData(lParam, RID_INPUT, lpb.OFFSET, Offset(dwSize), Len(rih)) <> dwSize Then
                m_EventMessage = "GetRawInputData doesn't return correct size!"
            End If
            MemGet lpb, lpb.OFFSET, raw
           
            If raw.header.dwType = RIM_TYPEMOUSE Then
                ' GET MOUSE INFO
                tmpx = raw.mouse.lLastX
                tmpy = raw.mouse.lLastY
                maxx = tmpx
               
                ' UPDATE RANGE OF MOUSE COORDINATES
                If GET_X_LPARAM(lParam) < m_iMinX Then m_iMinX = GET_X_LPARAM(lParam)
                If GET_X_LPARAM(lParam) > m_iMaxX Then m_iMaxX = GET_X_LPARAM(lParam)
                If GET_Y_LPARAM(lParam) < m_iMinY Then m_iMinY = GET_Y_LPARAM(lParam)
                If GET_Y_LPARAM(lParam) > m_iMaxY Then m_iMaxY = GET_Y_LPARAM(lParam)
               
                ' IDENTIFY WHICH MOUSE IT IS
                strNextID = _Trim$(Str$(raw.header.hDevice))
                iIndex = GetMouseIndex%(strNextID)
                If iIndex >= LBound(m_arrMouseInfo) Then
                    If iIndex <= UBound(m_arrMouseInfo) Then
                       
                        ' =============================================================================
                        ' SAVE MOUSE POINTER POSITION
                        
                        ' UPDATE ABSOLUTE POSITION
                        m_arrMouseInfo(iIndex).xPos = GET_X_LPARAM(lParam)
                        m_arrMouseInfo(iIndex).yPos = GET_Y_LPARAM(lParam)
                       
                        ' UPDATE DELTA
                        m_arrMouseInfo(iIndex).dx = raw.mouse.lLastX
                        m_arrMouseInfo(iIndex).dy = raw.mouse.lLastY
                        
                        ' =============================================================================
                        ' SAVE SCROLL WHEEL
                        ' (TBD)
                        
                        ' usButtonData changes value when scroll wheel moved (just stays at one value):
                        ' "usButtonData=" + Hex$(raw.mouse.usButtonData)
                        
                        ' SAVE SCROLL WHEEL POSITION TO:
                        ' m_arrMouseInfo(iIndex).wheel
                        
                        ' =============================================================================
                        ' DETECT BUTTON PRESS / RELEASE
                       
                        ' left button = 1 when down, 2 when released
                        if ((raw.mouse.usButtonFlags AND 1) = 1) then
                            m_arrMouseInfo(iIndex).LeftDown = TRUE
                            m_arrMouseInfo(iIndex).LeftCount = m_arrMouseInfo(iIndex).LeftCount + 1
                        elseif ((raw.mouse.usButtonFlags AND 2) = 2) then
                            m_arrMouseInfo(iIndex).LeftDown = FALSE
                        end if
                        
                        ' middle button = 16 when down, 32 when released
                        if ((raw.mouse.usButtonFlags AND 16) = 16) then
                            m_arrMouseInfo(iIndex).MiddleDown = TRUE
                            m_arrMouseInfo(iIndex).MiddleCount = m_arrMouseInfo(iIndex).MiddleCount + 1
                        elseif ((raw.mouse.usButtonFlags AND 32) = 32) then
                            m_arrMouseInfo(iIndex).MiddleDown = FALSE
                        end if
                        
                        ' right button = 4 when down, 8 when released
                        if ((raw.mouse.usButtonFlags AND 4) = 4) then
                            m_arrMouseInfo(iIndex).RightDown = TRUE
                            m_arrMouseInfo(iIndex).RightCount = m_arrMouseInfo(iIndex).RightCount + 1
                        elseif ((raw.mouse.usButtonFlags AND 8) = 8) then
                            m_arrMouseInfo(iIndex).RightDown = FALSE
                        end if
                        
                    End If
                End If
               
                InvalidateRect hwnd, 0, -1
                SendMessage hwnd, WM_PAINT, 0, 0
                MainWndProc = 0
            End If
            MemFree lpb
            MainWndProc = 0
            Exit Function
           
        Case WM_MOUSEMOVE
            ' SAVE RANGE OF MOUSE COORDINATES
            If GET_X_LPARAM(lParam) < m_iMinX Then m_iMinX = GET_X_LPARAM(lParam)
            If GET_X_LPARAM(lParam) > m_iMaxX Then m_iMaxX = GET_X_LPARAM(lParam)
            If GET_Y_LPARAM(lParam) < m_iMinY Then m_iMinY = GET_Y_LPARAM(lParam)
            If GET_Y_LPARAM(lParam) > m_iMaxY Then m_iMaxY = GET_Y_LPARAM(lParam)
           
            ' IDENTIFY WHICH MOUSE IT IS
            strNextID = _Trim$(Str$(raw.header.hDevice))
            iIndex = GetMouseIndex%(strNextID)
            If iIndex >= LBound(m_arrMouseInfo) Then
                If iIndex <= UBound(m_arrMouseInfo) Then
                    ' (DO NOTHING)
                End If
            End If
           
            InvalidateRect hwnd, 0, -1
            SendMessage hwnd, WM_PAINT, 0, 0
            MainWndProc = 0
            Exit Function
           
        Case WM_PAINT
'            hdc = BeginPaint(hwnd, Offset(ps))
'            GetClientRect hwnd, Offset(rc)
'            DrawText hdc, Offset(m_MouseMessage), Len(m_MouseMessage), Offset(rc), DT_CENTER
'            OffsetRect Offset(rc), 0, 200
           
            ' PRINT LIST OF RawInput DEVICES
            'DrawText hdc, Offset(m_RawInputMessage), Len(m_RawInputMessage), Offset(rc), DT_CENTER
            
'            EndPaint hwnd, Offset(ps)
'            MainWndProc = 0
'            Exit Function
           
        Case Else
            MainWndProc = DefWindowProc(hwnd, nMsg, wParam, lParam)
    End Select
End Function ' MainWndProc

' /////////////////////////////////////////////////////////////////////////////
' Initializes raw input stuff

Sub InitRawInput ()
    Dim As RAWINPUTDEVICE Rid(0 To 49)
    Dim As Unsigned Long nDevices
    Dim As RAWINPUTDEVICELIST RawInputDeviceList
    Dim As MEM pRawInputDeviceList
    ReDim As RAWINPUTDEVICELIST rawdevs(-1)
    Dim As Unsigned Long x
    Dim strNextID As String
    'dim lngNextID as long
   
    If GetRawInputDeviceList(0, Offset(nDevices), Len(RawInputDeviceList)) <> 0 Then
        Exit Sub
    End If
   
    pRawInputDeviceList = MemNew(Len(RawInputDeviceList) * nDevices)
    GetRawInputDeviceList pRawInputDeviceList.OFFSET, Offset(nDevices), Len(RawInputDeviceList)
   
    ' This small block of commented code proves that we've got the device list
    ReDim As RAWINPUTDEVICELIST rawdevs(0 To nDevices - 1)
    MemGet pRawInputDeviceList, pRawInputDeviceList.OFFSET, rawdevs()
   
    ' GET MOUSE INFO
    m_iMouseCount = 0
    m_RawInputMessage = "Number of raw input devices:" + Str$(nDevices) + Chr$(13)
    For x = 0 To UBound(rawdevs)
        m_RawInputMessage = m_RawInputMessage + Str$(rawdevs(x).hDevice) + ":" + Str$(rawdevs(x).dwType) + Chr$(13)
       
        ' Is it a mouse?
        'TODO: SAVE_MOUSE_INFO
        If rawdevs(x).dwType = 0 Then
            m_iMouseCount = m_iMouseCount + 1
            strNextID = _Trim$(Str$(rawdevs(x).hDevice))
            'lngNextID = Val(strNextID)
            'm_arrMouseInfo(m_iMouseCount-1).ID = lngNextID
            m_arrMouseInfo(m_iMouseCount - 1).ID = strNextID
        End If
       
    Next x
    m_RawInputMessage = m_RawInputMessage + Chr$(0)
   
    MemFree pRawInputDeviceList
   
    Rid(0).usUsagePage = &H01
    Rid(0).usUsage = &H02
    Rid(0).dwFlags = 0
   
    'DEBUG: SUBSTITUTE _WindowHandle
    Rid(0).hwndTarget = 0
    'Rid(0).hwndTarget = _WindowHandle
   
    If RegisterRawInputDevices(Offset(Rid()), 1, Len(Rid(0))) = 0 Then
        m_MouseMessage = "RawInput init failed" + Chr$(0)
    End If
End Sub ' InitRawInput

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END RAW INPUT FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN MOUSE TEST FUNCTIONS #1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Initialize mouse test stuff

'TODO: SAVE_MOUSE_INFO

Sub InitMouseTest
    Dim iIndex As Integer
    Dim iLoop As Integer
   
    ' FOR NOW ONLY SUPPORT UPTO 8 MICE
    If (m_iMouseCount > 8) Then m_iMouseCount = 8
   
    ' INITIALIZE CURSORS, MOUSE STATE, ETC.
    Restore CData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).c
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).x = 0
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).y = 0
        ' INITIALIZED BELOW: m_arrMouseInfo(iIndex).wheel = 127
        m_arrMouseInfo(iIndex).LeftDown = FALSE
        m_arrMouseInfo(iIndex).MiddleDown = FALSE
        m_arrMouseInfo(iIndex).RightDown = FALSE
        m_arrMouseInfo(iIndex).LeftCount = 0
        m_arrMouseInfo(iIndex).MiddleCount = 0
        m_arrMouseInfo(iIndex).RightCount = 0
    Next iLoop
   
    ' INITIALIZE X COORDINATES
    Restore XData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).x
    Next iLoop
   
    ' INITIALIZE Y COORDINATES
    Restore YData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).y
    Next iLoop
   
    ' INITIALIZE SCROLL WHEEL
    Restore WData
    iIndex = LBound(m_arrMouseInfo) - 1
    For iLoop = 1 To m_iMouseCount
        iIndex = iIndex + 1
        Read m_arrMouseInfo(iIndex).wheel
    Next iLoop
   
End Sub ' InitMouseTest

' /////////////////////////////////////////////////////////////////////////////
' Finds position in array m_arrMouseInfo where .ID = MouseID

Function GetMouseIndex% (MouseID As String)
    Dim iLoop As Integer
    Dim iIndex%
    iIndex% = LBound(m_arrMouseInfo) - 1
    For iLoop = LBound(m_arrMouseInfo) To UBound(m_arrMouseInfo)
        If m_arrMouseInfo(iLoop).ID = MouseID Then
            iIndex% = iLoop
            Exit For
        Else
            ' not it
        End If
    Next iLoop
    GetMouseIndex% = iIndex%
End Function ' GetMouseIndex%

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END MOUSE TEST FUNCTIONS #1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' based on code from:
' Qbasic Programs - Download free bas source code
' http://www.thedubber.altervista.org/qbsrc.htm

Sub DrawTextLine (y%, x%, y2%, x2%, c$)
    Dim i%
    Dim steep%
    Dim e%
    Dim sx%
    Dim dx%
    Dim sy%
    Dim dy%
    i% = 0: steep% = 0: e% = 0
    If (x2% - x%) > 0 Then sx% = 1: Else sx% = -1
    dx% = Abs(x2% - x%)
    If (y2% - y%) > 0 Then sy% = 1: Else sy% = -1
    dy% = Abs(y2% - y%)
    If (dy% > dx%) Then
        steep% = 1
        Swap x%, y%
        Swap dx%, dy%
        Swap sx%, sy%
    End If
    e% = 2 * dy% - dx%
    For i% = 0 To dx% - 1
        If steep% = 1 Then
            Locate y%, x%
            Print c$;
        Else
            Locate x%, y%
            Print c$;
        End If

        While e% >= 0
            y% = y% + sy%: e% = e% - 2 * dx%
        Wend
        x% = x% + sx%: e% = e% + 2 * dy%
    Next
    Locate x2%, y2%
    Print c$;
End Sub ' DrawTextLine

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END TEST OUTPUT FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GENERAL PURPOSE FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' FOR BITWISE OPERATIONS

function HasBit%(iByte as integer, iBit as integer)
    Dim iBitValue As Integer
    iBitValue = 2 ^ (iBit-1)
    HasBit% = ( (iByte And iBitValue) = iBitValue)
end function ' HasBit%

' /////////////////////////////////////////////////////////////////////////////
' Split and join strings
' https://www.qb64.org/forum/index.php?topic=1073.0
'
' FROM luke, QB64 Developer
' Date: February 15, 2019, 04:11:07 AM
'
' Given a string of words separated by spaces (or any other character),
' splits it into an array of the words. I've no doubt many people have
' written a version of this over the years and no doubt there's a million
' ways to do it, but I thought I'd put mine here so we have at least one
' version. There's also a join function that does the opposite
' array -> single string.
'
' Code is hopefully reasonably self explanatory with comments and a little demo.
' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.

'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
'
'delimiter$ must be one character long.
'result$() must have been REDIMmed previously.

' Modified to handle multi-character delimiters

Sub split (in$, delimiter$, result$())
    Dim start As Integer
    Dim finish As Integer
    Dim iDelimLen As Integer
    ReDim result$(-1)

    iDelimLen = Len(delimiter$)

    start = 1
    Do
        'While Mid$(in$, start, 1) = delimiter$
        While Mid$(in$, start, iDelimLen) = delimiter$
            'start = start + 1
            start = start + iDelimLen
            If start > Len(in$) Then
                Exit Sub
            End If
        Wend
        finish = InStr(start, in$, delimiter$)
        If finish = 0 Then
            finish = Len(in$) + 1
        End If

        ReDim _Preserve result$(0 To UBound(result$) + 1)

        result$(UBound(result$)) = Mid$(in$, start, finish - start)
        start = finish + 1
    Loop While start <= Len(in$)
End Sub ' split

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GENERAL PURPOSE FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DEBUGGING ROUTINES #DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Sub DebugPrint (MyString As String)
    If m_bDebug = TRUE Then
        '_Echo MyString
        ReDim arrLines(-1) As String
        Dim iLoop As Integer
        split MyString, Chr$(13), arrLines()
        For iLoop = LBound(arrLines) To UBound(arrLines)
            _Echo arrLines(iLoop)
        Next iLoop
    End If
End Sub ' DebugPrint

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DEBUGGING ROUTINES @DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ################################################################################################################################################################
' #REFERENCE

' =============================================================================
' SOME USEFUL STUFF FOR REFERENCE:

' Type Name               Type suffix symbol   Minimum value                  Maximum value                Size in Bytes
' ---------------------   ------------------   ----------------------------   --------------------------   -------------
' _BIT                    `                    -1                             0                            1/8
' _BIT * n                `n                   -128                           127                          n/8
' _UNSIGNED _BIT          ~`                   0                              1                            1/8
' _BYTE                   %%                   -128                           127                          1
' _UNSIGNED _BYTE         ~%%                  0                              255                          1
' INTEGER                 %                    -32,768                        32,767                       2
' _UNSIGNED INTEGER       ~%                   0                              65,535                       2
' LONG                    &                    -2,147,483,648                 2,147,483,647                4
' _UNSIGNED LONG          ~&                   0                              4,294,967,295                4
' _INTEGER64              &&                   -9,223,372,036,854,775,808     9,223,372,036,854,775,807    8
' _UNSIGNED _INTEGER64    ~&&                  0                              18,446,744,073,709,551,615   8
' SINGLE                  ! or none            -2.802597E-45                  +3.402823E+38                4
' DOUBLE                  #                    -4.490656458412465E-324        +1.797693134862310E+308      8
' _FLOAT                  ##                   -1.18E-4932                    +1.18E+4932                  32(10 used)
' _OFFSET                 %&                   -9,223,372,036,854,775,808     9,223,372,036,854,775,807    Use LEN
' _UNSIGNED _OFFSET       ~%&                  0                              18,446,744,073,709,551,615   Use LEN
' _MEM                    none                 combined memory variable type  N/A                          Use LEN

' div: int1% = num1% \ den1%
' mod: rem1% = num1% MOD den1%

' @END
Reply
#46
System won't print anything, it just exits the program with that code. The function is basically being called by STR$. Not sure what you're asking for on the other question, though. The events are all there to run the window created by CreateWindow and the callback function is registered with RegisterClass.

I see now that you mean line 381. Anyways, there's no way for it to be firing anything after WinMain because System kills the program. Everything is a bit out of order anyways. You wouldn't want your test outside of the loop that is displaying the window.
Tread on those who tread on you

Reply
#47
(09-12-2022, 09:25 PM)Spriggsy Wrote: System won't print anything, it just exits the program with that code. The function is basically being called by STR$. Not sure what you're asking for on the other question, though. The events are all there to run the window created by CreateWindow and the callback function is registered with RegisterClass.

I see now that you mean line 381. Anyways, there's no way for it to be firing anything after WinMain because System kills the program. Everything is a bit out of order anyways. You wouldn't want your test outside of the loop that is displaying the window.

Let me step back a second and present a more concreate example (see below). 
Just a simple skeleton for a Pong game that draws some stuff that gets moved around with the mouse. 
How would we merge in the API code so the program does the exact same thing, 
except instead of _MouseX, _MouseY, it gets 8 seperate mouse coordinates from RawInput? 

Hopefully this clarifies the kind of use case I am looking to get input for... 
I very much appreciate your help!

Code: (Select All)
Const FALSE = 0
Const TRUE = Not FALSE

' UDT TO HOLD THE INFO FOR EACH MOUSE
Type MouseInfoType
    ID As String ' mouse device ID

    c As String ' text cursor character
    x As Integer ' text x position
    y As Integer ' text y position

    xPos As Long ' hires x position
    yPos As Long ' hires y position

    dx As Long ' dx
    dy As Long ' dy

    wheel As Integer ' mouse wheel value
    LeftDown As Integer ' tracks left mouse button state, TRUE=down
    MiddleDown As Integer ' tracks middle mouse button state, TRUE=down
    RightDown As Integer ' tracks right mouse button state, TRUE=down

    'OldLeftDown As Integer ' tracks left mouse button state, TRUE=down
    'OldMiddleDown As Integer ' tracks middle mouse button state, TRUE=down
    'OldRightDown As Integer ' tracks right mouse button state, TRUE=down

    LeftCount As Integer ' counts left clicks
    MiddleCount As Integer ' counts middle clicks
    RightCount As Integer ' counts right clicks

    px As Long
    py As Long
    pwidth As Integer
    pheight As Integer
    pcolor As _Unsigned Long
End Type ' MouseInfoType

Dim Shared m_arrMouseInfo(8) As MouseInfoType ' STORES INFO FOR EACH MOUSE / PLAYER

game

Sub game
    Dim screen_color~&: screen_color~& = cBlack
    Dim wall_color~&: wall_color~& = cWhite
    ReDim arrColors(-1) As _Unsigned Long
    Dim width%
    Dim height%
    Dim x%, x1%, x2%
    Dim y%, y1%, y2%
    Dim dColor~&
    Dim message$
    Dim player_1_score%
    Dim player_2_score%
    Dim iLoop As Integer
    Dim xMin%, xMax%, yMin%, yMax%
   
    x% = 64
    y% = 64
    For iLoop = 1 To 8
        m_arrMouseInfo(iLoop).px = x%
        m_arrMouseInfo(iLoop).py = y%
        m_arrMouseInfo(iLoop).pwidth = 8
        m_arrMouseInfo(iLoop).pheight = 64
        x% = x% + 32
        y% = y% + 32
    Next iLoop
    m_arrMouseInfo(1).pcolor = cRed
    m_arrMouseInfo(2).pcolor = cOrange
    m_arrMouseInfo(3).pcolor = cYellow
    m_arrMouseInfo(4).pcolor = cLime
    m_arrMouseInfo(5).pcolor = cCyan
    m_arrMouseInfo(6).pcolor = cBlue
    m_arrMouseInfo(7).pcolor = cPurple
    m_arrMouseInfo(8).pcolor = cMagenta
   
    width% = 1024
    height% = 768
    xMin% = 1
    xMax% = width% - 8
    yMin% = 45
    yMax% = height% - (54 + 64 + 1)
   
    Screen _NewImage(width%, height%, 32) ' graphics screen
    '_FULLSCREEN _SQUAREPIXELS
   
    ' PAINT BACKGROUND COLOR
    Line (0, 0)-(width%, height%), screen_color~&, BF
   
    ' DRAW WALLS AROUND EDGES
    For x% = 7 To width% Step 20
        Line (x%, 40)-(x% + 10, 44), wall_color~&, BF
        Line (x%, height% - 50)-(x% + 10, height% - 54), wall_color~&, BF
    Next x%
   
    ' DRAW CENTER LINE
    For y% = 44 To (height% - 48) Step 20
        Line ((width% / 2) - 2, y%)-((width% / 2) + 2, y% + 10), wall_color~&, BF
    Next y%
   
    ' DRAW PLAYERS
    For iLoop = 1 To 8
        x1% = m_arrMouseInfo(iLoop).px
        y1% = m_arrMouseInfo(iLoop).py
        x2% = m_arrMouseInfo(iLoop).px + m_arrMouseInfo(iLoop).pwidth
        y2% = m_arrMouseInfo(iLoop).py + m_arrMouseInfo(iLoop).pheight
        Line (x1%, y1%)-(x2%, y2%), m_arrMouseInfo(iLoop).pcolor, BF ' Draw a solid box
        'LOCATE 1,1:PRINT "(" + cstr$(player_1_x1%) + "," + cstr$(player_1_y1%) + ") (" + cstr$(player_1_x2%) + "," + cstr$(player_1_y2%) + ")" + " (" + cstr$(player_1_color~&) + ")";
    Next iLoop
   
    ' PRINT INSTRUCTIONS, TEXT SCREEN AT 1024X768 IS 48 LINES X 128 CHARACTERS WIDE
    message$ = "AVOID MISSING BALL FOR HIGH SCORE"
    Locate 1, 64 - (Len(message$) / 2): Print message$;
   
    ' PRINT INITIAL SCORE
    Locate 2, 32: Print "0";
    Locate 2, 96: Print "0";
   
    ' SHOW MORE INSTRUCTIONS
    message$ = "PRESS <ESC> TO EXIT"
    Locate 47, 64 - (Len(message$) / 2): Print message$;
   
    Do
        ' ERASE PLAYER'S OLD POSITIONS
        For iLoop = 1 To 8
            x1% = m_arrMouseInfo(iLoop).px
            y1% = m_arrMouseInfo(iLoop).py
            x2% = m_arrMouseInfo(iLoop).px + m_arrMouseInfo(iLoop).pwidth
            y2% = m_arrMouseInfo(iLoop).py + m_arrMouseInfo(iLoop).pheight
            Line (x1%, y1%)-(x2%, y2%), screen_color~&, BF ' Draw a solid box
            'LOCATE 1,1:PRINT "(" + cstr$(player_1_x1%) + "," + cstr$(player_1_y1%) + ") (" + cstr$(player_1_x2%) + "," + cstr$(player_1_y2%) + ")" + " (" + cstr$(player_1_color~&) + ")";
        Next iLoop
           
        ' (RE)DRAW CENTER LINE
        For y% = 44 To (height% - 48) Step 20
            Line ((width% / 2) - 2, y%)-((width% / 2) + 2, y% + 10), wall_color~&, BF
        Next y%
       
        ' GET INPUT AND DRAW PLAYERS IN NEW POSITION
        For iLoop = 1 To 8
           
            ' READ MOUSE
            ' *** UPDATE TO READ SEPERATE MOUSE FOR EACH PLAYER
            While _MouseInput ' get latest mouse information
            Wend
            x% = _MouseX
            y% = _MouseY
           
            ' MAKE SURE VALUES DON'T EXCEED BOUNDS
            If x% < xMin% Then
                x% = xMin%
            ElseIf x% > xMax% Then
                x% = xMax%
            End If
            If y% < yMin% Then
                y% = yMin%
            ElseIf y% > yMax% Then
                y% = yMax%
            End If
           
            ' SAVE VALUES
            m_arrMouseInfo(iLoop).px = x%
            m_arrMouseInfo(iLoop).py = y%
           
            ' DRAW
            x1% = m_arrMouseInfo(iLoop).px
            y1% = m_arrMouseInfo(iLoop).py
            x2% = m_arrMouseInfo(iLoop).px + m_arrMouseInfo(iLoop).pwidth
            y2% = m_arrMouseInfo(iLoop).py + m_arrMouseInfo(iLoop).pheight
            Line (x1%, y1%)-(x2%, y2%), m_arrMouseInfo(iLoop).pcolor, BF ' Draw a solid box
            'LOCATE 1,1:PRINT "(" + cstr$(player_1_x1%) + "," + cstr$(player_1_y1%) + ") (" + cstr$(player_1_x2%) + "," + cstr$(player_1_y2%) + ")" + " (" + cstr$(player_1_color~&) + ")";
        Next iLoop
       
        ' PRINT SCORE
        Locate 2, 32: Print "PLAYER 1: 0"
        Locate 2, 96: Print "PLAYER 2: 0"
       
        ' UPDATE SCREEN
        _Display ' update screen with changes
       
        ' SET GAME SPEED IN FPS
        _Limit 60
    Loop Until _KeyHit = 27 ' ESCAPE to quit
   
    'IF _FULLSCREEN = 0 THEN _FULLSCREEN _OFF
End Sub ' game

Sub AddColor (ColorValue As _Unsigned Long, arrColor() As _Unsigned Long)
    ReDim _Preserve arrColor(0 To UBound(arrColor) + 1) As _Unsigned Long
    arrColor(UBound(arrColor)) = ColorValue
End Sub ' AddColor

Function cRed~& ()
    cRed = _RGB32(255, 0, 0)
End Function

Function cOrange~& ()
    cOrange = _RGB32(255, 165, 0)
End Function ' cOrange~&

Function cYellow~& ()
    cYellow = _RGB32(255, 255, 0)
End Function ' cYellow~&

Function cLime~& ()
    cLime = _RGB32(0, 255, 0)
End Function ' cLime~&

Function cCyan~& ()
    cCyan = _RGB32(0, 255, 255)
End Function ' cCyan~&

Function cBlue~& ()
    cBlue = _RGB32(0, 0, 255)
End Function ' cBlue~&

Function cPurple~& ()
    cPurple = _RGB32(128, 0, 255)
End Function ' cPurple~&

Function cMagenta~& ()
    cMagenta = _RGB32(255, 0, 255)
End Function ' cMagenta~&

Function cBlack~& ()
    cBlack = _RGB32(0, 0, 0)
End Function ' cBlack~&

Function cGray~& ()
    cGray = _RGB32(128, 128, 128)
End Function ' cGray~&

Function cWhite~& ()
    cWhite = _RGB32(255, 255, 255)
    'cWhite = _RGB32(254, 254, 254)
End Function ' cWhite~&

Function cEmpty~& ()
    'cEmpty~& = -1
    cEmpty = _RGB32(0, 0, 0, 0)
End Function ' cEmpty~&
Reply
#48
(09-12-2022, 09:25 PM)Spriggsy Wrote: System won't print anything, it just exits the program with that code. The function is basically being called by STR$. Not sure what you're asking for on the other question, though. The events are all there to run the window created by CreateWindow and the callback function is registered with RegisterClass.

I see now that you mean line 381. Anyways, there's no way for it to be firing anything after WinMain because System kills the program. Everything is a bit out of order anyways. You wouldn't want your test outside of the loop that is displaying the window.

Back to this, I need to familiarize with System, I didn't know it took parameters. 
What is it doing? What happens if we remove the System and just call the inner function? 
How can we use the Screen _NewImage, Line, and Print commands from within the Case WM_PAINT event? 
All these questions, to be experimented on and with, when I am back at the PC. 

You see what I'm trying to accomplish (e.g. previous reply's more concrete example). 
I think with some perseverence and creative thinking, it should be possible.
Reply
#49
(09-12-2022, 09:25 PM)Spriggsy Wrote: System won't print anything, it just exits the program with that code. The function is basically being called by STR$. Not sure what you're asking for on the other question, though. The events are all there to run the window created by CreateWindow and the callback function is registered with RegisterClass.

I see now that you mean line 381. Anyways, there's no way for it to be firing anything after WinMain because System kills the program. Everything is a bit out of order anyways. You wouldn't want your test outside of the loop that is displaying the window.

UPDATE: 
I haven't given up on this Spriggsy! Just got a little busy, is all... 
This, the MIDI thing, the WAV file thing, all still in the pipe. 
I figured it can't hurt to do some reading up on these API calls - below are my notes in case it helps anyone. 
I still am not convinced it's impossible to populate hwndMain with _WindowHandle of the existing app, and get the API functions to act on that. 
Also, does the RawInput require an actual window to work? 
What about the Windows desktop? 
Anyway, I will continue to play with this. 
If you have any breakthroughs, let me know! :-D

Code: (Select All)
----------------------------------------------------------------------------------------------------------------------------------------------------------------
WINDOWS API COMMANDS
----------------------------------------------------------------------------------------------------------------------------------------------------------------
GetRawInputDeviceList
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdevicelist
    Enumerates the raw input devices attached to the system.
RegisterRawInputDevices
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices
    Registers the devices that supply the raw input data.
GetRawInputData
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdata
    Retrieves the raw input from the specified device.
    Parameters:
        [in] hRawInput
            Type: HRAWINPUT
            A handle to the RAWINPUT structure. This comes from the lParam in WM_INPUT.
        [in] uiCommand
            Type: UINT
            The command flag. This parameter can be one of the following values.
            Value                   Meaning
            RID_HEADER 0x10000005   Get the header information from the RAWINPUT structure.
            RID_INPUT  0x10000003   Get the raw data from the RAWINPUT structure.
        [out, optional] pData
            Type: LPVOID
            A pointer to the data that comes from the RAWINPUT structure.
            This depends on the value of uiCommand.
            If pData is NULL, the required size of the buffer is returned in *pcbSize.
        [in, out] pcbSize
            Type: PUINT
            The size, in bytes, of the data in pData.
        [in] cbSizeHeader
            Type: UINT
            The size, in bytes, of the RAWINPUTHEADER structure.
        Return value
            Type: UINT
            If pData is NULL and the function is successful, the return value is 0.
            If pData is not NULL and the function is successful,
            the return value is the number of bytes copied into pData.
            If there is an error, the return value is (UINT)-1.
    Remarks
    GetRawInputData gets the raw input one RAWINPUT structure at a time.
    In contrast, GetRawInputBuffer gets an array of RAWINPUT structures.

DrawText
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawtext
    The DrawText function draws formatted text in the specified rectangle.
    It formats the text according to the specified method (expanding tabs,
    justifying characters, breaking lines, and so forth).
    To specify additional formatting options, use the DrawTextEx function.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
OTHERS:
FillRect function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-fillrect
    The FillRect function fills a rectangle by using the specified brush.
    This function includes the left and top borders, but excludes the right and bottom borders of the rectangle.
    Parameters
        [in] hDC
            A handle to the device context.
        [in] lprc
            A pointer to a RECT structure that contains the logical coordinates of the rectangle to be filled.
        [in] hbr
            A handle to the brush used to fill the rectangle.
        Return value
            If the function succeeds, the return value is nonzero.
            If the function fails, the return value is zero.
GetDC function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc
    The GetDC function retrieves a handle to a device context (DC) for the client area of a specified window or for the entire screen. You can use the returned handle in subsequent GDI functions to draw in the DC. The device context is an opaque data structure, whose values are used internally by GDI.
    The GetDCEx function is an extension to GetDC, which gives an application more control over how and whether clipping occurs in the client area.
    Parameters
        [in] hWnd
            A handle to the window whose DC is to be retrieved.
            If this value is NULL, GetDC retrieves the DC for the entire screen.
        Return value
            If the function succeeds, the return value is a handle to the DC for the specified window's client area.
            If the function fails, the return value is NULL.
LoadBitmapA function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadbitmapa
LoadBitmapW function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadbitmapw
OffsetRect function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-offsetrect
RedrawWindow function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-redrawwindow
ReleaseDC function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-releasedc
SetRect function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setrect
WindowFromDC function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-windowfromdc
BeginPaint function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-beginpaint

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
GetModuleHandle
    https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandlea
    GetModuleHandleA function (libloaderapi.h)
    Retrieves a module handle for the specified module. The module must have been loaded by the calling process.
    To avoid the race conditions described in the Remarks section, use the GetModuleHandleEx function.
        GetModuleHandleExA function (libloaderapi.h)
        https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa
        Retrieves a module handle for the specified module and increments the module's reference count
        unless GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT is specified.
        The module must have been loaded by the calling process.
RegisterClassEx
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerclassexa
    RegisterClassExA function (winuser.h)
    Registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function.
CreateWindowEx
    CreateWindowExA function (winuser.h)
        https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexa
        Creates an overlapped, pop-up, or child window with an extended window style;
        otherwise, this function is identical to the CreateWindow function.
        For more information about creating a window
        and for full descriptions of the other parameters of CreateWindowEx, see CreateWindow.
            CreateWindowA macro (winuser.h)
            https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowa
ShowWindow
    ShowWindow function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
    Sets the specified window's show state.
    Parameters
    [in] hWnd
        Type: HWND
        A handle to the window.
    [in] nCmdShow
        Type: int
        Controls how the window is to be shown.
        This parameter is ignored the first time an application calls ShowWindow,
        if the program that launched the application provides a STARTUPINFO structure.
        Otherwise, the first time ShowWindow is called, the value should be the value obtained
        by the WinMain function in its nCmdShow parameter. In subsequent calls, this parameter
        can be one of the following values.
        Value                             Meaning
        0 SW_HIDE                         Hides the window and activates another window.
        1 SW_SHOWNORMAL, SW_NORMAL        Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
        2 SW_SHOWMINIMIZED                Activates the window and displays it as a minimized window.
        3 SW_SHOWMAXIMIZED, SW_MAXIMIZE   Activates the window and displays it as a maximized window.
        4 SW_SHOWNOACTIVATE               Displays a window in its most recent size and position. This value is similar to SW_SHOWNORMAL, except that the window is not activated.
        5 SW_SHOW                         Activates the window and displays it in its current size and position.
        6 SW_MINIMIZE                     Minimizes the specified window and activates the next top-level window in the Z order.
        7 SW_SHOWMINNOACTIVE              Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated.
        8 SW_SHOWNA                       Displays the window in its current size and position. This value is similar to SW_SHOW, except that the window is not activated.
        9 SW_RESTORE                      Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.
        10 SW_SHOWDEFAULT                 Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application.
        11 SW_FORCEMINIMIZE               Minimizes a window, even if the thread that owns the window is not responding. This flag should only be used when minimizing windows from a different thread.
    Return value
        Type: BOOL
        If the window was previously visible, the return value is nonzero.
        If the window was previously hidden, the return value is zero.
UpdateWindow
    UpdateWindow function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-updatewindow
    The UpdateWindow function updates the client area of the specified window
    by sending a WM_PAINT message to the window if the window's update region is not empty.
    The function sends a WM_PAINT message directly to the window procedure of the specified window,
    bypassing the application queue. If the update region is empty, no message is sent.
    Parameters
        [in] hWnd
        Handle to the window to be updated.
    Return value
        If the function succeeds, the return value is nonzero.
        If the function fails, the return value is zero.
DefWindowProc
    DefWindowProcW function (winuser.h)
        https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-defwindowprocw
        Calls the default window procedure to provide default processing for any window messages that an application does not process. This function ensures that every message is processed.
        DefWindowProc is called with the same parameters received by the window procedure.
        Parameters
            [in] hWnd
                Type: HWND
                A handle to the window procedure that received the message.
            [in] Msg
                Type: UINT
                The message.
            [in] wParam
                Type: WPARAM
                Additional message information.
                The content of this parameter depends on the value of the Msg parameter.
            [in] lParam
                Type: LPARAM
                Additional message information.
                The content of this parameter depends on the value of the Msg parameter.
        Return value
            Type: LRESULT
            The return value is the result of the message processing and depends on the message.
    DefWindowProcA function (winuser.h)
        https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-defwindowproca
        Calls the default window procedure to provide default processing for any window messages that an application does not process. This function ensures that every message is processed.
        DefWindowProc is called with the same parameters received by the window procedure.
        Parameters
            [in] hWnd
                Type: HWND
                A handle to the window procedure that received the message.
            [in] Msg
                Type: UINT
                The message.
            [in] wParam
                Type: WPARAM
                Additional message information.
                The content of this parameter depends on the value of the Msg parameter.
            [in] lParam
                Type: LPARAM
                Additional message information.
                The content of this parameter depends on the value of the Msg parameter.
        Return value
            Type: LRESULT
            The return value is the result of the message processing and depends on the message.
GetClientRect
    GetClientRect function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect
    Retrieves the coordinates of a window's client area.
    The client coordinates specify the upper-left and lower-right corners of the client area.
    Because client coordinates are relative to the upper-left corner of a window's client area,
    the coordinates of the upper-left corner are (0,0).
    Parameters
        [in] hWnd
            Type: HWND
            A handle to the window whose client coordinates are to be retrieved.
        [out] lpRect
            Type: LPRECT
            A pointer to a RECT structure that receives the client coordinates.
            The left and top members are zero.
            The right and bottom members contain the width and height of the window.
    Return value
        Type: BOOL
        If the function succeeds, the return value is nonzero.
        If the function fails, the return value is zero.
        To get extended error information, call GetLastError.
InvalidateRect
    InvalidateRect function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-invalidaterect
    The InvalidateRect function adds a rectangle to the specified window's update region.
    The update region represents the portion of the window's client area that must be redrawn.
    Parameters
        [in] hWnd
            A handle to the window whose update region has changed.
            If this parameter is NULL, the system invalidates and redraws all windows,
            not just the windows for this application, and sends the WM_ERASEBKGND
            and WM_NCPAINT messages before the function returns.
            Setting this parameter to NULL is not recommended.
        [in] lpRect
            A pointer to a RECT structure that contains the client coordinates of the rectangle
            to be added to the update region.
            If this parameter is NULL, the entire client area is added to the update region.
        [in] bErase
            Specifies whether the background within the update region is to be erased when the
            update region is processed. If this parameter is TRUE, the background is erased when
            the BeginPaint function is called.
            If this parameter is FALSE, the background remains unchanged.
    Return value
        If the function succeeds, the return value is nonzero.
        If the function fails, the return value is zero.
OffsetRect
    OffsetRect function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-offsetrect
    The OffsetRect function moves the specified rectangle by the specified offsets.
    Parameters
        [in, out] lprc
            Pointer to a RECT structure that contains the logical coordinates of the rectangle to be moved.
        [in] dx
            Specifies the amount to move the rectangle left or right.
            This parameter must be a negative value to move the rectangle to the left.
        [in] dy
            Specifies the amount to move the rectangle up or down.
            This parameter must be a negative value to move the rectangle up.
    Return value
        If the function succeeds, the return value is nonzero.
        If the function fails, the return value is zero.
BeginPaint
    BeginPaint function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-beginpaint
    The BeginPaint function prepares the specified window for painting and fills a
    PAINTSTRUCT structure with information about the painting.
    Parameters
        [in] hWnd
            Handle to the window to be repainted.
        [out] lpPaint
            Pointer to the PAINTSTRUCT structure that will receive painting information.
    Return value
        If the function succeeds, the return value is the handle to a display device context for the specified window.
        If the function fails, the return value is NULL, indicating that no display device context is available.
EndPaint
    EndPaint function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-endpaint
    The EndPaint function marks the end of painting in the specified window.
    This function is required for each call to the BeginPaint function, but only after painting is complete.
    Parameters
        [in] hWnd
            Handle to the window that has been repainted.
        [in] lpPaint
            Pointer to a PAINTSTRUCT structure that contains the painting information retrieved by BeginPaint.
    Return value
        The return value is always nonzero.

GetMessage
    GetMessage function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage
    Retrieves a message from the calling thread's message queue.
    The function dispatches incoming sent messages until a posted message is available for retrieval.
    Unlike GetMessage, the PeekMessage function does not wait for a message to be posted before returning.
    (see above URL for details)
TranslateMessage
    TranslateMessage function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-translatemessage
    Translates virtual-key messages into character messages.
    The character messages are posted to the calling thread's message queue,
    to be read the next time the thread calls the GetMessage or PeekMessage function.
DispatchMessage
    DispatchMessage function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-dispatchmessage
    Dispatches a message to a window procedure.
    It is typically used to dispatch a message retrieved by the GetMessage function.
SendMessage
    SendMessage function (winuser.h)
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendmessage
    Sends the specified message to a window or windows.
    The SendMessage function calls the window procedure for the specified window
    and does not return until the window procedure has processed the message.
    To send a message and return immediately, use the SendMessageCallback or
    SendNotifyMessage function. To post a message to a thread's message queue and
    return immediately, use the PostMessage or PostThreadMessage function.

MAKEINTRESOURCE
    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makeintresourcea
    Converts an integer value to a resource type compatible with the resource-management functions.
    This macro is used in place of a string containing the name of the resource.

Library
    MAKELPARAM
        MAKELPARAM macro (winuser.h)
        https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makelparam
        Creates a value for use as an lParam parameter in a message.
        The macro concatenates the specified value
        Parameters
            l = The low-order word of the new value.
            h = The high-order word of the new value.
        Return value: None
    MAKELONG
        MAKELONG macro
        https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms632660(v=vs.85)
        Creates a LONG value by concatenating the specified values.
        Parameters
            wLow = The low-order word of the new value.
            wHigh = The high-order word of the new value.
        Return value
            Type: DWORD
            The return value is a LONG value.

windowsx
    GET_Y_LPARAM
        GET_Y_LPARAM macro (windowsx.h)
        https://docs.microsoft.com/en-us/windows/win32/api/windowsx/nf-windowsx-get_y_lparam
        Retrieves the signed y-coordinate from the given LPARAM value.
        Parameters
            lp = The data from which the y-coordinate is to be extracted.
        Return value
            Type: int
            Y-coordinate.
        Remarks
            Use GET_Y_LPARAM instead of HIWORD to extract signed coordinate data.
            Negative screen coordinates may be returned on multiple monitor systems.
    GET_X_LPARAM
        GET_X_LPARAM macro (windowsx.h)
        https://docs.microsoft.com/en-us/windows/win32/api/windowsx/nf-windowsx-get_x_lparam
        Retrieves the signed x-coordinate from the specified LPARAM value.
        Parameters
            lp = The data from which the x-coordinate is to be extracted.
        Return value
            Type: int
            X-coordinate.
        Remarks
            Use GET_X_LPARAM instead of LOWORD to extract signed coordinate data.
            Negative screen coordinates may be returned on multiple monitor systems.

----------------------------------------------------------------------------------------------------------------------------------------------------------------
WINDOWS REFERENCE
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Windows and Messages
https://docs.microsoft.com/en-us/windows/win32/winmsg/windowing
   
    Windows (Windows and Messages)
    https://docs.microsoft.com/en-us/windows/win32/winmsg/windows
   
        Window Reference
        https://docs.microsoft.com/en-us/windows/win32/winmsg/window-reference
           
            Windows (Windows and Messages) = Discusses windows in general.
            https://docs.microsoft.com/en-us/windows/win32/winmsg/windows
           
            Window Constants
            https://docs.microsoft.com/en-us/windows/win32/winmsg/constants
           
            Window functions
            https://docs.microsoft.com/en-us/windows/win32/winmsg/window-functions
           
            Window Macros
            https://docs.microsoft.com/en-us/windows/win32/winmsg/window-macros
           
            Window Messages (Windows and Messages)
            https://docs.microsoft.com/en-us/windows/win32/winmsg/window-messages
           
            Window Notifications
            https://docs.microsoft.com/en-us/windows/win32/winmsg/window-notifications
           
            Window Structures
            https://docs.microsoft.com/en-us/windows/win32/winmsg/window-structures
           
    Window Classes (Windows and Messages) = Describes the types of window classes, how the system locates them, and the elements that define the default behavior of windows that belong to them.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/window-classes
   
    Window Procedures = Discusses window procedures. Every window has an associated window procedure that processes all messages sent or posted to all windows of the class.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
   
    Messages and Message Queues = Describes messages and message queues and how to use them in your applications.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/messages-and-message-queues
   
    Timers = Discusses timers. A timer is an internal routine that repeatedly measures a specified interval, in milliseconds.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/timers
   
    Window Properties = Discusses window properties. A window property is any data assigned to a window.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/window-properties
   
    Configuration = Describes the functions that can be used to control the configuration of system metrics and various system attributes such as double-click time, screen saver time-out, window border width, and desktop pattern.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/configuration
   
    Hooks = Discusses hooks. A hook is a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/hooks
   
    Multiple Document Interface = Discusses the Multiple Document Interface which is a specification that defines a user interface for applications that enable the user to work with more than one document at the same time.
    https://docs.microsoft.com/en-us/windows/win32/winmsg/multiple-document-interface
Reply
#50
@madscijr

It isn't that it is impossible to use WindowHandle as our HWND.... It's just that we will most certainly have to register our window to accept messages and that we absolutely must use a callback function. Besides, oftentimes you don't even need to pass in the window's handle because a default of NULL/zero just tells it to use the calling window.
Tread on those who tread on you

Reply




Users browsing this thread: 35 Guest(s)