Skip to content

Commit b4185fc

Browse files
committed
Add README
1 parent 17ed6c5 commit b4185fc

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

README.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Age of Empires II scrollbug fix
2+
3+
## What is the scrollbug?
4+
5+
Sometimes when you tab out of the game, after tabbing back in the game will be stuck in a state where it is constantly scrolling in some direction.
6+
7+
This makes the game unplayable and requires a restart of the game. This is especially annoying in multiplayer games.
8+
9+
The scrollbug happens mostly when running the game in Wine, but has supposedly also been observed on Windows.
10+
11+
## How do I reliably reproduce the scrollbug?
12+
13+
- Use Wine. I don't know if these steps work on Windows.
14+
- Start a game, e.g. a standard single-player random map game
15+
- Hold the left-arrow key for 3 seconds
16+
- Release the left-arrow key
17+
- Wait for one second
18+
- Tab out of the game
19+
- Wait for one second
20+
- Tab back into the game
21+
- Congratulations; you now have a scroll bug
22+
23+
## Why is there a scrollbug?
24+
25+
Age of Empires II uses the `GetKeyboardState()` and `GetKeyState()` Win32 API functions to determine whether one of the scrolling keys is pressed.
26+
27+
In the result of these functions, the key stats are reported as a single byte.
28+
29+
According to the MSDN documentation,
30+
31+
- Bit 7 of the byte says whether the key is currently pressed
32+
- Bit 0 of the byte toggles each time the key is pressed
33+
- All other bits are not documented
34+
35+
Age of Empires II wants to check whether the key is currently pressed. To do this it checks whether the byte value is `>= 1` instead of checking if Bit 7 is set (`& 0x80`).
36+
37+
This works as long as bits 1..6 are zero.
38+
39+
Unfortunately, wine seems to use bit 2 to provide some other metadata, obviously related to tabbing out of the window, so it doesn't guarantee that bits 1..6 are always 0.
40+
41+
Windows also seems to sometimes use some of the other bits.
42+
43+
## Which versions of Age of Empires II have the scrollbug?
44+
45+
Every single one, i.e.:
46+
47+
- AoK
48+
- AoC
49+
- Forgotten Empires
50+
- UserPatch
51+
- AoE2:HD
52+
- AoE2:DE
53+
54+
## How does this fix work?
55+
56+
This uses the Microsoft Research [Detours](https://github.com/microsoft/Detours) library to inject replacements of `GetKeyState()` and `GetKeyboardState()` into the running Age of Empires II binary.
57+
58+
The replacement functions mask out bits 1..6 in the results.
59+
60+
The fix consists of two binaries:
61+
62+
- `age2_x1_fixed.exe` reads the configuration from `age2_x1_fixed.ini` and calls the `exe` that is specified in the `ini` file with the injector `dll` file that is specified in the `ini` file.
63+
- `fix_scrollbug32.dll` injects fixed versions of `GetKeyState()` and `GetKeyboardState()` into any 32-bit Windows executable it is used with.
64+
65+
## How do I build this fix?
66+
67+
- Use Windows (please, somebody port this to winegcc or mingw or _something_ that works on Linux)
68+
- Install Visual C++ Build Tools 2015
69+
- Get this source code (duh.)
70+
- Get `detours.lib` and `detours.h`, e.g. by building the Detours library from source by invoking `nmake`, or by downloading the binaries from this Github repo. Place these two files in a subfolder `detours/` of this source code
71+
- Call `build.bat`
72+
- You will now have a whole bunch of garbage files, plus
73+
- `fix_scrollbug32.dll`
74+
- `dll_inject.exe`
75+
- `dll_inject.ini`
76+
77+
## How do I use this fix?
78+
79+
`dll_inject.exe` can be renamed to whatever name. It is recommended to rename it to `{name_of_the_exe_you_want_to_fix}_fixed.exe`.
80+
81+
When launched, `dll_inject.exe` will
82+
83+
- open the `.ini` file with the same name
84+
- in that `.ini` file in the section `[dll_inject]`, read the keys `exe_file` and `dll_file`
85+
- launch the specified `exe` file and inject the specified `dll` file
86+
- wait until the exe file has finished
87+
88+
If you use the pre-compiled and pre-configured `age2_x1_fixed.exe`, `age2_x1_fixed.ini`, `fix_scrollbug32.dll` you can just place them in the `age2_x1` folder and launch `age2_x1_fixed.exe` instead of `age2_x1.exe`.

0 commit comments

Comments
 (0)