diff --git a/PS2Keyboard.cpp b/PS2Keyboard.cpp index 53bfa1a..f84e135 100644 --- a/PS2Keyboard.cpp +++ b/PS2Keyboard.cpp @@ -5,12 +5,17 @@ ** Mostly rewritten Paul Stoffregen 2010, 2011 ** Modified for use beginning with Arduino 13 by L. Abraham Smith, * - ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan ** + ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan * + ** Modified for ESP32 support * for more information you can read the original wiki in arduino.cc at http://www.arduino.cc/playground/Main/PS2Keyboard or http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html + Version 2.5 (January 2025) + - Better Inturpts + - Support for ESP32 + Version 2.4 (March 2013) - Support Teensy 3.0, Arduino Due, Arduino Leonardo & other boards - French keyboard layout, David Chochoi, tchoyyfr at yahoo dot fr @@ -53,55 +58,151 @@ #define BUFFER_SIZE 45 static volatile uint8_t buffer[BUFFER_SIZE]; static volatile uint8_t head, tail; -static uint8_t DataPin; +static uint8_t dataPin; +static uint8_t IRQPin; static uint8_t CharBuffer=0; static uint8_t UTF8next=0; static const PS2Keymap_t *keymap=NULL; +static bool capsLockOn = false; +static bool numLockOn = false; +static bool scrollLockOn = false; +static byte ledState = 0; -// The ISR for the external interrupt -void ps2interrupt(void) +#define LED_CONTROL 0xED + +#ifdef ESP32 +#define SUPPORT_IRAM_ATTR IRAM_ATTR +#else +#define SUPPORT_IRAM_ATTR // Empty definition for non-ESP32 boards +#endif + +// Parity check +// Return true for odd parity. +static bool parityCheck(uint16_t data) { - static uint8_t bitcount=0; - static uint8_t incoming=0; - static uint32_t prev_ms=0; - uint32_t now_ms; - uint8_t n, val; - - val = digitalRead(DataPin); - now_ms = millis(); - if (now_ms - prev_ms > 250) { - bitcount = 0; - incoming = 0; - } - prev_ms = now_ms; - n = bitcount - 1; - if (n <= 7) { - incoming |= (val << n); - } - bitcount++; - if (bitcount == 11) { - uint8_t i = head + 1; - if (i >= BUFFER_SIZE) i = 0; - if (i != tail) { - buffer[i] = incoming; - head = i; - } - bitcount = 0; - incoming = 0; - } + uint8_t count = 0; + for (int i = 0; i < 10; i++) { + count += (data >> i) & 1; + } + return count % 2 != 0; } +/* +code taken from https://karooza.net/how-to-interface-a-ps2-keyboard +parity was needed and the writing should have done on rising edeg not in falling +*/ +static void sendPS2Command(uint8_t cmdCode) { + uint16_t cmd = cmdCode; // Cast to 16-bit to add parity and stop bits -static inline uint8_t get_scan_code(void) -{ - uint8_t c, i; - - i = tail; - if (i == head) return 0; - i++; - if (i >= BUFFER_SIZE) i = 0; - c = buffer[i]; - tail = i; - return c; + // Add parity bit if not already set + if (!parityCheck(cmd)) { + cmd |= 0x0100; + } + + // Add stop bit + cmd |= 0x0200; + + // Set clock and data pins to output mode + pinMode(IRQPin, OUTPUT); + pinMode(dataPin, OUTPUT); + + // Start Request to Send by pulling clock low for 100us + digitalWrite(IRQPin, LOW); + unsigned long startMicros = micros(); + while (micros() - startMicros < 100); // Wait for 100us + + // Pull data low to send the start bit + digitalWrite(dataPin, LOW); + startMicros = micros(); + while (micros() - startMicros < 20); // Wait for 20us + + // Release clock line, allowing it to go high + pinMode(IRQPin, INPUT_PULLUP); + + // Send 8 data bits, 1 parity bit, and 1 stop bit + for (int i = 0; i < 10; i++) { + // Wait for keyboard to take clock low (start of bit transmission) + while (digitalRead(IRQPin) > 0); + + // Write the current bit to the data line + digitalWrite(dataPin, cmd & 0x0001); + cmd >>= 1; // Shift to the next bit + + // Wait for the keyboard to take clock high, indicating bit has been sampled + while (digitalRead(IRQPin) < 1); + } + + // Release data line (high) for the stop bit + pinMode(dataPin, INPUT_PULLUP); + + // Wait for keyboard to acknowledge by taking clock low + while (digitalRead(IRQPin) > 0); + + // Wait for keyboard ACK by checking data line goes low + while (digitalRead(dataPin) > 0); + + // Reset pins to input mode with pull-up resistors +#ifdef INPUT_PULLUP + pinMode(IRQPin, INPUT_PULLUP); + pinMode(dataPin, INPUT_PULLUP); +#else + pinMode(IRQPin, INPUT); + digitalWrite(IRQPin, HIGH); + pinMode(dataPin, INPUT); + digitalWrite(dataPin, HIGH); +#endif +} + +static void updateLEDs(byte command){ + + //Serial.print(LED_CONTROL); + sendPS2Command(LED_CONTROL); + // Serial.print(command); + sendPS2Command(command); + // Could not get this working +} + +// The ISR for the external interrupt +void SUPPORT_IRAM_ATTR ps2interrupt(void) { + static uint8_t bitCount = 0; + static uint8_t incoming = 0; + static uint32_t prevMillis = 0; + uint32_t nowMillis; + uint8_t bitPos, val; + + val = digitalRead(dataPin); + nowMillis = millis(); + if (nowMillis - prevMillis > 250) { + bitCount = 0; + incoming = 0; + } + prevMillis = nowMillis; + bitPos = bitCount - 1; + if (bitPos <= 7) { + incoming |= (val << bitPos); + } + bitCount++; + if (bitCount == 11) { + uint8_t i = head + 1; + if (i >= BUFFER_SIZE) i = 0; + if (i != tail) { + buffer[i] = incoming; + head = i; + } + bitCount = 0; + incoming = 0; + } +} + +static inline uint8_t getScanCode(void) { + uint8_t c, i; + + i = tail; + if (i == head) return 0; + i++; + if (i >= BUFFER_SIZE) i = 0; + c = buffer[i]; + tail = i; + return c; } // http://www.quadibloc.com/comp/scan.htm @@ -152,280 +253,7 @@ const PROGMEM PS2Keymap_t PS2Keymap_US = { 0 }; - -const PROGMEM PS2Keymap_t PS2Keymap_German = { - // without shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '^', 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0, - 0, 0, 'y', 's', 'a', 'w', '2', 0, - 0, 'c', 'x', 'd', 'e', '4', '3', 0, - 0, ' ', 'v', 'f', 't', 'r', '5', 0, - 0, 'n', 'b', 'h', 'g', 'z', '6', 0, - 0, 0, 'm', 'j', 'u', '7', '8', 0, - 0, ',', 'k', 'i', 'o', '0', '9', 0, - 0, '.', '-', 'l', PS2_o_DIAERESIS, 'p', PS2_SHARP_S, 0, - 0, 0, PS2_a_DIAERESIS, 0, PS2_u_DIAERESIS, '\'', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, '#', 0, 0, - 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - // with shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_DEGREE_SIGN, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0, - 0, 0, 'Y', 'S', 'A', 'W', '"', 0, - 0, 'C', 'X', 'D', 'E', '$', PS2_SECTION_SIGN, 0, - 0, ' ', 'V', 'F', 'T', 'R', '%', 0, - 0, 'N', 'B', 'H', 'G', 'Z', '&', 0, - 0, 0, 'M', 'J', 'U', '/', '(', 0, - 0, ';', 'K', 'I', 'O', '=', ')', 0, - 0, ':', '_', 'L', PS2_O_DIAERESIS, 'P', '?', 0, - 0, 0, PS2_A_DIAERESIS, 0, PS2_U_DIAERESIS, '`', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, '\'', 0, 0, - 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - 1, - // with altgr - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, '@', 0, 0, - 0, 0, 0, 0, 0, 0, PS2_SUPERSCRIPT_TWO, 0, - 0, 0, 0, 0, PS2_CURRENCY_SIGN, 0, PS2_SUPERSCRIPT_THREE, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, PS2_MICRO_SIGN, 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 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '~', 0, '#', 0, 0, - 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 } -}; - - -const PROGMEM PS2Keymap_t PS2Keymap_French = { - // without shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_SUPERSCRIPT_TWO, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'a', '&', 0, - 0, 0, 'w', 's', 'q', 'z', PS2_e_ACUTE, 0, - 0, 'c', 'x', 'd', 'e', '\'', '"', 0, - 0, ' ', 'v', 'f', 't', 'r', '(', 0, - 0, 'n', 'b', 'h', 'g', 'y', '-', 0, - 0, 0, ',', 'j', 'u', PS2_e_GRAVE, '_', 0, - 0, ';', 'k', 'i', 'o', PS2_a_GRAVE, PS2_c_CEDILLA, 0, - 0, ':', '!', 'l', 'm', 'p', ')', 0, - 0, 0, PS2_u_GRAVE, 0, '^', '=', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '$', 0, '*', 0, 0, - 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - // with shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'A', '1', 0, - 0, 0, 'W', 'S', 'Q', 'Z', '2', 0, - 0, 'C', 'X', 'D', 'E', '4', '3', 0, - 0, ' ', 'V', 'F', 'T', 'R', '5', 0, - 0, 'N', 'B', 'H', 'G', 'Y', '6', 0, - 0, 0, '?', 'J', 'U', '7', '8', 0, - 0, '.', 'K', 'I', 'O', '0', '9', 0, - 0, '/', PS2_SECTION_SIGN, 'L', 'M', 'P', PS2_DEGREE_SIGN, 0, - 0, 0, '%', 0, PS2_DIAERESIS, '+', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, PS2_POUND_SIGN, 0, PS2_MICRO_SIGN, 0, 0, - 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - 1, - // with altgr - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, '@', 0, 0, - 0, 0, 0, 0, 0, 0, '~', 0, - 0, 0, 0, 0, 0 /*PS2_EURO_SIGN*/, '{', '#', 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 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, PS2_CURRENCY_SIGN, 0, '#', 0, 0, - 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 } -}; - -const PROGMEM PS2Keymap_t PS2Keymap_Spanish = { - // without shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_MASCULINE_ORDINAL, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0, - 0, 0, 'z', 's', 'a', 'w', '2', 0, - 0, 'c', 'x', 'd', 'e', '4', '3', 0, - 0, ' ', 'v', 'f', 't', 'r', '5', 0, - 0, 'n', 'b', 'h', 'g', 'y', '6', 0, - 0, 0, 'm', 'j', 'u', '7', '8', 0, - 0, ',', 'k', 'i', 'o', '0', '9', 0, - 0, '.', '-', 'l', 'n', 'p', '\'', 0, - 0, 0, PS2_ACUTE_ACCENT, 0, '`', PS2_INVERTED_EXCLAMATION, 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, PS2_c_CEDILLA, 0, 0, - 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - // with shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_FEMININE_ORDINAL, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0, - 0, 0, 'Z', 'S', 'A', 'W', '\"', 0, - 0, 'C', 'X', 'D', 'E', '$', PS2_MIDDLE_DOT, 0, - 0, ' ', 'V', 'F', 'T', 'R', '%', 0, - 0, 'N', 'B', 'H', 'G', 'Y', '&', 0, - 0, 0, 'M', 'J', 'U', '/', '(', 0, - 0, ';', 'K', 'I', 'O', '=', ')', 0, - 0, ':', '_', 'L', 'N', 'P', '?', 0, - 0, 0, PS2_DIAERESIS, 0, '^', PS2_INVERTED_QUESTION_MARK, 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, PS2_C_CEDILLA, 0, 0, - 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - 1, - // with altgr - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '\\', 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '|', 0, - 0, 0, 'z', 's', 'a', 'w', '@', 0, - 0, 'c', 'x', 'd', PS2_EURO_SIGN, '~', '#', 0, - 0, ' ', 'v', 'f', 't', 'r', '5', 0, - 0, 'n', 'b', 'h', 'g', 'y', PS2_NOT_SIGN, 0, - 0, 0, 'm', 'j', 'u', '7', '8', 0, - 0, ',', 'k', 'i', 'o', '0', '9', 0, - 0, '.', '-', 'l', 'n', 'p', '\'', 0, - 0, 0, '{', 0, '[', PS2_INVERTED_EXCLAMATION, 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '}', 0, 0, - 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 } -}; - -const PROGMEM PS2Keymap_t PS2Keymap_Italian = { - // without shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '\\', 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0, - 0, 0, 'z', 's', 'a', 'w', '2', 0, - 0, 'c', 'x', 'd', 'e', '4', '3', 0, - 0, ' ', 'v', 'f', 't', 'r', '5', 0, - 0, 'n', 'b', 'h', 'g', 'y', '6', 0, - 0, 0, 'm', 'j', 'u', '7', '8', 0, - 0, ',', 'k', 'i', 'o', '0', '9', 0, - 0, '.', '-', 'l', PS2_o_GRAVE, 'p', '\'', 0, - 0, 0, PS2_a_GRAVE, 0, PS2_e_GRAVE, PS2_i_GRAVE, 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, PS2_u_GRAVE, 0, 0, - 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - // with shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '|', 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0, - 0, 0, 'Z', 'S', 'A', 'W', '\"', 0, - 0, 'C', 'X', 'D', 'E', '$', PS2_POUND_SIGN, 0, - 0, ' ', 'V', 'F', 'T', 'R', '%', 0, - 0, 'N', 'B', 'H', 'G', 'Y', '&', 0, - 0, 0, 'M', 'J', 'U', '/', '(', 0, - 0, ';', 'K', 'I', 'O', '=', ')', 0, - 0, ':', '_', 'L', PS2_c_CEDILLA, 0, '?', 0, - 0, 0, PS2_DEGREE_SIGN, 0, PS2_e_ACUTE, '^', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, PS2_SECTION_SIGN, 0, 0, - 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - 1, - // with altgr - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_NOT_SIGN, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', PS2_SUPERSCRIPT_ONE, 0, - 0, 0, 'z', 's', 'a', 'w', PS2_SUPERSCRIPT_TWO, 0, - 0, 'c', 'x', 'd', PS2_EURO_SIGN, PS2_FRACTION_ONE_QUARTER, PS2_SUPERSCRIPT_THREE, 0, - 0, ' ', 'v', 'f', 't', 'r', PS2_FRACTION_ONE_HALF, 0, - 0, 'n', 'b', 'h', 'g', 'y', PS2_NOT_SIGN, 0, - 0, 0, 'm', 'j', 'u', '{', '[', 0, - 0, ',', 'k', 'i', 'o', '}', ']', 0, - 0, '.', '-', 'l', '@', 'p', '\'', 0, - 0, 0, '#', 0, '[', '~', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, 0, 0, 0, - 0, PS2_LEFT_DOUBLE_ANGLE_QUOTE, 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 } -}; - -const PROGMEM PS2Keymap_t PS2Keymap_UK = { -// https://github.com/PaulStoffregen/PS2Keyboard/issues/15 - // without shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '`', 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0, - 0, 0, 'z', 's', 'a', 'w', '2', 0, - 0, 'c', 'x', 'd', 'e', '4', '3', 0, - 0, ' ', 'v', 'f', 't', 'r', '5', 0, - 0, 'n', 'b', 'h', 'g', 'y', '6', 0, - 0, 0, 'm', 'j', 'u', '7', '8', 0, - 0, ',', 'k', 'i', 'o', '0', '9', 0, - 0, '.', '/', 'l', ';', 'p', '-', 0, - 0, 0, '\'', 0, '[', '=', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '#', 0, 0, - 0, '\\', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - // with shift - {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12, - 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 172 /* ¬ */, 0, - 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0, - 0, 0, 'Z', 'S', 'A', 'W', '"', 0, - 0, 'C', 'X', 'D', 'E', '$', 163 /* £ */, 0, - 0, ' ', 'V', 'F', 'T', 'R', '%', 0, - 0, 'N', 'B', 'H', 'G', 'Y', '^', 0, - 0, 0, 'M', 'J', 'U', '&', '*', 0, - 0, '<', 'K', 'I', 'O', ')', '(', 0, - 0, '>', '?', 'L', ':', 'P', '_', 0, - 0, 0, '@', 0, '{', '+', 0, 0, - 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '}', 0, '~', 0, 0, - 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0, - 0, '1', 0, '4', '7', 0, 0, 0, - '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/, - PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0, - 0, 0, 0, PS2_F7 }, - 0 -}; + // no hate but I have remove this #define BREAK 0x01 #define MODIFIER 0x02 @@ -433,75 +261,127 @@ const PROGMEM PS2Keymap_t PS2Keymap_UK = { #define SHIFT_R 0x08 #define ALTGR 0x10 -static char get_iso8859_code(void) -{ - static uint8_t state=0; - uint8_t s; - char c; - - while (1) { - s = get_scan_code(); - if (!s) return 0; - if (s == 0xF0) { - state |= BREAK; - } else if (s == 0xE0) { - state |= MODIFIER; - } else { - if (state & BREAK) { - if (s == 0x12) { - state &= ~SHIFT_L; - } else if (s == 0x59) { - state &= ~SHIFT_R; - } else if (s == 0x11 && (state & MODIFIER)) { - state &= ~ALTGR; - } - // CTRL, ALT & WIN keys could be added - // but is that really worth the overhead? - state &= ~(BREAK | MODIFIER); - continue; - } - if (s == 0x12) { - state |= SHIFT_L; - continue; - } else if (s == 0x59) { - state |= SHIFT_R; - continue; - } else if (s == 0x11 && (state & MODIFIER)) { - state |= ALTGR; - } - c = 0; - if (state & MODIFIER) { - switch (s) { - case 0x70: c = PS2_INSERT; break; - case 0x6C: c = PS2_HOME; break; - case 0x7D: c = PS2_PAGEUP; break; - case 0x71: c = PS2_DELETE; break; - case 0x69: c = PS2_END; break; - case 0x7A: c = PS2_PAGEDOWN; break; - case 0x75: c = PS2_UPARROW; break; - case 0x6B: c = PS2_LEFTARROW; break; - case 0x72: c = PS2_DOWNARROW; break; - case 0x74: c = PS2_RIGHTARROW; break; - case 0x4A: c = '/'; break; - case 0x5A: c = PS2_ENTER; break; - default: break; - } - } else if ((state & ALTGR) && pgm_read_byte(keymap->uses_altgr)) { - if (s < PS2_KEYMAP_SIZE) - c = pgm_read_byte(keymap->altgr + s); - } else if (state & (SHIFT_L | SHIFT_R)) { - if (s < PS2_KEYMAP_SIZE) - c = pgm_read_byte(keymap->shift + s); - } else { - if (s < PS2_KEYMAP_SIZE) - c = pgm_read_byte(keymap->noshift + s); - } - state &= ~(BREAK | MODIFIER); - if (c) return c; - } - } +#define SCROLL_LOCK 0x01 +#define NUM_LOCK 0x02 +#define CAPS_LOCK 0x04 + +#define LED_CONTROL 0xED + + + +static char get_iso8859_code(void) { + static uint8_t state = 0; + uint8_t scanCode; + char character; + + while (1) { + // Retrieve the scan code + scanCode = getScanCode(); + if (!scanCode) return 0; // No scan code available + + // Handle special cases for scan codes + if (scanCode == 0xF0) { + state |= BREAK; // Set BREAK state + } else if (scanCode == 0xE0) { + state |= MODIFIER; // Set MODIFIER state for extended keys + } else { + // Handle key release (BREAK state) + if (state & BREAK) { + if (scanCode == 0x12) { + state &= ~SHIFT_L; // Release Left Shift + } else if (scanCode == 0x59) { + state &= ~SHIFT_R; // Release Right Shift + } else if (scanCode == 0x11 && (state & MODIFIER)) { + state &= ~ALTGR; // Release AltGr + } + // Reset states and continue to next scan code + state &= ~(BREAK | MODIFIER); + continue; + } + + // Handle key press events for modifiers and locks + if (scanCode == 0x12) { + state |= SHIFT_L; // Left Shift pressed + continue; + } else if (scanCode == 0x59) { + state |= SHIFT_R; // Right Shift pressed + continue; + } else if (scanCode == 0x11 && (state & MODIFIER)) { + state |= ALTGR; // AltGr pressed + } else if (scanCode == 0x58) { + capsLockOn = !capsLockOn; // Toggle Caps Lock + ledState = capsLockOn ? (ledState | CAPS_LOCK) : (ledState & ~CAPS_LOCK); + updateLEDs(ledState); + } else if (scanCode == 0x77) { + numLockOn = !numLockOn; // Toggle Num Lock + ledState = numLockOn ? (ledState | NUM_LOCK) : (ledState & ~NUM_LOCK); + updateLEDs(ledState); + } else if (scanCode == 0x7E) { + scrollLockOn = !scrollLockOn; // Toggle Scroll Lock + ledState = scrollLockOn ? (ledState | SCROLL_LOCK) : (ledState & ~SCROLL_LOCK); + updateLEDs(ledState); + } + + // Process scan codes based on the current state + character = 0; + if (state & MODIFIER) { + // Handle special keys with modifier (like arrow keys) + switch (scanCode) { + case 0x70: character = PS2_INSERT; break; + case 0x6C: character = PS2_HOME; break; + case 0x7D: character = PS2_PAGEUP; break; + case 0x71: character = PS2_DELETE; break; + case 0x69: character = PS2_END; break; + case 0x7A: character = PS2_PAGEDOWN; break; + case 0x75: character = PS2_UPARROW; break; + case 0x6B: character = PS2_LEFTARROW; break; + case 0x72: character = PS2_DOWNARROW; break; + case 0x74: character = PS2_RIGHTARROW; break; + case 0x4A: character = '/'; break; + case 0x5A: character = PS2_ENTER; break; + default: break; + } + } else if ((state & ALTGR) && pgm_read_byte(keymap->uses_altgr)) { + // Handle AltGr key combinations + if (scanCode < PS2_KEYMAP_SIZE) { + character = pgm_read_byte(keymap->altgr + scanCode); + } + } else if (capsLockOn) { + // Handle Caps Lock with or without Shift keys + if (state & (SHIFT_L | SHIFT_R)) { + if (scanCode < PS2_KEYMAP_SIZE) { + character = pgm_read_byte(keymap->noshift + scanCode); + } + } else { + if (scanCode < PS2_KEYMAP_SIZE) { + character = pgm_read_byte(keymap->shift + scanCode); + } + } + } else { + // Handle regular Shift and non-Shift key states + if (state & (SHIFT_L | SHIFT_R)) { + if (scanCode < PS2_KEYMAP_SIZE) { + character = pgm_read_byte(keymap->shift + scanCode); + } + } else { + if (scanCode < PS2_KEYMAP_SIZE) { + character = pgm_read_byte(keymap->noshift + scanCode); + } + } + } + + // Reset the states for the next scan code processing + state &= ~(BREAK | MODIFIER); + + // Return the character if one was generated + if (character) return character; + } + } } + + + bool PS2Keyboard::available() { if (CharBuffer || UTF8next) return true; CharBuffer = get_iso8859_code(); @@ -516,7 +396,7 @@ void PS2Keyboard::clear() { uint8_t PS2Keyboard::readScanCode(void) { - return get_scan_code(); + return getScanCode(); } int PS2Keyboard::read() { @@ -556,10 +436,10 @@ PS2Keyboard::PS2Keyboard() { // nothing to do here, begin() does it all } -void PS2Keyboard::begin(uint8_t data_pin, uint8_t irq_pin, const PS2Keymap_t &map) { - uint8_t irq_num=255; - - DataPin = data_pin; +void PS2Keyboard::begin(uint8_t data_pin, uint8_t irq_pin, const PS2Keymap_t &map) { + uint8_t irq_num = irq_pin; + IRQPin= irq_pin; + dataPin = data_pin; keymap = ↦ // initialize the pins @@ -571,138 +451,10 @@ void PS2Keyboard::begin(uint8_t data_pin, uint8_t irq_pin, const PS2Keymap_t &ma digitalWrite(irq_pin, HIGH); pinMode(data_pin, INPUT); digitalWrite(data_pin, HIGH); -#endif - -#ifdef CORE_INT_EVERY_PIN - irq_num = irq_pin; - -#else - switch(irq_pin) { - #ifdef CORE_INT0_PIN - case CORE_INT0_PIN: - irq_num = 0; - break; - #endif - #ifdef CORE_INT1_PIN - case CORE_INT1_PIN: - irq_num = 1; - break; - #endif - #ifdef CORE_INT2_PIN - case CORE_INT2_PIN: - irq_num = 2; - break; - #endif - #ifdef CORE_INT3_PIN - case CORE_INT3_PIN: - irq_num = 3; - break; - #endif - #ifdef CORE_INT4_PIN - case CORE_INT4_PIN: - irq_num = 4; - break; - #endif - #ifdef CORE_INT5_PIN - case CORE_INT5_PIN: - irq_num = 5; - break; - #endif - #ifdef CORE_INT6_PIN - case CORE_INT6_PIN: - irq_num = 6; - break; - #endif - #ifdef CORE_INT7_PIN - case CORE_INT7_PIN: - irq_num = 7; - break; - #endif - #ifdef CORE_INT8_PIN - case CORE_INT8_PIN: - irq_num = 8; - break; - #endif - #ifdef CORE_INT9_PIN - case CORE_INT9_PIN: - irq_num = 9; - break; - #endif - #ifdef CORE_INT10_PIN - case CORE_INT10_PIN: - irq_num = 10; - break; - #endif - #ifdef CORE_INT11_PIN - case CORE_INT11_PIN: - irq_num = 11; - break; - #endif - #ifdef CORE_INT12_PIN - case CORE_INT12_PIN: - irq_num = 12; - break; - #endif - #ifdef CORE_INT13_PIN - case CORE_INT13_PIN: - irq_num = 13; - break; - #endif - #ifdef CORE_INT14_PIN - case CORE_INT14_PIN: - irq_num = 14; - break; - #endif - #ifdef CORE_INT15_PIN - case CORE_INT15_PIN: - irq_num = 15; - break; - #endif - #ifdef CORE_INT16_PIN - case CORE_INT16_PIN: - irq_num = 16; - break; - #endif - #ifdef CORE_INT17_PIN - case CORE_INT17_PIN: - irq_num = 17; - break; - #endif - #ifdef CORE_INT18_PIN - case CORE_INT18_PIN: - irq_num = 18; - break; - #endif - #ifdef CORE_INT19_PIN - case CORE_INT19_PIN: - irq_num = 19; - break; - #endif - #ifdef CORE_INT20_PIN - case CORE_INT20_PIN: - irq_num = 20; - break; - #endif - #ifdef CORE_INT21_PIN - case CORE_INT21_PIN: - irq_num = 21; - break; - #endif - #ifdef CORE_INT22_PIN - case CORE_INT22_PIN: - irq_num = 22; - break; - #endif - #ifdef CORE_INT23_PIN - case CORE_INT23_PIN: - irq_num = 23; - break; - #endif - } -#endif - +#endif head = 0; tail = 0; + irq_num = digitalPinToInterrupt(irq_pin); if (irq_num < 255) { attachInterrupt(irq_num, ps2interrupt, FALLING); } diff --git a/PS2Keyboard.h b/PS2Keyboard.h index 4931e37..1ea44cc 100644 --- a/PS2Keyboard.h +++ b/PS2Keyboard.h @@ -25,12 +25,9 @@ #ifndef PS2Keyboard_h #define PS2Keyboard_h + +#include // for attachInterrupt, FALLING -#if defined(ARDUINO) && ARDUINO >= 100 -#include "Arduino.h" // for attachInterrupt, FALLING -#else -#include "WProgram.h" -#endif #include "utility/int_pins.h" diff --git a/README.md b/README.md index 931f685..99986f5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,117 @@ -#PS/2 Keyboard Library# +# PS/2 Keyboard Library with ESP32 Support -PS2Keyboard allows you to use a keyboard for user input. +This library provides support for using a PS/2 keyboard as an input device, with additional enhancements to support ESP32, making it compatible with LoRa-based chat applications and improved code structure. -http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html +## Original Project -![](http://www.pjrc.com/teensy/td_libs_PS2Keyboard.jpg) +The original PS/2 Keyboard Library was created by PJRC and allows easy interfacing of a PS/2 keyboard with microcontrollers, such as the Teensy. This library makes it easy to use a keyboard for user input. More details on the original project can be found here: + +- [PS2Keyboard Library](http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html) + +![Original Library](http://www.pjrc.com/teensy/td_libs_PS2Keyboard.jpg) + +## New Additions and Enhancements + +This fork includes additional features and improvements: + +- **ESP32 Support**: Added support for the ESP32 platform, making it compatible with LoRa-based chat applications and other ESP32 projects. +- **Efficient Interrupts**: Simplified interrupt handling for easier and more efficient management. +- **Caps Lock with Status LED**: Added support for the Caps Lock key along with an LED status indicator. +- **Code Optimization**: Removed bulky code sections, refactored to a modern C++ style, and enhanced code readability. + +## Getting Started + +### Prerequisites + +- **Platform**: This library is compatible with both the ESP32 and Teensy platforms. +- **Dependencies**: Ensure you have the required PS/2 keyboard and the correct wiring setup for your microcontroller. + +### Installation + +1. Clone this repository or download the library as a ZIP file. +2. Include the library in your project: + - For Arduino IDE: Go to `Sketch` -> `Include Library` -> `Add .ZIP Library...` and select the downloaded file. + - For PlatformIO: Add this library to your project’s `lib` folder. + +The following library dependency is shared across both environments: + +```ini +[common] +lib_deps = + https://github.com/lahirunirmalx/PS2Keyboard#dev-master +``` + +### Environment Configuration + +#### ESP32 Development Board + +This environment is set up for the ESP32 board, utilizing the Arduino framework with a monitor speed of 115200 baud. + +```ini +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +monitor_speed = 115200 +lib_deps = ${common.lib_deps} +``` + +#### Arduino Uno Board + +This environment is configured for the Arduino Uno board, also using the Arduino framework and a monitor speed of 115200 baud. + +```ini +[env:uno] +platform = atmelavr +board = uno +framework = arduino +monitor_speed = 115200 +lib_deps = ${common.lib_deps} +``` + +### Usage + +After installing the library, initialize the PS/2 keyboard with the appropriate pins for data and clock: + +```cpp +#include + +const int DataPin = 13; +const int IRQPin = 12; +PS2Keyboard keyboard; + +void setup() { + Serial.begin(9600); + keyboard.begin(DataPin, IRQPin); + Serial.println("PS/2 Keyboard ready for input..."); +} + +void loop() { + if (keyboard.available()) { + char c = keyboard.read(); + Serial.print(c); + } +} +``` + +Refer to the library's examples for more detailed usage. + +## Contributing + +Contributions are welcome! Whether it's bug fixes, new features, or documentation improvements, feel free to open an issue or submit a pull request. + +### Support the Original Developers + +This project is built upon the great work done by the original authors at PJRC. Please consider supporting their projects and acknowledging their contributions. + +## License + +This project is licensed under the [MIT License](LICENSE). + +--- + +### Acknowledgments + +Thanks to PJRC for the original PS/2 Keyboard Library and all contributors to the ESP32 and LoRa community who make embedded development more accessible. + +--- \ No newline at end of file diff --git a/library.json b/library.json index 77cc9c1..b6d8d99 100644 --- a/library.json +++ b/library.json @@ -21,15 +21,19 @@ { "name": "Cuningan", "email": "cuninganreset@gmail.com" + }, + { + "name": "Lahiru", + "email": "lahirunirmalx@gmail.com" } ], "repository": { "type": "git", - "url": "https://github.com/PaulStoffregen/PS2Keyboard.git" + "url": "https://github.com/lahirunirmalx/PS2Keyboard.git" }, - "version": "2.4", - "homepage": "http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html", + "version": "2.5", + "homepage": "", "frameworks": "arduino", "platforms": [ diff --git a/library.properties b/library.properties index 340d0ba..fd51f9b 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,10 @@ name=PS2Keyboard -version=2.4 -author=Christian Weichel, Paul Stoffregen, L. Abraham Smith, Cuningan +version=2.5 +author=Christian Weichel, Paul Stoffregen, L. Abraham Smith, Cuningan , lahirunirmalx maintainer=Paul Stoffregen sentence=Use a PS/2 Keyboard for input paragraph= category=Signal Input/Output -url=https://github.com/PaulStoffregen/PS2Keyboard +url=https://github.com/lahirunirmalx/PS2Keyboard architectures=*