-
-
Notifications
You must be signed in to change notification settings - Fork 152
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AUTOTYPE performs scripted keyboard entry into the running DOS program. It can be used to reliably skip intros, answer Q&A style questions that some games ask on startup, or conduct a simple demo. It allows for delaying input by any number of fractional seconds, as well defining the pacing between keystrokes. It uses the comma character "," to insert additional delays similar to modern phone numbers. It uses key_* names as defined by the mapper to avoid using SDL scancodes[1], which are unstable across platforms. This approach also allows the triggering of custom key bindings the use has defined. [1] https://wiki.libsdl.org/SDL_GetScancodeName "Warning: The returned name is by design not stable across platforms, e.g. the name for SDL_SCANCODE_LGUI is "Left GUI" under Linux but "Left Windows" under Microsoft Windows, and some scancodes like SDL_SCANCODE_NONUSBACKSLASH don't have any name at all. There are even scancodes that share names, e.g. SDL_SCANCODE_RETURN and SDL_SCANCODE_RETURN2 (both called "Return"). This function is therefore unsuitable for creating a stable cross-platform two-way mapping between strings and scancodes."
- Loading branch information
Showing
11 changed files
with
377 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
#include <algorithm> | ||
#include <cmath> | ||
#include <iomanip> | ||
#include <iostream> | ||
#include <limits> | ||
#include <string> | ||
#include <sstream> | ||
|
||
#include "support.h" | ||
#include "mapper.h" | ||
#include "dosbox.h" | ||
#include "programs.h" | ||
#include "program_autotype.h" | ||
|
||
void AUTOTYPE::PrintUsage() { | ||
WriteOut( | ||
"\033[32;1mAUTOTYPE\033[0m [-list] [-w WAIT] [-p PACE] button_1 [button_2 [...]] \n\n" | ||
"Where:\n" | ||
" -list: prints all available button names.\n" | ||
" -w WAIT: seconds before typing begins. Two second default; max of 30.\n" | ||
" -p PACE: seconds between each keystroke. Half-second default; max of 10.\n" | ||
"\n" | ||
" The sequence is comprised of one or more space-separated buttons.\n" | ||
" Autotyping begins after WAIT seconds, and each button is entered \n" | ||
" every PACE seconds. The , character inserts an extra PACE delay.\n" | ||
"\n" | ||
"Some examples:\n" | ||
" \033[32;1mAUTOTYPE\033[0m -w 1 -p 0.3 up enter , right enter\n" | ||
" \033[32;1mAUTOTYPE\033[0m -p 0.2 1 3 , , enter\n" | ||
" \033[32;1mAUTOTYPE\033[0m -w 1.3 esc esc esc enter p l a y e r enter\n"); | ||
} | ||
|
||
// Prints the key-names for the mapper's currently-bound events. | ||
void AUTOTYPE::PrintKeys() { | ||
const std::vector<std::string> names = MAPPER_GetEventNames("key_"); | ||
|
||
// Keep track of the longest key name | ||
size_t max_length = 0; | ||
for (const auto &name : names) | ||
max_length = (std::max)(name.length(), max_length); | ||
|
||
// Sanity check to avoid dividing by 0 | ||
if (!max_length) { | ||
WriteOut("AUTOTYPE: The mapper has no key bindings\n"); | ||
return; | ||
} | ||
|
||
// Setup our rows and columns | ||
const size_t console_width = 72; | ||
const size_t columns = console_width / max_length; | ||
const size_t rows = ceil_udivide(names.size(), columns); | ||
|
||
// Build the string output by rows and columns | ||
std::stringstream ss; | ||
auto name = names.begin(); | ||
for (size_t row = 0; row < rows; ++row) { | ||
for (size_t i = row; i < names.size(); i += rows) | ||
ss << std::setw(max_length + 1) << name[i]; | ||
ss << std::endl; | ||
} | ||
|
||
WriteOut(ss.str().c_str()); | ||
} | ||
|
||
/* | ||
* Reads a floating point argument from command line, where: | ||
* - name is a human description for the flag, ie: DELAY | ||
* - flag is the command-line flag, ie: -d or -delay | ||
* - default is the default value if the flag doesn't exist | ||
* - value will be populated with the default or provided value | ||
* | ||
* Returns: | ||
* true if 'value' is set to the default or read from the arg. | ||
* false if the argument was used but could not be parsed. | ||
*/ | ||
bool AUTOTYPE::ReadDoubleArg(const std::string &name, | ||
const char *flag, | ||
const double &def_value, | ||
const double &min_value, | ||
const double &max_value, | ||
double &value) { | ||
bool result = false; | ||
std::string str_value; | ||
// Is the user trying to set this flag? | ||
if (cmd->FindString(flag, str_value, true)) { | ||
double user_value; | ||
|
||
// Can the user's value be parsed? | ||
if (str_to_double(str_value, user_value)) { | ||
result = true; | ||
// Clamp the user's value if needed | ||
value = clamp(user_value, min_value, max_value); | ||
|
||
// If we had to clamp the users value, then inform them | ||
if (std::fabs(user_value - value) > std::numeric_limits<double>::epsilon()) | ||
WriteOut("AUTOTYPE: bounding %s value of %.2f to %.2f\n", | ||
name.c_str(), user_value, value); | ||
// Otherwise inform them we couldn't parse their value | ||
} else { | ||
WriteOut("AUTOTYPE: %s value '%s' is not a valid floating point number\n", | ||
name.c_str(), str_value.c_str()); | ||
} | ||
// Otherwise the user hasn't set this flag, so use the default | ||
} else { | ||
value = def_value; | ||
result = true; | ||
} | ||
return result; | ||
} | ||
|
||
void AUTOTYPE::Run() { | ||
|
||
//Hack To allow long commandlines | ||
ChangeToLongCmd(); | ||
|
||
// Usage | ||
if (!cmd->GetCount()) { | ||
PrintUsage(); | ||
return; | ||
} | ||
|
||
// Print available keys | ||
if (cmd->FindExist("-list", false)) { | ||
PrintKeys(); | ||
return; | ||
} | ||
|
||
// Get the wait delay in milliseconds | ||
double wait_s; | ||
constexpr double def_wait_s = 2.0; | ||
constexpr double min_wait_s = 0.0; | ||
constexpr double max_wait_s = 30.0; | ||
if (!ReadDoubleArg("WAIT", "-w", def_wait_s, min_wait_s,max_wait_s, wait_s)) | ||
return; | ||
const auto wait_ms = static_cast<uint32_t>(wait_s * 1000); | ||
|
||
// Get the inter-key pacing in milliseconds | ||
double pace_s; | ||
constexpr double def_pace_s = 0.5; | ||
constexpr double min_pace_s = 0.0; | ||
constexpr double max_pace_s = 10.0; | ||
if (!ReadDoubleArg("PACE", "-p", def_pace_s, min_pace_s, max_pace_s, pace_s)) | ||
return; | ||
const auto pace_ms = static_cast<uint32_t>(pace_s * 1000); | ||
|
||
// Get the button sequence | ||
std::vector<std::string> sequence; | ||
cmd->FillVector(sequence); | ||
if (sequence.empty()) { | ||
WriteOut("AUTOTYPE: button sequence is empty\n"); | ||
return; | ||
} | ||
MAPPER_AutoType(sequence, wait_ms, pace_ms); | ||
} | ||
|
||
void AUTOTYPE_ProgramStart(Program * *make) { | ||
*make = new AUTOTYPE; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#include "programs.h" | ||
|
||
class AUTOTYPE : public Program { | ||
public: | ||
void Run(); | ||
private: | ||
void PrintUsage(); | ||
void PrintKeys(); | ||
bool ReadDoubleArg(const std::string &name, | ||
const char *flag, | ||
const double &def_value, | ||
const double &min_value, | ||
const double &max_value, | ||
double &value); | ||
}; | ||
|
||
void AUTOTYPE_ProgramStart(Program * *make); |
Oops, something went wrong.