Categories
Final Report

GSoC Final Report

My project focused on extending ScummVM’s Keymapper system to a larger number of game engines. The Keymapper allows players to remap controls to their liking, but many engines in ScummVM still relied on fixed input handling. By integrating the Keymapper into more engines, the project set out to improve accessibility, provide a consistent user experience, and give players greater flexibility in how they play.


What I did:
I added Keymapper support to 24 engines, fixed a few bugs encountered during the implementations, and helped standardize keymapper action descriptions. This standardization reduces the number of unique strings in the codebase, easing the workload for translators.


The current state:
Keymapper support is now available in 24 additional engines, allowing players to remap controls in a wide range of games that previously relied on fixed input. Several of my pull requests have already been merged into the main ScummVM codebase, and the remaining ones are under review. Overall, the project goals have been successfully achieved, and the improvements are now part of ScummVM’s ongoing development.


What’s left to do:
All goals outlined in my proposal have been completed, I added Keymapper support to the 23(The first one was not part of proposal) engines I had committed to. Beyond the scope of the proposal, there are still around 40 engines in ScummVM without Keymapper support, which could be future work for anyone interested in continuing this effort.


List of PRs:

  1. Toltecs keymapper: Pull Request
  2. Sludge keymapper: Pull Request
  3. Supernova keymapper: Pull Request
  4. Voyeur keymapper: Pull Request
  5. Titanic keymapper: Pull Request
  6. Normalize keymapper action descriptions: Pull Request
  7. Sword25 keymapper: Pull Request
  8. TeenAgent keymapper: Pull Request
  9. NGI keymapper: Pull Request
  10. Buried keymapper: Pull Request
  11. Access keymapper: Pull Request
  12. EFH keymapper: Pull Request
  13. Sherlock keymapper: Pull Request
  14. Neverhood keymapper: Pull Request
  15. Prince keymapper: Pull Request
  16. Lab keymapper: Pull Request
  17. Petka keymapper: Pull Request
  18. Queen keymapper: Pull Request
  19. Fix capitalization in Queen keymapper action descriptions: Pull Request
  20. Pink keymapper: Pull Request
  21. Drascula keymapper: Pull Request
  22. Chamber keymapper: Pull Request
  23. Make EFH keymapper table use POD and avoid global constructors: Pull Request
  24. Hypno keymapper: Pull Request
  25. DM keymapper: Pull Request
  26. Private keymapper: Pull Request

Any challenges or important things you learned during the project:
Each engine in ScummVM handles input differently, so I had to study and adapt to new codebases before adding Keymapper support. In doing so, I often uncovered and fixed unrelated bugs. Working on a new engine every 3–4 days also greatly improved my ability to read, understand, and modify existing code, and gave me confidence in working with large, mature projects.


Conclusion:
This project successfully achieved its goals by bringing Keymapper support to 24 engines in ScummVM, making input more flexible and accessible for players. Along the way, I learned how to work effectively with large codebases and contribute to a mature open-source project. I’d like to thank my mentors and the ScummVM team for their guidance and support, and GSoC for giving me the opportunity to work on a project that will benefit both developers and players.

Categories
week 12

Week 12: Keymapper Support for Hypno and Dungeon Master

This week I worked on the Hypno and Dungeon Master engines. I also got my Chamber keymapper PR merged 🎉.


Hypno Engine

Working on the Hypno engine felt a bit nostalgic—it was actually the first engine I touched in ScummVM when I fixed a small bug as an intake task for GSoC.

The engine supports three different games, each with its own input handling. Because of this, I had to create separate keymaps for each game, rather than a single shared one.

Apart from that, the implementation was fairly straightforward. The main tasks were:

  • Disabling the keymapper in certain sections where the game uses full keyboard input

  • Enabling/disabling keymaps for some of the menus

Nothing particularly tricky, but it was nice to revisit the engine where my GSoC journey began.


Dungeon Master Engine

Dungeon Master was another unannounced engine that I added keymapper support to. Fortunately, it didn’t have any blocking bugs or missing features, so I was able to test it thoroughly without issues.

The engine came with a decent number of keys to map, but overall the process was smooth and didn’t pose any significant difficulties.


Wrap-Up

This week, I:

  • Added keymapper support for Hypno and Dungeon Master

  • Got my Chamber PR merged 🎉

Categories
Week 11

Week 11: Keymapper Support for Drascula and Chamber

This week I worked on two more engines: Drascula and Chamber. I also got my PRs for the Pink, EFH, Drascula, and Lab engines merged 🎉.


Drascula Engine

The Drascula engine wasn’t particularly difficult, but it came with a decent number of keys and keymaps. The process was straightforward overall, though it was somewhat time-consuming due to the sheer amount of keys that needed replacing.

One interesting aspect of this engine was that I came across my first in-game easter egg while testing the key actions—definitely a fun surprise during the work.

I also had to handle enabling and disabling keymaps in a few spots. Nothing too complicated, but still took time.


Chamber Engine

Chamber became my second unannounced engine (after Sludge engine) where I added keymapper support. Normally, I’ve been focusing only on announced and tested engines, to avoid running into unrelated bugs that might interfere with the keymapper work.

In this case, I only realized the engine was unannounced after I had already started working on it. Since I didn’t encounter any gameplay-breaking issues, I decided to go ahead and finish the keymapper implementation.

The work itself was on the simpler side. Chamber only had a handful of keys, and just a single keymap that needed to be toggled on and off. Figuring this out was quick and straightforward.


Wrap-Up

This week, I:

  • Added keymapper support for Drascula and Chamber

  • Got my Pink, EFH, Drascula, and Lab PRs merged 🎉

Categories
Week 10

Week 10: Queen and Pink Engines

This week I worked on adding keymapper support to the Queen and Pink engines. On top of that, I also got my Neverhood, Prince, and Queen keymapper PRs merged.


Queen Engine

The Queen engine was moderately challenging. It came with a good number of keys, but the real twist was the variable keybinds for some actions. these depended on the language of the player’s copy of the game. This was somewhat similar to what I encountered earlier in the Sherlock engine.

Another tricky part was that the keybind selection logic was embedded deep in the engine code. To make it compatible with the keymapper, I had to refactor the code so that the language-based key selection happened in the keymapper section instead. This made it accessible for usage in the keymapper initialization.

Some sections of the game also needed keymapper toggling. those were relatively straightforward to set up.


Pink Engine

Pink, at first glance, seemed simpler—fewer than 10 keys in total. But as always, appearances can be deceiving.

In the game, you can’t move your character freely. Movement only happens when you click an interactable object or character, at which point the character walks to the target and interacts with it automatically.

The key actions didn’t just trigger standard gameplay—they altered this entire interaction sequence. For example:

  • One action skips the walking animation entirely.

  • Another lets you walk to the target but cancels the interaction.

  • Yet another skips both walking and interaction, simply teleporting you there.

There were also keys that modified or skipped the sequence that plays when you interact with a target—like skipping a conversation, skipping part of it, or even restarting a dialog from the beginning if you missed something.

Identifying exactly what each key did was the hardest part here, but once that was figured out, mapping them to the keymapper went smoothly.


Wrap-Up

This week, I:

  • Added keymapper support for the Queen and Pink engines

  • Got my Neverhood, Prince, and Queen PRs merged 🎉

Categories
Week 9

Week 9: Lab and Petka

This week, I focused on adding keymapper support to two engines: Lab (used by The Labyrinth of Time) and Petka (used by Red Comrades 1 and 2)


Lab Engine

The Lab engine was moderately complex due to the game’s dual-interface design. The Labyrinth of Time features two main interaction modes: a point-and-click exploration interface and an inventory screen. This meant I had to track which interface the player was currently in and enable or disable the appropriate keymappers accordingly.

There are multiple ways to switch between these modes—such as right-clicking or clicking the inventory button—so I had to carefully identify and hook into all the transitions to ensure the keymappers toggled appropriately.

I also encountered, for the first time, a case where the game interface slightly varied depending on the version of the game. It was a simple adjustment but interesting to note.


Petka Engine

In contrast, Petka was simple and quick to implement. The game uses only a few keys and has a single interface, so a single keymapper was sufficient.

The only minor complication was the language barrier—the game is entirely in Russian, which made understanding certain actions and UI flows a bit more difficult. However, with some investigation and context clues, I was able to complete the mapping without major issues.


Wrap-Up

This week, I:

  • Implemented keymapper support for the Lab engine

  • Implemented keymapper support for the Petka engine
Categories
Week 8

Week 8: Keymapper Support for Neverhood and Prince Engines

After the intense and complex work on the Sherlock engine last week, this week felt like a welcome break. I focused on implementing keymapper support for two much simpler engines: Neverhood and Prince. Both were relatively lightweight in terms of required effort and complexity.


Neverhood Engine

The Neverhood engine was straightforward to work with. It has only a few core actions and menus, so mapping keys was a smooth process. I created keymaps for the available actions and then located the appropriate points in the code to enable and disable specific keymappers as needed.

Despite the simplicity, it was still important to ensure that everything was well integrated and that there were no unintended conflicts. Once the mappings were set up and tested, everything worked as expected.


Prince Engine

The Prince engine was even easier to handle. It involves only a few key actions, and unlike other engines, it didn’t require any additional keymapper switching logic. One keymap was enough to cover the entire gameplay.

Because of its simplicity, I didn’t need to worry about enabling or disabling different keymaps during runtime, which made the process very efficient.


Wrap-Up

This week, I:

  • Added keymapper support for the Neverhood engine

  • Added keymapper support to the Prince engine

Categories
Week 7

Week 7: Sherlock Engine Keymapper

This week was a major milestone: I passed my midterm evaluations! 🎉 Right after that, I dove straight into one of the most complex engines so far—the Sherlock engine. I also got my Buried and Access keymapper PRs merged earlier in the week.

Sherlock Engine

The Sherlock engine supports two games from The Lost Files of Sherlock Holmes series:

  • The Case of the Serrated Scalpel
  • The Case of the Rose Tattoo

This engine was by far the most complex I’ve worked on, with around 2000 insertions and 600 deletions. Both games have separate input handling code, yet they share some common code. This made changes particularly delicate—I had to make sure that updating one game’s behavior wouldn’t break the other.

The Case of the Serrated Scalpel

This game turned out to be the trickiest, mainly because it’s localized in 5 different languages. Each language has its own translated UI, including verbs like “Look” or “Talk”.

Why does this matter?
The game uses the first letter of a verb/option to trigger it via keyboard shortcuts. For example, “L” for “Look” (or its translated equivalent). Thankfully, the engine code already had these localized key bindings stored. I leveraged that to bind the correct keys to actions dynamically, based on the game’s language.

Another subtle challenge was visual feedback: when a verb is selected, the corresponding UI button appears pressed. If the player selects a different verb or deselects the current one, the button should visually “pop back out.” Implementing this required extra logic to track which verb is active and update the UI accordingly.

Also, the sheer number of possible actions took significant time to map properly.

The Case of the Rose Tattoo

Compared to Scalpel, this one had a slightly easier path since it’s not localized. Hence no need to worry about language-specific keybindings.

However, it still had more total actions, which made the task just as time-consuming. The logic was a bit cleaner here, so once the actions were identified, the process went fairly smoothly.


Wrap-Up

This week, I:

  • Passed my midterm evaluations 🎉
  • Got my Buried and Access keymapper PRs merged🎉
  • Implemented keymapper support for the Sherlock engine
Categories
Week 6

Week 6: EFH Keymapper and PR Cleanups

This week, I focused on implementing keymapper support for the Escape from Hell (EFH) engine and addressing feedback on my previous PRs. I also had three of my earlier PRs merged: Tetraedge, Sword25, and Teenagent.


EFH Engine

EFH was by far the most involved keymapper implementation I’ve done so far. Unlike other engines, EFH is controlled entirely via the keyboard—there’s no mouse support at all. This meant that without a proper keymapper, the game was essentially unplayable on devices without physical keyboards.

I started by listing out all the keys used in various gameplay scenarios and organizing them into 11 distinct keymaps. To make switching between these keymaps easier, I wrote a helper function that takes an enum and switches the keymapper context accordingly.

What made this implementation even trickier was that a previous contributor had partially implemented keymapper support—mainly for movement and a few other actions. While their work gave me a helpful starting point, I noticed a few issues:

  • Some important keys were missing or not fully mapped.

  • The partial mapping led to conflicts with unmapped actions.

To resolve this, I reviewed their commits to recover any missed inputs and reworked the implementation to cover all keyboard actions comprehensively. Once everything was mapped properly, the conflicts disappeared, and the engine behaved as expected. It took a while, but the process was smooth overall.


Fixes to Previous PRs

Alongside EFH, I also fixed some minor typos in the action descriptions across a few older PRs.

More importantly, I revisited the workaround I had written for the Access engine last week. That engine uses internal numeric codes for verbs rather than relying on keycodes, so I had initially matched keymapper actions to verb codes by relying on the order of actions—calculating the verb code by subtracting a base value.

A mentor correctly pointed out that this was dangerous. If someone ever changed the action order in the future, it would silently break. To fix this, I replaced the order-based logic with a proper mapping table that explicitly associates each action with its corresponding verb code. The function now loops through this table and passes the appropriate internal code only when a match is found—much safer and more maintainable.

Another improvement based on mentor feedback: I removed all engine-specific key bindings for the GMM (Global Main Menu). Since it’s already mapped in the global keymap, duplicating it in engine keymaps is unnecessary and could lead to confusion.

 


Wrap-Up

This week, I:

  • Implemented keymapper support for the EFH engine
  • Updated my previous keymapper PRs
  • Got my Tetraedge, Sword25, and Teenagent keymapper PRs merged 🎉
Categories
Week 5

Week 5: Buried and Access

This week, I focused on bringing keymapper support to two more engines: Buried and Access. Both engines came with their own set of challenges


Buried

The Buried engine had an unusual approach to input: it handled most keypresses on key release rather than on key press.

In terms of actual key replacement, there wasn’t much heavy lifting to do. However, the real challenge—like in some of the previous engines—was figuring out when to activate or deactivate keymaps. Buried has different contexts where certain keymaps should be enabled or ignored, and tracing that logic took the majority of my time this week.

Once I understood those transitions, hooking up the rest of the keymapper functionality was fairly smooth.


Access

Access was easier to work with in comparison, but it did come with one major twist: it used function keys (like F1, F2, etc.) to change the current active verb in the game.

The function responsible for switching verbs didn’t rely on keycodes—it used internal numeric codes corresponding to different verbs. I couldn’t just update that function to use actions instead, because it was used in other parts of the engine where those codes were passed directly.

To solve this, I came up with a workaround: I mapped keymapper actions to these verb codes by ensuring the actions were written in a specific order, and then calculated the correct internal code by subtracting a default base. It’s not the cleanest solution, but it worked without requiring intrusive changes to the engine’s logic.


Wrap-Up

This week, I:

  • Implemented keymapper support for Buried and Access

Next week, I’ll continue expanding support to more engines—each one bringing its own surprises.

Categories
Week 4

Week 4: Sword25, TeenAgent and NGI

This week, I focused on bringing keymapper support to three engines: Sword25, Teenagent, and NGI. Each had its own quirks, but none were too complex—so I was able to make steady progress across the board.


Sword25

The Sword25 engine uses script-driven input handling. That made things straightforward—no refactoring needed.

My job here was mostly investigative: figure out what each key does and document it for the keymapper. Since input behavior was defined in scripts, I didn’t need to touch much engine-level code. The entire process was smooth and quick.


Teenagent

Teenagent was also fairly simple. It involved defining a few custom actions for specific keys and setting up mouse input. The engine doesn’t have complex input modes or conditionally processed input, so once I identified the key behaviors, wiring up the keymapper didn’t take long.


NGI

The NGI engine was the most challenging of the three this week. While it didn’t introduce any new types of problems, it did have more keys and more complexity around where input is processed.

One big issue: keys pressed during menus, modals, or intros weren’t processed through the same input flow as in-game actions. That meant keymapper actions would either:

  • Be ignored in certain contexts, or worse…

  • Be interpreted in places they shouldn’t be

To fix this, I had to carefully trace the engine’s input handling paths and add logic to enable or disable the keymapper at the right times. Most of my time on NGI was spent understanding those flows and placing the toggles precisely.

Once that was in place, implementing custom actions and mapping key behaviors was straightforward.


Wrap-Up

This week, I:

  • Implemented keymapper support for Sword25, Teenagent, and NGI
  • Got the NGI keymapper PR merged
  • Got the keymapper action label normalization PR merged

Next week, I’ll continue this momentum and explore new engines.