DETAILS ABOUT THE SPECIFICS FOR THE TEENSY: http://sudomod.com/forum/viewtopic.php? ... 120#p23741
CURRENT VERSION 1.5 - FEB 14 2017
Recently I was setting up a build following various guides. Since I was using a Wii-U for my build I wanted a Teensy file that would be able to handle multiple cases. Including the ability to press keystrokes and change joystick modes. Most of the Teensy scripts I found were VERY specific to the device they were working with. I wanted something WAY more dynamic, that could be used for pretty much all cases. Something that I wouldn't have to think much about when wiring up the joysticks.
The code may seem a little more complex that what you have seen in the past. This is because I wanted code I could use across multiple builds, and it would allow for me to be flexible. It uses compiler directives. When running you will want the ones that are commented out currently to be commented out. If you want to test a specific thing, or you are defining your buttons just uncomment what you want to use. There is no need to change the code, the compiler directives will do that for you.
TEENSY PINOUTS:

A couple of things to keep in mind when using this code. If you are using analog sticks they must be defined on the right side of the teensy. Ports start from A0 (digital pin 21) and go down to A10 (digital pin 11) A11 = Digital pin 22.. Just remember to reference them as 0-11 when calling the analog reads.
The only pins that are important are the Ground (GND) pins. You will need to terminate most of your buttons on a ground. This is how a keyboard controller detect what is pressed. You will also want to avoid the , +5V, and RST pins as well, unless of course you are connecting them to something specific, like powering the joystick on the Wii-U controller.
The code may seem a little daunting, but if you pin up your teensy, then uncomment DEBUG_BUTTONS, you can basically run the teensy connected to your computer while you put the cursor beside what you are trying to set the key for, press that button and it'll put the pin number in the code for you. I call it lazy mans coding.. who really wants to screw with figuring out the pin locations..

A few things the code does when running... I have added a few "TOGGLE" modes to the system if you are holding down a specific key pattern. If you want to change it feel free. If you don't understand something please feel free to send me a PM, or post here and I'll try to help you out.
TOGGLES AVAILABLE:
- While holding power press START to enable MAME Mode (D-PAD Becomes Keys)
- While holding power press SELECT to disable MAME Mode (D-PAD becomes buttons)
- While holding power you can click the left stick and it will toggle between Joystick and Keyboard modes
- While holding power you can click the right stick and it will toggle between PSX and N64 modes default is N64, if you want to change the default change the variable GameState
CODE CHANGES V1.5
Added the ability to invert specific analog sticks.
If you want to invert a specific direction you need to change the entry matching the stick to true. Find the section in the code and change the variables. No need to change anything else in the code for inversion.
Code: Select all
// Analog Joystick Values required for inversion
int AnalogMap[] = {JoyRHorz, JoyRVert, JoyLHorz, JoyLVert};
bool AnalogInvert[] = {false, true, false, true}; // If you want to invert a stick set a value to true
CODE CHANGES V1.4
Added a blinking LED to the code so you could flash an LED when modes are being changed.
There is a compiler directive MODE_LED_USED if you want to use the flashing the LED.
Set FLASH_PIN to the pin you want to use.
Comment out MODE_LED_USED if you don't want to use the flash ability.
I used the following sequin LEDs: https://www.adafruit.com/product/1757
Keep in mind this code is designed for a Teensy 2.0 I have no idea if it will work on any other.
Code: Select all
//Teensy configure script for RetroPie controllers.
//Easy config, and setup for most controllers.
//by Zark Wizard 02/14/17
//ver 1.5
//If you like the script check out gymlete.com free iOS fitness app (GYMLETE in iTunes)
//leave us a review! Thanks.
//-------------- DEBUG DEFINES --------------
//#define DEBUG_BUTTONS 1 // Uncomment this line to debug Teensy
// If you set this to 1, buttons will output their #position so you can calibrate the code
// to use your button config easily
//#define DEBUG_MESSAGE 1 // Uncomment this line to debug Teensy
// If you want to output messages to the Teensy serial debugger uncomment this
//#define DEBUG_JOYSTICKS 1 // Uncomment this line to debug Teensy
// If you want to output messages to the Teensy serial debugger uncomment this
// This is so you can debug the analog joysticks.
#define USECOMMANDBUTTONS 1 // This enables command button availablity
// If you have keyboard commands that need to be available across emulators you
// will want to have command buttons available. If you don't, comment this
// out and it will not call the command functions
//-------------- Generic States --------------
bool CurrentState = true; // true = Joystick, false = Keyboard
int buttonState = 0;
int lastButtonState = 0;
bool DPad2Keys = false; // This is a mode that will switch the dpad to keys instead of buttons
bool LAST_DPad2Keys = DPad2Keys; // They need to start on the same mode
bool GameState = true; // Analog issues - true = N64Mode 1.5, false = PSXMode 1.8
int GameMode = 0;
int lastGameMode = 0;
int Lasthbut = 0;
int tbut = 0;
short Pressed = 0;
#define MODE_LED_USED 1 // comment out this line if you do not want to use a MODE LED.
// This is the pin position we use to flash, and control the LED Sequin
// This project uses https://www.adafruit.com/product/1757
#define FLASH_PIN 23
// Different modes that are available, flashing the LED so we know the mode
#define FLASH_KEYBOARD 4 // This is how many times it will flash
#define FLASHDELAY_KEYBOARD 250 // in ms
#define FLASH_JOYSTICK 10 // This is how many times it will flash
#define FLASHDELAY_JOYSTICK 50 // in ms
#define FLASH_N64 4 // This is how many times it will flash
#define FLASHDELAY_N64 250 // in ms
#define FLASH_PSX 10 // This is how many times it will flash
#define FLASHDELAY_PSX 50 // in ms
#define FLASH_MAME 4
#define FLASHDELAY_MAME 250 // in ms
#define FLASH_NONMAME 10
#define FLASHDELAY_NONMAME 50 // in ms
// Light LED if Button Home is being held down...
// change this to false if you don't want the LED to go solid when home is pressed
#define LIGHT_HOME true
//-------------- Default Multiplier (set to N64 mode) --------------
#define PSX_Value 1.8f
#define N64_Value 1.5f
// Chnaging this will have no effect, it gets set according to GameState
float StickMultiplier = 0.0f; // Change GameState above to false if you want PSXMode to start
// ------------- Left Side
// Joystick Digital Buttons
const int DirUp = 11;
const int DirDown = 22;
const int DirLeft = 12;
const int DirRight = 13;
// Left Side Top Buttons
const int ButL = 14;
const int ButZL = 15;
// ------------- Right Side
const int ButX = 0;
const int ButY = 7;
const int ButB = 4;
const int ButA = 1;
const int ButStart = 6; // Plus
const int ButSelect = 5; // Minus
//Right Side Top Buttons
const int ButR = 3;
const int ButZR = 2;
// ------------- Bottom Row
const int ButHome = 8;
const int ButTV = 9;
const int ButPower = 10;
// ---------------------------
//ANALOG CONTROLLERS REQUIRE ANALOG INPUT MAPPING A0-A10 Teensy 2.0
// ---------------------------
// ------------- Right Stick
// Joystick Analog Buttons
const int JoyRClick = 19; // Click is a digital mapping
const int JoyRVert = 1; // Analog Mapping A1
const int JoyRHorz = 0; // Analog Mapping A0
// ------------- Left Stick
const int JoyLClick = 18; // Click is a digital mapping
const int JoyLVert = 4; // Analog Mapping A4
const int JoyLHorz = 5; // Analog Mapping A5
// Analog Joystick Values required for inversion
int AnalogMap[] = {JoyRHorz, JoyRVert, JoyLHorz, JoyLVert};
bool AnalogInvert[] = {false, true, false, true}; // If you want to invert a stick set a value to true
#define AMAPPING sizeof(AnalogMap)
// ------------------- Mapping Sequence for Scan Routine
//Variables for the states of the various buttons
// ----------- FIRST MAPPING IS THE BUTTON TEST STATE CASE
#ifdef DEBUG_BUTTONS
// DO NOT CHANGE THE DEBUG STUFF... THIS IS FOR THE DIGITAL PINS
//Debug Pin out positions.... If you want to check the location of various pins and buttons
byte buttons[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
};
unsigned int keys[] = {KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5,
KEY_6, KEY_7, KEY_8, KEY_9, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F,
KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N
};
#else
// --------------------- CONTROLLER MAPPING
// Order is not important, since the mapping for the buttons is above, it gets
// the pins from what you set above, just map what you want to use..
// Set the buttons you want to use,
byte buttons[] = {DirUp, DirDown, DirLeft, DirRight, ButL, ButZL,
ButX, ButY, ButB, ButA, ButStart, ButSelect, ButR, ButZR,
JoyLClick, JoyRClick
};
// If you are in keyboard mode, map the key you want to press for the
// button you listed above. Make sure to have a 1:1 or you could end
// up with an issue
// ------------------- Mapping Sequence for Keyboard Scan Routine
unsigned int keys[] = {KEY_E, KEY_D, KEY_S, KEY_F, KEY_5, KEY_5,
KEY_X, KEY_Y, KEY_B, KEY_A, KEY_ENTER, KEY_5, KEY_5, KEY_Q,
KEY_ESC, KEY_TAB,
};
#endif
byte CommandButtons[] = {
ButTV
};
unsigned int CommandFunction[] = {
KEY_ESC
};
byte DirectionButtons[] = {
DirUp, DirDown, DirLeft, DirRight
};
unsigned int DirectionFunctions[] = {
KEY_E, KEY_D, KEY_S, KEY_F
};
byte HomeButtons[] = {
ButStart, ButSelect, ButTV, ButX, ButY, ButB, ButA, DirUp, DirDown, DirLeft, DirRight
};
unsigned int HomeFunctions[] = {
KEY_ENTER, KEY_TAB, KEY_F1, KEY_F12, KEY_DELETE, KEY_ESC, KEY_TAB, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT
};
#define NUMBUTTONS sizeof(buttons)
#define CMDBUTTONS sizeof(CommandButtons)
#define HBUTTONS sizeof(HomeButtons)
#define DBUTTONS sizeof(DirectionButtons)
void setup()
{
if (GameState)
StickMultiplier = N64_Value;
else
StickMultiplier = PSX_Value;
#ifdef MODE_LED_USED
pinMode(FLASH_PIN, OUTPUT);
#endif
//Special for the Teensy is the INPUT_PULLUP
pinMode(ButPower, INPUT_PULLUP);
pinMode(ButHome, INPUT_PULLUP);
//It enables a pullup resitor on the pin.
for (byte i=0; i< NUMBUTTONS; i++) {
pinMode(buttons[i], INPUT_PULLUP);
}
#ifndef DEBUG_BUTTONS
// Command buttons are onle available if we aren't in debugging buttons
for (byte i=0; i< CMDBUTTONS; i++) {
pinMode(CommandButtons[i], INPUT_PULLUP);
}
#endif
}
int ReadAnalog(int pinPos) {
int pV = analogRead(pinPos);
bool InvertStick = false;
// Scan through the Analog values and see if anything is set to inverse, if it is
// we need to apply the offset validation
for (byte i=0; i< AMAPPING; i++) {
if (AnalogMap[i]==pinPos) {
InvertStick = AnalogInvert[i];
if (InvertStick)
#ifdef DEBUG_JOYSTICKS
// Joystick print outs to check functions....
Serial.printf("PP %d IP %d ",i,pinPos);
#endif
break;
}
}
if (InvertStick)
pV = (pV - 512) * StickMultiplier - 512;
else
pV = (pV - 512) * StickMultiplier + 512;;
pV = abs(pV);
// Make sure we don't exceen the max and minimum for the analog stick.
// if (pV > 1023)
// pV=1023;
// if (pV < 0)
// pV = 0;
return pV;
}
void AnalogMove()
{
int LeftX = ReadAnalog(JoyLHorz);
int LeftY = ReadAnalog(JoyLVert);
int RightX = ReadAnalog(JoyRHorz);
int RightY = ReadAnalog(JoyRVert);
#ifdef DEBUG_JOYSTICKS
// Joystick print outs to check functions....
Serial.printf("Left X:%d, Y:%d Right X:%d, Y:%d\n",LeftX, LeftY, RightX, RightY);
#endif
Joystick.X(LeftX);
Joystick.Y(LeftY);
Joystick.sliderLeft(RightX);
Joystick.sliderRight(RightY);
}
void CheckCommandButtons() {
// Command buttons are onle available if we aren't in debugging buttons
for (byte i=0; i< CMDBUTTONS; i++) {
if (digitalRead(CommandButtons[i]) == LOW) {
Keyboard.press(CommandFunction[i]);
delay(150);
}
else {
Keyboard.release(CommandFunction[i]);
}
}
}
void DPad() {
// Command buttons are onle available if we aren't in debugging buttons
for (byte i=0; i< DBUTTONS; i++) {
if (digitalRead(DirectionButtons[i]) == LOW) {
Keyboard.press(DirectionFunctions[i]);
delay(150);
}
else {
Keyboard.release(DirectionFunctions[i]);
}
}
}
void loop_joystick() {
int spos = 0;
if (DPad2Keys) {
spos = DBUTTONS;
DPad();
}
for (byte i=spos; i< NUMBUTTONS; i++) {
if (digitalRead(buttons[i]) == LOW) {
Joystick.button((buttons[i]+1), 1);
} else {
Joystick.button((buttons[i]+1), 0);
}
}
AnalogMove();
#ifdef USECOMMANDBUTTONS
// Check to see if their are using any command buttons
CheckCommandButtons();
#endif
}
void loop_keyboard() {
for (byte i=0; i< NUMBUTTONS; i++) {
if (digitalRead(buttons[i]) == LOW) {
Keyboard.press(keys[i]);
delay(150);
}
else {
Keyboard.release(keys[i]);
}
}
// If we want to play MAME and some others we might want to support Analog Joystick as well
AnalogMove();
#ifdef USECOMMANDBUTTONS
// Check to see if their are using any command buttons
CheckCommandButtons();
#endif
}
void loop_keyboarddebug() {
for (byte i=0; i< NUMBUTTONS; i++) {
if (digitalRead(buttons[i]) == LOW) {
Serial.println(i);
Keyboard.print(i);
delay(500); // half second delay, if you are mapping while you are running
}
else {
}
}
}
void FlashModeLED(int xTimes, int msDelay) {
#ifdef MODE_LED_USED
for (byte i=0; i< xTimes; i++) {
digitalWrite(FLASH_PIN, HIGH); // turn the LED on by making the voltage HIGH
delay(msDelay);
digitalWrite(FLASH_PIN, LOW); // turn the LED off by making the voltage LOW
delay(msDelay);
}
#endif
}
void SetButtonState() {
buttonState = digitalRead(JoyLClick);
if (buttonState != lastButtonState) {
if (buttonState == LOW) {
CurrentState = !CurrentState;
if (CurrentState) {
FlashModeLED(FLASH_JOYSTICK, FLASHDELAY_JOYSTICK);
#ifdef DEBUG_MESSAGE
Serial.println("Joystick Mode Active");
#endif
}
else {
FlashModeLED(FLASH_KEYBOARD, FLASHDELAY_KEYBOARD);
#ifdef DEBUG_MESSAGE
Serial.println("Keyboard Mode Active");
#endif
}
}
}
lastButtonState = buttonState;
}
void SetGameState() {
GameMode = digitalRead(JoyRClick);
if (GameMode != lastGameMode) {
if (GameMode == LOW) {
GameState = !GameState;
if (GameState) { // Setting N64 Mode
StickMultiplier = N64_Value;
FlashModeLED(FLASH_N64, FLASHDELAY_N64);
#ifdef DEBUG_MESSAGE
Serial.printf("N64 Mode - ");
Serial.println(StickMultiplier);
#endif
}
else { // Setting PSX Mode
StickMultiplier = PSX_Value;
FlashModeLED(FLASH_PSX, FLASHDELAY_PSX);
#ifdef DEBUG_MESSAGE
Serial.printf("PSX Mode - ");
Serial.println(StickMultiplier);
#endif
}
}
}
lastGameMode = GameMode;
}
void HomeCombo() {
for (byte i=0; i< HBUTTONS; i++) {
if (digitalRead(HomeButtons[i]) == LOW) {
Keyboard.press(HomeFunctions[i]);
delay(150);
}
else {
Keyboard.release(HomeFunctions[i]);
}
}
}
void MAMECheck() {
GameMode = digitalRead(ButStart);
if (GameMode == LOW && !DPad2Keys) {
DPad2Keys = true;
FlashModeLED(FLASH_MAME, FLASHDELAY_MAME);
#ifdef DEBUG_MESSAGE
Serial.println("MAME Mode - ON");
#endif
}
GameMode = digitalRead(ButSelect);
if (GameMode == LOW && DPad2Keys) {
DPad2Keys = false;
FlashModeLED(FLASH_NONMAME, FLASHDELAY_NONMAME);
#ifdef DEBUG_MESSAGE
Serial.println("MAME Mode - OFF");
#endif
}
LAST_DPad2Keys = DPad2Keys;
}
void loop() {
#ifdef DEBUG_BUTTONS
loop_keyboarddebug();
#else
// Power button is used to look for toggle mode. If you have the power button held down
// the teensy will look for either the left or right stick press to change modes.
// if you are not holding down power, things will work normally
tbut = digitalRead(ButPower);
int hbut = digitalRead(ButHome);
if (tbut == LOW) {
SetButtonState();
SetGameState();
MAMECheck();
}
if (hbut == LOW) {
// Enter specific keys while home button is pressed
HomeCombo();
#ifdef MODE_LED_USED
// We want to turn off the LED, it was just on.
if (LIGHT_HOME && Lasthbut != hbut) {
digitalWrite(FLASH_PIN, HIGH); // turn the LED on by making the voltage HIGH
}
Lasthbut = hbut;
#endif
}
#ifdef MODE_LED_USED
if (hbut == HIGH) {
// We want to turn off the LED, it was just on.
if (LIGHT_HOME && Lasthbut != hbut) {
digitalWrite(FLASH_PIN, LOW); // turn the LED off by making the voltage LOW
}
Lasthbut = hbut;
}
#endif
if (tbut == HIGH && hbut == HIGH) { // If either is LOW we are doing a mode change so don't call these..
if (CurrentState)
loop_joystick();
else
loop_keyboard();
}
#endif
}
If you have questions about the code please feel free to ask.