top | item 41568418

Things you should know about Windows Input, but would rather not

176 points| w4rh4wk5 | 1 year ago |ph3at.github.io

107 comments

order
[+] mdaniel|1 year ago|reply
I have to be very disciplined about switching my layout back to US English before launching games because they seem insistent on using the mapping for WASD versus the keys for WASD. But, worse (IMHO): some games use the keys and thus I can't predict whether the game was coded correctly or not and thus I just gave up and made it part of my launch process

I have secret desires to convert one of my old MacBook Pro devices into a Steam-via-Proton setup to get out from under the tyranny of Windows but since gaming is designed to be a break from "work" ... that's why it's not already done

[+] Denvercoder9|1 year ago|reply
Your computer doesn't actually know what the keys for WASD are. It just receives a number (commonly called scan code) for the pressed key from the keyboard, and has to use the mapping to determine which key that actually was.

There's some convention for which scan code to use for which physical position on a keyboard, but that's not correlated with what's actually printed on the key caps. E.g. on common QWERTY keyboards the "A" key will have scan code 4, but on AZERTY keyboards it will have scan code 20.

Games can probably get away by listening for the scan codes of the keys in the position commonly used by WASD, but it's a bit fragile, and they can't actually tell you what's printed on the keys they're listening to. The lack of consistenency is certainly annoying, though...

[+] w4rh4wk5|1 year ago|reply
We've invested some time to improve this situation for the games we port, at least to some extent. Keyboard input is read as a combination of scan code + win32 virtual key information to determine the physical key pressed on your keyboard. This way the keybindings are (almost) independent of the keyboard layout.

However, we also reflect your current key bindings with dynamic button prompts that tell you which key to press in game. For this we translate the determined physical key back through the selected keyboard layout to figure out what the corresponding label on your keyboard might be.

Most of this is just win32 API shenanigans, but the following post provides a bit more detail on reading inputs this way.

https://blog.molecular-matters.com/2011/09/05/properly-handl...

[+] giancarlostoro|1 year ago|reply
Not sure about Macbook Pro, but I converted my Windows 11 gaming desktop to Linux and Steam with Proton works just fine for all the games I care about. The only game that didn't play was Starfield and that was fixed shortly after a few weeks.
[+] sickofparadox|1 year ago|reply
This is the kind of slippery problem I would never think about but would make me want to break my keyboard if I encountered in real life.
[+] justin66|1 year ago|reply
That's easier than just changing the key bindings in game?
[+] SleepyMyroslav|1 year ago|reply
If author reads comments I just wanted to confirm that everything seems to be correct.

The fun parts you might not know is eg. that if you want to ship on steam you will need legacy messages for its overlay to function. Because its a web based thing ^_^

Practical solutions usually include either letting user to pick their perfect input type and assume they know limitations like no windowed mode. Or expecting users to reduce 8k to reasonable number in mouse software. Users already know how to read forums or reddit and games that do now work fine with 4k/8k polling rates are well known and numerous.

There is an alternative that my colleagues going to explore = make it Microsoft problem. There is Microsoft provided library that can do input for you ...

[+] durante_a|1 year ago|reply
If the library you are alluding to is GameInput, then I tried that and it sadly did not solve the problem.
[+] pentamassiv|1 year ago|reply
I maintain a library to simulate input on Windows, macOS and Linux. There are a ton of quirks on all of these platforms. On Windows you can simulate text input. The text cannot start with a new line character though. It is perfectly fine if it's not the first one though. macOS also allows you to simulate text input, but the text has to be shorter than 21 characters. Linux is especially difficult with X11, multiple Wayland protocols and libei.
[+] indrora|1 year ago|reply
Look into contributing to LibTAS.

It’s very Linux specific but can frame by frame manipulate the input that an application is getting, meant for speed runs of games.

[+] Scramblejams|1 year ago|reply
If it's available, I'd love a link.
[+] anaisbetts|1 year ago|reply
I would point people to the new GameInput API - https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/inp...

GameInput does everything these older APIs do without having to mix them all together or use a bunch of them to get the information you want

[+] durante_a|1 year ago|reply
I tried GameInput, sadly it doesn't solve this issue.

You still need legacy input for Window interactions, and the message queue still gets flooded by fast-polling mice.

[+] dezgeg|1 year ago|reply
Another "fun" thing is old joysticks and steering wheels that require calibration. This used to be done in the windows control panel such that not every game needs to implement that... However it seems the latest API in fashion that eg. Unity uses just totally ignores that native calibration totally. (Could just be an Unity side problem also). So bunch of old wheels are broken on Unity.
[+] gmueckl|1 year ago|reply
What's equallt bad these days is the fact that the calibration UI is hidden in the third or fourth level of nested dialog windows recent versions of the Control Panel. Even finding it is a hunting game.

Many, but not all recent game controllers come with accurate and stable enough calibration so that you don't need to do this very often or at all. It's mostly older hardware that needs to go through the process. Most 10 year old controllers (sticks/wheels etc.) can still be perfectly usable today after calibration!

[+] msp26|1 year ago|reply
Shoutout to Elden Ring where the entire game freezes when your (wireless) mouse goes to sleep.
[+] lostmsu|1 year ago|reply
Sounds like a gameplay mechanics a-la Braid.
[+] klabb3|1 year ago|reply
Issue closed (Works as intended)
[+] Animats|1 year ago|reply
I use winit, which is a Rust crate for dealing with windows (lower case) and keyboard/mouse events. It supports Microsoft Windows, MacOS, Linux/X11, Linux/Wayland, Android, web browsers, and Redox OS. Trying to abstract over all of those works, almost.

Reading keyboard arrows or WASD has timing problems. Although the program gets key code up/down events, the key repeat software seems to interfere with the timing of the events and slows them down. Software repeats can be ignored, but still cause problems. Holding down a repeating key for long periods can cause lost events. X11 is especially bad, but there seem to be some problems with Windows, too.

Another thing nobody has fixed in the Rust game dev ecosystem yet because the developer base is tiny. Rust needs one good first person shooter project with enough push behind it to wring out the performance problems in interactive 3D.

[+] lostmsu|1 year ago|reply
I don't know about Linux, but in Windows all input messages come with a timestamp, so even if you happen to process it later you should know when the key was actually pressed. That might help when simulating physics, animation or other stuff.
[+] kazinator|1 year ago|reply
Japanese IME on Windows is insane; it's always switching to A mode. You're always fighting it to go to あ.
[+] Rels|1 year ago|reply
I also hate this behavior. My understanding is that it doesn't get noticed by native users as it's not an issue when the JP input is the only input, so it's mainly an issue for language learners.

It's been on my mind to try the google IME for some time, to see if it fixes this issue, but haven't got around trying it yet.

[+] jchw|1 year ago|reply
I just had a thought: I really wonder how mouse-in-pointer[1] mode interacts with raw input. I had looked into mouse-in-pointer somewhat extensively to try to understand how it behaves[2], in part because I'd really like WM_POINTER in wine some day (but I fear I will never actually be able to contribute to that effort, since I'm just not in-the-weeds enough with Wine input, and I don't think anyone is interested in holding my hand to figure it out.) However, one thing I definitely never thought about is raw input. It's pretty clear that both are implemented somewhere in kernel mode, in front of the event processing queue, so I bet they have an interaction. WM_POINTER events also implement batching, so I wonder if enabling both and ensuring the windowproc doesn't let it fallback can solve some problems. Probably not, but worth a shot.

[1]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/...

[2]: https://github.com/jchv/WmPointerDemo

> Disable legacy input, create your own legacy input events at low frequency. Another one in the category of “silly ideas that probably could work”, but there are a lot of legacy messages and this would be another support nightmare.

This was my first thought when reading the article. Frankly it would be a pain, but this seems like the sort of thing that someone only has to do one time.

[+] wvenable|1 year ago|reply
I would think you only have to generate enough legacy mouse messages that your application works. I'm sure I'm probably missing some catch here but I know plenty of applications that simulate input.

(Calling them "legacy" messages seems weird -- this is the normal current way that input messages work for regular applications).

[+] modeless|1 year ago|reply
> Use a separate process to provide raw input. This is a bit of a silly idea

I don't think this is silly at all. People are too timid about using multiple processes in general. It's OK, there's nothing wrong with it! We ought to have more libraries to help make multiprocess apps.

[+] sebazzz|1 year ago|reply
> This is not an empty phrase: we have observed performance losses of 10-15% in extremely CPU-limited cases just by calling XInputGetState for all controllers every frame while none are connected!

Is this why a game renders only a few frames per second and slows down in time when my wireless Xbox controller disconnects due to low battery? I always assumed it was some mechanism to make the gameplay “fair” if your controller had an intermittent disconnect.

[+] YetiSpaghetti|1 year ago|reply
I think the author has two issues in their approach.

1) You should be processing the whole message queue for all types of messages in one go. When using raw input, author is peeking for "not input" event types. To me, this seems suspicious for performance. With a raw input device registered, the message queue is going to be huge.

While I don't know the underlying data structure of the message queue, if we assume an array, then the author's code will do a while loop of O(N) lookups for "not input" messages and remove them.

The correct approach is to dispatch the whole queue and ignore messages of types that you don't care about in your message handler.

2) You SHOULD be using the legacy input events for games, not raw input. The OS input massaging (ex: acceleration) is something that should remain consistent between applications. If there's acceleration: that's what users expect. You don't want the mouse to suddenly behave different in your application. Your games tuning values (sensitivity, accel) should apply relative to the OS values.

[+] Matheus28|1 year ago|reply
For shooter games, raw input is preferred. You want the same amount of mouse movement to move your camera the same amount every time.

In those type of games, you aren’t controlling a cursor, so there’s no “expected behavior”.

[+] munchler|1 year ago|reply
> You SHOULD be using the legacy input events for games, not raw input.

The author claims that this generates an overwhelming number of events for a high-performance mouse. Is this not the case?

[+] wackget|1 year ago|reply
I'm gonna ask here because I've not found a solution anywhere else:

I loved the Middle-earth: Shadow of Mordor game but when I tried to play its sequel, Middle-earth: Shadow of War, I found the mouse input absolutely horrible.

Horrendous mouse lag, floaty camera control, and all the signs of a "mouse emulating gamepad" type situation.

Does anyone know if there's a way to fix this game? I'd love to play it on PC with a mouse but can't stomach it as-is.

[+] CrimsonRain|1 year ago|reply
Sometimes, enabling "raw mouse input" option in the game solves this completely. Ofc this depends on the game, and also not all games have this option. The ones that don't, you can try reducing your mouse DPI to 400 and polling rate to lowest; I think 125hz. Don't remember.

btw, I never played this particular game but lots of others have this issue.

[+] wodenokoto|1 year ago|reply
The worst part of inputs is that my mouse wheel can only scroll in whole lines and the left-right wheel doesn’t work most places where the trackpad can scroll left and right - and the trackpad can scroll with much higher fidelity than whole lines.
[+] phibz|1 year ago|reply
It reads like he is assuming that missing messages from the mouse is not allowable.

I would say think of it this way: what happens when the mouse moves between USB hid messages?

If the mouse moves between messages sent via USB HID do the later messages capture the delta between the last and current message. Including the movement that happened in between?

Do the input messages, both those sent over USB by the mouse as well processed and presented by Windows, give relative or absolute positions?

The messages already represent a discrete sampling if a signal. You should be able to recreate the original information reasonably well without processing every single message.

[+] p_l|1 year ago|reply
Standard USB HID Mouse reports relative position change to previous report, so the reported position is difference from last polled one.
[+] phendrenad2|1 year ago|reply
Can you disable and re-enable NOLEGACY on-the-fly? Maybe you can disable it when you calculate that the user has moved the mouse outside of the game window region.
[+] meepmorp|1 year ago|reply
apparently not:

> This would at least solve the problem for the vast majority of users, but it’s not possible, as far as I can tell. You seemingly cannot switch between legacy and raw input once you’ve enabled it. You might think RIDEV_REMOVE would help, but that completely removes all input that the device generates, including both legacy and raw input.

[+] okibry|1 year ago|reply
Is the solution look like rare limit in the client side ?

And maybe it will have some missed event between your ticker for processing game logic and fps.

[+] kazinator|1 year ago|reply
One thing I'd like to see fixed in computer keyboard input in general is how Shift is handled for capitals.

I find it next to impossible to type "Now" really fast without having it come out as "NOw" much of the time. (Why I'm using this example is that it's the first word of the "Now is the time ..." test sentence).

The timing required is strict. The Shift key must be down before the letter key is down.

Keys activate strictly and immediately on the down event.

Note that virtual buttons on most contemporary GUIs, clicked by mouse, do not work this way. You must click and release the button for it to activate. If you click OK on some dialog, but change your mind while still holding down the mouse button, you can back out of it, by moving the cursor out of the button's area. You also cannot click down outside of the button, then move into the button and release. The button must receive both mouse down and mouse up, without the pointer leaving the area, in order to activate.

I'd like a mode in which the down events of non-modifier keys are deliberately delayed by some configurable number of milliseconds, so that when the user hits a modifier key at around the same time, and that key lands a little bit late, it is still taken into account.

It would also be nice to be able to experiment with a mode in which keystrokes are generated by their up events, not down, and the modifier is sampled at that time.

[+] zaat|1 year ago|reply
I can't find any viable alternative. Keyboard is much faster than those click and release interfaces. Keyboards also have repeat keys, when you press a character for a long time you can actually press and depress the shift key and see the change in the line of characters input. This is extremely useful feature in games, graphic design software and other applications.

Generation of keystroke based on the up event, beside been incompatible with repeating keys for long strokes, will slow down typing significantly, as it requires tracking timing pressing keys for longer duration. I'm pretty sure that this isn't only effect of me being used to track keypress timing on the way down, but an unavoidable result of the duration of the action.

Waiting for up event on contemporary GUI, when the contempt UI is a sluggish fit-to-nothing dirty touchscreen in a public kiosk is sensible. When you know an interface will yield more errors than intended input it is only sensible to assume that any input is a mistake unless the user is making an effort to validate it.

[+] akira2501|1 year ago|reply
> The timing required is strict.

Your keyboard has a serial interface to your computer. Events are generated serially. If you press one first it will register first.

> keystrokes are generated by their up events

We don't do this because then you can't have auto repeat.

[+] zelon88|1 year ago|reply
> prevent performance collapse by just not processing more than N message queue events per frame. N=5

Why is this an issue? Your mouse is sending raw input 80,000 times per second to a screen that can only display 120 pictures per second.

Kinda sounds like an arbitrary problem that people who believe 8k mouses are necessary would worry about.

[+] maccard|1 year ago|reply
> Your mouse is sending raw input 80,000 times per second to a screen that can only display 120 pictures per second.

8 thousand, not 80 thousand. Many screens can display (much more) than 120 frames per second - My monitor goes to 240hz, there are 300hz displays available.

Rendering rate is very often not tied to game update rates - games can update their state at significantly higher rates than they display. A decent number of games have a "high level" skill of doing things like "pre-shooting" where the winner of a fight is done by figuring out "who realistically did it first".

Assuming that you can poll at 125hz is wrong.

> Why is this an issue? ... Kinda sounds like an arbitrary problem that people who believe 8k mouses are necessary would worry about.

People have these devices and run our games. We (unfortunately) need to handle them, just like a website needs to handle a poorly behaved client. Also depending on _when_ you sample, (i.e. which 5 messages you handle), you can get incorrect information from the device.

[+] VyseofArcadia|1 year ago|reply
Simulation resolution needs to be higher than display resolution. Simulating physics at only 120Hz can lead to jank. This is similarly true in the spacial dimensions, where even old games would run the game simulation at more than 640x480 for fidelity.
[+] kevingadd|1 year ago|reply
I've seen high mouse polling rates cause genuine performance problems in real games. It was a surprise to me too, but I ended up dropping my polling rate from 4000 to 500 to fix it.
[+] andrewmcwatters|1 year ago|reply
I know this doesn’t address the technical questions asked or the concerns prompted, but if your mouse is causing your games to have performance issues…

It’s not a high-end mouse.

Yeah, yeah OK polling rates, etc. Whatever. But honestly, PC gamers have been mostly fine for over 20 years of dealing with mouse input. Some major engines didn’t even support raw input until after the mid-2000s.

You can put a V8 on a Corolla… but if the curb weight changes and the torque eats up your tires, well, what did you expect? It’s just idiot engineering.

[+] kbolino|1 year ago|reply
Early USB keyboards and mice were inferior to their PS/2 counterparts and it took a good few years for those issues to be overcome. Keyboards with N-key rollover and mice with decent resolution have tangible benefits for many types of games over their bargain-bin counterparts. It doesn't take much money to get to good enough, but that doesn't mean everything out there is good enough.
[+] CrimsonRain|1 year ago|reply
You just don't know what you are talking about. You are essentially saying horse carriage was great for transportation. A car isn't an upgrade. PC gamers were fine with 60hz monitor. 120hz is not high end/is not needed... high end mice are essential for certain games; esp esports ones.