Close
0%
0%

Oh Cheat!

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

Similar projects worth following
OH CHEAT is a keystroke generator designed for quick introducing cheat codes in games like GTA series, but can also be modified for other purposes like shooting a Haduken or performing a Fatality.

The circuit is based on Digispark and provide support for up to 7 keys, but this number can be increased by using shift registers or another method.

Of course it is possible to use some application for performing the same function when typing the function keys but hey, what's the fun on that?

This project is dedicated to Joey, Paul, Willy and Frankie.

The heart of the project is the DigiKeyboard library for Digispark. All i have to do is debounce the buttons and once one of them is stroked (after 100ms of debounce) the cheat is sent by the command

DigiKeyboard.print("cheat"); 

Digispark have 4 I/O pins but one of them is connected to ground by a LED. So I have 3 pins with pullups to work. The simplest way of doing that is my encoding the buttons using a matrix of diodes. Apart the zero, we have then 7 logic states to work with.

When the first key is pressed, only PB0 goes to ground. The second key makes PB2 go to ground. The third key make both go low. The fourth make PB5 go low and so on.

Unfortunately DigiKey connector disposition is a mess. The I/O pins header misses a GND and VCC what makes life tough if you want to make a plug-in board that needs power. As for this project I only needed a ground reference for the switches and then I used the PB1 pin to work as a virtual ground by using it as an output at zero level. Then I could design a board that can be plugged in directly in DigiSpark.

By the Way the name of the project is a reference to PAC MAN for MSX computers that literally screams Oh Sh** when the player is bit by a ghost whose names are:


  • 1 × Digispark
  • 12 × 1N4148 Discrete Semiconductors / Diodes and Rectifiers
  • 7 × Tactile Switch

  • Entry for HAD 2016 prize, Phase 4: Automation

    danjovic07/11/2016 at 20:57 0 comments

    I've decided to apply this project to phase 4 of Hackaday 2016 prize which involves automation. This post is to clarify/complete some information required;

    About the challenge:

    The project was conceived for playing "GTA" game series in a PC computer by automate the entry of cheat codes composed by single keystrokes.

    About the licenses/permissions:

    The project is released underGPL 2.0.

    About Third party licences/restrictions

    The project is based on Digi-Spark board.

    Copyright of information used on the article.

    "Oh Sh*t!" game was property of Aackosoft International B.V. (now extinct)

    "MSX" is a trademark fromASCII Corporation

    "GTA San Andreas" is a trademark from Rockstar

  • Video: Oh Cheat! in Action

    danjovic02/09/2016 at 17:50 0 comments

    Here you are a small video of Oh Cheat! in action playing GTA San Andreas.

  • Usinga a Chinese Digispark Clone

    danjovic02/06/2016 at 11:33 0 comments

    The Chinese Digispark clones are very cheap and have a female USB connector which is good but they ship with RESET enabled which means that PB5 is not available for use.

    To perform the change it is necessary to change the HFuse configuration of the ATTiny85.

    I have used AVeRCADE with USBasp firmware for doing that, but any ISP programmer will do fine. The connections to a 10 pin are show below. However it is possible to use other methods, for example using an Arduino (link).

    The command for programming the High fuse to its correct configuration is:
    avrdude -c usbasp -p t85 -U hfuse:w:0x5f:m
    If everything works fine you should see something like that

  • Standalone board design

    danjovic01/28/2016 at 17:24 0 comments

    I've created a standalone design for the board, single sided and using only pth components.

  • Extended Digispark Keyboard library

    danjovic01/25/2016 at 23:37 3 comments

    I've made an extension to the SendKeyStroke method of DigiKeyboard.h by adding a key down time parameter.

    SendKeyStroke method now has a third parameter to allow the simulation of pressing time (in milliseconds) that the key remains pressed until is released.

    void sendKeyStroke(byte keyStroke, byte modifiers, uint16_t key_down_time);

    If 'key_down_time' is zero then don't release the key, it should be done manually by sendKeysStroke(0). As 'zero' means forever, the minimum press time time is 1ms and the maximum is 65535ms.

    Examples:

    DigiKeyboard.sendKeyStroke(KEY_B);        // Send a B to host
    DigiKeyboard.sendKeyStroke(KEY_A,0,300); // Send an A to host, takes 300ms until release
    
    DigiKeyboard.sendKeyStroke(KEY_C,0,0);    //Send a C to host and keep it pushed
    DigiKeyboard.delay(2000);                 // wait 2 seconds
    DigiKeyboard.sendKeyStroke(0);            // now release any key pressed.

    Tried to send a pull request to original project but without success, though. Either way the extended function is below:

      void sendKeyStroke(byte keyStroke, byte modifiers, uint16_t key_down_time) {
       	while (!usbInterruptIsReady()) {
          // Note: We wait until we can send keystroke
          //       so we know the previous keystroke was
          //       sent.
        	usbPoll();
        	_delay_ms(5);
        }
        
        memset(reportBuffer, 0, sizeof(reportBuffer));
    		
        reportBuffer[0] = modifiers;
        reportBuffer[1] = keyStroke;
        
        usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
    		
      	while (!usbInterruptIsReady()) {
          // Note: We wait until we can send keystroke
          //       so we know the previous keystroke was
          //       sent.
        	usbPoll();
        	_delay_ms(5);
        }
    	
    	// Pressing time (in milliseconds) that the key remains pressed
    	// until is released. If is zero don't release the key (it should be
    	// done manually by sendKeysStroke(0). Therefore minimum time is 1ms
    	// and the maximum is 65535ms.
    	if (key_down_time) {
    		while (key_down_time--) {
    			usbPoll();      
    			_delay_ms(1);
    		}
    		// Now send 'no key' pressed
    		memset(reportBuffer, 0, sizeof(reportBuffer));
    		usbSetInterrupt(reportBuffer, sizeof(reportBuffer));	
    	} 
      }

  • Busted!

    danjovic01/22/2016 at 15:50 0 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()) {
        	usbPoll();
        	_delay_ms(5);
        } 
        memset(reportBuffer, 0, sizeof(reportBuffer));		
        reportBuffer[0] = modifiers;
        reportBuffer[1] = keyStroke;
        usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
        while (!usbInterruptIsReady()) {
        	usbPoll();
        	_delay_ms(5);
        }
    
             /*   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);
        DigiKeyboard.delay(50);
        sendKeyStroke_nostop(0,0);
      }
    }
    I have fiddled with this delay and found that 20ms is not enough but 50ms is fine.

    Bug Busted!!

  • Oh Sh**t, it's not working!

    danjovic01/21/2016 at 13:35 0 comments

    I still haven't figured out why do the game (GTASA) is not accepting the keystrokes, though it can really recognize some of the strokes.

    I wrote my own 'print' method to put each key, then a zero but not worked. Then I've inserted a delay between keystrokes, and yet is not working. Even tried to send several zeros in between each keystroke but still no success.

    void my_DigiKeyboard_print ( char *str ) {
      uint8_t data;
      
      while (*str) {
        data = pgm_read_byte_near(ascii_to_scan_code_table + (*str++ - 8));
        DigiKeyboard.sendKeyStroke(data & 0b01111111, data >> 7 ? MOD_SHIFT_RIGHT : 0); 
        DigiKeyboard.sendKeyStroke(0);
        DigiKeyboard.sendKeyStroke(0);
        DigiKeyboard.sendKeyStroke(0);    
        DigiKeyboard.delay(100);   
      }  
    }

    In any other application the keys are correctly injected, it is weird.. I still have more work to do.

  • Prototype

    danjovic01/21/2016 at 03:16 0 comments

    For development of the firmware I have used a protoboard

    I don't have a DigiSpark here but I have a DIY clone (named Cricket)

    After I have built a keyboard with tactile switches. Sadly the perfboard only have room for 6 keys but nevermind, I don't give a cheat about 7th key.

View all 8 project logs

Enjoy this project?

Share

Discussions

danjovic wrote 01/21/2016 at 23:01 point

Found something. It seems that the detection is related with the time the key stood ON, I mean by how many keyboard scans a given key remained active (press down) before the next press up. 

  Are you sure? yes | no

ejonesss wrote 01/21/2016 at 16:18 point

1.  i could not find a digispark or Cricket on sparkfun  would an arduino work?  

2. i think just like blizzard games rockstar games may be running some warden cheat detector so it may see the device or even the interpreter for the usb interface    

  Are you sure? yes | no

danjovic wrote 01/21/2016 at 16:50 point

The library I have used is specific for Digispark. You can find chinese clones at very cheap though.

  Are you sure? yes | no

danjovic wrote 01/22/2016 at 03:08 point

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates