Merge pull request #1298 from barrar/master

Anti-ghost improvement for older keyboards with empty spots in matrix
master
Jack Humbert 2017-05-15 12:20:17 -04:00 committed by GitHub
commit 7cbbf62f5f
2 changed files with 45 additions and 18 deletions

View File

@ -61,23 +61,51 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "visualizer/visualizer.h" # include "visualizer/visualizer.h"
#endif #endif
#ifdef MATRIX_HAS_GHOST #ifdef MATRIX_HAS_GHOST
static bool has_ghost_in_row(uint8_t row) extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
{ static matrix_row_t get_real_keys(uint8_t row, matrix_row_t rowdata){
matrix_row_t matrix_row = matrix_get_row(row); matrix_row_t out = 0;
// No ghost exists when less than 2 keys are down on the row for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (((matrix_row - 1) & matrix_row) == 0) //read each key in the row data and check if the keymap defines it as a real key
return false; if (pgm_read_byte(&keymaps[0][row][col]) && (rowdata & (1<<col))){
//this creates new row data, if a key is defined in the keymap, it will be set here
out |= 1<<col;
}
}
return out;
}
// Ghost occurs when the row shares column line with other row static inline bool popcount_more_than_one(matrix_row_t rowdata)
{
rowdata &= rowdata-1; //if there are less than two bits (keys) set, rowdata will become zero
return rowdata;
}
static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata)
{
/* No ghost exists when less than 2 keys are down on the row.
If there are "active" blanks in the matrix, the key can't be pressed by the user,
there is no doubt as to which keys are really being pressed.
The ghosts will be ignored, they are KC_NO. */
rowdata = get_real_keys(row, rowdata);
if ((popcount_more_than_one(rowdata)) == 0){
return false;
}
/* Ghost occurs when the row shares a column line with other row,
and two columns are read on each row. Blanks in the matrix don't matter,
so they are filtered out.
If there are two or more real keys pressed and they match columns with
at least two of another row's real keys, the row will be ignored. Keep in mind,
we are checking one row at a time, not all of them at once.
*/
for (uint8_t i=0; i < MATRIX_ROWS; i++) { for (uint8_t i=0; i < MATRIX_ROWS; i++) {
if (i != row && (matrix_get_row(i) & matrix_row)) if (i != row && popcount_more_than_one(get_real_keys(i, matrix_get_row(i)) & rowdata)){
return true; return true;
}
} }
return false; return false;
} }
#endif #endif
__attribute__ ((weak)) __attribute__ ((weak))
@ -127,7 +155,7 @@ void keyboard_task(void)
{ {
static matrix_row_t matrix_prev[MATRIX_ROWS]; static matrix_row_t matrix_prev[MATRIX_ROWS];
#ifdef MATRIX_HAS_GHOST #ifdef MATRIX_HAS_GHOST
static matrix_row_t matrix_ghost[MATRIX_ROWS]; // static matrix_row_t matrix_ghost[MATRIX_ROWS];
#endif #endif
static uint8_t led_status = 0; static uint8_t led_status = 0;
matrix_row_t matrix_row = 0; matrix_row_t matrix_row = 0;
@ -139,18 +167,18 @@ void keyboard_task(void)
matrix_change = matrix_row ^ matrix_prev[r]; matrix_change = matrix_row ^ matrix_prev[r];
if (matrix_change) { if (matrix_change) {
#ifdef MATRIX_HAS_GHOST #ifdef MATRIX_HAS_GHOST
if (has_ghost_in_row(r)) { if (has_ghost_in_row(r, matrix_row)) {
/* Keep track of whether ghosted status has changed for /* Keep track of whether ghosted status has changed for
* debugging. But don't update matrix_prev until un-ghosted, or * debugging. But don't update matrix_prev until un-ghosted, or
* the last key would be lost. * the last key would be lost.
*/ */
if (debug_matrix && matrix_ghost[r] != matrix_row) { //if (debug_matrix && matrix_ghost[r] != matrix_row) {
matrix_print(); // matrix_print();
} //}
matrix_ghost[r] = matrix_row; //matrix_ghost[r] = matrix_row;
continue; continue;
} }
matrix_ghost[r] = matrix_row; //matrix_ghost[r] = matrix_row;
#endif #endif
if (debug_matrix) matrix_print(); if (debug_matrix) matrix_print();
for (uint8_t c = 0; c < MATRIX_COLS; c++) { for (uint8_t c = 0; c < MATRIX_COLS; c++) {

View File

@ -57,7 +57,6 @@ static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) &&
.time = (timer_read() | 1) \ .time = (timer_read() | 1) \
} }
/* it runs once at early stage of startup before keyboard_init. */ /* it runs once at early stage of startup before keyboard_init. */
void keyboard_setup(void); void keyboard_setup(void);
/* it runs once after initializing host side protocol, debug and MCU peripherals. */ /* it runs once after initializing host side protocol, debug and MCU peripherals. */