a'course, you can't have a MAME cabinet without a nice set of arcade controls (or two sets
and to interface all those nice buttons to the laptop there's the teensy++ usb microcontroller board. this little guy (among other cooler, more complex microcontrollery things) can take physical button presses and translate them into usb keyboard presses my little linux box can understand. and with the teensyduino add-on, i can program this thing with easy-to-use arduino environment. w00t!
there's only one problem: the Keyboard class that's provided can only do up to 6 simultaneous virtual keypresses, not enough if i'm gonna wire up two sets of controllers on this thing.
never to fear, my c++ skills are here. i dug in to the directory where teensyduino got installed and added a generic send method to the Keyboard class. here's the deets (i copied most of send_now() and made a few modifications) (unfortunatly, i don't have a teensy board yet, so i don't even know if this poo is gonna work. who want's to by ol' dick a birthday present? =]):
usb_api.h
class usb_keyboard_class : public Print { public: virtual void write(uint8_t); void write_unicode(uint16_t unicode_code_point); void set_modifier(uint8_t); void set_key1(uint8_t); void set_key2(uint8_t); void set_key3(uint8_t); void set_key4(uint8_t); void set_key5(uint8_t); void set_key6(uint8_t); void send_now(void); // here's the method i added void send(uint8_t, uint8_t*, uint8_t); private: void write_keycode(KEYCODE_TYPE key); void write_key(uint8_t code); uint8_t utf8_state; uint16_t unicode_wchar; };
usb_api.cpp
void usb_keyboard_class::send(uint8_t modifier_keys, uint8_t* keys, uint8_t n_keys) { uint8_t i, intr_state, timeout; if (!usb_configuration) return; intr_state = SREG; cli(); UENUM = KEYBOARD_ENDPOINT; timeout = UDFNUML + 50; while (1) { // are we ready to transmit? if (UEINTX & (1<<RWAL)) break; SREG = intr_state; // has the USB gone offline? if (!usb_configuration) return; // have we waited too long? if (UDFNUML == timeout) return; // get ready to try checking again intr_state = SREG; cli(); UENUM = KEYBOARD_ENDPOINT; } UEDATX = modifier_keys; UEDATX = 0; for(i = 0; i < n_keys; i++){ UEDATX = keys[i]; } UEINTX = 0x3A; keyboard_idle_count = 0; SREG = intr_state; }
here's what i got on how to use this shiny new method:
arcadestick.pde
/** * Compile with Teensduino * Board: Teensy++ 2.0 * USB Type: Keyboard + Mouse */ #ifdef STR_PRODUCT # undef STR_PRODUCT #endif #define STR_PRODUCT L"DeathByAutoScroll Arcade Stick (X-Arcade Dual Compatible)" #define MAX_SIMULTANEOUS_KEYS 25 uint8_t keys[MAX_SIMULTANEOUS_KEYS]; uint8_t modifier_keys; uint8_t n_keys; void setupPins(){ // no need, all pins are defaulted to INPUT } void reset(){ modifier_keys = 0; n_keys = 0; } void addKey(uint8_t key){ keys[n_keys++] = key; } void addModifierKey(uint8_t key){ modifier_keys |= key; } void setKeys(){ // convert physical button presses to keyboard keys presses // follows x-arcdae dual-joystick keyboard mapping scheme // see http://www.xgaming.com/service/ServiceFiles/X-Arcade%20Tankstick%20Manual%20USA.pdf // player1 buttons on PORTD // player2 buttons on PORTC // player1 direction on lower nibble of PORTA // player2 direction on upper nibble of PORTA // player 1 // direction //p1 up if(PIN_A0){ addKey(KEYPAD_8); } //p1 down if(PIN_A1){ addKey(KEYPAD_2); } //p1 left if(PIN_A2){ addKey(KEYPAD_4); } //p1 right if(PIN_A3){ addKey(KEYPAD_6); } // buttons //p1 1 if(PIN_D0){ addModifierKey(MODIFIERKEY_LEFT_CTRL); } //p1 2 if(PIN_D1){ addModifierKey(MODIFIERKEY_LEFT_ALT); } //p1 3 if(PIN_D2){ addKey(KEY_SPACE); } //p1 4 if(PIN_D3){ addModifierKey(MODIFIERKEY_LEFT_SHIFT); } //p1 5 if(PIN_D4){ addKey(KEY_Z); } //p1 6 if(PIN_D5){ addKey(KEY_X); } //p1 start if(PIN_D6){ addKey(KEY_1); } //p1 coin if(PIN_D7){ addKey(KEY_3); } // player 2 // direction //p2 up if(PIN_A4){ addKey(KEY_R); } //p2 down if(PIN_A5){ addKey(KEY_F); } //p2 left if(PIN_A6){ addKey(KEY_D); } //p2 right if(PIN_A7){ addKey(KEY_G); } // buttons //p2 1 if(PIN_C0){ addKey(KEY_A); } //p2 2 if(PIN_C1){ addKey(KEY_S); } //p2 3 if(PIN_C2){ addKey(KEY_Q); } //p2 4 if(PIN_C3){ addKey(KEY_W); } //p2 5 if(PIN_C4){ addKey(KEY_E); } //p2 6 if(PIN_C5){ addKey(KEY_LEFT_BRACE); } //p2 start if(PIN_C6){ addKey(KEY_2); } //p2 coin if(PIN_C7){ addKey(KEY_4); } } void setup(){ setupPins(); } void loop(){ reset(); setKeys(); Keyboard.send(modifier_keys, keys, n_keys); }
now all i need is a sheet or two of MDF, a little cash for the parts, and a lot of free time to make it all happen.