Ooops
August 04, 2020, 11:41:21 AM

Author Topic: Getting Raw Mouse Input?  (Read 945 times)

Offline Kippykip

  • Full Member
  • ***
  • Posts: 122
    • Kippykip Forums!
Getting Raw Mouse Input?
« on: August 14, 2019, 04:34:40 PM »
Alrighty so I'm trying to find a way of using Win32 WM_INPUT commands into BlitzMax.
The MouseX() and MouseY() are great for cursor stuff, but for games it's a bit tricky messing with mouse movement since most computers by default have "Enhance pointer precision" turned on and high DPI mouses have enough precision to be measured by raw input but not enough to move the cursor.

The closest thing I could find is this code archive:
https://www.syntaxbomb.com/index.php?topic=1026.0

But every Win32 Extern example relating to inputs I've come across so far isn't compatible with BlitzMax-NG, and I haven't had much luck porting code over and compiling successfully.
I remember a while ago running into a similar problem trying to set the Window Icon to what's set in the executable, but just involved encasing an old codearchive piece with LParam() or something.
Here's that code if you're interested:
Code: [Select]
'Windows only
Function SetIcon()
?Win32
SendMessageW(GetActiveWindow(), WM_SETICON, 0, LParam(LoadIconW(GetModuleHandleW(Null), 101)))
?
End Function

I really would appreciate any help!

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 468
Re: Getting Raw Mouse Input?
« Reply #1 on: August 16, 2019, 04:13:45 PM »
To make it 64-bit compatible you need to change Int to Byte Ptr when Int is a 32-bit handle or address, this is in Externs and in Types mirroring a structure. You have to be careful and look everything up. Another gotcha is Int Ptr, that will be cast to Long Ptr in 64-bit but it will be declared as Int Ptr in Externs. Also there is struct alignment, in 64-bit this is 8 bytes minimum so any Int field will actually occupy 8 bytes.

Offline Kippykip

  • Full Member
  • ***
  • Posts: 122
    • Kippykip Forums!
Re: Getting Raw Mouse Input?
« Reply #2 on: December 07, 2019, 01:46:47 PM »
Hmm... bump perhaps?

Offline Kippykip

  • Full Member
  • ***
  • Posts: 122
    • Kippykip Forums!
Re: Getting Raw Mouse Input?
« Reply #3 on: July 28, 2020, 09:39:23 PM »
Whew, I finally figured it out after digging though mingw source files all day and looking at other modules that include windows DLL's.
https://github.com/Kippykip/BMX-RawMouse

Offline Derron

  • Hero Member
  • *****
  • Posts: 3074
Re: Getting Raw Mouse Input?
« Reply #4 on: July 29, 2020, 08:19:14 AM »
Thanks for upping - maybe it is useful for someone else than just you. good job.


bye
Ron

Offline Kippykip

  • Full Member
  • ***
  • Posts: 122
    • Kippykip Forums!
Re: Getting Raw Mouse Input?
« Reply #5 on: July 29, 2020, 04:52:20 PM »
Hmm it seems the method used to create the custom WinProc function (which calls the original WinProc afterwards) has a lot of weird side effects.
Some examples I've noticed is you can't use GetActiveWindow() to see if the game is focused anymore.
But also MouseX() and MouseY() no longer work, same with HideMouse() and ShowMouse().

The weirdest thing however all those above effects happen before I've even registered the RawInputDevices and whatnot.
The keyboard isn't affected at all.

Hmm, anyone know on how to extend the WinProc without screwing the built in modules? Or why it would be doing that in the first place?
Bit of an oddball this one

Offline Scaremonger

  • Jr. Member
  • **
  • Posts: 84
    • ITSpeedway - Ramblings of a geek!
Re: Getting Raw Mouse Input?
« Reply #6 on: July 29, 2020, 07:41:58 PM »
Hi,
This is an old bit of code from my library, so I don't know if it needs updating, but it might help you with your question...

Basically, you save the current WndProc and insert your own, calling the old one at the end...

Code: [Select]
SuperStrict
' WndProc() based on code by grable at:
' http://www.blitzbasic.com/Community/posts.php?topic=67031

Const WINDOW_FLAGS:Int = WINDOW_TITLEBAR | WINDOW_RESIZABLE

Global window:TGadget = CreateWindow( "Test", 64,64, 256,256, Null, WINDOW_FLAGS | WINDOW_CLIENTCOORDS)
Global OldWindowFunc:Int = SetWindowFunc( window, WindowFunc)

While WaitEvent()
Select CurrentEvent.ID
Case EVENT_WINDOWCLOSE
If CurrentEvent.Source = window Then Exit
EndSelect
Wend
End

Function DriveFromMask:String( unitmask:Int)
Local i:Int
For i = 0 Until 26
If unitmask & $1 Then Exit
unitmask :Shr 1
Next
Return Chr(Asc("A") + i)
EndFunction

Function WindowFunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int) "Win32"
Local hdr:Int Ptr = Int Ptr(lparam)
Select msg
Case WM_DEVICECHANGE
Select wparam
Case DBT_DEVICEARRIVAL
If hdr[1] = DBT_DEVTYP_VOLUME Then
If hdr[4] & DBTF_MEDIA Then
' cdrom / disk drive
Notify "Media inserted into drive " + DriveFromMask( hdr[3])
Else
' other / usb
Notify "Inserted volume as drive " + DriveFromMask( hdr[3])
EndIf
EndIf

Case DBT_DEVICEREMOVECOMPLETE
If hdr[1] = DBT_DEVTYP_VOLUME Then
If hdr[4] & DBTF_MEDIA Then
' cdrom / disk drive
Notify "Media removed from drive " + DriveFromMask( hdr[3])
Else
' other / usb
Notify "Removed volume registered as drive " + DriveFromMask( hdr[3])
EndIf
EndIf
EndSelect

' this MUST be handled, otherwise MaxGUI freezes on window close.
Case WM_DESTROY
SetWindowLong( hwnd, GWL_WNDPROC, OldWindowFunc)
EndSelect
Return CallWindowProc( OldWindowFunc, hwnd, msg, wparam, Int(lparam))
EndFunction


'
' device change notification
'
Const WM_DEVICECHANGE:Int = 537

Const DBT_NO_DISK_SPACE:Int = $47
Const DBT_CONFIGMGPRIVATE:Int = $7FFF
Const DBT_DEVICEARRIVAL:Int = $8000
Const DBT_DEVICEQUERYREMOVE:Int = $8001
Const DBT_DEVICEQUERYREMOVEFAILED:Int = $8002
Const DBT_DEVICEREMOVEPENDING:Int = $8003
Const DBT_DEVICEREMOVECOMPLETE:Int = $8004
Const DBT_DEVICETYPESPECIFIC:Int = $8005
Const DBT_DEVTYP_OEM:Int = 0
Const DBT_DEVTYP_DEVNODE:Int = 1
Const DBT_DEVTYP_VOLUME:Int = 2
Const DBT_DEVTYP_PORT:Int = 3
Const DBT_DEVTYP_NET:Int = 4
Const DBT_DEVTYP_DEVICEINTERFACE:Int = 5
Const DBT_DEVTYP_HANDLE:Int = 6
Const DBT_APPYBEGIN:Int = 0
Const DBT_APPYEND:Int = 1
Const DBT_DEVNODES_CHANGED:Int = 7
Const DBT_QUERYCHANGECONFIG:Int = $17
Const DBT_CONFIGCHANGED:Int = $18
Const DBT_CONFIGCHANGECANCELED:Int = $19
Const DBT_MONITORCHANGE:Int = $1B
Const DBT_SHELLLOGGEDON:Int = 32
Const DBT_CONFIGMGAPI32:Int = 34
Const DBT_VXDINITCOMPLETE:Int = 35
Const DBT_VOLLOCKQUERYLOCK:Int = $8041
Const DBT_VOLLOCKLOCKTAKEN:Int = $8042
Const DBT_VOLLOCKLOCKFAILED:Int = $8043
Const DBT_VOLLOCKQUERYUNLOCK:Int = $8044
Const DBT_VOLLOCKLOCKRELEASED:Int = $8045
Const DBT_VOLLOCKUNLOCKFAILED:Int = $8046
Const DBT_USERDEFINED:Int = $FFFF

Const DBTF_MEDIA:Int = 1
Const DBTF_NET:Int = 2

Const DEVICE_NOTIFY_WINDOW_HANDLE:Int = 0
Const DEVICE_NOTIFY_SERVICE_HANDLE:Int = 1
Const DEVICE_NOTIFY_ALL_INTERFACE_CLASSES:Int = 4


'
' setting window function
'
Const GWL_WNDPROC:Int = -4

Extern "Win32"
Function SetWindowLong:Int(HWND:Int,nIndex:Int,dwNewLong:Int) = "SetWindowLongA@12"
Function GetWindowLong:Int(HWND:Int,nIndex:Int) = "GetWindowLongA@8"
Function CallWindowProc:Int( prevwndproc:Int, hwnd:Int, msg:Int, wparam:Int, lparam:Int) = "CallWindowProcA@20"
EndExtern

Function SetWindowFunc:Int( window:TGadget, newfunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int))
Local hwnd:Int = QueryGadget( window, QUERY_HWND)
Local oldfunc:Int = GetWindowLong( hwnd, GWL_WNDPROC)
SetWindowLong( hwnd, GWL_WNDPROC, Int(Byte Ptr newfunc))
Return oldfunc
EndFunction
Follow me at ITSpeedway.net.

Offline Kippykip

  • Full Member
  • ***
  • Posts: 122
    • Kippykip Forums!
Re: Getting Raw Mouse Input?
« Reply #7 on: July 30, 2020, 12:09:40 PM »
Hi,
This is an old bit of code from my library, so I don't know if it needs updating, but it might help you with your question...

Basically, you save the current WndProc and insert your own, calling the old one at the end...

Code: [Select]
SuperStrict
' WndProc() based on code by grable at:
' http://www.blitzbasic.com/Community/posts.php?topic=67031

Const WINDOW_FLAGS:Int = WINDOW_TITLEBAR | WINDOW_RESIZABLE

Global window:TGadget = CreateWindow( "Test", 64,64, 256,256, Null, WINDOW_FLAGS | WINDOW_CLIENTCOORDS)
Global OldWindowFunc:Int = SetWindowFunc( window, WindowFunc)

While WaitEvent()
Select CurrentEvent.ID
Case EVENT_WINDOWCLOSE
If CurrentEvent.Source = window Then Exit
EndSelect
Wend
End

Function DriveFromMask:String( unitmask:Int)
Local i:Int
For i = 0 Until 26
If unitmask & $1 Then Exit
unitmask :Shr 1
Next
Return Chr(Asc("A") + i)
EndFunction

Function WindowFunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int) "Win32"
Local hdr:Int Ptr = Int Ptr(lparam)
Select msg
Case WM_DEVICECHANGE
Select wparam
Case DBT_DEVICEARRIVAL
If hdr[1] = DBT_DEVTYP_VOLUME Then
If hdr[4] & DBTF_MEDIA Then
' cdrom / disk drive
Notify "Media inserted into drive " + DriveFromMask( hdr[3])
Else
' other / usb
Notify "Inserted volume as drive " + DriveFromMask( hdr[3])
EndIf
EndIf

Case DBT_DEVICEREMOVECOMPLETE
If hdr[1] = DBT_DEVTYP_VOLUME Then
If hdr[4] & DBTF_MEDIA Then
' cdrom / disk drive
Notify "Media removed from drive " + DriveFromMask( hdr[3])
Else
' other / usb
Notify "Removed volume registered as drive " + DriveFromMask( hdr[3])
EndIf
EndIf
EndSelect

' this MUST be handled, otherwise MaxGUI freezes on window close.
Case WM_DESTROY
SetWindowLong( hwnd, GWL_WNDPROC, OldWindowFunc)
EndSelect
Return CallWindowProc( OldWindowFunc, hwnd, msg, wparam, Int(lparam))
EndFunction


'
' device change notification
'
Const WM_DEVICECHANGE:Int = 537

Const DBT_NO_DISK_SPACE:Int = $47
Const DBT_CONFIGMGPRIVATE:Int = $7FFF
Const DBT_DEVICEARRIVAL:Int = $8000
Const DBT_DEVICEQUERYREMOVE:Int = $8001
Const DBT_DEVICEQUERYREMOVEFAILED:Int = $8002
Const DBT_DEVICEREMOVEPENDING:Int = $8003
Const DBT_DEVICEREMOVECOMPLETE:Int = $8004
Const DBT_DEVICETYPESPECIFIC:Int = $8005
Const DBT_DEVTYP_OEM:Int = 0
Const DBT_DEVTYP_DEVNODE:Int = 1
Const DBT_DEVTYP_VOLUME:Int = 2
Const DBT_DEVTYP_PORT:Int = 3
Const DBT_DEVTYP_NET:Int = 4
Const DBT_DEVTYP_DEVICEINTERFACE:Int = 5
Const DBT_DEVTYP_HANDLE:Int = 6
Const DBT_APPYBEGIN:Int = 0
Const DBT_APPYEND:Int = 1
Const DBT_DEVNODES_CHANGED:Int = 7
Const DBT_QUERYCHANGECONFIG:Int = $17
Const DBT_CONFIGCHANGED:Int = $18
Const DBT_CONFIGCHANGECANCELED:Int = $19
Const DBT_MONITORCHANGE:Int = $1B
Const DBT_SHELLLOGGEDON:Int = 32
Const DBT_CONFIGMGAPI32:Int = 34
Const DBT_VXDINITCOMPLETE:Int = 35
Const DBT_VOLLOCKQUERYLOCK:Int = $8041
Const DBT_VOLLOCKLOCKTAKEN:Int = $8042
Const DBT_VOLLOCKLOCKFAILED:Int = $8043
Const DBT_VOLLOCKQUERYUNLOCK:Int = $8044
Const DBT_VOLLOCKLOCKRELEASED:Int = $8045
Const DBT_VOLLOCKUNLOCKFAILED:Int = $8046
Const DBT_USERDEFINED:Int = $FFFF

Const DBTF_MEDIA:Int = 1
Const DBTF_NET:Int = 2

Const DEVICE_NOTIFY_WINDOW_HANDLE:Int = 0
Const DEVICE_NOTIFY_SERVICE_HANDLE:Int = 1
Const DEVICE_NOTIFY_ALL_INTERFACE_CLASSES:Int = 4


'
' setting window function
'
Const GWL_WNDPROC:Int = -4

Extern "Win32"
Function SetWindowLong:Int(HWND:Int,nIndex:Int,dwNewLong:Int) = "SetWindowLongA@12"
Function GetWindowLong:Int(HWND:Int,nIndex:Int) = "GetWindowLongA@8"
Function CallWindowProc:Int( prevwndproc:Int, hwnd:Int, msg:Int, wparam:Int, lparam:Int) = "CallWindowProcA@20"
EndExtern

Function SetWindowFunc:Int( window:TGadget, newfunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int))
Local hwnd:Int = QueryGadget( window, QUERY_HWND)
Local oldfunc:Int = GetWindowLong( hwnd, GWL_WNDPROC)
SetWindowLong( hwnd, GWL_WNDPROC, Int(Byte Ptr newfunc))
Return oldfunc
EndFunction

Cool, I'll test this method out and see whether it has the same issues as above!

Offline Kippykip

  • Full Member
  • ***
  • Posts: 122
    • Kippykip Forums!
Re: Getting Raw Mouse Input?
« Reply #8 on: July 30, 2020, 02:25:05 PM »
Hi,
This is an old bit of code from my library, so I don't know if it needs updating, but it might help you with your question...

Basically, you save the current WndProc and insert your own, calling the old one at the end...

Code: [Select]
SuperStrict
' WndProc() based on code by grable at:
' http://www.blitzbasic.com/Community/posts.php?topic=67031

Const WINDOW_FLAGS:Int = WINDOW_TITLEBAR | WINDOW_RESIZABLE

Global window:TGadget = CreateWindow( "Test", 64,64, 256,256, Null, WINDOW_FLAGS | WINDOW_CLIENTCOORDS)
Global OldWindowFunc:Int = SetWindowFunc( window, WindowFunc)

While WaitEvent()
Select CurrentEvent.ID
Case EVENT_WINDOWCLOSE
If CurrentEvent.Source = window Then Exit
EndSelect
Wend
End

Function DriveFromMask:String( unitmask:Int)
Local i:Int
For i = 0 Until 26
If unitmask & $1 Then Exit
unitmask :Shr 1
Next
Return Chr(Asc("A") + i)
EndFunction

Function WindowFunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int) "Win32"
Local hdr:Int Ptr = Int Ptr(lparam)
Select msg
Case WM_DEVICECHANGE
Select wparam
Case DBT_DEVICEARRIVAL
If hdr[1] = DBT_DEVTYP_VOLUME Then
If hdr[4] & DBTF_MEDIA Then
' cdrom / disk drive
Notify "Media inserted into drive " + DriveFromMask( hdr[3])
Else
' other / usb
Notify "Inserted volume as drive " + DriveFromMask( hdr[3])
EndIf
EndIf

Case DBT_DEVICEREMOVECOMPLETE
If hdr[1] = DBT_DEVTYP_VOLUME Then
If hdr[4] & DBTF_MEDIA Then
' cdrom / disk drive
Notify "Media removed from drive " + DriveFromMask( hdr[3])
Else
' other / usb
Notify "Removed volume registered as drive " + DriveFromMask( hdr[3])
EndIf
EndIf
EndSelect

' this MUST be handled, otherwise MaxGUI freezes on window close.
Case WM_DESTROY
SetWindowLong( hwnd, GWL_WNDPROC, OldWindowFunc)
EndSelect
Return CallWindowProc( OldWindowFunc, hwnd, msg, wparam, Int(lparam))
EndFunction


'
' device change notification
'
Const WM_DEVICECHANGE:Int = 537

Const DBT_NO_DISK_SPACE:Int = $47
Const DBT_CONFIGMGPRIVATE:Int = $7FFF
Const DBT_DEVICEARRIVAL:Int = $8000
Const DBT_DEVICEQUERYREMOVE:Int = $8001
Const DBT_DEVICEQUERYREMOVEFAILED:Int = $8002
Const DBT_DEVICEREMOVEPENDING:Int = $8003
Const DBT_DEVICEREMOVECOMPLETE:Int = $8004
Const DBT_DEVICETYPESPECIFIC:Int = $8005
Const DBT_DEVTYP_OEM:Int = 0
Const DBT_DEVTYP_DEVNODE:Int = 1
Const DBT_DEVTYP_VOLUME:Int = 2
Const DBT_DEVTYP_PORT:Int = 3
Const DBT_DEVTYP_NET:Int = 4
Const DBT_DEVTYP_DEVICEINTERFACE:Int = 5
Const DBT_DEVTYP_HANDLE:Int = 6
Const DBT_APPYBEGIN:Int = 0
Const DBT_APPYEND:Int = 1
Const DBT_DEVNODES_CHANGED:Int = 7
Const DBT_QUERYCHANGECONFIG:Int = $17
Const DBT_CONFIGCHANGED:Int = $18
Const DBT_CONFIGCHANGECANCELED:Int = $19
Const DBT_MONITORCHANGE:Int = $1B
Const DBT_SHELLLOGGEDON:Int = 32
Const DBT_CONFIGMGAPI32:Int = 34
Const DBT_VXDINITCOMPLETE:Int = 35
Const DBT_VOLLOCKQUERYLOCK:Int = $8041
Const DBT_VOLLOCKLOCKTAKEN:Int = $8042
Const DBT_VOLLOCKLOCKFAILED:Int = $8043
Const DBT_VOLLOCKQUERYUNLOCK:Int = $8044
Const DBT_VOLLOCKLOCKRELEASED:Int = $8045
Const DBT_VOLLOCKUNLOCKFAILED:Int = $8046
Const DBT_USERDEFINED:Int = $FFFF

Const DBTF_MEDIA:Int = 1
Const DBTF_NET:Int = 2

Const DEVICE_NOTIFY_WINDOW_HANDLE:Int = 0
Const DEVICE_NOTIFY_SERVICE_HANDLE:Int = 1
Const DEVICE_NOTIFY_ALL_INTERFACE_CLASSES:Int = 4


'
' setting window function
'
Const GWL_WNDPROC:Int = -4

Extern "Win32"
Function SetWindowLong:Int(HWND:Int,nIndex:Int,dwNewLong:Int) = "SetWindowLongA@12"
Function GetWindowLong:Int(HWND:Int,nIndex:Int) = "GetWindowLongA@8"
Function CallWindowProc:Int( prevwndproc:Int, hwnd:Int, msg:Int, wparam:Int, lparam:Int) = "CallWindowProcA@20"
EndExtern

Function SetWindowFunc:Int( window:TGadget, newfunc:Int( hwnd:Int, msg:Int, wparam:Int, lparam:Int))
Local hwnd:Int = QueryGadget( window, QUERY_HWND)
Local oldfunc:Int = GetWindowLong( hwnd, GWL_WNDPROC)
SetWindowLong( hwnd, GWL_WNDPROC, Int(Byte Ptr newfunc))
Return oldfunc
EndFunction
OH WOW YES!!!!!!!!!
IT WORKS!!!!!
I updated the github page to fix the bugs, thanks so much man! :)

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal