Skip to content

udf/aoe_keystate_fix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 

Repository files navigation

What is this?

A fix for the scrolling bug in Age of Empires.

It works by using a proxy dll that modifies the return values of the GetKeyboardState, GetKeyState and, GetAsyncKeystate functions when they are called.

All other functions are simply forward exports to the original functions from user32.dll.

Usage

Change the string USER32.DLL in your Age of Empires exe to USER33.DLL and drop the user33.dll from the release page into the same folder as your game exe.

Note that you don't need a hex editor to find and change this string (Notepad++ works, regular Notepad might mess up the encoding and corrupt the exe)

You'll know if it's loaded when you start the game and get a message box like this:

Compilation

Use MinGW:

i686-w64-mingw32-gcc -s user33.c user33.def -shared -o user33.dll

(you might need to replace i686-w64-mingw32-gcc with the name/path of gcc on your system)

Why?

As noted in the documentation for GetKeyboardState, GetKeyState, and GetAsyncKeystate: only the high bit should be checked if you want to know if a key is pressed. Age of Empires II HD (and likely other versions) simply check if the return value is > 0. This breaks when Windows or Wine uses the middle bits for internal stuff, the latter happens when switching workspaces or putting the game in the scratchpad in i3wm.

Credit goes to Steam user Sulix for discovering that the problem is with how the game handles the return value of the functions:

thread

Note that Sulix only patched the GetKeyboardState function, but the game calls all three of the functions in several places (which would explain why the tech tree still bugs with his fix):
(screenshots from radare2)

Instead of patching the calls in the exe as he outlines, this project patches the function exports to make the game's incorrect logic always work.
This means it easily works across different versions of the game and requires less effort to use and develop.

Why do I have to modify my exe?

Because it makes the fix more portable:

Windows lets you redirect LoadLibrary calls of "Known DLLs" using a manifest file. More information can be found here.

However I couldn't get this to work on windows 7 (it might have something to do with cache, which I couldn't get to clear), additionally Wine doesn't seem to follow manifest files, instead it uses this section in winecfg to override a library version.

This works, however it means that I would have to do runtime function forwarding by jumping to the entry point of the original functions (under the "Background" section) (because the linker will try to link to our functions, since we have the same name as the the original dll), which is slower and would require an absolute path (since loading by name would load our dll first) to the real user32.dll which is different on 64-bit and 32-bit systems.

TODO

  • Automated patching of the exe (though, how hard is it to change one byte in a hex editor?)
  • Tests across more versions of the game

About

A fix for the scrolling bug in Age of Empires

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages