From c01630410074671dd0be9b296167a3659d3c3dce Mon Sep 17 00:00:00 2001 From: Ronald Schaten Date: Sat, 19 Jul 2008 20:17:43 +0000 Subject: [PATCH] implemented algorithm to prevent ghost-keys --- firmware/main.c | 60 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/firmware/main.c b/firmware/main.c index e452c02..b58ec95 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -289,6 +289,7 @@ static void hardwareInit(void) { /* ------------------------------------------------------------------------- */ static uint8_t reportBuffer[8]; ///< buffer for HID reports +static uint8_t oldReportBuffer[8]; ///< buffer for the last sent HID report static uint8_t idleRate; ///< in 4ms units static uint8_t protocolVer = 1; ///< 0 = boot protocol, 1 = report protocol uint8_t expectReport = 0; ///< flag to indicate if we expect an USB-report @@ -428,6 +429,7 @@ void usbSendReport(uint8_t mode, uint8_t key) { /* ------------------------------------------------------------------------- */ uint8_t curmatrix[16]; ///< contains current state of the keyboard +uint8_t ghostmatrix[16]; ///< contains pressed keys that belong to a ghost-key situation /** * The keymatrix-array contains positions of keys in the matrix. Here you can @@ -493,7 +495,7 @@ typedef struct { /** * Convert an ASCII-character to the corresponding key-code and modifier-code * combination. - * \parm character ASCII-character to convert + * \param character ASCII-character to convert * \return structure containing the combination */ Key charToKey(char character) { @@ -670,6 +672,31 @@ void printMatrix(void) { sendString("---"); } +/** + * Checks if more than one bit in data is set. + * \param data value to check + * \return true if more than one bit is set + */ +uint8_t bitcount2(uint16_t data) { + data &= (data - 1); + return data != 0; +} + +/** + * check if reportBuffer contains the key + * \param buffer buffer to check + * \param key key to search + * \return 1 if buffer contains key, 0 otherwise + */ +uint8_t bufferContains(uint8_t* buffer, uint8_t key) { + for (uint8_t i = 2; i < sizeof(buffer); i++) { + if (buffer[i] == key) { + return 1; + } + } + return 0; +} + /** * Scan and debounce keypresses. This is the main worker function for normal * keyboard operation, the code contains lot of comments. Basically, it first @@ -679,7 +706,8 @@ void printMatrix(void) { * so we can be pretty sure that the keys are in a certain state (as in: not * bouncing). Then, the codes for keys and modifiers are searched from the two * arrays, the USB-message to send the state is prepared. The return value of - * this function indicates if the message has to be sent. + *~ this function indicates if the message has to be sent. + * \return flag to indicate whether something has changed */ uint8_t scankeys(void) { @@ -703,6 +731,14 @@ uint8_t scankeys(void) { } _delay_us(30); uint8_t data = ~PINCOLUMNS; + // check if we have to prevent ghost-keys + uint16_t rows= (PINROWS1 << 8) | PINROWS2; + if (bitcount2(~rows) && bitcount2(data)) { + // ghost-key situation detected + ghostmatrix[row] = data; + } else { + ghostmatrix[row] = 0x00; + } if (data != curmatrix[row]) { // if a change was detected debounce = 10; // activate debounce counter @@ -721,13 +757,15 @@ uint8_t scankeys(void) { uint8_t data = curmatrix[row]; // restore buffer if (data != 0xff) { // anything on this row? - optimization for (uint8_t col = 0; col <= 7; col++) { // check every bit on this row - uint8_t key, modifier; + uint8_t key, modifier, isghostkey; if (data & (1 << col)) { key = pgm_read_byte(&keymatrix[row][col]); modifier = pgm_read_byte(&modmatrix[row][col]); + isghostkey = ghostmatrix[row] & (1 << col); } else { key = KEY_Reserved; modifier = MOD_NONE; + isghostkey = 0x00; } if (key != KEY_Reserved) { // keycode should be added to report if (reportIndex >= sizeof(reportBuffer)) { // too many keycodes @@ -736,8 +774,17 @@ uint8_t scankeys(void) { retval |= 0x02; // continue decoding to get modifiers } } else { - reportBuffer[reportIndex] = key; // set next available entry - reportIndex++; + if (isghostkey) { + // we're in a ghost-key situation + if (bufferContains(oldReportBuffer, key)) { + // this key has been pressed before, so we still send it + reportBuffer[reportIndex] = key; // set next available entry + reportIndex++; + } + } else { + reportBuffer[reportIndex] = key; // set next available entry + reportIndex++; + } } } if (modifier != MOD_NONE) { // modifier should be added to report @@ -766,6 +813,8 @@ int main(void) { usbInit(); sei(); + memset(oldReportBuffer, 0, sizeof(oldReportBuffer)); // clear old report buffer + scankeys(); while (1) { // main event loop @@ -790,6 +839,7 @@ int main(void) { if (updateNeeded && usbInterruptIsReady()) { updateNeeded = 0; usbSetInterrupt(reportBuffer, sizeof(reportBuffer)); + memcpy(oldReportBuffer, reportBuffer, sizeof(oldReportBuffer)); } } return 0;