RE: kind of works? reading multiple mice: any c programmers want to look at this? - SpriggsySpriggs - 09-12-2022
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.
RE: kind of works? reading multiple mice: any c programmers want to look at this? - madscijr - 09-12-2022
(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.
RE: kind of works? reading multiple mice: any c programmers want to look at this? - SpriggsySpriggs - 09-12-2022
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.
RE: kind of works? reading multiple mice: any c programmers want to look at this? - madscijr - 09-12-2022
(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
RE: kind of works? reading multiple mice: any c programmers want to look at this? - madscijr - 09-12-2022
(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
RE: kind of works? reading multiple mice: any c programmers want to look at this? - SpriggsySpriggs - 09-12-2022
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.
RE: kind of works? reading multiple mice: any c programmers want to look at this? - madscijr - 09-12-2022
(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~&
RE: kind of works? reading multiple mice: any c programmers want to look at this? - madscijr - 09-13-2022
(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.
RE: kind of works? reading multiple mice: any c programmers want to look at this? - madscijr - 09-15-2022
(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
RE: kind of works? reading multiple mice: any c programmers want to look at this? - SpriggsySpriggs - 09-15-2022
@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.
|