Optional dump key and output path features #458

Merged
lobotomy-x merged 15 commits from dump-key into main 2026-04-17 23:08:50 +02:00
lobotomy-x commented 2026-01-05 04:02:54 +01:00 (Migrated from github.com)

Dump Key feature

  • off by default, can be set in the profile taking either a decimal or hex int value corresponding to VK scancode
  • when enabled the startup process uses a detached thread to listen for keypresses, this has been streamlined from previous pr by using a lambda
  • actual value of the key is printed to the console during config load which is helpful if the user has a local overriding profile and is generally just nice QOL
  • requires std::thread and std::atomic to compile

Sleep timeout feature

  • logic has been simplified and actually uses fewer conditionals either way
  • when no dump key is set we just Sleep without bothering to check as the default value of 0 will yield the thread which effectively does nothing
  • if we have a key setup then inside the same loop we do a shortcircuited eval that checks the elapsed time only if a sleep timeout
  • timeout is expected in ms as usual but when its less than 1000 we can assume the user probably wants it in seconds so we automatically convert that
  • timeout settings are printed during config load just to clean up the main thread a little bit

SDK path

  • very minimal implementation, no environment variables or anything related to the dll file location in this patch
  • If an absolute path is given it will work as expected, otherwise its relative to the game working dir and can use .. to access parent paths

The one change I see as possibly controversial is calling using namespace std::chrono in main thread. I did this to avoid having to wrap the short-circuited conditional that checks for the timeout and I also adjusted the final time calculation to use the same code and handle it inline with the print statement. If you prefer not to import the namespace or would rather use a shorthand as we already did for fs = filesystem in settings I can rewrite that. But its just an aesthetic change so if you don't mind it then I think we're good

I also did include a block of code that makes it so clicking and highlighting text on the console won't block the thread but I left it commented out in case thats an intended feature. I thought it made sense to leave it there for anyone compiling themselves since its not super well known and I personally find it annoying when I accidentally freeze a game.

I did not bother with the example config and separate doc I had done earlier but I did add some basic explanation of features in the readme and anyone who builds it themselves should find adequate explanation in the comments as to why things are done the way they are.

The detached thread inside the lambda is very well tested and isn't particularly fragile imo but if someone who has no clue what they're doing goes and tries to mess with that section they will probably have a bad time. e.g. if they want to capture another variable declared in the main thread, ignore the comment, and pass it by reference instead of by value it will 100% crash every time. So if you end up getting issues made about std::terminate or dangling reference crashes I would probably just tell them not to touch what they don't understand. I don't mind being tagged in an issue though and I'll add that if you wanted to ever update to C++ 20+ we can make it more thread safe with jthreads but I wasn't gonna push for that and I think this is totally fine as is.

**Dump Key feature** - off by default, can be set in the profile taking either a decimal or hex int value corresponding to VK scancode - when enabled the startup process uses a detached thread to listen for keypresses, this has been streamlined from previous pr by using a lambda - actual value of the key is printed to the console during config load which is helpful if the user has a local overriding profile and is generally just nice QOL - requires std::thread and std::atomic to compile **Sleep timeout feature** - logic has been simplified and actually uses fewer conditionals either way - when no dump key is set we just Sleep without bothering to check as the default value of 0 will yield the thread which effectively does nothing - if we have a key setup then inside the same loop we do a shortcircuited eval that checks the elapsed time only if a sleep timeout - timeout is expected in ms as usual but when its less than 1000 we can assume the user probably wants it in seconds so we automatically convert that - timeout settings are printed during config load just to clean up the main thread a little bit **SDK path** - very minimal implementation, no environment variables or anything related to the dll file location in this patch - If an absolute path is given it will work as expected, otherwise its relative to the game working dir and can use .. to access parent paths The one change I see as possibly controversial is calling `using namespace std::chrono` in main thread. I did this to avoid having to wrap the short-circuited conditional that checks for the timeout and I also adjusted the final time calculation to use the same code and handle it inline with the print statement. If you prefer not to import the namespace or would rather use a shorthand as we already did for fs = filesystem in settings I can rewrite that. But its just an aesthetic change so if you don't mind it then I think we're good I also did include a block of code that makes it so clicking and highlighting text on the console won't block the thread but I left it commented out in case thats an intended feature. I thought it made sense to leave it there for anyone compiling themselves since its not super well known and I personally find it annoying when I accidentally freeze a game. I did not bother with the example config and separate doc I had done earlier but I did add some basic explanation of features in the readme and anyone who builds it themselves should find adequate explanation in the comments as to why things are done the way they are. The detached thread inside the lambda is very well tested and isn't particularly fragile imo but if someone who has no clue what they're doing goes and tries to mess with that section they will probably have a bad time. e.g. if they want to capture another variable declared in the main thread, ignore the comment, and pass it by reference instead of by value it will 100% crash every time. So if you end up getting issues made about std::terminate or dangling reference crashes I would probably just tell them not to touch what they don't understand. I don't mind being tagged in an issue though and I'll add that if you wanted to ever update to C++ 20+ we can make it more thread safe with jthreads but I wasn't gonna push for that and I think this is totally fine as is.
Fischsalat commented 2026-01-10 13:42:42 +01:00 (Migrated from github.com)
  1. No using namespace anything
  2. Please match the coding-style to the rest of the codebase (See UE Coding Standard minus all of the prefixes.
  3. Why does waiting/checking-keys need a new thread?
  4. Was any of this code written with AI, if so, which part?
1. No `using namespace` anything 2. Please match the coding-style to the rest of the codebase (See [UE Coding Standard](https://dev.epicgames.com/documentation/en-us/unreal-engine/epic-cplusplus-coding-standard-for-unreal-engine) minus all of the prefixes. 3. Why does waiting/checking-keys need a new thread? 4. Was any of this code written with AI, if so, which part?
lobotomy-x commented 2026-01-19 06:54:49 +01:00 (Migrated from github.com)
  1. Done
  2. I believe this should be good. Opted for slightly clearer and more verbose style as mentioned in the page
  3. Its not. I was mistaken although it is a common design option its not relevant and needed here after all. I did originally have issues with the dump proceeding on its own or the dll unloading when trying to do it in a single thread but I realize now that I was testing on a fork with a proxy loader so the game calling functions that referenced our dll may have been the issue or it might have been some problems with loading too early. Either way I have removed the lambda and threading entirely with no loss in functionality. I think I got carried away with fixing the threading related bugs and forgot to actually verify it was needed on a clean branch when I returned to this recently.
  4. No AI gen here, I do not trust it with C++ and have tab autocomplete disabled because it annoys me. I did use the info gemini shows when googling about asynckeyinput issues but only as a general reference. I do also use the analyze with copilot function in visual studio when debugging as it does a good job finding the actual relevant code and saves me some reading, just have to ignore the code suggestions.
1. Done 2. I believe this should be good. Opted for slightly clearer and more verbose style as mentioned in the page 3. Its not. I was mistaken although it is a common design option its not relevant and needed here after all. I did originally have issues with the dump proceeding on its own or the dll unloading when trying to do it in a single thread but I realize now that I was testing on a fork with a proxy loader so the game calling functions that referenced our dll may have been the issue or it might have been some problems with loading too early. Either way I have removed the lambda and threading entirely with no loss in functionality. I think I got carried away with fixing the threading related bugs and forgot to actually verify it was needed on a clean branch when I returned to this recently. 4. No AI gen here, I do not trust it with C++ and have tab autocomplete disabled because it annoys me. I did use the info gemini shows when googling about asynckeyinput issues but only as a general reference. I do also use the analyze with copilot function in visual studio when debugging as it does a good job finding the actual relevant code and saves me some reading, just have to ignore the code suggestions.
Fischsalat commented 2026-02-01 00:23:24 +01:00 (Migrated from github.com)

Ok thank you for cleaning up things and providing this pull request in the first place. I apologize for the long delay before this response, I was quite busy lately.

The last thing I'll ask of you is to move the if-else block at Main.cpp:32 into a subfunction to keep main clean. Maybe in Settings.cpp add void Settings::Config::WaitForDumperToStart(). After such a change is made I will merge this pullrequest.

Ok thank you for cleaning up things and providing this pull request in the first place. I apologize for the long delay before this response, I was quite busy lately. The last thing I'll ask of you is to move the if-else block at `Main.cpp:32` into a subfunction to keep main clean. Maybe in Settings.cpp add `void Settings::Config::WaitForDumperToStart()`. After such a change is made I will merge this pullrequest.
lobotomy-x commented 2026-02-14 00:17:15 +01:00 (Migrated from github.com)

Hey, no worries at all, I've been taking my sweet time with this. And I'm actually glad you held me to higher standards because I've just recently started a job as an unreal engine dev and we use Epic code standards so the review was helpful.

I think this should be all good now although its hard to say for sure since github does not display whitespace. But I think the functionality is what you're looking for

Hey, no worries at all, I've been taking my sweet time with this. And I'm actually glad you held me to higher standards because I've just recently started a job as an unreal engine dev and we use Epic code standards so the review was helpful. I think this should be all good now although its hard to say for sure since github does not display whitespace. But I think the functionality is what you're looking for
Fischsalat commented 2026-02-14 00:28:36 +01:00 (Migrated from github.com)

That is very nice to hear, I wish you success in your new job! I'll test the code in the next few days and then I'll merge it.

That is very nice to hear, I wish you success in your new job! I'll test the code in the next few days and then I'll merge it.
Sign in to join this conversation.
No description provided.