summaryrefslogtreecommitdiff
path: root/tmk_core
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core')
-rw-r--r--tmk_core/common.mk4
-rw-r--r--tmk_core/common/action.c135
-rw-r--r--tmk_core/common/action.h7
-rw-r--r--tmk_core/common/action_code.h5
-rw-r--r--tmk_core/common/action_tapping.c30
-rw-r--r--tmk_core/common/action_util.c70
-rw-r--r--tmk_core/common/action_util.h20
-rw-r--r--tmk_core/common/avr/suspend.c5
-rw-r--r--tmk_core/common/backlight.c5
-rw-r--r--tmk_core/common/backlight.h1
-rw-r--r--tmk_core/common/bootmagic.c14
-rw-r--r--tmk_core/common/command.c17
-rw-r--r--tmk_core/common/keyboard.c138
-rw-r--r--tmk_core/common/matrix.h65
-rw-r--r--tmk_core/common/nodebug.h12
-rw-r--r--tmk_core/doc/keymap.md8
-rw-r--r--tmk_core/protocol/lufa/lufa.c6
-rw-r--r--tmk_core/rules.mk42
18 files changed, 384 insertions, 200 deletions
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index 9cb2eb8ecd..b5d7e39dd1 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -60,6 +60,10 @@ ifeq ($(strip $(AUDIO_ENABLE)), yes)
OPT_DEFS += -DAUDIO_ENABLE
endif
+ifeq ($(strip $(UNICODE_ENABLE)), yes)
+ OPT_DEFS += -DUNICODE_ENABLE
+endif
+
ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
OPT_DEFS += -DUSB_6KRO_ENABLE
endif
diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c
index f9e6c17dc3..be6dea2b79 100644
--- a/tmk_core/common/action.c
+++ b/tmk_core/common/action.c
@@ -46,7 +46,7 @@ void action_exec(keyevent_t event)
#ifndef NO_ACTION_TAPPING
action_tapping_process(record);
#else
- process_action(&record);
+ process_record(&record);
if (!IS_NOEVENT(record.event)) {
dprint("processed: "); debug_record(record); dprintln();
}
@@ -56,34 +56,32 @@ void action_exec(keyevent_t event)
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
bool disable_action_cache = false;
-void process_action_nocache(keyrecord_t *record)
+void process_record_nocache(keyrecord_t *record)
{
disable_action_cache = true;
- process_action(record);
+ process_record(record);
disable_action_cache = false;
}
#else
-void process_action_nocache(keyrecord_t *record)
+void process_record_nocache(keyrecord_t *record)
{
- process_action(record);
+ process_record(record);
}
#endif
__attribute__ ((weak))
-void process_action_kb(keyrecord_t *record) {}
+bool process_record_quantum(keyrecord_t *record) {
+ return true;
+}
-void process_action(keyrecord_t *record)
+void process_record(keyrecord_t *record)
{
- keyevent_t event = record->event;
-#ifndef NO_ACTION_TAPPING
- uint8_t tap_count = record->tap.count;
-#endif
-
- if (IS_NOEVENT(event)) { return; }
+ if (IS_NOEVENT(record->event)) { return; }
- process_action_kb(record);
+ if(!process_record_quantum(record))
+ return;
- action_t action = store_or_get_action(event.pressed, event.key);
+ action_t action = store_or_get_action(record->event.pressed, record->event.key);
dprint("ACTION: "); debug_action(action);
#ifndef NO_ACTION_LAYER
dprint(" layer_state: "); layer_debug();
@@ -91,10 +89,37 @@ void process_action(keyrecord_t *record)
#endif
dprintln();
+ process_action(record, action);
+}
+
+void process_action(keyrecord_t *record, action_t action)
+{
+ bool do_release_oneshot = false;
+ keyevent_t event = record->event;
+#ifndef NO_ACTION_TAPPING
+ uint8_t tap_count = record->tap.count;
+#endif
+
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ if (has_oneshot_layer_timed_out()) {
+ dprintf("Oneshot layer: timeout\n");
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+ }
+#endif
+
if (event.pressed) {
// clear the potential weak mods left by previously pressed keys
clear_weak_mods();
}
+
+#ifndef NO_ACTION_ONESHOT
+ // notice we only clear the one shot layer if the pressed key is not a modifier.
+ if (is_oneshot_layer_active() && event.pressed && !IS_MOD(action.key.code)) {
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+ do_release_oneshot = !is_oneshot_layer_active();
+ }
+#endif
+
switch (action.kind.id) {
/* Key and Mods */
case ACT_LMODS:
@@ -139,24 +164,37 @@ void process_action(keyrecord_t *record)
// Oneshot modifier
if (event.pressed) {
if (tap_count == 0) {
+ dprint("MODS_TAP: Oneshot: 0\n");
register_mods(mods);
- }
- else if (tap_count == 1) {
+ } else if (tap_count == 1) {
dprint("MODS_TAP: Oneshot: start\n");
set_oneshot_mods(mods);
- }
- else {
+ #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
+ } else if (tap_count == ONESHOT_TAP_TOGGLE) {
+ dprint("MODS_TAP: Toggling oneshot");
+ clear_oneshot_mods();
+ set_oneshot_locked_mods(mods);
+ register_mods(mods);
+ #endif
+ } else {
register_mods(mods);
}
} else {
if (tap_count == 0) {
clear_oneshot_mods();
unregister_mods(mods);
- }
- else if (tap_count == 1) {
+ } else if (tap_count == 1) {
// Retain Oneshot mods
- }
- else {
+ #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
+ if (mods & get_mods()) {
+ clear_oneshot_locked_mods();
+ clear_oneshot_mods();
+ unregister_mods(mods);
+ }
+ } else if (tap_count == ONESHOT_TAP_TOGGLE) {
+ // Toggle Oneshot Layer
+ #endif
+ } else {
clear_oneshot_mods();
unregister_mods(mods);
}
@@ -309,6 +347,44 @@ void process_action(keyrecord_t *record)
event.pressed ? layer_move(action.layer_tap.val) :
layer_clear();
break;
+ #ifndef NO_ACTION_ONESHOT
+ case OP_ONESHOT:
+ // Oneshot modifier
+ #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
+ do_release_oneshot = false;
+ if (event.pressed) {
+ del_mods(get_oneshot_locked_mods());
+ if (get_oneshot_layer_state() == ONESHOT_TOGGLED) {
+ reset_oneshot_layer();
+ layer_off(action.layer_tap.val);
+ break;
+ } else if (tap_count < ONESHOT_TAP_TOGGLE) {
+ layer_on(action.layer_tap.val);
+ set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
+ }
+ } else {
+ add_mods(get_oneshot_locked_mods());
+ if (tap_count >= ONESHOT_TAP_TOGGLE) {
+ reset_oneshot_layer();
+ clear_oneshot_locked_mods();
+ set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED);
+ } else {
+ clear_oneshot_layer_state(ONESHOT_PRESSED);
+ }
+ }
+ #else
+ if (event.pressed) {
+ layer_on(action.layer_tap.val);
+ set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
+ } else {
+ clear_oneshot_layer_state(ONESHOT_PRESSED);
+ if (tap_count > 1) {
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+ }
+ }
+ #endif
+ break;
+ #endif
default:
/* tap key */
if (event.pressed) {
@@ -372,6 +448,18 @@ void process_action(keyrecord_t *record)
default:
break;
}
+
+#ifndef NO_ACTION_ONESHOT
+ /* Because we switch layers after a oneshot event, we need to release the
+ * key before we leave the layer or no key up event will be generated.
+ */
+ if (do_release_oneshot && !(get_oneshot_layer_state() & ONESHOT_PRESSED ) ) {
+ record->event.pressed = false;
+ layer_on(get_oneshot_layer());
+ process_record(record);
+ layer_off(get_oneshot_layer());
+ }
+#endif
}
@@ -560,6 +648,7 @@ bool is_tap_key(keypos_t key)
switch (action.layer_tap.code) {
case 0x00 ... 0xdf:
case OP_TAP_TOGGLE:
+ case OP_ONESHOT:
return true;
}
return false;
diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h
index 44ec3047ba..e8aa12a7cb 100644
--- a/tmk_core/common/action.h
+++ b/tmk_core/common/action.h
@@ -59,14 +59,15 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt);
void action_function(keyrecord_t *record, uint8_t id, uint8_t opt);
/* keyboard-specific key event (pre)processing */
-void process_action_kb(keyrecord_t *record);
+bool process_record_quantum(keyrecord_t *record);
/* Utilities for actions. */
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
extern bool disable_action_cache;
#endif
-void process_action_nocache(keyrecord_t *record);
-void process_action(keyrecord_t *record);
+void process_record_nocache(keyrecord_t *record);
+void process_record(keyrecord_t *record);
+void process_action(keyrecord_t *record, action_t action);
void register_code(uint8_t code);
void unregister_code(uint8_t code);
void register_mods(uint8_t mods);
diff --git a/tmk_core/common/action_code.h b/tmk_core/common/action_code.h
index 2b0b0b077e..ca729aaece 100644
--- a/tmk_core/common/action_code.h
+++ b/tmk_core/common/action_code.h
@@ -76,7 +76,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* 101E|LLLL|1111 0001 On/Off (0xF1) [NOT TAP]
* 101E|LLLL|1111 0010 Off/On (0xF2) [NOT TAP]
* 101E|LLLL|1111 0011 Set/Clear (0xF3) [NOT TAP]
- * 101E|LLLL|1111 xxxx Reserved (0xF4-FF)
+ * 101E|LLLL|1111 0100 One Shot Layer (0xF4) [TAP]
+ * 101E|LLLL|1111 xxxx Reserved (0xF5-FF)
* ELLLL: layer 0-31(E: extra bit for layer 16-31)
*
*
@@ -250,6 +251,7 @@ enum layer_pram_tap_op {
OP_ON_OFF,
OP_OFF_ON,
OP_SET_CLEAR,
+ OP_ONESHOT,
};
#define ACTION_LAYER_BITOP(op, part, bits, on) (ACT_LAYER<<12 | (op)<<10 | (on)<<8 | (part)<<5 | ((bits)&0x1f))
#define ACTION_LAYER_TAP(layer, key) (ACT_LAYER_TAP<<12 | (layer)<<8 | (key))
@@ -266,6 +268,7 @@ enum layer_pram_tap_op {
#define ACTION_LAYER_ON_OFF(layer) ACTION_LAYER_TAP((layer), OP_ON_OFF)
#define ACTION_LAYER_OFF_ON(layer) ACTION_LAYER_TAP((layer), OP_OFF_ON)
#define ACTION_LAYER_SET_CLEAR(layer) ACTION_LAYER_TAP((layer), OP_SET_CLEAR)
+#define ACTION_LAYER_ONESHOT(layer) ACTION_LAYER_TAP((layer), OP_ONESHOT)
#define ACTION_LAYER_MODS(layer, mods) ACTION_LAYER_TAP((layer), 0xe0 | ((mods)&0x0f))
/* With Tapping */
#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))
diff --git a/tmk_core/common/action_tapping.c b/tmk_core/common/action_tapping.c
index e6343e6da7..ff78d7f2ab 100644
--- a/tmk_core/common/action_tapping.c
+++ b/tmk_core/common/action_tapping.c
@@ -89,7 +89,7 @@ bool process_tapping(keyrecord_t *keyp)
debug("Tapping: First tap(0->1).\n");
tapping_key.tap.count = 1;
debug_tapping_key();
- process_action(&tapping_key);
+ process_record(&tapping_key);
// copy tapping state
keyp->tap = tapping_key.tap;
@@ -103,7 +103,7 @@ bool process_tapping(keyrecord_t *keyp)
*/
else if (IS_RELEASED(event) && waiting_buffer_typed(event)) {
debug("Tapping: End. No tap. Interfered by typing key\n");
- process_action(&tapping_key);
+ process_record(&tapping_key);
tapping_key = (keyrecord_t){};
debug_tapping_key();
// enqueue
@@ -131,7 +131,7 @@ bool process_tapping(keyrecord_t *keyp)
}
// Release of key should be process immediately.
debug("Tapping: release event of a key pressed before tapping\n");
- process_action(keyp);
+ process_record(keyp);
return true;
}
else {
@@ -148,7 +148,7 @@ bool process_tapping(keyrecord_t *keyp)
if (IS_TAPPING_KEY(event.key) && !event.pressed) {
debug("Tapping: Tap release("); debug_dec(tapping_key.tap.count); debug(")\n");
keyp->tap = tapping_key.tap;
- process_action(keyp);
+ process_record(keyp);
tapping_key = *keyp;
debug_tapping_key();
return true;
@@ -157,7 +157,7 @@ bool process_tapping(keyrecord_t *keyp)
if (tapping_key.tap.count > 1) {
debug("Tapping: Start new tap with releasing last tap(>1).\n");
// unregister key
- process_action(&(keyrecord_t){
+ process_record(&(keyrecord_t){
.tap = tapping_key.tap,
.event.key = tapping_key.event.key,
.event.time = event.time,
@@ -175,7 +175,7 @@ bool process_tapping(keyrecord_t *keyp)
if (!IS_NOEVENT(event)) {
debug("Tapping: key event while last tap(>0).\n");
}
- process_action(keyp);
+ process_record(keyp);
return true;
}
}
@@ -185,7 +185,7 @@ bool process_tapping(keyrecord_t *keyp)
if (tapping_key.tap.count == 0) {
debug("Tapping: End. Timeout. Not tap(0): ");
debug_event(event); debug("\n");
- process_action(&tapping_key);
+ process_record(&tapping_key);
tapping_key = (keyrecord_t){};
debug_tapping_key();
return false;
@@ -193,7 +193,7 @@ bool process_tapping(keyrecord_t *keyp)
if (IS_TAPPING_KEY(event.key) && !event.pressed) {
debug("Tapping: End. last timeout tap release(>0).");
keyp->tap = tapping_key.tap;
- process_action(keyp);
+ process_record(keyp);
tapping_key = (keyrecord_t){};
return true;
}
@@ -201,7 +201,7 @@ bool process_tapping(keyrecord_t *keyp)
if (tapping_key.tap.count > 1) {
debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
// unregister key
- process_action(&(keyrecord_t){
+ process_record(&(keyrecord_t){
.tap = tapping_key.tap,
.event.key = tapping_key.event.key,
.event.time = event.time,
@@ -219,7 +219,7 @@ bool process_tapping(keyrecord_t *keyp)
if (!IS_NOEVENT(event)) {
debug("Tapping: key event while last timeout tap(>0).\n");
}
- process_action(keyp);
+ process_record(keyp);
return true;
}
}
@@ -233,7 +233,7 @@ bool process_tapping(keyrecord_t *keyp)
keyp->tap = tapping_key.tap;
if (keyp->tap.count < 15) keyp->tap.count += 1;
debug("Tapping: Tap press("); debug_dec(keyp->tap.count); debug(")\n");
- process_action(keyp);
+ process_record(keyp);
tapping_key = *keyp;
debug_tapping_key();
return true;
@@ -253,12 +253,12 @@ bool process_tapping(keyrecord_t *keyp)
// should none in buffer
// FIX: interrupted when other key is pressed
tapping_key.tap.interrupted = true;
- process_action(keyp);
+ process_record(keyp);
return true;
}
} else {
if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
- process_action(keyp);
+ process_record(keyp);
return true;
}
} else {
@@ -280,7 +280,7 @@ bool process_tapping(keyrecord_t *keyp)
debug_tapping_key();
return true;
} else {
- process_action(keyp);
+ process_record(keyp);
return true;
}
}
@@ -347,7 +347,7 @@ void waiting_buffer_scan_tap(void)
WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
tapping_key.tap.count = 1;
waiting_buffer[i].tap.count = 1;
- process_action(&tapping_key);
+ process_record(&tapping_key);
debug("waiting_buffer_scan_tap: found at ["); debug_dec(i); debug("]\n");
debug_waiting_buffer();
diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c
index a2d6577b24..61ff202bef 100644
--- a/tmk_core/common/action_util.c
+++ b/tmk_core/common/action_util.c
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "report.h"
#include "debug.h"
#include "action_util.h"
+#include "action_layer.h"
#include "timer.h"
static inline void add_key_byte(uint8_t code);
@@ -47,11 +48,70 @@ report_keyboard_t *keyboard_report = &(report_keyboard_t){};
#ifndef NO_ACTION_ONESHOT
static int8_t oneshot_mods = 0;
+static int8_t oneshot_locked_mods = 0;
+int8_t get_oneshot_locked_mods(void) { return oneshot_locked_mods; }
+void set_oneshot_locked_mods(int8_t mods) { oneshot_locked_mods = mods; }
+void clear_oneshot_locked_mods(void) { oneshot_locked_mods = 0; }
#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
static int16_t oneshot_time = 0;
+inline bool has_oneshot_mods_timed_out() {
+ return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT;
+}
#endif
#endif
+/* oneshot layer */
+#ifndef NO_ACTION_ONESHOT
+/* oneshot_layer_data bits
+* LLLL LSSS
+* where:
+* L => are layer bits
+* S => oneshot state bits
+*/
+static int8_t oneshot_layer_data = 0;
+
+inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; }
+inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; }
+
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+static int16_t oneshot_layer_time = 0;
+inline bool has_oneshot_layer_timed_out() {
+ return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT &&
+ !(get_oneshot_layer_state() & ONESHOT_TOGGLED);
+}
+#endif
+
+/* Oneshot layer */
+void set_oneshot_layer(uint8_t layer, uint8_t state)
+{
+ oneshot_layer_data = layer << 3 | state;
+ layer_on(layer);
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_layer_time = timer_read();
+#endif
+}
+void reset_oneshot_layer(void) {
+ oneshot_layer_data = 0;
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_layer_time = 0;
+#endif
+}
+void clear_oneshot_layer_state(oneshot_fullfillment_t state)
+{
+ uint8_t start_state = oneshot_layer_data;
+ oneshot_layer_data &= ~state;
+ if (!get_oneshot_layer_state() && start_state != oneshot_layer_data) {
+ layer_off(get_oneshot_layer());
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_layer_time = 0;
+#endif
+ }
+}
+bool is_oneshot_layer_active(void)
+{
+ return get_oneshot_layer_state();
+}
+#endif
void send_keyboard_report(void) {
keyboard_report->mods = real_mods;
@@ -60,7 +120,7 @@ void send_keyboard_report(void) {
#ifndef NO_ACTION_ONESHOT
if (oneshot_mods) {
#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
- if (TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT) {
+ if (has_oneshot_mods_timed_out()) {
dprintf("Oneshot: timeout\n");
clear_oneshot_mods();
}
@@ -70,6 +130,7 @@ void send_keyboard_report(void) {
clear_oneshot_mods();
}
}
+
#endif
host_keyboard_send(keyboard_report);
}
@@ -143,11 +204,12 @@ void clear_oneshot_mods(void)
oneshot_time = 0;
#endif
}
+uint8_t get_oneshot_mods(void)
+{
+ return oneshot_mods;
+}
#endif
-
-
-
/*
* inspect keyboard state
*/
diff --git a/tmk_core/common/action_util.h b/tmk_core/common/action_util.h
index 1a95cec10e..dd0c4c2bfe 100644
--- a/tmk_core/common/action_util.h
+++ b/tmk_core/common/action_util.h
@@ -56,10 +56,30 @@ void clear_macro_mods(void);
/* oneshot modifier */
void set_oneshot_mods(uint8_t mods);
+uint8_t get_oneshot_mods(void);
void clear_oneshot_mods(void);
void oneshot_toggle(void);
void oneshot_enable(void);
void oneshot_disable(void);
+bool has_oneshot_mods_timed_out(void);
+
+int8_t get_oneshot_locked_mods(void);
+void set_oneshot_locked_mods(int8_t mods);
+void clear_oneshot_locked_mods(void);
+
+typedef enum {
+ ONESHOT_PRESSED = 0b01,
+ ONESHOT_OTHER_KEY_PRESSED = 0b10,
+ ONESHOT_START = 0b11,
+ ONESHOT_TOGGLED = 0b100
+} oneshot_fullfillment_t;
+void set_oneshot_layer(uint8_t layer, uint8_t state);
+uint8_t get_oneshot_layer(void);
+void clear_oneshot_layer_state(oneshot_fullfillment_t state);
+void reset_oneshot_layer(void);
+bool is_oneshot_layer_active(void);
+uint8_t get_oneshot_layer_state(void);
+bool has_oneshot_layer_timed_out(void);
/* inspect */
uint8_t has_anykey(void);
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c
index 4980680198..a6f3c64414 100644
--- a/tmk_core/common/avr/suspend.c
+++ b/tmk_core/common/avr/suspend.c
@@ -114,9 +114,7 @@ bool suspend_wakeup_condition(void)
matrix_power_up();
matrix_scan();
matrix_power_down();
- for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
- if (matrix_get_row(r)) return true;
- }
+ if (matrix_key_count()) return true;
return false;
}
@@ -146,4 +144,3 @@ ISR(WDT_vect)
}
}
#endif
-
diff --git a/tmk_core/common/backlight.c b/tmk_core/common/backlight.c
index 2f6fc1cd6c..c9e8fd3fd2 100644
--- a/tmk_core/common/backlight.c
+++ b/tmk_core/common/backlight.c
@@ -83,3 +83,8 @@ void backlight_level(uint8_t level)
eeconfig_update_backlight(backlight_config.raw);
backlight_set(backlight_config.level);
}
+
+uint8_t get_backlight_level(void)
+{
+ return backlight_config.level;
+} \ No newline at end of file
diff --git a/tmk_core/common/backlight.h b/tmk_core/common/backlight.h
index 525ec8bbef..f573092674 100644
--- a/tmk_core/common/backlight.h
+++ b/tmk_core/common/backlight.h
@@ -36,5 +36,6 @@ void backlight_toggle(void);
void backlight_step(void);
void backlight_set(uint8_t level);
void backlight_level(uint8_t level);
+uint8_t get_backlight_level(void);
#endif
diff --git a/tmk_core/common/bootmagic.c b/tmk_core/common/bootmagic.c
index 2c1b1adfc5..30e8a0f20f 100644
--- a/tmk_core/common/bootmagic.c
+++ b/tmk_core/common/bootmagic.c
@@ -105,15 +105,13 @@ void bootmagic(void)
}
}
-static bool scan_keycode(uint8_t keycode)
-{
- for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+static bool scan_keycode(uint8_t keycode) {
+ for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
matrix_row_t matrix_row = matrix_get_row(r);
- for (uint8_t c = 0; c < MATRIX_COLS; c++) {
- if (matrix_row & ((matrix_row_t)1<<c)) {
- if (keycode == keymap_key_to_keycode(0, (keypos_t){ .row = r, .col = c })) {
- return true;
- }
+ for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
+ if (matrix_row & (matrix_row_t)1 << c) {
+ keypos_t key = (keypos_t){ .row = r, .col = c };
+ if (keycode == keymap_key_to_keycode(0, key)) return true;
}
}
}
diff --git a/tmk_core/common/command.c b/tmk_core/common/command.c
index f06abaf7f0..024d7c67a3 100644
--- a/tmk_core/common/command.c
+++ b/tmk_core/common/command.c
@@ -33,20 +33,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "led.h"
#include "command.h"
#include "backlight.h"
+#include "quantum.h"
#ifdef MOUSEKEY_ENABLE
#include "mousekey.h"
#endif
#ifdef PROTOCOL_PJRC
-# include "usb_keyboard.h"
-# ifdef EXTRAKEY_ENABLE
-# include "usb_extra.h"
-# endif
+ #include "usb_keyboard.h"
+ #ifdef EXTRAKEY_ENABLE
+ #include "usb_extra.h"
+ #endif
#endif
#ifdef PROTOCOL_VUSB
-# include "usbdrv.h"
+ #include "usbdrv.h"
#endif
#ifdef AUDIO_ENABLE
@@ -357,9 +358,11 @@ static bool command_common(uint8_t code)
clear_keyboard(); // clear to prevent stuck keys
print("\n\nJumping to bootloader... ");
#ifdef AUDIO_ENABLE
- play_goodbye_tone();
+ stop_all_notes();
+ shutdown_user();
+ #else
+ _delay_ms(1000);
#endif
- _delay_ms(1000);
bootloader_jump(); // not return
break;
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 1d99818481..bd543c45e1 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -1,5 +1,5 @@
/*
-Copyright 2011,2012,2013 Jun Wako <wakojun@gmail.com>
+Copyright 2011, 2012, 2013 Jun Wako <wakojun@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,13 +27,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "command.h"
#include "util.h"
#include "sendchar.h"
+#include "eeconfig.h"
+#include "backlight.h"
#ifdef BOOTMAGIC_ENABLE
- #include "bootmagic.h"
+# include "bootmagic.h"
#else
- #include "magic.h"
+# include "magic.h"
#endif
-#include "eeconfig.h"
-#include "backlight.h"
#ifdef MOUSEKEY_ENABLE
# include "mousekey.h"
#endif
@@ -41,40 +41,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "ps2_mouse.h"
#endif
#ifdef SERIAL_MOUSE_ENABLE
-#include "serial_mouse.h"
+# include "serial_mouse.h"
#endif
#ifdef ADB_MOUSE_ENABLE
-#include "adb.h"
+# include "adb.h"
#endif
-
#ifdef MATRIX_HAS_GHOST
-static bool has_ghost_in_row(uint8_t row)
-{
- matrix_row_t matrix_row = matrix_get_row(row);
- // No ghost exists when less than 2 keys are down on the row
- if (((matrix_row - 1) & matrix_row) == 0)
- return false;
-
- // Ghost occurs when the row shares column line with other row
- for (uint8_t i=0; i < MATRIX_ROWS; i++) {
- if (i != row && (matrix_get_row(i) & matrix_row))
- return true;
+static bool is_row_ghosting(uint8_t row){
+ matrix_row_t state = matrix_get_row(row);
+ /* no ghosting happens when only one key in the row is pressed */
+ if (!(state - 1 & state)) return false;
+ /* ghosting occurs when two keys in the same column are pressed */
+ for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
+ if (r != row && matrix_get_row(r) & state) return true;
}
return false;
}
+
#endif
+__attribute__ ((weak))
+void matrix_setup(void) {
+}
-__attribute__ ((weak)) void matrix_setup(void) {}
-void keyboard_setup(void)
-{
+void keyboard_setup(void) {
matrix_setup();
}
-void keyboard_init(void)
-{
-
+void keyboard_init(void) {
timer_init();
matrix_init();
#ifdef PS2_MOUSE_ENABLE
@@ -86,104 +81,85 @@ void keyboard_init(void)
#ifdef ADB_MOUSE_ENABLE
adb_mouse_init();
#endif
-
-
#ifdef BOOTMAGIC_ENABLE
bootmagic();
#else
magic();
#endif
-
#ifdef BACKLIGHT_ENABLE
backlight_init();
#endif
-
#if defined(NKRO_ENABLE) && defined(FORCE_NKRO)
keyboard_nkro = true;
#endif
-
}
-/*
- * Do keyboard routine jobs: scan mantrix, light LEDs, ...
- * This is repeatedly called as fast as possible.
- */
-void keyboard_task(void)
-{
- static matrix_row_t matrix_prev[MATRIX_ROWS];
-#ifdef MATRIX_HAS_GHOST
- static matrix_row_t matrix_ghost[MATRIX_ROWS];
-#endif
- static uint8_t led_status = 0;
- matrix_row_t matrix_row = 0;
- matrix_row_t matrix_change = 0;
-
+/* does routine keyboard jobs */
+void keyboard_task(void) {
+ static uint8_t led_status;
matrix_scan();
- for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
- matrix_row = matrix_get_row(r);
- matrix_change = matrix_row ^ matrix_prev[r];
- if (matrix_change) {
+ for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
+ static matrix_row_t previous_matrix[MATRIX_ROWS];
+ matrix_row_t state = matrix_get_row(r);
+ matrix_row_t changes = state ^ previous_matrix[r];
+ if (changes) {
#ifdef MATRIX_HAS_GHOST
- if (has_ghost_in_row(r)) {
- /* Keep track of whether ghosted status has changed for
- * debugging. But don't update matrix_prev until un-ghosted, or
- * the last key would be lost.
+ static matrix_row_t deghosting_matrix[MATRIX_ROWS];
+ if (is_row_ghosting(r)) {
+ /* debugs the deghosting mechanism */
+ /* doesn't update previous_matrix until the ghosting has stopped
+ * in order to prevent the last key from being lost
*/
- if (debug_matrix && matrix_ghost[r] != matrix_row) {
+ if (debug_matrix && deghosting_matrix[r] != state) {
matrix_print();
}
- matrix_ghost[r] = matrix_row;
+ deghosting_matrix[r] = state;
continue;
}
- matrix_ghost[r] = matrix_row;
+ deghosting_matrix[r] = state;
#endif
if (debug_matrix) matrix_print();
- for (uint8_t c = 0; c < MATRIX_COLS; c++) {
- if (matrix_change & ((matrix_row_t)1<<c)) {
- action_exec((keyevent_t){
- .key = (keypos_t){ .row = r, .col = c },
- .pressed = (matrix_row & ((matrix_row_t)1<<c)),
- .time = (timer_read() | 1) /* time should not be 0 */
- });
- // record a processed key
- matrix_prev[r] ^= ((matrix_row_t)1<<c);
- // process a key per task call
- goto MATRIX_LOOP_END;
+ for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
+ matrix_row_t mask = (matrix_row_t)1 << c;
+ if (changes & mask) {
+ keyevent_t event;
+ event.key = (keypos_t){ .row = r, .col = c };
+ event.pressed = state & mask;
+ /* the time should not be 0 */
+ event.time = timer_read() | 1;
+ action_exec(event);
+ /* records the processed key event */
+ previous_matrix[r] ^= mask;
+ /* processes one key event per call */
+ goto event_processed;
}
}
}
}
- // call with pseudo tick event when no real key event.
+ /* sends tick events when the keyboard is idle */
action_exec(TICK);
-
-MATRIX_LOOP_END:
-
+event_processed:
#ifdef MOUSEKEY_ENABLE
- // mousekey repeat & acceleration
+ /* repeats and accelerates the mouse keys */
mousekey_task();
#endif
-
#ifdef PS2_MOUSE_ENABLE
ps2_mouse_task();
#endif
-
#ifdef SERIAL_MOUSE_ENABLE
- serial_mouse_task();
+ serial_mouse_task();
#endif
-
#ifdef ADB_MOUSE_ENABLE
- adb_mouse_task();
+ adb_mouse_task();
#endif
-
- // update LED
+ /* updates the LEDs */
if (led_status != host_keyboard_leds()) {
led_status = host_keyboard_leds();
keyboard_set_leds(led_status);
}
}
-void keyboard_set_leds(uint8_t leds)
-{
- if (debug_keyboard) { debug("keyboard_set_led: "); debug_hex8(leds); debug("\n"); }
+void keyboard_set_leds(uint8_t leds) {
+ if (debug_keyboard) dprintf("Keyboard LEDs state: %x\n", leds);
led_set(leds);
}
diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h
index 0b013fc989..5f380aaaba 100644
--- a/tmk_core/common/matrix.h
+++ b/tmk_core/common/matrix.h
@@ -14,59 +14,68 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
#ifndef MATRIX_H
#define MATRIX_H
#include <stdint.h>
#include <stdbool.h>
-
-#if (MATRIX_COLS <= 8)
-typedef uint8_t matrix_row_t;
-#elif (MATRIX_COLS <= 16)
-typedef uint16_t matrix_row_t;
-#elif (MATRIX_COLS <= 32)
-typedef uint32_t matrix_row_t;
+#if MATRIX_COLS <= 8
+typedef uint8_t matrix_row_t;
+#elif MATRIX_COLS <= 16
+typedef uint16_t matrix_row_t;
+#elif MATRIX_COLS <= 32
+typedef uint32_t matrix_row_t;
#else
-#error "MATRIX_COLS: invalid value"
+# error "There are too many columns."
#endif
-#define MATRIX_IS_ON(row, col) (matrix_get_row(row) && (1<<col))
+#if DIODE_DIRECTION == ROW2COL
+# if MATRIX_ROWS <= 8
+typedef uint8_t matrix_col_t;
+# elif MATRIX_ROWS <= 16
+typedef uint16_t matrix_col_t;
+# elif MATRIX_ROWS <= 32
+typedef uint32_t matrix_col_t;
+# else
+# error "There are too many rows."
+# endif
+#endif
+typedef struct {
+ uint8_t input_addr:4;
+ uint8_t bit:4;
+} io_pin_t;
#ifdef __cplusplus
extern "C" {
#endif
-
-/* number of matrix rows */
+/* counts the number of rows in the matrix */
uint8_t matrix_rows(void);
-/* number of matrix columns */
+/* counts the number of columns in the matrix */
uint8_t matrix_cols(void);
-/* should be called at early stage of startup before matrix_init.(optional) */
+/* sets up the matrix before matrix_init */
void matrix_setup(void);
-/* intialize matrix for scaning. */
+/* intializes the matrix */
void matrix_init(void);
-/* scan all key states on matrix */
+/* scans the entire matrix */
uint8_t matrix_scan(void);
-/* whether modified from previous scan. used after matrix_scan. */
+/* checks if the matrix has been modified */
bool matrix_is_modified(void) __attribute__ ((deprecated));
-/* whether a swtich is on */
+/* checks if a key is pressed */
bool matrix_is_on(uint8_t row, uint8_t col);
-/* matrix state on row */
+/* inspects the state of a row in the matrix */
matrix_row_t matrix_get_row(uint8_t row);
-/* print matrix for debug */
+/* prints the matrix for debugging */
void matrix_print(void);
-
-
-/* power control */
+/* counts the total number of keys pressed */
+uint8_t matrix_key_count(void);
+/* controls power to the matrix */
void matrix_power_up(void);
void matrix_power_down(void);
-
-/* keyboard-specific setup/loop functionality */
-void matrix_init_kb(void);
-void matrix_scan_kb(void);
-
+/* executes code for Quantum */
+void matrix_init_quantum(void);
+void matrix_scan_quantum(void);
#ifdef __cplusplus
}
#endif
diff --git a/tmk_core/common/nodebug.h b/tmk_core/common/nodebug.h
index 93309ada47..5e18656e5b 100644
--- a/tmk_core/common/nodebug.h
+++ b/tmk_core/common/nodebug.h
@@ -16,10 +16,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NODEBUG_H
-#define NODEBUG_H 1
+#define NODEBUG_H
-#define NO_DEBUG
-#include "debug.h"
-#undef NO_DEBUG
+#ifndef NO_DEBUG
+ #define NO_DEBUG
+ #include "debug.h"
+ #undef NO_DEBUG
+#else
+ #include "debug.h"
+#endif
#endif
diff --git a/tmk_core/doc/keymap.md b/tmk_core/doc/keymap.md
index d4a129b208..4d42fbe5cb 100644
--- a/tmk_core/doc/keymap.md
+++ b/tmk_core/doc/keymap.md
@@ -528,14 +528,20 @@ This is a feature to assign both toggle layer and momentary switch layer action
### 4.3 Oneshot Modifier
-This runs onetime effects which modify only on just one following key. It works as normal modifier key when holding down while oneshot modifier when tapping.
+This runs onetime effects which modify only on just one following key. It works as normal modifier key when holding down while oneshot modifier when tapping. The behavior of oneshot modifiers is similar to the [sticky keys](https://en.wikipedia.org/wiki/StickyKeys) functionality found in most operating systems.
ACTION_MODS_ONESHOT(MOD_LSFT)
+Oneshot layer key:
+
+ ACTION_LAYER_ONESHOT(MY_LAYER)
+
Say you want to type 'The', you have to push and hold Shift key before type 't' then release it before type 'h' and 'e', otherwise you'll get 'THe' or 'the' unintentionally. With Oneshot Modifier you can tap Shift then type 't', 'h' and 'e' normally, you don't need to holding Shift key properly here. This mean you can release Shift before 't' is pressed down.
Oneshot effect is cancel unless following key is pressed down within `ONESHOT_TIMEOUT` of `config.h`. No timeout when it is `0` or not defined.
+Most implementations of sticky keys allow you to lock a modifier by double tapping the modifier. The layer then remains locked untill the modifier is tapped again. To enable this behaviour for oneshot modifiers set `ONESHOT_TAP_TOGGLE` to the number taps required. The feature is disabled if `ONESHOT_TAP_TOGGLE<2` or not defined.
+
### 4.4 Tap Toggle Mods
Similar to layer tap toggle, this works as a momentary modifier when holding, but toggles on with several taps. A single tap will 'unstick' the modifier again.
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index f03f9a9b92..b70b52bf4d 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -883,7 +883,7 @@ int main(void)
midi_register_cc_callback(&midi_device, cc_callback);
midi_register_sysex_callback(&midi_device, sysex_callback);
- init_notes();
+ // init_notes();
// midi_send_cc(&midi_device, 0, 1, 2);
// midi_send_cc(&midi_device, 15, 1, 0);
// midi_send_noteon(&midi_device, 0, 64, 127);
@@ -947,10 +947,10 @@ void fallthrough_callback(MidiDevice * device,
if (cnt == 3) {
switch (byte0 & 0xF0) {
case MIDI_NOTEON:
- play_note(((double)261.6)*pow(2.0, -1.0)*pow(2.0,(byte1 & 0x7F)/12.0), (byte2 & 0x7F) / 8);
+ play_note(((double)261.6)*pow(2.0, -4.0)*pow(2.0,(byte1 & 0x7F)/12.0), (byte2 & 0x7F) / 8);
break;
case MIDI_NOTEOFF:
- stop_note(((double)261.6)*pow(2.0, -1.0)*pow(2.0,(byte1 & 0x7F)/12.0));
+ stop_note(((double)261.6)*pow(2.0, -4.0)*pow(2.0,(byte1 & 0x7F)/12.0));
break;
}
}
diff --git a/tmk_core/rules.mk b/tmk_core/rules.mk
index 860fc1a931..326d2a7872 100644
--- a/tmk_core/rules.mk
+++ b/tmk_core/rules.mk
@@ -142,6 +142,9 @@ CFLAGS += $(CSTANDARD)
ifdef CONFIG_H
CFLAGS += -include $(CONFIG_H)
endif
+ifdef CONFIG_USER_H
+ CFLAGS += -include $(CONFIG_USER_H)
+endif
#---------------- Compiler Options C++ ----------------
@@ -176,6 +179,9 @@ CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
ifdef CONFIG_H
CPPFLAGS += -include $(CONFIG_H)
endif
+ifdef CONFIG_USER_H
+ CPPFLAGS += -include $(CONFIG_USER_H)
+endif
#---------------- Assembler Options ----------------
@@ -192,6 +198,9 @@ ASFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
ifdef CONFIG_H
ASFLAGS += -include $(CONFIG_H)
endif
+ifdef CONFIG_USER_H
+ ASFLAGS += -include $(CONFIG_USER_H)
+endif
#---------------- Library Options ----------------
@@ -308,7 +317,12 @@ REMOVE = rm -f
REMOVEDIR = rmdir
COPY = cp
WINSHELL = cmd
-
+# Autodecct teensy loader
+ifneq (, $(shell which teensy-loader-cli 2>/dev/null)))
+ TEENSY_LOADER_CLI = teensy-loader-cli
+else
+ TEENSY_LOADER_CLI = teensy_loader_cli
+endif
# Define Messages
# English
@@ -357,7 +371,13 @@ ALL_ASFLAGS = -mmcu=$(MCU) -x assembler-with-cpp $(ASFLAGS) $(EXTRAFLAGS)
# Default target.
-all: begin gccversion sizebefore build sizeafter end
+all:
+ $(MAKE) begin
+ $(MAKE) gccversion
+ $(MAKE) sizebefore
+ $(MAKE) build
+ $(MAKE) sizeafter
+ $(MAKE) end
# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
@@ -378,12 +398,10 @@ lib: $(LIBNAME)
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
- @echo
@echo $(MSG_BEGIN)
end:
@echo $(MSG_END)
- @echo
# Display size of file.
@@ -412,14 +430,14 @@ program: $(TARGET).hex $(TARGET).eep
$(PROGRAM_CMD)
teensy: $(TARGET).hex
- teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
+ $(TEENSY_LOADER_CLI) -mmcu=$(MCU) -w -v $(TARGET).hex
flip: $(TARGET).hex
batchisp -hardware usb -device $(MCU) -operation erase f
batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program
batchisp -hardware usb -device $(MCU) -operation start reset 0
-dfu: $(TARGET).hex
+dfu: $(TARGET).hex sizeafter
ifneq (, $(findstring 0.7, $(shell dfu-programmer --version 2>&1)))
dfu-programmer $(MCU) erase --force
else
@@ -490,13 +508,11 @@ COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(TARGET).elf
- @echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
- @echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
@@ -504,25 +520,21 @@ extcoff: $(TARGET).elf
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
- @echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
%.eep: %.elf
- @echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
# Create extended listing file from ELF output file.
%.lss: %.elf
- @echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S -z $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
- @echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
@@ -532,7 +544,6 @@ extcoff: $(TARGET).elf
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
- @echo
@echo $(MSG_CREATING_LIBRARY) $@
$(AR) $@ $(OBJ)
@@ -541,14 +552,12 @@ extcoff: $(TARGET).elf
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
- @echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
- @echo
mkdir -p $(@D)
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
@@ -556,7 +565,6 @@ $(OBJDIR)/%.o : %.c
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
- @echo
mkdir -p $(@D)
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
@@ -574,7 +582,6 @@ $(OBJDIR)/%.o : %.cpp
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
- @echo
mkdir -p $(@D)
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
@@ -589,7 +596,6 @@ $(OBJDIR)/%.o : %.S
clean: begin clean_list end
clean_list :
- @echo
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET).cof