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

w4rh4wk5 | 175 points

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

mdaniel | 2 days ago

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 ...

SleepyMyroslav | 2 days ago

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.

pentamassiv | 2 days ago

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

anaisbetts | 2 days ago

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.

dezgeg | 2 days ago

Shoutout to Elden Ring where the entire game freezes when your (wireless) mouse goes to sleep.

msp26 | 2 days ago

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.

Animats | 2 days ago

Japanese IME on Windows is insane; it's always switching to A mode. You're always fighting it to go to あ.

kazinator | 2 days ago

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.

jchw | 2 days ago

> 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.

sebazzz | a day ago

> 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.

modeless | 2 days ago

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.

YetiSpaghetti | 2 days ago

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.

wackget | 2 days ago

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.

wodenokoto | a day ago

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.

phibz | 2 days ago

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.

phendrenad2 | 2 days ago

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.

okibry | 2 days ago

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.

kazinator | 2 days ago

> 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.

zelon88 | 2 days ago

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.

andrewmcwatters | 2 days ago

>If you are already an expert on game input on Windows, please skip directly to our current solution and tell us how to do it better, because I hope fervently that it’s not the best!

This is a neat thing to see at the top of an article, very in line with the hacker spirit.

LordDragonfang | 2 days ago

meanwhile under wayland if you move your 8k mouse too much then the socket event buffer fills up and the compositor terminates the connection, killing the app

blibble | 2 days ago

> A few days later after the build is pushed to beta testers, you get a bug report that the game window can no longer be moved around. And then you realize that you just disabled the system’s ability to move the window around, because that is done using legacy input.

I don't think I've seen any AAA games that allow me to run them in windowed mode with decent performance.

Valorant, for example, switches to windowed mode when I press Alt-Enter by mistake, but doesn't allow me to interact with the window much. It also locks up completely when Alt-Tabbing, so I don't know what's going on there.

Plus, I think the general expectation is to always run AAA games in full-screen mode. In such cases, disabling legacy messages is a viable approach.

rkharsan64 | 2 days ago