Merge commit 'a074364c3731d66b56d988c8a6c960a83ea0e0a1' as 'tmk_core'
This commit is contained in:
commit
1a02ebcc61
13
tmk_core/.gitignore
vendored
Normal file
13
tmk_core/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
.dep
|
||||
*.o
|
||||
*.eep
|
||||
*.elf
|
||||
*.hex
|
||||
*.lss
|
||||
*.lst
|
||||
*.map
|
||||
*.sym
|
||||
tags
|
||||
*~
|
||||
build/
|
||||
*.bak
|
6
tmk_core/.gitmodules
vendored
Normal file
6
tmk_core/.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[submodule "protocol/lufa/LUFA-git"]
|
||||
path = protocol/lufa/LUFA-git
|
||||
url = https://github.com/abcminiuser/lufa.git
|
||||
[submodule "protocol/usb_hid/USB_Host_Shield_2.0"]
|
||||
path = protocol/usb_hid/USB_Host_Shield_2.0
|
||||
url = https://github.com/felis/USB_Host_Shield_2.0.git
|
296
tmk_core/README.md
Normal file
296
tmk_core/README.md
Normal file
@ -0,0 +1,296 @@
|
||||
TMK Keyboard Firmware Collection
|
||||
================================
|
||||
This is a keyboard firmware with some useful features for Atmel AVR controller.
|
||||
|
||||
Source code is available here: <http://github.com/tmk/tmk_keyboard>
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
These features can be used in your keyboard.
|
||||
|
||||
* Multi-layer Keymap - Multiple keyboard layouts with layer switching
|
||||
* Mouse key - Mouse control with keyboard
|
||||
* System Control Key - Power Down, Sleep, Wake Up and USB Remote Wake up
|
||||
* Media Control Key - Volume Down/Up, Mute, Next/Prev track, Play, Stop and etc
|
||||
* USB NKRO - 120 keys(+ 8 modifiers) simultaneously
|
||||
* PS/2 mouse support - PS/2 mouse(TrackPoint) as composite device
|
||||
* Keyboard protocols - PS/2, ADB, M0110, Sun and other old keyboard protocols
|
||||
* User Function - Customizable function of key with writing code
|
||||
* Macro - Very primitive at this time
|
||||
* Keyboard Tricks - Oneshot modifier and modifier with tapping feature
|
||||
* Debug Console - Messages for debug and interaction with firmware
|
||||
* Virtual DIP Switch - Configurations stored EEPROM(Boot Magic)
|
||||
* Locking CapsLock - Mechanical switch support for CapsLock
|
||||
* Breathing Sleep LED - Sleep indicator with charm during USB suspend
|
||||
* Backlight - Control backlight levels
|
||||
|
||||
|
||||
Projects
|
||||
--------
|
||||
You can find some keyboard specific projects under `converter` and `keyboard` directory.
|
||||
|
||||
### converter
|
||||
* [ps2_usb](converter/ps2_usb/) - [PS/2 keyboard to USB][GH_ps2]
|
||||
* [adb_usb](converter/adb_usb/) - [ADB keyboard to USB][GH_adb]
|
||||
* [m0110_usb](converter/m0110_usb) - [Macintosh 128K/512K/Plus keyboard to USB][GH_m0110]
|
||||
* [terminal_usb](converter/terminal_usb/) - [IBM Model M terminal keyboard(PS/2 scancode set3) to USB][GH_terminal]
|
||||
* [news_usb](converter/news_usb/) - [Sony NEWS keyboard to USB][GH_news]
|
||||
* [x68k_usb](converter/x68k_usb/) - [Sharp X68000 keyboard to USB][GH_x68k]
|
||||
* [sun_usb](converter/sun_usb/) - [Sun] to USB(type4, 5 and 3?)
|
||||
* [pc98_usb](converter/pc98_usb/) - [PC98] to USB
|
||||
* [usb_usb](converter/usb_usb/) - USB to USB(experimental)
|
||||
* [ascii_usb](converter/ascii_usb/) - ASCII(Serial console terminal) to USB
|
||||
* [ibm4704_usb](converter/ibm4704_usb) - [IBM 4704 keyboard Converter][GH_ibm4704]
|
||||
|
||||
### keyboard
|
||||
* [hhkb](keyboard/hhkb/) - [Happy Hacking Keyboard pro][GH_hhkb] **my main board**
|
||||
* [gh60](keyboard/gh60/) - [GH60] DIY 60% keyboard [prototype][GH60_proto] **my second board**
|
||||
* [hbkb](keyboard/hbkb/) - [Happy Buckling spring keyboard][GH_hbkb](IBM Model M 60% mod)
|
||||
* [hid_liber](keyboard/hid_liber/) - [HID liberation][HID_liber] controller (by alaricljs)
|
||||
* [phantom](keyboard/phantom/) - [Phantom] keyboard (by Tranquilite)
|
||||
* [IIgs_Standard](keyboard/IIgs/) - Apple [IIGS] keyboard mod(by JeffreySung)
|
||||
* [macway](keyboard/macway/) - [Compact keyboard mod][GH_macway] [retired]
|
||||
* [KMAC](keyboard/kmac/) - Korean custom keyboard
|
||||
* [Lightsaber](keyboard/lightsaber/) - Korean custom keyboard
|
||||
* [Infinity](keyboard/infinity/) - Massdrop [Infinity keyboard][Infinity]
|
||||
* [NerD](keyboard/nerd/) - Korean custom keyboard
|
||||
* [KittenPaw](keyboard/kitten_paw) - Custom Majestouch controller
|
||||
* [Lightpad](keyboard/lightpad) - Korean custom keypad
|
||||
* [ghost_squid](keyboard/ghost_squid/) - [The Ghost Squid][ghost_squid] controller for [Cooler Master QuickFire XT][cmxt]
|
||||
|
||||
### Extenal projects using tmk_keyboard
|
||||
* [ErgoDox_cub-uanic][cub-uanic] - Split Ergonomic Keyboard [ErgoDox][ergodox_org]
|
||||
* [mcdox][mcdox_tmk] - [mcdox][mcdox]
|
||||
|
||||
|
||||
[GH_macway]: http://geekhack.org/showwiki.php?title=Island:11930
|
||||
[GH_hhkb]: http://geekhack.org/showwiki.php?title=Island:12047
|
||||
[GH_ps2]: http://geekhack.org/showwiki.php?title=Island:14618
|
||||
[GH_adb]: http://geekhack.org/showwiki.php?title=Island:14290
|
||||
[GH_hhkb_bt]: http://geekhack.org/showwiki.php?title=Island:20851
|
||||
[GH_m0110]: http://geekhack.org/showwiki.php?title=Island:24965
|
||||
[GH_news]: http://geekhack.org/showwiki.php?title=Island:25759
|
||||
[GH_terminal]: http://geekhack.org/showwiki.php?title=Island:27272
|
||||
[GH_x68k]: http://geekhack.org/showwiki.php?title=Island:29060
|
||||
[GH_hbkb]: http://geekhack.org/showwiki.php?title=Island:29483
|
||||
[GH_ibm4704]: http://geekhack.org/index.php?topic=54706.0
|
||||
[HID_liber]: http://deskthority.net/wiki/HID_Liberation_Device_-_DIY_Instructions
|
||||
[Phantom]: http://geekhack.org/index.php?topic=26742
|
||||
[GH60]: http://geekhack.org/index.php?topic=34959
|
||||
[GH60_proto]: http://geekhack.org/index.php?topic=37570.0
|
||||
[PC98]: http://en.wikipedia.org/wiki/NEC_PC-9801
|
||||
[Sun]: http://en.wikipedia.org/wiki/Sun-3
|
||||
[IIGS]: http://en.wikipedia.org/wiki/Apple_IIGS
|
||||
[Infinity]: https://www.massdrop.com/buy/infinity-keyboard-kit
|
||||
[ghost_squid]: http://deskthority.net/wiki/Costar_replacement_controllers#The_Ghost_Squid
|
||||
[cmxt]: http://gaming.coolermaster.com/en/products/keyboards/quickfirext/
|
||||
[ergodox_org]: http://ergodox.org/
|
||||
[cub-uanic]: https://github.com/cub-uanic/tmk_keyboard/tree/master/keyboard/ergodox
|
||||
[mcdox]: https://github.com/DavidMcEwan/mcdox
|
||||
[mcdox_tmk]: https://github.com/DavidMcEwan/tmk_keyboard/tree/master/keyboard/mcdox
|
||||
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
**GPLv2** or later. Some protocol files are under **Modified BSD License**.
|
||||
LUFA, PJRC and V-USB stack have their own license respectively.
|
||||
|
||||
|
||||
|
||||
Build Firmware and Program Controller
|
||||
-------------------------------------
|
||||
See [doc/build.md](doc/build.md).
|
||||
|
||||
|
||||
|
||||
Change your keymap
|
||||
------------------
|
||||
See [doc/keymap.md](doc/keymap.md).
|
||||
|
||||
|
||||
|
||||
Magic Commands
|
||||
--------------
|
||||
To see help press `Magic` + `H`.
|
||||
|
||||
`Magic` key bind may be `LShift` + `RShift` in many project, but `Power` key on ADB converter. `Magic` keybind can be vary on each project, check `config.h` in project directory.
|
||||
|
||||
Following commands can be also executed with `Magic` + key. In console mode `Magic` keybind is not needed.
|
||||
|
||||
----- Command Help -----
|
||||
c: enter console mode
|
||||
d: toggle debug enable
|
||||
x: toggle matrix debug
|
||||
k: toggle keyboard debug
|
||||
m: toggle mouse debug
|
||||
v: print device version & info
|
||||
t: print timer count
|
||||
s: print status
|
||||
e: print eeprom config
|
||||
n: toggle NKRO
|
||||
0/F10: switch to Layer0
|
||||
1/F1: switch to Layer1
|
||||
2/F2: switch to Layer2
|
||||
3/F3: switch to Layer3
|
||||
4/F4: switch to Layer4
|
||||
PScr: power down/remote wake-up
|
||||
Caps: Lock Keyboard(Child Proof)
|
||||
Paus: jump to bootloader
|
||||
|
||||
**TBD**
|
||||
|
||||
### Boot Magic Configuration - Virtual DIP Switch
|
||||
Boot Magic are executed during boot up time. Press Magic key below then plug in keyboard cable.
|
||||
Note that you must use keys of **Layer 0** as Magic keys. These settings are stored in EEPROM so that retain your configure over power cycles.
|
||||
|
||||
To avoid configuring accidentally additive salt key `KC_SPACE` also needs to be pressed along with the following configuration keys. The salt key is configurable in `config.h`. See [common/bootmagic.h](common/bootmagic.h).
|
||||
|
||||
#### General
|
||||
- Skip reading EEPROM to start with default configuration(`ESC`)
|
||||
- Clear configuration stored in EEPROM to reset configuration(`Backspace`)
|
||||
|
||||
#### Bootloader
|
||||
- Kick up Bootloader(`B`)
|
||||
|
||||
#### Debug
|
||||
- Debug enable(`D`)
|
||||
- Debug matrix enable(`D`+`X`)
|
||||
- Debug keyboard enable(`D`+`K`)
|
||||
- Debug mouse enable(`D`+`M`)
|
||||
|
||||
#### Keymap
|
||||
- Swap Control and CapsLock(`Left Control`)
|
||||
- Change CapsLock to Control(`Caps Lock`)
|
||||
- Swap LeftAlt and Gui(`Left Alt`)
|
||||
- Swap RightAlt and Gui(`Right Alt`)
|
||||
- Disable Gui(`Left Gui`)
|
||||
- Swap Grave and Escape(`Grave`)
|
||||
- Swap BackSlash and BackSpace(`Back Slash`)
|
||||
- Enable NKRO on boot(`N`)
|
||||
|
||||
#### Default Layer
|
||||
- Set Default Layer to 0(`0`)
|
||||
- Set Default Layer to 1(`1`)
|
||||
- Set Default Layer to 2(`2`)
|
||||
- Set Default Layer to 3(`3`)
|
||||
- Set Default Layer to 4(`4`)
|
||||
- Set Default Layer to 5(`5`)
|
||||
- Set Default Layer to 6(`6`)
|
||||
- Set Default Layer to 7(`7`)
|
||||
|
||||
#### Caution
|
||||
Unintentional use of this feature will cause user confusion.
|
||||
|
||||
TODO: Magic key combination to avoid unintentional press during plug in
|
||||
|
||||
**TBD**
|
||||
|
||||
|
||||
Mechanical Locking support
|
||||
--------------------------
|
||||
This feature makes it possible for you to use mechanical switch for `CapsLock`, `NumLock` or `ScrollLock`. To enable this feature define these macros in `config.h` and use `KC_LCAP`, `KC_LNUM` or `KC_LSCR` in keymap for locking key instead of normal `KC_CAPS`, `KC_NLCK` or `KC_SLCK`. Resync option tries to keep lock switch state consistent with keyboard LED state.
|
||||
|
||||
#define LOCKING_SUPPORT_ENABLE
|
||||
#define LOCKING_RESYNC_ENABLE
|
||||
|
||||
|
||||
Start Your Own Project
|
||||
-----------------------
|
||||
**TBD**
|
||||
### Config.h Options
|
||||
#### 1. USB vendor/product ID and device description
|
||||
#define VENDOR_ID 0xFEED
|
||||
#define PRODUCT_ID 0xBEEF
|
||||
#define MANUFACTURER t.m.k.
|
||||
#define PRODUCT Macway mod
|
||||
#define DESCRIPTION t.m.k. keyboard firmware for Macway mod
|
||||
|
||||
#### 2. Keyboard matrix configuration
|
||||
#define MATRIX_ROWS 8
|
||||
#define MATRIX_COLS 8
|
||||
#define MATRIX_HAS_GHOST
|
||||
|
||||
|
||||
|
||||
Architecture
|
||||
------------
|
||||
Architecture Diagram
|
||||
+---------------+---------------+-------------+
|
||||
| Host | Keyboard | Matrix, LED |
|
||||
___________ |-----------+-+ +-------------+ | +-----------|
|
||||
/ /| Keys/Mouse | Protocol |d| | Action | | | Protocol |
|
||||
/__________/ |<-----------| LUFA |r| | Layer, Tap | | | Matrix |
|
||||
|.--------.| | LED | V-USB |i| |-------------| | | PS/2,IBM | __________________
|
||||
|| || |----------->| PJRC |v| | Keymap | | | ADB,M0110| Keys / /_/_/_/_/_/_/_/ /|
|
||||
|| Host || | Console | iWRAP(BT)|e| | Mousekey | | | SUN/NEWS |<----------/ /_/_/_/_/_/_/_/ / /
|
||||
||________||/.<-----------| UART |r| | Report | | | X68K/PC98| Control / /_/_/_/_/_/_/_/ / /
|
||||
`_========_'/| |---------------------------------------------|-------->/___ /_______/ ___/ /
|
||||
|_o______o_|/ | Sendchar, Print, Debug, Command, ... | |_________________|/
|
||||
+---------------------------------------------+ Keyboard
|
||||
|
||||
|
||||
|
||||
Debugging
|
||||
--------
|
||||
Use PJRC's `hid_listen` to see debug messages. You can use the tool for debug even if firmware use LUFA stack.
|
||||
|
||||
You can use xprintf() to display debug info on `hid_listen`, see `common/xprintf.h`.
|
||||
|
||||
|
||||
|
||||
Files and Directories
|
||||
-------------------
|
||||
### Top
|
||||
* common/ - common codes
|
||||
* protocol/ - keyboard protocol support
|
||||
* keyboard/ - keyboard projects
|
||||
* converter/ - protocol converter projects
|
||||
* doc/ - documents
|
||||
* common.mk - Makefile for common
|
||||
* protocol.mk - Makefile for protocol
|
||||
* rules.mk - Makefile for build rules
|
||||
|
||||
### Common
|
||||
* host.h
|
||||
* host_driver.h
|
||||
* keyboard.h
|
||||
* command.h
|
||||
* keymap.h
|
||||
* action.h
|
||||
* keycode.h
|
||||
* matrix.h
|
||||
* led.h
|
||||
* mousekey.h
|
||||
* report.h
|
||||
* debug.h
|
||||
* print.h
|
||||
* bootloader.h
|
||||
* sendchar.h
|
||||
* timer.h
|
||||
* util.h
|
||||
|
||||
### Keyboard Protocols
|
||||
* lufa/ - LUFA USB stack
|
||||
* pjrc/ - PJRC USB stack
|
||||
* vusb/ - Objective Development V-USB
|
||||
* iwrap/ - Bluetooth HID for Bluegiga iWRAP
|
||||
* ps2.c - PS/2 protocol
|
||||
* adb.c - Apple Desktop Bus protocol
|
||||
* m0110.c - Macintosh 128K/512K/Plus keyboard protocol
|
||||
* news.c - Sony NEWS keyboard protocol
|
||||
* x68k.c - Sharp X68000 keyboard protocol
|
||||
* serial_soft.c - Asynchronous Serial protocol implemented by software
|
||||
|
||||
|
||||
|
||||
Coding Style
|
||||
-------------
|
||||
- Doesn't use Tab to indent, use 4-spaces instead.
|
||||
|
||||
|
||||
|
||||
Other Keyboard Firmware Projects
|
||||
------------------
|
||||
You can learn a lot about keyboard firmware from these. See [doc/other_projects.md](doc/other_projects.md).
|
77
tmk_core/common.mk
Normal file
77
tmk_core/common.mk
Normal file
@ -0,0 +1,77 @@
|
||||
COMMON_DIR = common
|
||||
SRC += $(COMMON_DIR)/host.c \
|
||||
$(COMMON_DIR)/keyboard.c \
|
||||
$(COMMON_DIR)/action.c \
|
||||
$(COMMON_DIR)/action_tapping.c \
|
||||
$(COMMON_DIR)/action_macro.c \
|
||||
$(COMMON_DIR)/action_layer.c \
|
||||
$(COMMON_DIR)/action_util.c \
|
||||
$(COMMON_DIR)/keymap.c \
|
||||
$(COMMON_DIR)/print.c \
|
||||
$(COMMON_DIR)/debug.c \
|
||||
$(COMMON_DIR)/util.c \
|
||||
$(COMMON_DIR)/avr/suspend.c \
|
||||
$(COMMON_DIR)/avr/xprintf.S \
|
||||
$(COMMON_DIR)/avr/timer.c \
|
||||
$(COMMON_DIR)/avr/bootloader.c
|
||||
|
||||
|
||||
# Option modules
|
||||
ifdef BOOTMAGIC_ENABLE
|
||||
SRC += $(COMMON_DIR)/bootmagic.c
|
||||
SRC += $(COMMON_DIR)/avr/eeconfig.c
|
||||
OPT_DEFS += -DBOOTMAGIC_ENABLE
|
||||
endif
|
||||
|
||||
ifdef MOUSEKEY_ENABLE
|
||||
SRC += $(COMMON_DIR)/mousekey.c
|
||||
OPT_DEFS += -DMOUSEKEY_ENABLE
|
||||
OPT_DEFS += -DMOUSE_ENABLE
|
||||
endif
|
||||
|
||||
ifdef EXTRAKEY_ENABLE
|
||||
OPT_DEFS += -DEXTRAKEY_ENABLE
|
||||
endif
|
||||
|
||||
ifdef CONSOLE_ENABLE
|
||||
OPT_DEFS += -DCONSOLE_ENABLE
|
||||
else
|
||||
OPT_DEFS += -DNO_PRINT
|
||||
OPT_DEFS += -DNO_DEBUG
|
||||
endif
|
||||
|
||||
ifdef COMMAND_ENABLE
|
||||
SRC += $(COMMON_DIR)/command.c
|
||||
OPT_DEFS += -DCOMMAND_ENABLE
|
||||
endif
|
||||
|
||||
ifdef NKRO_ENABLE
|
||||
OPT_DEFS += -DNKRO_ENABLE
|
||||
endif
|
||||
|
||||
ifdef USB_6KRO_ENABLE
|
||||
OPT_DEFS += -DUSB_6KRO_ENABLE
|
||||
endif
|
||||
|
||||
ifdef SLEEP_LED_ENABLE
|
||||
SRC += $(COMMON_DIR)/sleep_led.c
|
||||
OPT_DEFS += -DSLEEP_LED_ENABLE
|
||||
OPT_DEFS += -DNO_SUSPEND_POWER_DOWN
|
||||
endif
|
||||
|
||||
ifdef BACKLIGHT_ENABLE
|
||||
SRC += $(COMMON_DIR)/backlight.c
|
||||
OPT_DEFS += -DBACKLIGHT_ENABLE
|
||||
endif
|
||||
|
||||
ifdef KEYMAP_SECTION_ENABLE
|
||||
OPT_DEFS += -DKEYMAP_SECTION_ENABLE
|
||||
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
|
||||
endif
|
||||
|
||||
# Version string
|
||||
OPT_DEFS += -DVERSION=$(shell (git describe --always --dirty || echo 'unknown') 2> /dev/null)
|
||||
|
||||
|
||||
# Search Path
|
||||
VPATH += $(TMK_DIR)/common
|
565
tmk_core/common/action.c
Normal file
565
tmk_core/common/action.c
Normal file
@ -0,0 +1,565 @@
|
||||
/*
|
||||
Copyright 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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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/>.
|
||||
*/
|
||||
#include "host.h"
|
||||
#include "keycode.h"
|
||||
#include "keyboard.h"
|
||||
#include "mousekey.h"
|
||||
#include "command.h"
|
||||
#include "led.h"
|
||||
#include "backlight.h"
|
||||
#include "action_layer.h"
|
||||
#include "action_tapping.h"
|
||||
#include "action_macro.h"
|
||||
#include "action_util.h"
|
||||
#include "action.h"
|
||||
|
||||
#ifdef DEBUG_ACTION
|
||||
#include "debug.h"
|
||||
#else
|
||||
#include "nodebug.h"
|
||||
#endif
|
||||
|
||||
|
||||
void action_exec(keyevent_t event)
|
||||
{
|
||||
if (!IS_NOEVENT(event)) {
|
||||
dprint("\n---- action_exec: start -----\n");
|
||||
dprint("EVENT: "); debug_event(event); dprintln();
|
||||
}
|
||||
|
||||
keyrecord_t record = { .event = event };
|
||||
|
||||
#ifndef NO_ACTION_TAPPING
|
||||
action_tapping_process(record);
|
||||
#else
|
||||
process_action(&record);
|
||||
if (!IS_NOEVENT(record.event)) {
|
||||
dprint("processed: "); debug_record(record); dprintln();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void process_action(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; }
|
||||
|
||||
action_t action = layer_switch_get_action(event.key);
|
||||
dprint("ACTION: "); debug_action(action);
|
||||
#ifndef NO_ACTION_LAYER
|
||||
dprint(" layer_state: "); layer_debug();
|
||||
dprint(" default_layer_state: "); default_layer_debug();
|
||||
#endif
|
||||
dprintln();
|
||||
|
||||
switch (action.kind.id) {
|
||||
/* Key and Mods */
|
||||
case ACT_LMODS:
|
||||
case ACT_RMODS:
|
||||
{
|
||||
uint8_t mods = (action.kind.id == ACT_LMODS) ? action.key.mods :
|
||||
action.key.mods<<4;
|
||||
if (event.pressed) {
|
||||
if (mods) {
|
||||
add_weak_mods(mods);
|
||||
send_keyboard_report();
|
||||
}
|
||||
register_code(action.key.code);
|
||||
} else {
|
||||
unregister_code(action.key.code);
|
||||
if (mods) {
|
||||
del_weak_mods(mods);
|
||||
send_keyboard_report();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#ifndef NO_ACTION_TAPPING
|
||||
case ACT_LMODS_TAP:
|
||||
case ACT_RMODS_TAP:
|
||||
{
|
||||
uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods :
|
||||
action.key.mods<<4;
|
||||
switch (action.layer_tap.code) {
|
||||
#ifndef NO_ACTION_ONESHOT
|
||||
case MODS_ONESHOT:
|
||||
// Oneshot modifier
|
||||
if (event.pressed) {
|
||||
if (tap_count == 0) {
|
||||
register_mods(mods);
|
||||
}
|
||||
else if (tap_count == 1) {
|
||||
dprint("MODS_TAP: Oneshot: start\n");
|
||||
set_oneshot_mods(mods);
|
||||
}
|
||||
else {
|
||||
register_mods(mods);
|
||||
}
|
||||
} else {
|
||||
if (tap_count == 0) {
|
||||
clear_oneshot_mods();
|
||||
unregister_mods(mods);
|
||||
}
|
||||
else if (tap_count == 1) {
|
||||
// Retain Oneshot mods
|
||||
}
|
||||
else {
|
||||
clear_oneshot_mods();
|
||||
unregister_mods(mods);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case MODS_TAP_TOGGLE:
|
||||
if (event.pressed) {
|
||||
if (tap_count <= TAPPING_TOGGLE) {
|
||||
register_mods(mods);
|
||||
}
|
||||
} else {
|
||||
if (tap_count < TAPPING_TOGGLE) {
|
||||
unregister_mods(mods);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (event.pressed) {
|
||||
if (tap_count > 0) {
|
||||
if (record->tap.interrupted) {
|
||||
dprint("MODS_TAP: Tap: Cancel: add_mods\n");
|
||||
// ad hoc: set 0 to cancel tap
|
||||
record->tap.count = 0;
|
||||
register_mods(mods);
|
||||
} else {
|
||||
dprint("MODS_TAP: Tap: register_code\n");
|
||||
register_code(action.key.code);
|
||||
}
|
||||
} else {
|
||||
dprint("MODS_TAP: No tap: add_mods\n");
|
||||
register_mods(mods);
|
||||
}
|
||||
} else {
|
||||
if (tap_count > 0) {
|
||||
dprint("MODS_TAP: Tap: unregister_code\n");
|
||||
unregister_code(action.key.code);
|
||||
} else {
|
||||
dprint("MODS_TAP: No tap: add_mods\n");
|
||||
unregister_mods(mods);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef EXTRAKEY_ENABLE
|
||||
/* other HID usage */
|
||||
case ACT_USAGE:
|
||||
switch (action.usage.page) {
|
||||
case PAGE_SYSTEM:
|
||||
if (event.pressed) {
|
||||
host_system_send(action.usage.code);
|
||||
} else {
|
||||
host_system_send(0);
|
||||
}
|
||||
break;
|
||||
case PAGE_CONSUMER:
|
||||
if (event.pressed) {
|
||||
host_consumer_send(action.usage.code);
|
||||
} else {
|
||||
host_consumer_send(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef MOUSEKEY_ENABLE
|
||||
/* Mouse key */
|
||||
case ACT_MOUSEKEY:
|
||||
if (event.pressed) {
|
||||
mousekey_on(action.key.code);
|
||||
mousekey_send();
|
||||
} else {
|
||||
mousekey_off(action.key.code);
|
||||
mousekey_send();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_ACTION_LAYER
|
||||
case ACT_LAYER:
|
||||
if (action.layer_bitop.on == 0) {
|
||||
/* Default Layer Bitwise Operation */
|
||||
if (!event.pressed) {
|
||||
uint8_t shift = action.layer_bitop.part*4;
|
||||
uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
|
||||
uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
|
||||
switch (action.layer_bitop.op) {
|
||||
case OP_BIT_AND: default_layer_and(bits | mask); break;
|
||||
case OP_BIT_OR: default_layer_or(bits | mask); break;
|
||||
case OP_BIT_XOR: default_layer_xor(bits | mask); break;
|
||||
case OP_BIT_SET: default_layer_and(mask); default_layer_or(bits); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Layer Bitwise Operation */
|
||||
if (event.pressed ? (action.layer_bitop.on & ON_PRESS) :
|
||||
(action.layer_bitop.on & ON_RELEASE)) {
|
||||
uint8_t shift = action.layer_bitop.part*4;
|
||||
uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
|
||||
uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
|
||||
switch (action.layer_bitop.op) {
|
||||
case OP_BIT_AND: layer_and(bits | mask); break;
|
||||
case OP_BIT_OR: layer_or(bits | mask); break;
|
||||
case OP_BIT_XOR: layer_xor(bits | mask); break;
|
||||
case OP_BIT_SET: layer_and(mask); layer_or(bits); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#ifndef NO_ACTION_TAPPING
|
||||
case ACT_LAYER_TAP:
|
||||
case ACT_LAYER_TAP_EXT:
|
||||
switch (action.layer_tap.code) {
|
||||
case 0xe0 ... 0xef:
|
||||
/* layer On/Off with modifiers(left only) */
|
||||
if (event.pressed) {
|
||||
layer_on(action.layer_tap.val);
|
||||
register_mods(action.layer_tap.code & 0x0f);
|
||||
} else {
|
||||
layer_off(action.layer_tap.val);
|
||||
unregister_mods(action.layer_tap.code & 0x0f);
|
||||
}
|
||||
break;
|
||||
case OP_TAP_TOGGLE:
|
||||
/* tap toggle */
|
||||
if (event.pressed) {
|
||||
if (tap_count < TAPPING_TOGGLE) {
|
||||
layer_invert(action.layer_tap.val);
|
||||
}
|
||||
} else {
|
||||
if (tap_count <= TAPPING_TOGGLE) {
|
||||
layer_invert(action.layer_tap.val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_ON_OFF:
|
||||
event.pressed ? layer_on(action.layer_tap.val) :
|
||||
layer_off(action.layer_tap.val);
|
||||
break;
|
||||
case OP_OFF_ON:
|
||||
event.pressed ? layer_off(action.layer_tap.val) :
|
||||
layer_on(action.layer_tap.val);
|
||||
break;
|
||||
case OP_SET_CLEAR:
|
||||
event.pressed ? layer_move(action.layer_tap.val) :
|
||||
layer_clear();
|
||||
break;
|
||||
default:
|
||||
/* tap key */
|
||||
if (event.pressed) {
|
||||
if (tap_count > 0) {
|
||||
dprint("KEYMAP_TAP_KEY: Tap: register_code\n");
|
||||
register_code(action.layer_tap.code);
|
||||
} else {
|
||||
dprint("KEYMAP_TAP_KEY: No tap: On on press\n");
|
||||
layer_on(action.layer_tap.val);
|
||||
}
|
||||
} else {
|
||||
if (tap_count > 0) {
|
||||
dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n");
|
||||
unregister_code(action.layer_tap.code);
|
||||
} else {
|
||||
dprint("KEYMAP_TAP_KEY: No tap: Off on release\n");
|
||||
layer_off(action.layer_tap.val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
/* Extentions */
|
||||
#ifndef NO_ACTION_MACRO
|
||||
case ACT_MACRO:
|
||||
action_macro_play(action_get_macro(record, action.func.id, action.func.opt));
|
||||
break;
|
||||
#endif
|
||||
#ifdef BACKLIGHT_ENABLE
|
||||
case ACT_BACKLIGHT:
|
||||
if (!event.pressed) {
|
||||
switch (action.backlight.opt) {
|
||||
case BACKLIGHT_INCREASE:
|
||||
backlight_increase();
|
||||
break;
|
||||
case BACKLIGHT_DECREASE:
|
||||
backlight_decrease();
|
||||
break;
|
||||
case BACKLIGHT_TOGGLE:
|
||||
backlight_toggle();
|
||||
break;
|
||||
case BACKLIGHT_STEP:
|
||||
backlight_step();
|
||||
break;
|
||||
case BACKLIGHT_LEVEL:
|
||||
backlight_level(action.backlight.level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case ACT_COMMAND:
|
||||
break;
|
||||
#ifndef NO_ACTION_FUNCTION
|
||||
case ACT_FUNCTION:
|
||||
action_function(record, action.func.id, action.func.opt);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Utilities for actions.
|
||||
*/
|
||||
void register_code(uint8_t code)
|
||||
{
|
||||
if (code == KC_NO) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LOCKING_SUPPORT_ENABLE
|
||||
else if (KC_LOCKING_CAPS == code) {
|
||||
#ifdef LOCKING_RESYNC_ENABLE
|
||||
// Resync: ignore if caps lock already is on
|
||||
if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) return;
|
||||
#endif
|
||||
add_key(KC_CAPSLOCK);
|
||||
send_keyboard_report();
|
||||
del_key(KC_CAPSLOCK);
|
||||
send_keyboard_report();
|
||||
}
|
||||
|
||||
else if (KC_LOCKING_NUM == code) {
|
||||
#ifdef LOCKING_RESYNC_ENABLE
|
||||
if (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) return;
|
||||
#endif
|
||||
add_key(KC_NUMLOCK);
|
||||
send_keyboard_report();
|
||||
del_key(KC_NUMLOCK);
|
||||
send_keyboard_report();
|
||||
}
|
||||
|
||||
else if (KC_LOCKING_SCROLL == code) {
|
||||
#ifdef LOCKING_RESYNC_ENABLE
|
||||
if (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) return;
|
||||
#endif
|
||||
add_key(KC_SCROLLLOCK);
|
||||
send_keyboard_report();
|
||||
del_key(KC_SCROLLLOCK);
|
||||
send_keyboard_report();
|
||||
}
|
||||
#endif
|
||||
|
||||
else if IS_KEY(code) {
|
||||
// TODO: should push command_proc out of this block?
|
||||
if (command_proc(code)) return;
|
||||
|
||||
#ifndef NO_ACTION_ONESHOT
|
||||
/* TODO: remove
|
||||
if (oneshot_state.mods && !oneshot_state.disabled) {
|
||||
uint8_t tmp_mods = get_mods();
|
||||
add_mods(oneshot_state.mods);
|
||||
|
||||
add_key(code);
|
||||
send_keyboard_report();
|
||||
|
||||
set_mods(tmp_mods);
|
||||
send_keyboard_report();
|
||||
oneshot_cancel();
|
||||
} else
|
||||
*/
|
||||
#endif
|
||||
{
|
||||
add_key(code);
|
||||
send_keyboard_report();
|
||||
}
|
||||
}
|
||||
else if IS_MOD(code) {
|
||||
add_mods(MOD_BIT(code));
|
||||
send_keyboard_report();
|
||||
}
|
||||
else if IS_SYSTEM(code) {
|
||||
host_system_send(KEYCODE2SYSTEM(code));
|
||||
}
|
||||
else if IS_CONSUMER(code) {
|
||||
host_consumer_send(KEYCODE2CONSUMER(code));
|
||||
}
|
||||
}
|
||||
|
||||
void unregister_code(uint8_t code)
|
||||
{
|
||||
if (code == KC_NO) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LOCKING_SUPPORT_ENABLE
|
||||
else if (KC_LOCKING_CAPS == code) {
|
||||
#ifdef LOCKING_RESYNC_ENABLE
|
||||
// Resync: ignore if caps lock already is off
|
||||
if (!(host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK))) return;
|
||||
#endif
|
||||
add_key(KC_CAPSLOCK);
|
||||
send_keyboard_report();
|
||||
del_key(KC_CAPSLOCK);
|
||||
send_keyboard_report();
|
||||
}
|
||||
|
||||
else if (KC_LOCKING_NUM == code) {
|
||||
#ifdef LOCKING_RESYNC_ENABLE
|
||||
if (!(host_keyboard_leds() & (1<<USB_LED_NUM_LOCK))) return;
|
||||
#endif
|
||||
add_key(KC_NUMLOCK);
|
||||
send_keyboard_report();
|
||||
del_key(KC_NUMLOCK);
|
||||
send_keyboard_report();
|
||||
}
|
||||
|
||||
else if (KC_LOCKING_SCROLL == code) {
|
||||
#ifdef LOCKING_RESYNC_ENABLE
|
||||
if (!(host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK))) return;
|
||||
#endif
|
||||
add_key(KC_SCROLLLOCK);
|
||||
send_keyboard_report();
|
||||
del_key(KC_SCROLLLOCK);
|
||||
send_keyboard_report();
|
||||
}
|
||||
#endif
|
||||
|
||||
else if IS_KEY(code) {
|
||||
del_key(code);
|
||||
send_keyboard_report();
|
||||
}
|
||||
else if IS_MOD(code) {
|
||||
del_mods(MOD_BIT(code));
|
||||
send_keyboard_report();
|
||||
}
|
||||
else if IS_SYSTEM(code) {
|
||||
host_system_send(0);
|
||||
}
|
||||
else if IS_CONSUMER(code) {
|
||||
host_consumer_send(0);
|
||||
}
|
||||
}
|
||||
|
||||
void register_mods(uint8_t mods)
|
||||
{
|
||||
if (mods) {
|
||||
add_mods(mods);
|
||||
send_keyboard_report();
|
||||
}
|
||||
}
|
||||
|
||||
void unregister_mods(uint8_t mods)
|
||||
{
|
||||
if (mods) {
|
||||
del_mods(mods);
|
||||
send_keyboard_report();
|
||||
}
|
||||
}
|
||||
|
||||
void clear_keyboard(void)
|
||||
{
|
||||
clear_mods();
|
||||
clear_keyboard_but_mods();
|
||||
}
|
||||
|
||||
void clear_keyboard_but_mods(void)
|
||||
{
|
||||
clear_weak_mods();
|
||||
clear_keys();
|
||||
send_keyboard_report();
|
||||
#ifdef MOUSEKEY_ENABLE
|
||||
mousekey_clear();
|
||||
mousekey_send();
|
||||
#endif
|
||||
#ifdef EXTRAKEY_ENABLE
|
||||
host_system_send(0);
|
||||
host_consumer_send(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_tap_key(keypos_t key)
|
||||
{
|
||||
action_t action = layer_switch_get_action(key);
|
||||
|
||||
switch (action.kind.id) {
|
||||
case ACT_LMODS_TAP:
|
||||
case ACT_RMODS_TAP:
|
||||
case ACT_LAYER_TAP:
|
||||
case ACT_LAYER_TAP_EXT:
|
||||
return true;
|
||||
case ACT_MACRO:
|
||||
case ACT_FUNCTION:
|
||||
if (action.func.opt & FUNC_TAP) { return true; }
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* debug print
|
||||
*/
|
||||
void debug_event(keyevent_t event)
|
||||
{
|
||||
dprintf("%04X%c(%u)", (event.key.row<<8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time);
|
||||
}
|
||||
|
||||
void debug_record(keyrecord_t record)
|
||||
{
|
||||
debug_event(record.event);
|
||||
#ifndef NO_ACTION_TAPPING
|
||||
dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' '));
|
||||
#endif
|
||||
}
|
||||
|
||||
void debug_action(action_t action)
|
||||
{
|
||||
switch (action.kind.id) {
|
||||
case ACT_LMODS: dprint("ACT_LMODS"); break;
|
||||
case ACT_RMODS: dprint("ACT_RMODS"); break;
|
||||
case ACT_LMODS_TAP: dprint("ACT_LMODS_TAP"); break;
|
||||
case ACT_RMODS_TAP: dprint("ACT_RMODS_TAP"); break;
|
||||
case ACT_USAGE: dprint("ACT_USAGE"); break;
|
||||
case ACT_MOUSEKEY: dprint("ACT_MOUSEKEY"); break;
|
||||
case ACT_LAYER: dprint("ACT_LAYER"); break;
|
||||
case ACT_LAYER_TAP: dprint("ACT_LAYER_TAP"); break;
|
||||
case ACT_LAYER_TAP_EXT: dprint("ACT_LAYER_TAP_EXT"); break;
|
||||
case ACT_MACRO: dprint("ACT_MACRO"); break;
|
||||
case ACT_COMMAND: dprint("ACT_COMMAND"); break;
|
||||
case ACT_FUNCTION: dprint("ACT_FUNCTION"); break;
|
||||
default: dprint("UNKNOWN"); break;
|
||||
}
|
||||
dprintf("[%X:%02X]", action.kind.param>>8, action.kind.param&0xff);
|
||||
}
|
82
tmk_core/common/action.h
Normal file
82
tmk_core/common/action.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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 ACTION_H
|
||||
#define ACTION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "keyboard.h"
|
||||
#include "keycode.h"
|
||||
#include "action_code.h"
|
||||
#include "action_macro.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* tapping count and state */
|
||||
typedef struct {
|
||||
bool interrupted :1;
|
||||
bool reserved2 :1;
|
||||
bool reserved1 :1;
|
||||
bool reserved0 :1;
|
||||
uint8_t count :4;
|
||||
} tap_t;
|
||||
|
||||
/* Key event container for recording */
|
||||
typedef struct {
|
||||
keyevent_t event;
|
||||
#ifndef NO_ACTION_TAPPING
|
||||
tap_t tap;
|
||||
#endif
|
||||
} keyrecord_t;
|
||||
|
||||
/* Execute action per keyevent */
|
||||
void action_exec(keyevent_t event);
|
||||
|
||||
/* action for key */
|
||||
action_t action_for_key(uint8_t layer, keypos_t key);
|
||||
|
||||
/* macro */
|
||||
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt);
|
||||
|
||||
/* user defined special function */
|
||||
void action_function(keyrecord_t *record, uint8_t id, uint8_t opt);
|
||||
|
||||
/* Utilities for actions. */
|
||||
void process_action(keyrecord_t *record);
|
||||
void register_code(uint8_t code);
|
||||
void unregister_code(uint8_t code);
|
||||
void register_mods(uint8_t mods);
|
||||
void unregister_mods(uint8_t mods);
|
||||
//void set_mods(uint8_t mods);
|
||||
void clear_keyboard(void);
|
||||
void clear_keyboard_but_mods(void);
|
||||
void layer_switch(uint8_t new_layer);
|
||||
bool is_tap_key(keypos_t key);
|
||||
|
||||
/* debug */
|
||||
void debug_event(keyevent_t event);
|
||||
void debug_record(keyrecord_t record);
|
||||
void debug_action(action_t action);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ACTION_H */
|
315
tmk_core/common/action_code.h
Normal file
315
tmk_core/common/action_code.h
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
Copyright 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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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 ACTION_CODE_H
|
||||
#define ACTION_CODE_H
|
||||
|
||||
/* Action codes
|
||||
* ============
|
||||
* 16bit code: action_kind(4bit) + action_parameter(12bit)
|
||||
*
|
||||
*
|
||||
* Key Actions(00xx)
|
||||
* -----------------
|
||||
* ACT_MODS(000r):
|
||||
* 000r|0000|0000 0000 No action code
|
||||
* 000r|0000|0000 0001 Transparent code
|
||||
* 000r|0000| keycode Key
|
||||
* 000r|mods|0000 0000 Modifiers
|
||||
* 000r|mods| keycode Modifiers+Key(Modified key)
|
||||
* r: Left/Right flag(Left:0, Right:1)
|
||||
*
|
||||
* ACT_MODS_TAP(001r):
|
||||
* 001r|mods|0000 0000 Modifiers with OneShot
|
||||
* 001r|mods|0000 0001 Modifiers with tap toggle
|
||||
* 001r|mods|0000 00xx (reserved)
|
||||
* 001r|mods| keycode Modifiers with Tap Key(Dual role)
|
||||
*
|
||||
*
|
||||
* Other Keys(01xx)
|
||||
* ----------------
|
||||
* ACT_USAGE(0100): TODO: Not needed?
|
||||
* 0100|00| usage(10) System control(0x80) - General Desktop page(0x01)
|
||||
* 0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C)
|
||||
* 0100|10| usage(10) (reserved)
|
||||
* 0100|11| usage(10) (reserved)
|
||||
*
|
||||
* ACT_MOUSEKEY(0110): TODO: Not needed?
|
||||
* 0101|xxxx| keycode Mouse key
|
||||
*
|
||||
* 011x|xxxx xxxx xxxx (reseved)
|
||||
*
|
||||
*
|
||||
* Layer Actions(10xx)
|
||||
* -------------------
|
||||
* ACT_LAYER(1000):
|
||||
* 1000|oo00|pppE BBBB Default Layer Bitwise operation
|
||||
* oo: operation(00:AND, 01:OR, 10:XOR, 11:SET)
|
||||
* ppp: 4-bit chunk part(0-7)
|
||||
* EBBBB: bits and extra bit
|
||||
* 1000|ooee|pppE BBBB Layer Bitwise Operation
|
||||
* oo: operation(00:AND, 01:OR, 10:XOR, 11:SET)
|
||||
* ppp: 4-bit chunk part(0-7)
|
||||
* EBBBB: bits and extra bit
|
||||
* ee: on event(01:press, 10:release, 11:both)
|
||||
*
|
||||
* 1001|xxxx|xxxx xxxx (reserved)
|
||||
* 1001|oopp|BBBB BBBB 8-bit Bitwise Operation???
|
||||
*
|
||||
* ACT_LAYER_TAP(101x):
|
||||
* 101E|LLLL| keycode On/Off with tap key
|
||||
* 101E|LLLL|1110 mods On/Off with modifiers(0xE0-EF)
|
||||
* 101E|LLLL|1111 0000 Invert with tap toggle(0xF0)
|
||||
* 101E|LLLL|1111 0001 On/Off
|
||||
* 101E|LLLL|1111 0010 Off/On
|
||||
* 101E|LLLL|1111 0011 Set/Clear
|
||||
* 101E|LLLL|1111 xxxx Reserved(0xF4-FF)
|
||||
* ELLLL: layer 0-31(E: extra bit for layer 16-31)
|
||||
*
|
||||
*
|
||||
* Extensions(11xx)
|
||||
* ----------------
|
||||
* ACT_MACRO(1100):
|
||||
* 1100|opt | id(8) Macro play?
|
||||
* 1100|1111| id(8) Macro record?
|
||||
*
|
||||
* ACT_BACKLIGHT(1101):
|
||||
* 1101|opt |level(8) Backlight commands
|
||||
*
|
||||
* ACT_COMMAND(1110):
|
||||
* 1110|opt | id(8) Built-in Command exec
|
||||
*
|
||||
* ACT_FUNCTION(1111):
|
||||
* 1111| address(12) Function?
|
||||
* 1111|opt | id(8) Function?
|
||||
*/
|
||||
enum action_kind_id {
|
||||
/* Key Actions */
|
||||
ACT_MODS = 0b0000,
|
||||
ACT_LMODS = 0b0000,
|
||||
ACT_RMODS = 0b0001,
|
||||
ACT_MODS_TAP = 0b0010,
|
||||
ACT_LMODS_TAP = 0b0010,
|
||||
ACT_RMODS_TAP = 0b0011,
|
||||
/* Other Keys */
|
||||
ACT_USAGE = 0b0100,
|
||||
ACT_MOUSEKEY = 0b0101,
|
||||
/* Layer Actions */
|
||||
ACT_LAYER = 0b1000,
|
||||
ACT_LAYER_TAP = 0b1010, /* Layer 0-15 */
|
||||
ACT_LAYER_TAP_EXT = 0b1011, /* Layer 16-31 */
|
||||
/* Extensions */
|
||||
ACT_MACRO = 0b1100,
|
||||
ACT_BACKLIGHT = 0b1101,
|
||||
ACT_COMMAND = 0b1110,
|
||||
ACT_FUNCTION = 0b1111
|
||||
};
|
||||
|
||||
|
||||
/* Action Code Struct
|
||||
*
|
||||
* NOTE:
|
||||
* In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15).
|
||||
* AVR looks like a little endian in avr-gcc.
|
||||
* Not portable across compiler/endianness?
|
||||
*
|
||||
* Byte order and bit order of 0x1234:
|
||||
* Big endian: Little endian:
|
||||
* -------------------- --------------------
|
||||
* FEDC BA98 7654 3210 0123 4567 89AB CDEF
|
||||
* 0001 0010 0011 0100 0010 1100 0100 1000
|
||||
* 0x12 0x34 0x34 0x12
|
||||
*/
|
||||
typedef union {
|
||||
uint16_t code;
|
||||
struct action_kind {
|
||||
uint16_t param :12;
|
||||
uint8_t id :4;
|
||||
} kind;
|
||||
struct action_key {
|
||||
uint8_t code :8;
|
||||
uint8_t mods :4;
|
||||
uint8_t kind :4;
|
||||
} key;
|
||||
struct action_layer_bitop {
|
||||
uint8_t bits :4;
|
||||
uint8_t xbit :1;
|
||||
uint8_t part :3;
|
||||
uint8_t on :2;
|
||||
uint8_t op :2;
|
||||
uint8_t kind :4;
|
||||
} layer_bitop;
|
||||
struct action_layer_tap {
|
||||
uint8_t code :8;
|
||||
uint8_t val :5;
|
||||
uint8_t kind :3;
|
||||
} layer_tap;
|
||||
struct action_usage {
|
||||
uint16_t code :10;
|
||||
uint8_t page :2;
|
||||
uint8_t kind :4;
|
||||
} usage;
|
||||
struct action_backlight {
|
||||
uint8_t level :8;
|
||||
uint8_t opt :4;
|
||||
uint8_t kind :4;
|
||||
} backlight;
|
||||
struct action_command {
|
||||
uint8_t id :8;
|
||||
uint8_t opt :4;
|
||||
uint8_t kind :4;
|
||||
} command;
|
||||
struct action_function {
|
||||
uint8_t id :8;
|
||||
uint8_t opt :4;
|
||||
uint8_t kind :4;
|
||||
} func;
|
||||
} action_t;
|
||||
|
||||
|
||||
/* action utility */
|
||||
#define ACTION_NO 0
|
||||
#define ACTION_TRANSPARENT 1
|
||||
#define ACTION(kind, param) ((kind)<<12 | (param))
|
||||
|
||||
|
||||
/*
|
||||
* Key Actions
|
||||
*/
|
||||
/* Mod bits: 43210
|
||||
* bit 0 ||||+- Control
|
||||
* bit 1 |||+-- Shift
|
||||
* bit 2 ||+--- Alt
|
||||
* bit 3 |+---- Gui
|
||||
* bit 4 +----- LR flag(Left:0, Right:1)
|
||||
*/
|
||||
enum mods_bit {
|
||||
MOD_LCTL = 0x01,
|
||||
MOD_LSFT = 0x02,
|
||||
MOD_LALT = 0x04,
|
||||
MOD_LGUI = 0x08,
|
||||
MOD_RCTL = 0x11,
|
||||
MOD_RSFT = 0x12,
|
||||
MOD_RALT = 0x14,
|
||||
MOD_RGUI = 0x18,
|
||||
};
|
||||
enum mods_codes {
|
||||
MODS_ONESHOT = 0x00,
|
||||
MODS_TAP_TOGGLE = 0x01,
|
||||
};
|
||||
#define ACTION_KEY(key) ACTION(ACT_MODS, (key))
|
||||
#define ACTION_MODS(mods) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | 0)
|
||||
#define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | (key))
|
||||
#define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | (key))
|
||||
#define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | MODS_ONESHOT)
|
||||
#define ACTION_MODS_TAP_TOGGLE(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | MODS_TAP_TOGGLE)
|
||||
|
||||
|
||||
/*
|
||||
* Other Keys
|
||||
*/
|
||||
enum usage_pages {
|
||||
PAGE_SYSTEM,
|
||||
PAGE_CONSUMER
|
||||
};
|
||||
#define ACTION_USAGE_SYSTEM(id) ACTION(ACT_USAGE, PAGE_SYSTEM<<10 | (id))
|
||||
#define ACTION_USAGE_CONSUMER(id) ACTION(ACT_USAGE, PAGE_CONSUMER<<10 | (id))
|
||||
#define ACTION_MOUSEKEY(key) ACTION(ACT_MOUSEKEY, key)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Layer Actions
|
||||
*/
|
||||
enum layer_param_on {
|
||||
ON_PRESS = 1,
|
||||
ON_RELEASE = 2,
|
||||
ON_BOTH = 3,
|
||||
};
|
||||
enum layer_param_bit_op {
|
||||
OP_BIT_AND = 0,
|
||||
OP_BIT_OR = 1,
|
||||
OP_BIT_XOR = 2,
|
||||
OP_BIT_SET = 3,
|
||||
};
|
||||
enum layer_pram_tap_op {
|
||||
OP_TAP_TOGGLE = 0xF0,
|
||||
OP_ON_OFF,
|
||||
OP_OFF_ON,
|
||||
OP_SET_CLEAR,
|
||||
};
|
||||
#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))
|
||||
/* Default Layer */
|
||||
#define ACTION_DEFAULT_LAYER_SET(layer) ACTION_DEFAULT_LAYER_BIT_SET((layer)/4, 1<<((layer)%4))
|
||||
/* Layer Operation */
|
||||
#define ACTION_LAYER_CLEAR(on) ACTION_LAYER_BIT_AND(0, 0, (on))
|
||||
#define ACTION_LAYER_MOMENTARY(layer) ACTION_LAYER_ON_OFF(layer)
|
||||
#define ACTION_LAYER_TOGGLE(layer) ACTION_LAYER_INVERT(layer, ON_RELEASE)
|
||||
#define ACTION_LAYER_INVERT(layer, on) ACTION_LAYER_BIT_XOR((layer)/4, 1<<((layer)%4), (on))
|
||||
#define ACTION_LAYER_ON(layer, on) ACTION_LAYER_BIT_OR( (layer)/4, 1<<((layer)%4), (on))
|
||||
#define ACTION_LAYER_OFF(layer, on) ACTION_LAYER_BIT_AND((layer)/4, ~(1<<((layer)%4)), (on))
|
||||
#define ACTION_LAYER_SET(layer, on) ACTION_LAYER_BIT_SET((layer)/4, 1<<((layer)%4), (on))
|
||||
#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_MODS(layer, mods) ACTION_LAYER_TAP((layer), 0xe0 | (mods)&0x0f)
|
||||
/* With Tapping */
|
||||
#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))
|
||||
#define ACTION_LAYER_TAP_TOGGLE(layer) ACTION_LAYER_TAP((layer), OP_TAP_TOGGLE)
|
||||
/* Bitwise Operation */
|
||||
#define ACTION_LAYER_BIT_AND(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), (on))
|
||||
#define ACTION_LAYER_BIT_OR( part, bits, on) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), (on))
|
||||
#define ACTION_LAYER_BIT_XOR(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), (on))
|
||||
#define ACTION_LAYER_BIT_SET(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), (on))
|
||||
/* Default Layer Bitwise Operation */
|
||||
#define ACTION_DEFAULT_LAYER_BIT_AND(part, bits) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), 0)
|
||||
#define ACTION_DEFAULT_LAYER_BIT_OR( part, bits) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), 0)
|
||||
#define ACTION_DEFAULT_LAYER_BIT_XOR(part, bits) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), 0)
|
||||
#define ACTION_DEFAULT_LAYER_BIT_SET(part, bits) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), 0)
|
||||
|
||||
|
||||
/*
|
||||
* Extensions
|
||||
*/
|
||||
enum backlight_opt {
|
||||
BACKLIGHT_INCREASE = 0,
|
||||
BACKLIGHT_DECREASE = 1,
|
||||
BACKLIGHT_TOGGLE = 2,
|
||||
BACKLIGHT_STEP = 3,
|
||||
BACKLIGHT_LEVEL = 4,
|
||||
};
|
||||
/* Macro */
|
||||
#define ACTION_MACRO(id) ACTION(ACT_MACRO, (id))
|
||||
#define ACTION_MACRO_TAP(id) ACTION(ACT_MACRO, FUNC_TAP<<8 | (id))
|
||||
#define ACTION_MACRO_OPT(id, opt) ACTION(ACT_MACRO, (opt)<<8 | (id))
|
||||
/* Backlight */
|
||||
#define ACTION_BACKLIGHT_INCREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_INCREASE << 8)
|
||||
#define ACTION_BACKLIGHT_DECREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_DECREASE << 8)
|
||||
#define ACTION_BACKLIGHT_TOGGLE() ACTION(ACT_BACKLIGHT, BACKLIGHT_TOGGLE << 8)
|
||||
#define ACTION_BACKLIGHT_STEP() ACTION(ACT_BACKLIGHT, BACKLIGHT_STEP << 8)
|
||||
#define ACTION_BACKLIGHT_LEVEL(level) ACTION(ACT_BACKLIGHT, BACKLIGHT_LEVEL << 8 | level)
|
||||
/* Command */
|
||||
#define ACTION_COMMAND(id, opt) ACTION(ACT_COMMAND, (opt)<<8 | (addr))
|
||||
/* Function */
|
||||
enum function_opts {
|
||||
FUNC_TAP = 0x8, /* indciates function is tappable */
|
||||
};
|
||||
#define ACTION_FUNCTION(id) ACTION(ACT_FUNCTION, (id))
|
||||
#define ACTION_FUNCTION_TAP(id) ACTION(ACT_FUNCTION, FUNC_TAP<<8 | (id))
|
||||
#define ACTION_FUNCTION_OPT(id, opt) ACTION(ACT_FUNCTION, (opt)<<8 | (id))
|
||||
|
||||
#endif /* ACTION_CODE_H */
|
138
tmk_core/common/action_layer.c
Normal file
138
tmk_core/common/action_layer.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include <stdint.h>
|
||||
#include "keyboard.h"
|
||||
#include "action.h"
|
||||
#include "util.h"
|
||||
#include "action_layer.h"
|
||||
|
||||
#ifdef DEBUG_ACTION
|
||||
#include "debug.h"
|
||||
#else
|
||||
#include "nodebug.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Default Layer State
|
||||
*/
|
||||
uint32_t default_layer_state = 0;
|
||||
|
||||
static void default_layer_state_set(uint32_t state)
|
||||
{
|
||||
debug("default_layer_state: ");
|
||||
default_layer_debug(); debug(" to ");
|
||||
default_layer_state = state;
|
||||
default_layer_debug(); debug("\n");
|
||||
clear_keyboard_but_mods(); // To avoid stuck keys
|
||||
}
|
||||
|
||||
void default_layer_debug(void)
|
||||
{
|
||||
dprintf("%08lX(%u)", default_layer_state, biton32(default_layer_state));
|
||||
}
|
||||
|
||||
void default_layer_set(uint32_t state)
|
||||
{
|
||||
default_layer_state_set(state);
|
||||
}
|
||||
|
||||
#ifndef NO_ACTION_LAYER
|
||||
void default_layer_or(uint32_t state)
|
||||
{
|
||||
default_layer_state_set(default_layer_state | state);
|
||||
}
|
||||
void default_layer_and(uint32_t state)
|
||||
{
|
||||
default_layer_state_set(default_layer_state & state);
|
||||
}
|
||||
void default_layer_xor(uint32_t state)
|
||||
{
|
||||
default_layer_state_set(default_layer_state ^ state);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NO_ACTION_LAYER
|
||||
/*
|
||||
* Keymap Layer State
|
||||
*/
|
||||
uint32_t layer_state = 0;
|
||||
|
||||
static void layer_state_set(uint32_t state)
|
||||
{
|
||||
dprint("layer_state: ");
|
||||
layer_debug(); dprint(" to ");
|
||||
layer_state = state;
|
||||
layer_debug(); dprintln();
|
||||
clear_keyboard_but_mods(); // To avoid stuck keys
|
||||
}
|
||||
|
||||
void layer_clear(void)
|
||||
{
|
||||
layer_state_set(0);
|
||||
}
|
||||
|
||||
void layer_move(uint8_t layer)
|
||||
{
|
||||
layer_state_set(1UL<<layer);
|
||||
}
|
||||
|
||||
void layer_on(uint8_t layer)
|
||||
{
|
||||
layer_state_set(layer_state | (1UL<<layer));
|
||||
}
|
||||
|
||||
void layer_off(uint8_t layer)
|
||||
{
|
||||
layer_state_set(layer_state & ~(1UL<<layer));
|
||||
}
|
||||
|
||||
void layer_invert(uint8_t layer)
|
||||
{
|
||||
layer_state_set(layer_state ^ (1UL<<layer));
|
||||
}
|
||||
|
||||
void layer_or(uint32_t state)
|
||||
{
|
||||
layer_state_set(layer_state | state);
|
||||
}
|
||||
void layer_and(uint32_t state)
|
||||
{
|
||||
layer_state_set(layer_state & state);
|
||||
}
|
||||
void layer_xor(uint32_t state)
|
||||
{
|
||||
layer_state_set(layer_state ^ state);
|
||||
}
|
||||
|
||||
void layer_debug(void)
|
||||
{
|
||||
dprintf("%08lX(%u)", layer_state, biton32(layer_state));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
action_t layer_switch_get_action(keypos_t key)
|
||||
{
|
||||
action_t action;
|
||||
action.code = ACTION_TRANSPARENT;
|
||||
|
||||
#ifndef NO_ACTION_LAYER
|
||||
uint32_t layers = layer_state | default_layer_state;
|
||||
/* check top layer first */
|
||||
for (int8_t i = 31; i >= 0; i--) {
|
||||
if (layers & (1UL<<i)) {
|
||||
action = action_for_key(i, key);
|
||||
if (action.code != ACTION_TRANSPARENT) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* fall back to layer 0 */
|
||||
action = action_for_key(0, key);
|
||||
return action;
|
||||
#else
|
||||
action = action_for_key(biton32(default_layer_state), key);
|
||||
return action;
|
||||
#endif
|
||||
}
|
77
tmk_core/common/action_layer.h
Normal file
77
tmk_core/common/action_layer.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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 ACTION_LAYER_H
|
||||
#define ACTION_LAYER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "keyboard.h"
|
||||
#include "action.h"
|
||||
|
||||
|
||||
/*
|
||||
* Default Layer
|
||||
*/
|
||||
extern uint32_t default_layer_state;
|
||||
void default_layer_debug(void);
|
||||
void default_layer_set(uint32_t state);
|
||||
|
||||
#ifndef NO_ACTION_LAYER
|
||||
/* bitwise operation */
|
||||
void default_layer_or(uint32_t state);
|
||||
void default_layer_and(uint32_t state);
|
||||
void default_layer_xor(uint32_t state);
|
||||
#else
|
||||
#define default_layer_or(state)
|
||||
#define default_layer_and(state)
|
||||
#define default_layer_xor(state)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Keymap Layer
|
||||
*/
|
||||
#ifndef NO_ACTION_LAYER
|
||||
extern uint32_t layer_state;
|
||||
void layer_debug(void);
|
||||
void layer_clear(void);
|
||||