News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Input handling with WM_INPUT and other win32/win64 questions

Started by ccdcmc421, March 25, 2025, 10:02:26 AM

Previous topic - Next topic

ccdcmc421

Hi MASM community!

 I was working on a simple 2d game using the win64 API. I understand that using 64-bit is overkill for a lot of things, but I thought that this would be a fun and highly engaging challenge to keep me busy!

I came across input handling for my game after having all the items set-up and ready to go for it. However, the way I had it designed originally using GetAsyncKeyState function had me very dissatisfied because I simply didn't like how the input felt using this to interpret keyboard data.

After a bit of thinking I thought that the best approach would be to use Raw Input data. I was going to use RAWINPUTDEVICE Struct, as suggested by other forums, microsoft, and games before me, but I came across the struggle that this item actually isn't in the win64.inc file or at all in any part of win64 api. However, it does exist in the 32 bit windows.inc file. I was also looking around for WM_INPUT Message. To my surprise this item also doesn't exist within win64. :nie:

I guess what I wanted to ask after all this information presented itself to me was to understand, outside of architectural differences, why are there certain items that don't exist from win32 to win64 such RAWINPUTDEVICE struct and WM_INPUT?
I'm not sure if I should manually create the struct and the message value myself?
What effect would that have on my application if I used something meant for win32 and brought it to win64? I would assume it would be backwards compatible.

Also, does anyone here have any experience setting up their program to use raw input? I would seriously appreciate some examples!  :biggrin:

Thank you for the read! If I need to elaborate more, please let me know!

NoCforMe

The short answer is just that the 64-bit MASM package here is woefully underdeveloped and missing tons of stuff. Not by design, just by lack of effort.

Which doesn't bother me in the least, as I find Win32 to be more than adequate for any programming tasks I want to undertake.
Assembly language programming should be fun. That's why I do it.

NoCforMe

Since it sounds as if you are only looking for input from the keyboard, might I suggest that you look for these messages in your window procedure: WM_KEYDOWN & WM_KEYUP for a lower-level implementation, or WM_CHAR to capture keyboard characters as they're typed.

Very easy to implement.
Assembly language programming should be fun. That's why I do it.

ccdcmc421

Quote from: NoCforMe on March 25, 2025, 10:41:24 AMSince it sounds as if you are only looking for input from the keyboard, might I suggest that you look for these messages in your window procedure: WM_KEYDOWN & WM_KEYUP for a lower-level implementation, or WM_CHAR to capture keyboard characters as they're typed.

Very easy to implement.

Hi NoCforMe!

I have tried using those messages, but when I do, there seems to be like a quarter of a second delay... I originally did want to try using the WM_KEYDOWN. But I was unhappy with the results due to the delay. So then I moved to trying GetAsynchKeyState

What my vision for the program was, is to have very crisp and responsive inputs.

NoCforMe

Interesting, that delay: I totally get that you don't want that!
So what's your environment? DOS? Windows (x)?
I use the "raw" keystroke messages in Windows 7 and have never experienced any delay.

Assembly language programming should be fun. That's why I do it.

ccdcmc421

Quote from: NoCforMe on March 25, 2025, 11:15:43 AMInteresting, that delay: I totally get that you don't want that!
So what's your environment? DOS? Windows (x)?
I use the "raw" keystroke messages in Windows 7 and have never experienced any delay.



currently, I am using Windows 11. How do you setup raw input for windows 7?

NoCforMe

I should clarify what I mean by "raw" keystroke messages: by that I mean the basic messages like WM_KEYDOWN and WM_CHAR. I don't mean the "raw input" mode that gives you WM_INPUT messages.

If you don't already know, to receive WM_INPUT messages you first need to register your application with the raw input device(s) you want to access; this is done through the RegisterRawInputDevices() function (click link for the Micro$oft Learn page on this). You'll need to set up one or more RAWINPUTDEVICE structures to do this.

I have no idea how to use "raw input" this way, as I've never played around with this. Seems kinda complicated ...

BTW, are you sure the delay handling keystrokes isn't due a delay somewhere in your code? As I wrote before, I've never experienced any kind of delay handling keyboard input using the low-level keyboard messages (not WM_INPUT).
Assembly language programming should be fun. That's why I do it.

ccdcmc421

Quote from: NoCforMe on March 25, 2025, 11:53:47 AMI should clarify what I mean by "raw" keystroke messages: by that I mean the basic messages like WM_KEYDOWN and WM_CHAR. I don't mean the "raw input" mode that gives you WM_INPUT messages.

If you don't already know, to receive WM_INPUT messages you first need to register your application with the raw input device(s) you want to access; this is done through the RegisterRawInputDevices() function (click link for the Micro$oft Learn page on this). You'll need to set up one or more RAWINPUTDEVICE structures to do this.

I have no idea how to use "raw input" this way, as I've never played around with this. Seems kinda complicated ...

BTW, are you sure the delay handling keystrokes isn't due a delay somewhere in your code? As I wrote before, I've never experienced any kind of delay handling keyboard input using the low-level keyboard messages (not WM_INPUT).

You know what, I actually haven't tried WM_CHAR yet! hopefully this is my solution! I'll give it a shot and let you know!

zedd151

AV software could also be slowing down your code, while 'inspecting' it. What Antivirus software are you running? Any "realtime" protection may be interfering here...

 This may give some clue for the apparent slow reaction time for keyboard messages.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

ccdcmc421

Quote from: zedd151 on March 25, 2025, 12:16:46 PMAV software could also be slowing down your code, while 'inspecting' it. What Antivirus software are you running? This may give some clue for the apparent slow reaction time for keyboard messages.

Hi Zedd151!

I am not running any sort of AV right now.. I have windows defender disabled currently.

zedd151

Okay, that is not the issue then. Good to hear it. My PC would grind almost to a halt when realtime protection was enabled, especially for my tiny assembly programs.  :smiley:  AV software typically deems small assembly programs as 'suspect' and scrutinizes them endlessly and sometimes quarantining them. Those days are gone for me forever. On Windows 10, btw.

Carry on.  :tongue:
I am with NoCforMe on this one. Since it is not an AV issue, something must me amiss in your code. Keyboard messages are supposed to be handled instantly whether using WM_KEYUP, WM_KEYDOWN, or WM_CHAR. (Or at least have the perception of instantaneous action)
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

ccdcmc421

Quote from: NoCforMe on March 25, 2025, 11:53:47 AMI should clarify what I mean by "raw" keystroke messages: by that I mean the basic messages like WM_KEYDOWN and WM_CHAR. I don't mean the "raw input" mode that gives you WM_INPUT messages.

If you don't already know, to receive WM_INPUT messages you first need to register your application with the raw input device(s) you want to access; this is done through the RegisterRawInputDevices() function (click link for the Micro$oft Learn page on this). You'll need to set up one or more RAWINPUTDEVICE structures to do this.

I have no idea how to use "raw input" this way, as I've never played around with this. Seems kinda complicated ...

BTW, are you sure the delay handling keystrokes isn't due a delay somewhere in your code? As I wrote before, I've never experienced any kind of delay handling keyboard input using the low-level keyboard messages (not WM_INPUT).

to elaborate more on this, I have tried to set-up the RAWINPUTDEVICE struct, but every time I set that item up, I get 03E6 error in GetLastError.... when I set it up, I'll show you what I tried in setting that up in one moment.

ccdcmc421


since I'm on x64, we're using fastcall, I have tried also setting hwndTarget to DD to see if that might be the issue too. RCX should also be an array of RAWINPUTDEVICE struct from my understanding... I tried to set it up like this but I have a theory that I could be doing it wrong too.

RAWINPUTDEVICE STRUCT
    usUsagePage   DW ?
    usUsage       DW ?
    dwFlags       DD ?
    hwndTarget    DQ ?
RAWINPUTDEVICE ENDS

RawInputDevices RAWINPUTDEVICE <>
.code
....
;whatever code here to get to setting up RAWDEVICEINPUT Struct
         
mov     WORD PTR [RawInputDevices.usUsagePage], 1     ; Generic Desktop Controls
mov     WORD PTR [RawInputDevices.usUsage], 6        ; Usage for Keyboard
mov     DWORD PTR [RawInputDevices.dwFlags], 0        ; No special flags
mov     DWORD PTR [RawInputDevices.hwndTarget], RAX ; I have also tried setting this to 0 as I have heard that you can set it to 0 and it follows the keyboard's focus. But it still yielded the same result.

mov     RCX, OFFSET RawInputDevices
mov     RDX, 1
mov     R8, SIZEOF RAWINPUTDEVICE
call    RegisterRawInputDevices
Call GetLastError

RAX = 00000000000003E6

NoCforMe

Try WM_CHAR and let us know how it works.
That "raw input" stuff is just too damn complicated.

BTW, rather than just displaying a meaningless hex value from GetLastError(), use this to actually display a message showing what the error actually is:
ShowLastError PROC
LOCAL buffer[256]:BYTE

CALL GetLastError
MOV EDX, EAX
PUSH EAX
INVOKE FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM OR FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, EDX, 0, ADDR buffer, SIZEOF buffer, NULL
INVOKE MessageBox, 0, ADDR buffer, NULL, MB_OK
POP EAX
RET

ShowLastError ENDP
Assembly language programming should be fun. That's why I do it.

ccdcmc421


Quote from: NoCforMe on March 25, 2025, 12:35:09 PMTry WM_CHAR and let us know how it works.
That "raw input" stuff is just too damn complicated.

BTW, rather than just displaying a meaningless hex value from GetLastError(), use this to actually display a message showing what the error actually is:
ShowLastError PROC
LOCAL buffer[256]:BYTE

CALL GetLastError
MOV EDX, EAX
PUSH EAX
INVOKE FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM OR FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, EDX, 0, ADDR buffer, SIZEOF buffer, NULL
INVOKE MessageBox, 0, ADDR buffer, NULL, MB_OK
POP EAX
RET

ShowLastError ENDP


Neat advice! Thank you for your patience!

I'll try it out and let you all know!