/* Commodore 64 keyboard decoding software. Written by Jeroen Janmaat in 2013, 2014. This version 2014/03/03. */ int outpins[8] = {2,3,4,5,6,7,8,13}; int inpins[8] = {9,10,11,12,A0,A1,A2,A3}; int altpin = A4; //int sensepin = A5; int ii; int jj; int kk; int lowcount; int lii; int lkk; /* byte keys_tbl[8][8] = { {'1', KEY_TAB, KEY_LEFT_CTRL, KEY_ESC, ' ', KEY_LEFT_GUI, 'q', '2'}, {'3', 'w', 'a', KEY_LEFT_SHIFT, 'z', 's', 'e', '4'}, {'5', 'r', 'd', 'x', 'c', 'f', 't', '6'}, {'7', 'y', 'g', 'v', 'b', 'h', 'u', '8'}, {'9', 'i', 'j', 'n', 'm', 'k', 'o', '0'}, {'+', 'p', 'l', ',', '.', ':', '@', '-'}, {'#', '*', KEY_SEMICOLON, KEY_SLASH, KEY_RIGHT_SHIFT, KEY_EQUALS, KEY_CARET, KEY_HOME}, {KEY_BACKSPACE, KEY_RETURN, KEY_ARROW_RIGHT, KEY_ARROW_DOWN, KEY_F1, KEY_F3, KEY_F5, KEY_F7}}; */ // Table containing keyboard assignments with no modifier keys pressed byte keys_tbl[8][8] = { {0x1E, 0x2B, 0xE0, 0x29, 0x2C, 0xE3, 0x14, 0x1F}, {0x20, 0x1A, 0x04, 0xE1, 0x1D, 0x16, 0x08, 0x21}, {0x22, 0x15, 0x07, 0x1B, 0x06, 0x09, 0x17, 0x23}, {0x24, 0x1C, 0x0A, 0x19, 0x05, 0x0B, 0x18, 0x25}, {0x26, 0x0C, 0x0D, 0x11, 0x10, 0x0E, 0x12, 0x27}, {0x2E, 0x13, 0x0F, 0x36, 0x37, 0x33, 0x1F, 0x2D}, {0x20, 0x25, 0x33, 0x38, 0xE5, 0x2E, 0x23, 0x50}, {0x2A, 0x28, 0x4F, 0x51, 0x80, 0x00, 0x00, 0x01}}; // Accompanying modifiers to map certain keys (such as "*" and "@") to US keyboard byte keys_tbl_mod[8][8] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00}, {0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00}}; // Table containing keyboard assignments with Right Shift modifier key pressed byte keys_tbl_rshift[8][8] = { {0x1E, 0x2B, 0xE0, 0x29, 0x2C, 0xE3, 0x14, 0x34}, {0x20, 0x1A, 0x04, 0xE1, 0x1D, 0x16, 0x08, 0x21}, {0x22, 0x15, 0x07, 0x1B, 0x06, 0x09, 0x17, 0x24}, {0x34, 0x1C, 0x0A, 0x19, 0x05, 0x0B, 0x18, 0x26}, {0x27, 0x0C, 0x0D, 0x11, 0x10, 0x0E, 0x12, 0x27}, {0x2E, 0x13, 0x0F, 0x36, 0x37, 0x30, 0x1F, 0x2D}, {0x20, 0x25, 0x2F, 0x38, 0xE5, 0x2E, 0x13, 0x4F}, {0x4C, 0x28, 0x50, 0x52, 0x40, 0x10, 0x20, 0x08}}; // Accompanying modifiers to map home and left and up arrow to US keyboard byte keys_tbl_rshift_mod[8][8] = { {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x08}, {0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Table containing keyboard assignments with Left Shift modifier key pressed byte keys_tbl_lshift[8][8] = { {0x1E, 0x2B, 0xE0, 0x29, 0x2C, 0xE3, 0x14, 0x34}, {0x20, 0x1A, 0x04, 0xE1, 0x1D, 0x16, 0x08, 0x21}, {0x22, 0x15, 0x07, 0x1B, 0x06, 0x09, 0x17, 0x24}, {0x34, 0x1C, 0x0A, 0x19, 0x05, 0x0B, 0x18, 0x26}, {0x27, 0x0C, 0x0D, 0x11, 0x10, 0x0E, 0x12, 0x27}, {0x2E, 0x13, 0x0F, 0x36, 0x37, 0x30, 0x1F, 0x2D}, {0x20, 0x25, 0x2F, 0x38, 0xE5, 0x2E, 0x13, 0x50}, {0x4C, 0x28, 0x4F, 0x51, 0x40, 0x10, 0x20, 0x08}}; // Accompanying modifiers to map to US keyboard byte keys_tbl_lshift_mod[8][8] = { {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00}, {0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02}, {0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x04, 0x03}, {0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00}}; // Table containing keyboard assignments with GUI modifier key pressed ("CBM") byte keys_tbl_gui[8][8] = { {0x1E, 0x2B, 0xE0, 0x29, 0x2C, 0xE3, 0x14, 0x1F}, {0x20, 0x1A, 0x04, 0xE1, 0x1D, 0x35, 0x08, 0x21}, {0x22, 0x15, 0x07, 0x1B, 0x06, 0x2D, 0x17, 0x23}, {0x24, 0x1C, 0x0A, 0x19, 0x31, 0x0B, 0x18, 0x25}, {0x26, 0x0C, 0x35, 0x11, 0x31, 0x0E, 0x12, 0x27}, {0x2E, 0x13, 0x0F, 0x36, 0x37, 0x30, 0x1F, 0x2D}, {0x20, 0x25, 0x2F, 0x38, 0xE5, 0x2E, 0x23, 0x4A}, {0x2A, 0x28, 0x4F, 0x51, 0x3A, 0x3C, 0x3E, 0x40}}; // Accompanying modifiers to map certain keys (such as "\" and "|") to US keyboard byte keys_tbl_gui_mod[8][8] = { {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, {0x08, 0x08, 0x08, 0x08, 0x08, 0x02, 0x08, 0x08}, {0x08, 0x08, 0x08, 0x08, 0x08, 0x02, 0x08, 0x08}, {0x08, 0x08, 0x08, 0x08, 0x02, 0x08, 0x08, 0x08}, {0x08, 0x08, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08}, {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}}; // Admin for keys // Key pressed? byte keys_new[8][8] = { {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}}; // Pressed just before? byte keys_set[8][8] = { {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}}; // Seperate check for RESTORE key; this key is not part of the regular matrix byte key_alt_new = 0; byte key_alt_set = 0; // Modifier keys Shift, Control, Alt, GUI // LShift, RShift, Control, Restore, CBM byte modkeys_set[5] = {0,0,0,0,0}; void setup() { Serial.begin(115200); for(jj=0;jj<8;jj++) pinMode(outpins[jj], OUTPUT); for(jj=0;jj<8;jj++) pinMode(inpins[jj], INPUT_PULLUP); pinMode(altpin, INPUT_PULLUP); } void loop() { /* This turns on (and off) the 8 'vertical' lines of the Commodore 64 keyboard matrix one by one. */ for(ii=0;ii<8;ii++) { for(jj=0;jj<8;jj++) digitalWrite(outpins[jj],!(((1<>jj)); /* Once a particular line is selected, the eight horizontal lines of the keyboard matrix are scanned to determine the state of the keys. */ for (kk=0;kk<8;kk++) { keys_new[ii][kk]=!(digitalRead(inpins[kk])); if(keys_new[ii][kk]) { if(ii==1 && kk==3) modkeys_set[0] = 1; if(ii==6 && kk==4) modkeys_set[1] = 1; if(ii==0 && kk==2) modkeys_set[2] = 1; if(ii==8 && kk==8) modkeys_set[3] = 1; if(ii==0 && kk==5) modkeys_set[4] = 1; if(!keys_set[ii][kk]) { //Serial.write(0xFE); //Serial.write(0x0); if(!modkeys_set[0] & !modkeys_set[1] & !modkeys_set[2] & !modkeys_set[3] & !modkeys_set[4]) { if(ii==7 & kk>3) { Serial.write(0xFD); Serial.write(0x03); Serial.write(0x03); Serial.write(keys_tbl[ii][kk]); Serial.write(keys_tbl_mod[ii][kk]); } else { Serial.write(0xFE); Serial.write(0x02); Serial.write(keys_tbl_mod[ii][kk]); Serial.write(keys_tbl[ii][kk]); } } if(modkeys_set[0] & !modkeys_set[1] & !modkeys_set[2] & !modkeys_set[3] & !modkeys_set[4]) { if(ii==7 & kk>3) { Serial.write(0xFD); Serial.write(0x03); Serial.write(0x03); Serial.write(keys_tbl_lshift[ii][kk]); Serial.write(keys_tbl_lshift_mod[ii][kk]); } else { Serial.write(0xFE); Serial.write(0x02); Serial.write(keys_tbl_lshift_mod[ii][kk]); Serial.write(keys_tbl_lshift[ii][kk]); } } if(!modkeys_set[0] & modkeys_set[1] & !modkeys_set[2] & !modkeys_set[3] & !modkeys_set[4]) { if(ii==7 & kk>3) { Serial.write(0xFD); Serial.write(0x03); Serial.write(0x03); Serial.write(keys_tbl_rshift[ii][kk]); Serial.write(keys_tbl_rshift_mod[ii][kk]); } else { Serial.write(0xFE); Serial.write(0x02); Serial.write(keys_tbl_rshift_mod[ii][kk]); Serial.write(keys_tbl_rshift[ii][kk]); } } if(modkeys_set[0] & modkeys_set[1] & !modkeys_set[2] & !modkeys_set[3] & !modkeys_set[4]) { Serial.write(0xFE); Serial.write(0x02); Serial.write(keys_tbl_lshift_mod[ii][kk]); Serial.write(keys_tbl_rshift[ii][kk]); } if(!modkeys_set[0] & !modkeys_set[1] & !modkeys_set[2] & !modkeys_set[3] & modkeys_set[4]) { Serial.write(0xFE); Serial.write(0x02); Serial.write(keys_tbl_gui_mod[ii][kk]); Serial.write(keys_tbl_gui[ii][kk]); } if(!modkeys_set[0] & !modkeys_set[1] & modkeys_set[2] & !modkeys_set[3] & !modkeys_set[4]) { Serial.write(0xFE); Serial.write(0x02); Serial.write(0x01); Serial.write(keys_tbl[ii][kk]); } if(!modkeys_set[0] & !modkeys_set[1] & !modkeys_set[2] & modkeys_set[3] & !modkeys_set[4]) { Serial.write(0xFE); Serial.write(0x02); Serial.write(0x04); Serial.write(keys_tbl[ii][kk]); } if(!modkeys_set[0] & modkeys_set[1] & !modkeys_set[2] & modkeys_set[3] & !modkeys_set[4]) { Serial.write(0xFE); Serial.write(0x02); Serial.write(0x04); Serial.write(keys_tbl_rshift[ii][kk]); } if(!modkeys_set[0] & !modkeys_set[1] & !modkeys_set[2] & modkeys_set[3] & modkeys_set[4]) { Serial.write(0xFE); Serial.write(0x02); Serial.write(0x04); Serial.write(keys_tbl_gui[ii][kk]); } // Make special case for if right shift is pressed -- use appropriate table and force shift key if left shift is pressed as well } keys_set[ii][kk]++; // Scheme to detect most recently pressed key } if(!keys_new[ii][kk] & (keys_set[ii][kk] > 0)) { keys_set[ii][kk] = 0; if(ii==1 && kk==3) modkeys_set[0] = 0; if(ii==6 && kk==4) modkeys_set[1] = 0; if(ii==0 && kk==2) modkeys_set[2] = 0; if(ii==8 && kk==8) modkeys_set[3] = 0; if(ii==0 && kk==5) modkeys_set[4] = 0; Serial.write(0xFE); Serial.write(0x00); if(ii==7 & kk>3) { Serial.write(0xFD); Serial.write(0x03); Serial.write(0x03); Serial.write(0); Serial.write(0); } } } /* Also check the "Restore" key; this key is not part of the regular matrix. */ key_alt_new=!(digitalRead(altpin)); if(key_alt_new) { if(!key_alt_set) { modkeys_set[3] = 1; key_alt_set = 1; //Serial.println("Alt key pressed"); } } if(!key_alt_new & key_alt_set) { modkeys_set[3] = 0; key_alt_set = 0; //Serial.println("Alt key released"); } } // scanning cycle delay(35); // Delay to wait out keyboard bounce } // loop