Skip to content

Fix keymapping stutter and lag - #83

Merged
Depal1 merged 5 commits into
PlayCover:3.0.0-stagingfrom
XuYicong:lower-lag
Feb 23, 2023
Merged

Depal1 merged 5 commits into
PlayCover:3.0.0-stagingfrom
XuYicong:lower-lag

Conversation

@XuYicong

@XuYicong XuYicong commented Feb 11, 2023 •

Copy link
Copy Markdown
Member

Depends on #79

Fixes PlayCover/PlayCover#765

Keymapping used to stutter and lag in performance-intensive games, especially with low power mode or external mouse. This is because the event handler rountines are not given enough priority by the game. Although it's in the main thread which is the highest priority thread, games still have a preference on some jobs over others. It turns out that the way the events were delivered, which was by dispatch queue, is not treated as a top priority by Genshin Impact. The game thinks that jobs in this queue is not important and can be delayed or ignored in high load circumstances. This is the behaviour of the GameController API used. The reason it does so may be that it works in the iOS layer instead of native MacOS layer.

In this fix, keyboard and mouse event handling methods are switched from GC API to native NSEvents, which somehow is polled at a much higher frequency and priority.

By the way, I also make the cursor move to center whenever cursor is hidden. This somehow may fix some weird mouse behaviours especially in windowed mode.
Also fixed a problem where devices with low precision scroll wheel scroll too little distance.
Also turned up WASD panel sensitivity a bit so that people no longer need giant WASD in keymap.

@XuYicong
XuYicong marked this pull request as ready for review February 11, 2023 19:40
@XuYicong
XuYicong changed the base branch from master to 3.0.0-staging February 11, 2023 19:40
@FlyMeToTheMoonAndLetMePlayAmongTheStars

FlyMeToTheMoonAndLetMePlayAmongTheStars commented Feb 16, 2023 •

Copy link
Copy Markdown
Contributor

Been testing these changes for the past few days, everything works great so far, but there's a few noteworthy things:

  • mouse input (to pan in-game camera) will feel slower than before, however, this gives you better precision for aiming, and make the mouse input/acceleration more consistent with how it actually works in macOS system. Not an issue, but should probably be mentioned somewhere to tell users to get used to it so they don't think it's a bug or anything
  • these changes likely have fixed the random camera zoom issue in Genshin, or at least I've not ran into it yet in the past couple days
  • the WASD size fix only applies if you're using A9X, A12X, or M1 models in Genshin Impact, if you use M2 or any of the iPhone models, the in-game joystick UI is somehow much larger and will still need an abnormally big WASD area to restore full gliding speed

@IsaacMarovitz

Copy link
Copy Markdown
Member

The reason it does so may be that it works in the iOS layer instead of native MacOS layer.

IMO before we switch to using NSEvents and fragment our input code between 2 different frameworks we should try moving GC to macOS layer

@XuYicong

Copy link
Copy Markdown
Member Author

I have tested moving GC to AKInterface and it behaves the same as if putting GC in iOS layer. If low power mode is on, the game becomes unplayable. Even if low power mode is off, mouse move still stutters.

We can also see from this sampling of main thread. Mouse moved handler is called by GC from AKInterface, but in the main dispatch queue.
thread sampling GC

Comparing to scroll wheel events which use NSEvents, which is called as an observer callback function instead of dispatch queue. Note that the stacktrace of it contains Genshin's private procedure, which means the game is actively polling for events.

Note also that GC handler has only one sample but NSEvent handler has three samples. This suggests that NSEvent handlers are executed at about 3 times of frequency as GC handlers.

thread samping NSEvent

So it turns out that my previous guess is wrong. It's not because the handler in iOS layer that makes it slow, but the problem with GC API itself.

My new guess is that heavy games are not expected to use GC's event handlers, but should actively poll for events when the game renders every frame. As we cannot hack into the game's render loop and inject an event-checking call there, it's not suitable for us to use GC API.

@IsaacMarovitz

Copy link
Copy Markdown
Member

Alr thanks for looking into it 👍

@Depal1
Depal1 merged commit cd17c12 into PlayCover:3.0.0-staging Feb 23, 2023
XuYicong pushed a commit to XuYicong/PlayTools that referenced this pull request Mar 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants