]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/keyboard.c
faster, less bits :)
[qmk_firmware.git] / tmk_core / common / keyboard.c
1 /*
2 Copyright 2011, 2012, 2013 Jun Wako <wakojun@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdint.h>
19 #include "keyboard.h"
20 #include "matrix.h"
21 #include "keymap.h"
22 #include "host.h"
23 #include "led.h"
24 #include "keycode.h"
25 #include "timer.h"
26 #include "print.h"
27 #include "debug.h"
28 #include "command.h"
29 #include "util.h"
30 #include "sendchar.h"
31 #include "eeconfig.h"
32 #include "backlight.h"
33 #include "action_layer.h"
34 #ifdef BOOTMAGIC_ENABLE
35 #   include "bootmagic.h"
36 #else
37 #   include "magic.h"
38 #endif
39 #ifdef MOUSEKEY_ENABLE
40 #   include "mousekey.h"
41 #endif
42 #ifdef PS2_MOUSE_ENABLE
43 #   include "ps2_mouse.h"
44 #endif
45 #ifdef SERIAL_MOUSE_ENABLE
46 #   include "serial_mouse.h"
47 #endif
48 #ifdef ADB_MOUSE_ENABLE
49 #   include "adb.h"
50 #endif
51 #ifdef RGBLIGHT_ENABLE
52 #   include "rgblight.h"
53 #endif
54 #ifdef FAUXCLICKY_ENABLE
55 #   include "fauxclicky.h"
56 #endif
57 #ifdef SERIAL_LINK_ENABLE
58 #   include "serial_link/system/serial_link.h"
59 #endif
60 #ifdef VISUALIZER_ENABLE
61 #   include "visualizer/visualizer.h"
62 #endif
63
64
65 #ifdef MATRIX_HAS_GHOST
66 extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
67 static matrix_row_t get_real_keys(uint8_t row, matrix_row_t rowdata){
68     matrix_row_t out = 0;
69     for (int col = 0; col < MATRIX_COLS; col++) {
70         if (pgm_read_byte(&keymaps[0][row][col]) && ((rowdata & (1<<col)))){
71             out |= 1<<col;
72         }
73     }
74     return out;
75 }
76
77 static inline bool countones(matrix_row_t row)
78 {
79     row &= row-1;
80     return row;
81 }
82
83 static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata)
84 {
85     rowdata = get_real_keys(row, rowdata);
86     if (((rowdata - 1) & rowdata) == 0){
87         return false;
88     }
89     /* No ghost exists when less than 2 keys are down on the row.
90     If there are "active" blanks in the matrix, the key can't be pressed by the user,
91     there is no doubt as to which keys are really being pressed.
92     The ghosts will be ignored, they are KC_NO.   */
93     // Ghost occurs when the row shares column line with other row, blanks in the matrix don't matter
94     // If there are more than two real keys pressed and they match another row's real keys, the row will be ignored.
95     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
96         if (i != row && countones(get_real_keys(i, matrix_get_row(i)) & rowdata)){
97             return true;
98         }
99     }
100     return false;
101 }
102
103 #endif
104
105
106 __attribute__ ((weak))
107 void matrix_setup(void) {
108 }
109
110 void keyboard_setup(void) {
111     matrix_setup();
112 }
113
114 void keyboard_init(void) {
115     timer_init();
116     matrix_init();
117 #ifdef PS2_MOUSE_ENABLE
118     ps2_mouse_init();
119 #endif
120 #ifdef SERIAL_MOUSE_ENABLE
121     serial_mouse_init();
122 #endif
123 #ifdef ADB_MOUSE_ENABLE
124     adb_mouse_init();
125 #endif
126 #ifdef BOOTMAGIC_ENABLE
127     bootmagic();
128 #else
129     magic();
130 #endif
131 #ifdef BACKLIGHT_ENABLE
132     backlight_init();
133 #endif
134 #ifdef RGBLIGHT_ENABLE
135     rgblight_init();
136 #endif
137 #ifdef FAUXCLICKY_ENABLE
138     fauxclicky_init();
139 #endif
140 #if defined(NKRO_ENABLE) && defined(FORCE_NKRO)
141     keymap_config.nkro = 1;
142 #endif
143 }
144
145 /*
146  * Do keyboard routine jobs: scan mantrix, light LEDs, ...
147  * This is repeatedly called as fast as possible.
148  */
149 void keyboard_task(void)
150 {
151     static matrix_row_t matrix_prev[MATRIX_ROWS];
152 #ifdef MATRIX_HAS_GHOST
153   //  static matrix_row_t matrix_ghost[MATRIX_ROWS];
154 #endif
155     static uint8_t led_status = 0;
156     matrix_row_t matrix_row = 0;
157     matrix_row_t matrix_change = 0;
158
159     matrix_scan();
160     for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
161         matrix_row = matrix_get_row(r);
162         matrix_change = matrix_row ^ matrix_prev[r];
163         if (matrix_change) {
164 #ifdef MATRIX_HAS_GHOST
165             if (has_ghost_in_row(r, matrix_row)) {
166                 /* Keep track of whether ghosted status has changed for
167                  * debugging. But don't update matrix_prev until un-ghosted, or
168                  * the last key would be lost.
169                  */
170                 //if (debug_matrix && matrix_ghost[r] != matrix_row) {
171                 //    matrix_print();
172                 //}
173                 //matrix_ghost[r] = matrix_row;
174                 continue;
175             }
176             //matrix_ghost[r] = matrix_row;
177 #endif
178             if (debug_matrix) matrix_print();
179             for (uint8_t c = 0; c < MATRIX_COLS; c++) {
180                 if (matrix_change & ((matrix_row_t)1<<c)) {
181                     action_exec((keyevent_t){
182                         .key = (keypos_t){ .row = r, .col = c },
183                         .pressed = (matrix_row & ((matrix_row_t)1<<c)),
184                         .time = (timer_read() | 1) /* time should not be 0 */
185                     });
186                     // record a processed key
187                     matrix_prev[r] ^= ((matrix_row_t)1<<c);
188                     // process a key per task call
189                     goto MATRIX_LOOP_END;
190                 }
191             }
192         }
193     }
194     // call with pseudo tick event when no real key event.
195     action_exec(TICK);
196
197 MATRIX_LOOP_END:
198
199 #ifdef MOUSEKEY_ENABLE
200     // mousekey repeat & acceleration
201     mousekey_task();
202 #endif
203
204 #ifdef PS2_MOUSE_ENABLE
205     ps2_mouse_task();
206 #endif
207
208 #ifdef SERIAL_MOUSE_ENABLE
209     serial_mouse_task();
210 #endif
211
212 #ifdef ADB_MOUSE_ENABLE
213     adb_mouse_task();
214 #endif
215
216 #ifdef SERIAL_LINK_ENABLE
217         serial_link_update();
218 #endif
219
220 #ifdef VISUALIZER_ENABLE
221     visualizer_update(default_layer_state, layer_state, visualizer_get_mods(), host_keyboard_leds());
222 #endif
223
224     // update LED
225     if (led_status != host_keyboard_leds()) {
226         led_status = host_keyboard_leds();
227         keyboard_set_leds(led_status);
228     }
229 }
230
231 void keyboard_set_leds(uint8_t leds)
232 {
233     if (debug_keyboard) { debug("keyboard_set_led: "); debug_hex8(leds); debug("\n"); }
234     led_set(leds);
235 }