A project log for Oh Cheat!

USB keystroke generator for quick typing cheat codes in games like GTA.

danjovicdanjovic 01/22/2016 at 15:500 Comments

I have found the problem with GTA: The game kinda sample the keyboard state, so if the key remain pressed for a few time it won't be recognized. I got that insight when I realized that sometimes the game recognized one of the keys (like A that makes the character move left).

By analyzing Digispark.h I have noticed that the SendKeyStroke function sends a key up right after the key pressed.

  void sendKeyStroke(byte keyStroke, byte modifiers) {
   	while (!usbInterruptIsReady()) {
    memset(reportBuffer, 0, sizeof(reportBuffer));		
    reportBuffer[0] = modifiers;
    reportBuffer[1] = keyStroke;
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
    while (!usbInterruptIsReady()) {

         /*   HERE WAS THE PROBLEM WITH GTA   */

    // This stops endlessly repeating keystrokes:  
    memset(reportBuffer, 0, sizeof(reportBuffer));      
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));

To solve that without messing with the Digispark routines I have simply copied the code into my sketch and ripped off the last two lines of code that send the zero (no key).

The compiler complained about a missing definition of reportBuffer variable. Strangely enough the definition of such variable is not defined on DigiKeyboard.h. (it is defined in DigiMouse.h and DigiJoystick.h though!).

To fix it I have just created the variable and it compiled (and worked as well).

//   __   __        _      _    _
//   \ \ / /_ _ _ _(_)__ _| |__| |___ ___
//    \ V / _` | '_| / _` | '_ \ / -_|_-<
//     \_/\__,_|_| |_\__,_|_.__/_\___/__/
uint8_t ticks = 0;
uint8_t lastkey = 0;
uint8_t temp, key;
uchar     reportBuffer[2];
I have also added a custom 'print' function that for each character sent to host it waits a small delay and then sends a zero (no press).
// Print a string to the host, and add a key up after a delay 
void DigiKeyboard_print ( char *str ) {
  uint8_t data;
  while (*str) {
    data = pgm_read_byte_near(ascii_to_scan_code_table + (*str++ - 8));
    sendKeyStroke_nostop(data & 0b01111111, data >> 7 ? MOD_SHIFT_RIGHT : 0);
I have fiddled with this delay and found that 20ms is not enough but 50ms is fine.

Bug Busted!!