]> git.donarmstrong.com Git - tmk_firmware.git/commitdiff
Merge branch 'keymap2'
authortmk <nobody@nowhere>
Mon, 11 Feb 2013 03:48:49 +0000 (12:48 +0900)
committertmk <nobody@nowhere>
Mon, 11 Feb 2013 03:48:49 +0000 (12:48 +0900)
Conflicts:
common/keyboard.c

24 files changed:
README.md
common.mk
common/action.c [new file with mode: 0644]
common/action.h [new file with mode: 0644]
common/action_macro.c [new file with mode: 0644]
common/action_macro.h [new file with mode: 0644]
common/command.c
common/debug.h
common/host.c
common/host.h
common/keyboard.c
common/keyboard.h
common/keycode.h
common/keymap.c [new file with mode: 0644]
common/keymap.h
common/print.c
common/print.h
common/report.h
doc/keycode.txt [new file with mode: 0644]
keyboard/hhkb/Makefile.lufa
keyboard/hhkb/Makefile.vusb
keyboard/hhkb/config.h
keyboard/hhkb/keymap.c
keyboard/hhkb/matrix.c

index 65fc72f539a1fe0acf85148455668b69e33faf5b..cf09a9407e32e0f8e68dc8d2f969e383d05085fa 100644 (file)
--- a/README.md
+++ b/README.md
@@ -7,12 +7,17 @@ Source code is available here: <http://github.com/tmk/tmk_keyboard>
 
 Features
 --------
-* Mouse key             - Mouse control by 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              - Can send 120 keys(+ 8 modifiers) simultaneously.
-* PS/2 mouse support    - integrate PS/2 mouse(TrackPoint) into keyboard as composite device.
-* keyboard protocols    - PS/2, ADB and old keyboard protocols.
+* 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
 
 
 Projects
@@ -24,11 +29,17 @@ Projects
 * terminal_usb  - [IBM Model M terminal keyboard(PS/2 scancode set3) to USB][GH_terminal]
 * news_usb      - [Sony NEWS keyboard to USB][GH_news]
 * x68k_usb      - [Sharp X68000 keyboard to USB][GH_x68k]
+* sun_usb       - Sun to USB(type4, 5 and 3?)
+* usb_usb       - USB to USB(experimental)
 
 ### keyboard
-* hhkb      - [Happy Hacking Keyboard professional][GH_hhkb]
-* macway    - [Compact keyboard mod][GH_macway]
-* hbkb      - [Happy Buckling sprint keyboard(IBM Model M mod)][GH_hbkb]
+* hhkb          - [Happy Hacking Keyboard professional][GH_hhkb]
+* macway        - [Compact keyboard mod][GH_macway]
+* hbkb          - [Happy Buckling sprint keyboard(IBM Model M mod)][GH_hbkb]
+* IIgs_Standard - Apple IIGS keyboard mod(by JeffreySung)
+* hid_liber     - [HID liberation controller][HID_liber](by alaricljs)
+* phantom       - [Phantom keyboard][PHANTOM] (by Tranquilite)
+* gh60          - [GH60 keyboard][GH60]
 
 [GH_macway]:    http://geekhack.org/showwiki.php?title=Island:11930
 [GH_hhkb]:      http://geekhack.org/showwiki.php?title=Island:12047
@@ -40,52 +51,99 @@ Projects
 [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
+[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
 
 
 
-Files & Directories
--------------------
-### Top
-* common/       - common codes
-* protocol/     - keyboard protocol support
-* keyboard/     - keyboard projects
-* converter/    - protocol converter projects
-* doc/          - documents
-* common.mk     - Makefile for common
-* protoco.mk    - Makefile for protocol
-* rules.mk      - Makefile for build rules
+Build & Program
+---------------
+### Install Tools
+First, you need tools to build firmware and program your controller. I assume you are on Windows here.
 
-### Keyboard Protocols
-* 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
+1. Install [WinAVR][winavr]. This is old but works well for this purpose. `WinAVR` is a tool set to build firmware including C compiler(gcc) and make commands. You can use [CrossPack][crosspack] instead if you are on Mac.
+
+2. Install [Atmel FLIP][flip]. `FLIP` is a tool to program(load) firmware into AVR controller(ATMega32u4) via DFU bootloader. ATMega32u4 has DFU bootloader by factory default. You can use [dfu-programmer][dfu-prog] instead if you are on Mac.
+
+3. Install driver for DFU bootloader. At first time you start DFU bootloader on Chip 'Found New Hardware Wizard' will come up on Windows. If you install device driver properly you can find chip name like 'ATmega32U4' under 'LibUSB-Win32 Devices' tree on 'Device Manager'. If not you shall need to update its driver on 'Device Manager'. You will find the driver in `FLIP` install directory like: C:\Program Files (x86)\Atmel\Flip 3.4.5\usb\. If you use `dfu-programmer` install its driver.
+
+If you use PJRC Teensy you don't need step 2 and 3, just get [Teensy loader][teensy-loader].
+
+
+### Download source
+You can find firmware source at github: https://github.com/tmk/tmk_keyboard
+
+If you are familiar with `Git` tools you are recommended to use it.  
+If not you can download zip archive from: https://github.com/tmk/tmk_keyboard/archive/master.zip
 
 
-Build & Program
----------------
 ### Build firmware
-To compile you need `AVR GCC`, `AVR Libc` and `GNU make`.
-You can use [WinAVR][winavr] on Windows and [CrossPack][crosspack] on Mac.
+1.  Open terminal window to get access to commands. You can use `cmd` in Windows or `Terminal.app` on Mac OSX. In Windows press `Windows` key and `R` then enter `cmd` in Run command dialog showing up.
+
+2. Move to project directory in the firmware source.
+
+    cd tmk_keyboard/{keyboard or converter}/<project>
+
+3. Build firmware using GNU `make` command. You'll see <project>_<variant>.hex file in that directory unless something unexpected occurs in build process.
+
+    mkae -f Makefile.<variant> clean
+    make -f Makefile.<variant>
 
-    $ cd <project>
-    $ make
 
-The firmware will be compiled as a file `tmk_<project>.hex`.
 
-[winavr]:       http://winavr.sourceforge.net/
-[crosspack]:    http://www.obdev.at/products/crosspack/index.html
 
 ### Program Controller
+Sock AVR USB chip including ATmega32U4 has DFU bootloader by factory default, you can use DFU tools for this purpose. `FLIP` is a DFU tool on Windows offered by Atmel. Open source command line DFU tool `dfu-programmer` also supports AVR chips, which run on Linux, Mac OSX and even Windows. If you have a PJRC Teensy you should use `Teensy Loader`.
+
+#### DFU bootloader
+To program AVR chip with DFU bootloader use `FLIP` or `dfu-programmer`.
 If you have a proper program command in `Makefile` just type this.
 
-    $ make program
+`FLIP` has two version of tool, GUI app and command line program. If you want GUI see tutorial section below.
+To use command line tool run this command. Note that you need to set PATH variable properly.
+
+    $ make -f Makefile.<variant> flip
+
+To program with `dfu-programmer` run:
+
+    $ make -f Makefile.<variant> dfu
+
+#### Teensy
+If you have PJRC Teensy see instruction of `Teensy Loader` at: <http://www.pjrc.com/teensy/loader.html>
+Or use this command if you have command line version of Teensy Loader installed.
+
+    $ make -f Makefile.<variant> teensy
 
-As for `Teensy` you can use `PJRC's loader` to program hex file. <http://www.pjrc.com/teensy/loader.html>
+
+#### Other programmer
+You may want to use other you favorite programmer like `avrdude` with AVRISPmkII, Aruduino or USBasp. In that case you can still use make target `program` for build with configuring PROGRAM_CMD in Makefile.
+
+    $ make -f Makefile.<variant> program
+
+
+
+#### FLIP GUI tutorial
+1. On menu bar click Device -> Select, then. `ATmega32u4`.
+2. On menu bar click Settings -> Communication -> USB, then click 'Open' button on 'USB Port Connection' dialog.
+At this point you'll see greyouted widgets on the app get colored and ready.
+
+3. On menu bar click File -> Load HEX File, then select your firmware hex file on File Selector dialog.
+4. On 'Operations Flow' panel click 'Run' button to load the firmware binary to the chip. Note that you should keep 'Erase', 'Blank Check', 'Program' and 'Verify' check boxes selected.
+5. Re-plug USB cord or click 'Start Application' button to restart your controller.
+Done.
+
+See also these instaructions if you need.
+
+- <http://code.google.com/p/micropendous/wiki/LoadingFirmwareWithFLIP>
+- <http://www.atmel.com/Images/doc7769.pdf>
+
+
+[winavr]:       http://winavr.sourceforge.net/
+[crosspack]:    http://www.obdev.at/products/crosspack/index.html
+[flip]:         http://www.atmel.com/tools/FLIP.aspx
+[dfu-prog]:     http://dfu-programmer.sourceforge.net/
+[teensy-loader]:http://www.pjrc.com/teensy/loader.html
 
 
 
@@ -106,20 +164,22 @@ Note that ***comment out*** to disable them.
     NKRO_ENABLE = yes          # USB Nkey Rollover
 
 ### 3. Programmer
-Set proper command for your controller, bootloader and programmer.
+Optional. Set proper command for your controller, bootloader and programmer.
 
     # for PJRC Teensy
     PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
 
-    # for Atmel AT90USBKEY
+    # for Atmel chip with DFU bootloader
     PROGRAM_CMD = dfu-programmer $(MCU) flash $(TARGET).hex
 
-    # avrdude
+    # avrdude with other methods
     PROGRAM_CMD = avrdude -p $(MCU) -c avrispmkII -P USB -U flash:w:$(TARGET).hex
     PROGRAM_CMD = avrdude -p $(MCU) -c usbasp -U flash:w:$(TARGET).hex
     PROGRAM_CMD = avrdude -p $(MCU) -c arduino -P COM1 -b 57600 -U flash:w:$(TARGET).hex
 
-config.h Options
+
+
+Config.h Options
 ----------------
 ### 1. USB vendor/product ID and device description
     #define VENDOR_ID       0xFEED
@@ -145,42 +205,458 @@ config.h Options
 
 Keymap
 ------
+Many of existent projects offer keymap framework to define your own keymap easily. The following will explain how you can define keymap using this framework.
+ Instead, you can also implement your own `keymap_get_action()` to return action code for each key if you want.
+
+This is keymap example for [HHKB](http://en.wikipedia.org/wiki/Happy_Hacking_Keyboard) keyboard. Keymap is defined in `keymaps[]` array.
+
+    static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+        /* Layer 0: Default Layer
+         * ,-----------------------------------------------------------.
+         * |Esc|  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|  \|  `|
+         * |-----------------------------------------------------------|
+         * |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  [|  ]|Backs|
+         * |-----------------------------------------------------------|
+         * |Contro|  A|  S|  D|  F|  G|  H|  J|  K|  L|  ;|  '|Enter   |
+         * |-----------------------------------------------------------|
+         * |Shift   |  Z|  X|  C|  V|  B|  N|  M|  ,|  .|  /|Shift |Fn1|
+         * `-----------------------------------------------------------'
+         *       |Gui|Alt  |Space                  |Alt  |Fn2|
+         *       `-------------------------------------------'
+         */
+        KEYMAP(ESC, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSLS,GRV, \
+               TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSPC, \
+               LCTL,A,   S,   D,   F,   G,   H,   J,   K,   L,   FN2, QUOT,ENT, \
+               LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, SLSH,RSFT,FN1, \
+                    LGUI,LALT,          SPC,                RALT,FN3),
+
+        /* Layer 1: HHKB mode (HHKB Fn)
+         * ,-----------------------------------------------------------.
+         * |Pwr| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
+         * |-----------------------------------------------------------|
+         * |Caps |   |   |   |   |   |   |   |Psc|Slk|Pus|Up |   |Backs|
+         * |-----------------------------------------------------------|
+         * |Contro|VoD|VoU|Mut|   |   |  *|  /|Hom|PgU|Lef|Rig|Enter   |
+         * |-----------------------------------------------------------|
+         * |Shift   |   |   |   |   |   |  +|  -|End|PgD|Dow|Shift |Fn1|
+         * `-----------------------------------------------------------'
+         *      |Gui |Alt  |Space                  |Alt  |Gui|
+         *      `--------------------------------------------'
+         */ 
+        KEYMAP(PWR, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
+               CAPS,NO,  NO,  NO,  NO,  NO,  NO,  NO,  PSCR,SLCK,PAUS,UP,  NO,  BSPC, \
+               LCTL,VOLD,VOLU,MUTE,NO,  NO,  PAST,PSLS,HOME,PGUP,LEFT,RGHT,ENT, \
+               LSFT,NO,  NO,  NO,  NO,  NO,  PPLS,PMNS,END, PGDN,DOWN,RSFT,FN0, \
+                    LGUI,LALT,          SPC,                RALT,RGUI),
+        /* Layer 2: Mouse mode (Semicolon)
+         * ,-----------------------------------------------------------.
+         * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
+         * |-----------------------------------------------------------|
+         * |Tab  |   |   |   |   |   |MwL|MwD|MwU|MwR|   |   |   |Backs|
+         * |-----------------------------------------------------------|
+         * |Contro|   |   |   |   |   |McL|McD|McU|McR|Fn0|   |Return  |
+         * |-----------------------------------------------------------|
+         * |Shift   |   |   |   |   |Mb3|Mb2|Mb1|Mb4|Mb5|   |Shift |   |
+         * `-----------------------------------------------------------'
+         *      |Gui |Alt  |Mb1                    |Alt  |Fn0|
+         *      `--------------------------------------------'
+         * Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel 
+         */
+        KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
+               TAB, NO,  NO,  NO,  NO,  NO,  WH_L,WH_D,WH_U,WH_R,NO,  NO,  NO,  BSPC, \
+               LCTL,NO,  ACL0,ACL1,ACL2,NO,  MS_L,MS_D,MS_U,MS_R,FN0, QUOT,ENT, \
+               LSFT,NO,  NO,  NO,  NO,  BTN3,BTN2,BTN1,BTN4,BTN5,SLSH,RSFT,NO, \
+                    LGUI,LALT,          BTN1,               RALT,FN0),
+    };
+
+    static const uint16_t PROGMEM fn_actions[] = {
+        ACTION_LAYER_DEFAULT,                           // FN0
+        ACTION_LAYER_SET(1),                            // FN1
+        ACTION_LAYER_SET_TAP_KEY(2, KC_SCLN),           // FN2
+        ACTION_LAYER_BIT_TOGGLE(2),                     // FN3
+    };
+
+
+
+### 1. Keycode
+See `common/keycode.h`. Keycode is 8bit internal code to inidicate action performed on key in keymap. Keycode has `KC_` prefixed symbol respectively. Most of keycodes like `KC_A` have simple action register key on press and unregister on release, on the other some of keycodes has some special actions like Fn keys, Media contorl keys, System control keys and Mouse keys.
+
+ ***In `KEYMAP` definition you need to omit prefix part `KC_` of keycode to keep keymap compact.*** For example, just use `A` instead you place `KC_A` in `KEYMAP`. Some keycodes has 4-letter short name in addition to descriptive name, you'll prefer short one in `KEYMAP`.
+
+#### 1.1 Normal key
+- `KC_NO` for no aciton
+- `KC_A` to `KC_Z`, `KC_1` to `KC_0` for alpha numeric key
+- `KC_MINS`, `KC_EQL`, `KC_GRV`, `KC_RBRC`, `KC_LBRC`, `KC_COMM`, `KC_DOT`, `KC_BSLS`, `KC_SLSH`, `KC_SCLN`, `KC_QUOT`
+- `KC_ESC`, `KC_TAB`, `KC_SPC`, `KC_BSPC`, `KC_ENT`, `KC_DEL`, `KC_INS`
+- `KC_UP`, `KC_DOWN`, `KC_RGHT`, `KC_LEFT`, `KC_PGUP`, `KC_PGDN`, `KC_HOME`, `KC_END`
+- `KC_CAPS`, `KC_NLCK`, `KC_SLCK`, `KC_PSCR`, `KC_PAUS`, `KC_APP`, `KC_F1` to `KC_F24`
+- `KC_P1` to `KC_P0`, `KC_PDOT`, `KC_PCMM`, `KC_PSLS`, `KC_PAST`, `KC_PMNS`, `KC_PPLS`, `KC_PEQL`, `KC_PENT` for keypad.
+
+#### 1.2 Modifier
+There are 8 modifiers which has discrimination between left and right. 
+
+- `KC_LCTL` and `KC_RCTL` for Control
+- `KC_LSFT` and `KC_RSFT` for Shift
+- `KC_LALT` and `KC_RALT` for Alt
+- `KC_LGUI` and `KC_RGUI` for Windows key or Command key in Mac
+
+#### 1.3 Fn key
+ **`KC_FNnn`** are `Fn` keys which not given any action at the beginning unlike most of keycodes has its own action. To use these keys in `KEYMAP` you need to assign action you want at first. Action of `Fn` is defined in `fn_actions[]` and index of the array is identical with number part of `KC_FNnn`. Thus `KC_FN0` designates action defined in first element of the array. ***32 `Fn` keys can be defined at most.***
+
+#### 1.4 Mousekey
+- `KC_MS_U`, `KC_MS_D`, `KC_MS_L`, `KC_MS_R` for mouse cursor
+- `KC_WH_U`, `KC_WH_D`, `KC_WH_L`, `KC_WH_R` for mouse wheel
+- `KC_BTN1`, `KC_BTN2`, `KC_BTN3`, `KC_BTN4`, `KC_BTN5` for mouse buttons
+
+#### 1.5 System & Media key
+- `KC_PWR`, `KC_SLEP`, `KC_WAKE` for Power, Sleep, Wake
+- `KC_MUTE`, `KC_VOLU`, `KC_VOLD` for audio volume control
+- `KC_MNXT`, `KC_MPRV`, `KC_MSTP`, `KC_MPLY`, `KC_MSEL` for media control
+- `KC_MAIL`, `KC_CALC`, `KC_MYCM` for application launch
+- `KC_WSCH`, `KC_WHOM`, `KC_WBAK`, `KC_WFWD`, `KC_WSTP`, `KC_WREF`, `KC_WFAV` for web browser operation
+
+#### Keycode Table
+ See [keycode table](doc/keycode.txt) in `doc/keycode.txt`  or `common/keycode.h` for the detail or other keycodes.
+
+ In regard to implementation side most of keycodes are identical with [HID usage] sent to host for real and some virtual keycodes are defined to support special actions.
+[HID usage]: http://www.usb.org/developers/devclass_docs/Hut1_11.pdf
+
+
+
+### 2. Action
+See `common/action.h`. Action is a 16bit code and defines function to perform on events of a key like press, release, hold and tap. You can define various actions to use various action codes.
 
+Most of keys just register 8bit keycode as HID usage(or scan code) to host, but to support other complex features needs 16bit extended action codes internally. But using 16bit action codes in keymap results in double size in memory against keycodes. To avoid this waste 8bit keycodes are used in `KEYMAP` to define instead of action codes. ***Keycodes can be considered as subset of action codes.*** Like `KC_A`(0x04) is equal to a `Key` action(0x0004) that transmit keycode of *'A'*.
+
+#### 2.1 Key action
+Key is simple action that registers keycode on press of key and unregister on release.
+You can define `Key` action on *'A'* key with:
+
+    ACTION_KEY(KC_A)
+
+But you don't need to use this expression directly because you can just put symbol `A` in `KEYMAP` definition.
+
+ Say you want to assign a key to `Shift + 1` to get charactor *'!'* or `Alt + Tab` to switch windows.
+
+    ACTION_MOD_KEY(KC_LSHIFT, KC_1)
+    ACTION_MOD_KEY(KC_LALT, KC_TAB)
+
+Or `Alt,Shift + Tab` can be defined.
+
+    ACTION_MODS_KEY((MOD_BIT(KC_LALT) | MOD_BIT(KC_LSHIFT)), KC_TAB)
+
+These actions are comprised of strokes of modifiers and a key. `Macro` action is needed if you want more complex key strokes.
+
+#### 2.2 Layer Actions
+This sets `default layer` into `current layer`. With this action you can return to `default layer`.
+
+    ACTION_LAYER_DEFAULT
+
+`Layer Set` action sets given layer argument to `current layer`. `Layer Set` action can take 0 to 15 as argument.
+
+    ACTION_LAYER_SET(layer)
+    ACTION_LAYER_SET_TOGGLE(layer)
+    ACTION_LAYER_SET_TAP_KEY(layer, key)
+    ACTION_LAYER_SET_TAP_TOGGLE(layer)
+
+`Layer Bit` action XOR bits with `current layer`. `Layer Bit` action can take 0 to 8 as argument. 
+
+    ACTION_LAYER_BIT(bits)
+    ACTION_LAYER_BIT_TOGGLE(bits)
+    ACTION_LAYER_BIT_TAP_KEY(bits, key)
+    ACTION_LAYER_BIT_TAP_TOGGLE(bits)
+
+These acitons change `default layer`.
+    ACTION_LAYER_SET_DEFAULT(layer)
+    ACTION_LAYER_BIT_DEFAULT(bits)
+
+
+#### 2.3 Macro action
+***NOT FIXED***
+`Macro` action indicates complex key strokes.
+    MACRO( MD(LSHIFT), D(D), END )
+    MACRO( U(D), MU(LSHIFT), END )
+    MACRO( I(255), T(H), T(E), T(L), T(L), W(255), T(O), END )
+
+##### 2.3.1 Normal mode
+- **I()**   change interavl of stroke.
+- **D()**   press key
+- **U()**   release key
+- **T()**   type key(press and release)
+- **W()**   wait
+- **MD()**  modifier down
+- **MU()**  modifier up
+- **END**   end mark
+
+##### 2.3.2 Extended mode
+
+***TODO: sample impl***
+See `keyboard/hhkb/keymap.c` for sample.
+
+
+#### 2.4 Function action
+***NOT FIXED***
+There are two type of action, normal `Function` and tappable `Function`.
+These actions call user defined function with `id`, `opt`, and key event information as arguments.
+
+##### 2.4.1 Function
+To define normal `Function` action in keymap use this.
+
+    ACTION_FUNCTION(id, opt)
+
+##### 2.4.2 Function with tap
+To define tappable `Function` action in keymap use this.
+
+    ACTION_FUNCTION_TAP(id, opt)
+
+##### 2.4.3 Implement user function
+`Function` actions can be defined freely with C by user in callback function:
+
+    void keymap_call_function(keyrecord_t *event, uint8_t id, uint8_t opt)
+
+This C function is called every time key is operated, argument `id` selects action to be performed and `opt` can be used for option. Functon `id` can be 0-255 and `opt` can be 0-15.
+
+ `keyrecord_t` is comprised of key event and tap count. `keyevent_t` indicates which and when key is pressed or released. From `tap_count` you can know tap state, 0 means no tap. These information will be used in user function to decide how action of key is performed.
+
+    typedef struct {
+        keyevent_t  event;
+        uint8_t     tap_count;
+    } keyrecord_t;
+
+    typedef struct {
+        key_t    key;
+        bool     pressed;
+        uint16_t time;
+    } keyevent_t;
+
+    typedef struct {
+        uint8_t col;
+        uint8_t row;
+    } key_t;
+
+***TODO: sample impl***
+See `keyboard/hhkb/keymap.c` for sample.
+
+
+
+
+
+### 3. Layer
+ Layer is key-action map to assign action to every physical key. You can define multiple layers in keymap and select a layer out of keymap during operation at will.
+
+ First layer is indexed by `Layer 0` which usually become **`default layer`** and active in initial state. **`current layer`** is active layer at that time and can be changed with user interaction. You can define **16 layers** at most in default keymap framework.
+
+ you can define a layer with placing keycode symbols separated with `comma` in `KEYMAP`, which is formed with resemblance to physical keyboard layout so as you can easily put keycode on place you want to map. ***You can define most of keys with just using keycodes*** except for `Fn` key serving special actions.
+
+
+
+### 4. Layer switching
+You can have some ways to switch layer with these actions.
+There are two kind of layer switch action `Layer Set` and `Layer Bit` and two type of switching behaviour **Momentary** and **Toggle**.
+
+#### 4.1 Momentary switching
+Momentary switching changes layer only while holding Fn key.
+
+##### 4.1.1 Momentary Set
+This `Layer Set` action sets new layer `Layer 1` to `current layer` on key press event.
+
+    ACTION_LAYER_SET(1)
+
+It switches to destination layer immediately when key is pressed, after that actions on keymap of destination layer is perfomed. ***Thus you shall need to place action to come back on destination layer***, or you will be stuck in destination layer without way to get back. To get back to `default layer` you can use this action.
+
+    ACTION_LAYER_DEFAULT
+
+##### 4.1.2 Momentary Bit
+This `Layer Bit` action performs XOR `1` with `current layer` on both press and release event. If you are on `Layer 0` now next layer to switch will be `Layer 1`. To come back to previous layer you need to place same action on destination layer.
+
+    ACTION_LAYER_BIT(1)
+
+#### 4.2 Toggle switching
+Toggle switching changes layer after press then release. You keep being on the layer until you press key to return.
+
+##### 4.2.1 Toggle Set
+This `Layer Set Toggle` action is to set `Layer 1` to `current layer` on release and do none on press.
+
+    ACTION_LAYER_SET_TOGGLE(1)
+
+To get back to `default layer` you can use this action.
+
+    ACTION_LAYER_DEFAULT
+
+##### 4.2.2 Toggle Bit
+This `Layer Bit Toggle` action is to XOR `1` with `current layer` on release and do none on press. If you are on `Layer 2` you'll switch to `Layer 3` on press. To come back to previous layer you need to place same action on destination layer.
+
+    ACTION_LAYER_BIT_TOGGLE(1)
+
+
+#### 4.3 Momentary switching with Tap key
+These actions switch to layer only while holding `Fn` key and register key on tap. **Tap** means to press and release key quickly.
+
+    ACTION_LAYER_SET_TAP_KEY(2, KC_SCLN)
+    ACTION_LAYER_SET_BIT_KEY(2, KC_SCLN)
+
+With these you can place layer switching function on normal alphabet key like `;` without losing its original register function.
+
+#### 4.4 Momentary switching with Tap Toggle
+This changes layer only while holding `Fn` key and toggle layer after several taps. **Tap** means to press and release key quickly.
+
+    ACTION_LAYER_SET_TAP_TOGGLE(layer)
+    ACTION_LAYER_BIT_TAP_TOGGLE(layer)
+
+Number of taps can be defined with `TAPPING_TOGGLE` in `config.h`, `5` by default.
+
+
+
+
+Legacy Keymap
+-------------
+This was used in prior version and still works due to legacy support code in `common/keymap.c`. Legacy keymap doesn't support many of features that new keymap offers.
+
+In comparison with new keymap how to define Fn key is different. It uses two arrays `fn_layer[]` and `fn_keycode[]`. The index of arrays corresponds with postfix number of `Fn` key. Array `fn_layer[]` indicates destination layer to switch and `fn_keycode[]` has keycodes to send when tapping `Fn` key.
+
+In following setting example, `Fn0`, `Fn1` and `Fn2` switch layer to 1, 2 and 2 respectively. `Fn2` registers `Space` key when tap while `Fn0` and `Fn1` doesn't send any key.
+
+    static const uint8_t PROGMEM fn_layer[] = {
+        1,              // Fn0
+        2,              // Fn1
+        2,              // Fn2
+    };
+
+    static const uint8_t PROGMEM fn_keycode[] = {
+        KC_NO,          // Fn0
+        KC_NO,          // Fn1
+        KC_SPC,         // Fn2
+    };
 
-Build your own firmware
------------------------
 
 
 Debuging
 --------
-Use PJRC's `hid_listen` to see debug messages and press `<COMMAND> + H` to debug menu. 
-See `config.h` for definition of `<COMMAND>` key combination.
+Use PJRC's `hid_listen` to see debug messages. You can use the tool for debug even if firmware use LUFA stack.
+
+You will see output from firmware like this.
+
+    r/c 01234567
+    00: 00000000
+    01: 00000000
+    02: 00000000
+    03: 00000000
+    04: 00000000
+    05: 00000000
+    06: 00000000
+    07: 00000000
+
+    ---- action_exec: start -----
+    EVENT: 0307u(22511)
+    Tapping: Tap release(2)
+    ACTION: ACT_LAYER[5:2C]
+    LAYER_PRESSED: Tap: unregister_code
+    TAPPING_KEY=0307u(22511):2
+    processed: 0307u(22511):2
+
+    Tapping: End(Timeout after releasing last tap): FFFFu(22715)
+    TAPPING_KEY=0000u(0):0
+
+
+
 
+Magic Comannds
+--------------
+To see help press `Magic` + `H`.
 
-Other Keyboard Projects
+ `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
+    p:      toggle print enable
+    v:      print device version & info
+    t:      print timer count
+    s:      print status
+    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
+
+### Boot Magic
+Magic commands are executed when boot time. Press `Magic` command key then pulgin.
+
+Define these macros in config.h.
+
+    IS_BOOTMAGIC_DEBUG
+    IS_BOOTMAGIC_BOOTLOADER
+
+***TODO: sample impl***
+See `keyboard/hhkb/config.h` for sample.
+
+
+
+Start Your Own Project
 -----------------------
-### PJRC USB Keyboard/Mouse Example
-- <http://www.pjrc.com/teensy/usb_keyboard.html>
-- <http://www.pjrc.com/teensy/usb_mouse.html>
 
-### kbupgrade
-- <http://github.com/rhomann/kbupgrade>
-- <http://geekhack.org/showwiki.php?title=Island:8406>
 
-### c64key
-- <http://symlink.dk/projects/c64key/>
 
-### rump
-- <http://mg8.org/rump/>
-- <http://github.com/clee/rump>
+Files & Directories
+-------------------
+### Top
+* common/       - common codes
+* protocol/     - keyboard protocol support
+* keyboard/     - keyboard projects
+* converter/    - protocol converter projects
+* doc/          - documents
+* common.mk     - Makefile for common
+* protoco.mk    - Makefile for protocol
+* rules.mk      - Makefile for build rules
+
+### Common
+* action.[ch]
+* action_macro.[ch]
+* bootloader.[ch]
+* command.[ch]
+* controller_teensy.h
+* debug.[ch]
+* host.[ch]
+* host_driver.h
+* keyboard.[ch]
+* keycode.h
+* keymap.[ch]
+* led.h
+* matrix.h
+* mousekey.[ch]
+* print.[ch]
+* report.h
+* sendchar.h
+* sendchar_null.c
+* sendchar_uart.c
+* timer.[ch]
+* uart.[ch]
+* util.[ch]
+
+### 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
 
-### dulcimer
-- <http://www.schatenseite.de/dulcimer.html>
 
-### humblehacker-keyboard
-- <http://github.com/humblehacker>
-- <http://www.humblehacker.com/keyboard/>
-- <http://geekhack.org/showwiki.php?title=Island:6292>
 
-### ps2avr
-- <http://sourceforge.net/projects/ps2avr/>
+License
+-------
+Under `GPL` 2 or later. Some protocol files are under `Modified BSD License`.
+PJRC stack has its own license.
index 66f9fd0999c6cb25f70400f5580d97a0e992d5e7..86518f03fb41f3e75c7a2990ccc358925e5dc697 100644 (file)
--- a/common.mk
+++ b/common.mk
@@ -1,6 +1,9 @@
 COMMON_DIR = common
 SRC += $(COMMON_DIR)/host.c \
        $(COMMON_DIR)/keyboard.c \
+       $(COMMON_DIR)/action.c \
+       $(COMMON_DIR)/action_macro.c \
+       $(COMMON_DIR)/keymap.c \
        $(COMMON_DIR)/command.c \
        $(COMMON_DIR)/timer.c \
        $(COMMON_DIR)/print.c \
diff --git a/common/action.c b/common/action.c
new file mode 100644 (file)
index 0000000..6d53367
--- /dev/null
@@ -0,0 +1,883 @@
+/*
+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 "timer.h"
+#include "keymap.h"
+#include "keycode.h"
+#include "keyboard.h"
+#include "mousekey.h"
+#include "command.h"
+#include "util.h"
+#include "debug.h"
+#include "action.h"
+
+
+static void process_action(keyrecord_t *record);
+static bool process_tapping(keyrecord_t *record);
+static void waiting_buffer_scan_tap(void);
+
+static void debug_event(keyevent_t event);
+static void debug_record(keyrecord_t record);
+static void debug_action(action_t action);
+static void debug_tapping_key(void);
+static void debug_waiting_buffer(void);
+
+
+/*
+ * Tapping
+ */
+/* period of tapping(ms) */
+#ifndef TAPPING_TERM
+#define TAPPING_TERM    200
+#endif
+
+/* tap count needed for toggling a feature */
+#ifndef TAPPING_TOGGLE
+#define TAPPING_TOGGLE  5
+#endif
+
+/* stores a key event of current tap. */
+static keyrecord_t tapping_key = {};
+
+#define IS_TAPPING()            !IS_NOEVENT(tapping_key.event)
+#define IS_TAPPING_PRESSED()    (IS_TAPPING() && tapping_key.event.pressed)
+#define IS_TAPPING_RELEASED()   (IS_TAPPING() && !tapping_key.event.pressed)
+#define IS_TAPPING_KEY(k)       (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
+#define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
+
+
+/*
+ * Waiting buffer
+ *
+ * stores key events waiting for settling current tap.
+ */
+#define WAITING_BUFFER_SIZE 8
+static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
+
+/* point to empty cell to enq */
+static uint8_t waiting_buffer_head = 0;
+
+/* point to the oldest data cell to deq */
+static uint8_t waiting_buffer_tail = 0;
+
+static bool waiting_buffer_enq(keyrecord_t record)
+{
+    if (IS_NOEVENT(record.event)) {
+        return true;
+    }
+
+    if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
+        debug("waiting_buffer_enq: Over flow.\n");
+        return false;
+    }
+
+    waiting_buffer[waiting_buffer_head] = record;
+    waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;
+
+    debug("waiting_buffer_enq: "); debug_waiting_buffer();
+    return true;
+}
+
+static void waiting_buffer_clear(void)
+{
+    waiting_buffer_head = 0;
+    waiting_buffer_tail = 0;
+}
+
+#if TAPPING_TERM >= 500
+static bool waiting_buffer_typed(keyevent_t event)
+{
+    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+        if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed !=  waiting_buffer[i].event.pressed) {
+            return true;
+        }
+    }
+    return false;
+}
+#endif
+
+bool waiting_buffer_has_anykey_pressed(void)
+{
+    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+        if (waiting_buffer[i].event.pressed) return true;
+    }
+    return false;
+}
+
+
+/* Oneshot modifier
+ *
+ * Problem: Want to capitalize like 'The' but the result tends to be 'THe'.
+ * Solution: Oneshot modifier have its effect on only one key coming next.
+ *           Tap Shift, then type 't', 'h' and 'e'. Not need to hold Shift key.
+ *
+ *  Hold:       works as normal modifier.
+ *  Tap:        one shot modifier.
+ *  2 Tap:      cancel one shot modifier.
+ *  5-Tap:      toggles enable/disable oneshot feature.
+ */
+static struct {
+    uint8_t mods;
+    uint8_t time;
+    bool    ready;
+    bool    disabled;
+}   oneshot_state;
+
+static void oneshot_start(uint8_t mods, uint16_t time)
+{
+    oneshot_state.mods = mods;
+    oneshot_state.time = time;
+    oneshot_state.ready = true;
+}
+
+static void oneshot_cancel(void)
+{
+    oneshot_state.mods = 0;
+    oneshot_state.time = 0;
+    oneshot_state.ready = false;
+}
+
+static void oneshot_toggle(void)
+{
+    oneshot_state.disabled = !oneshot_state.disabled;
+}
+
+
+
+void action_exec(keyevent_t event)
+{
+    if (!IS_NOEVENT(event)) {
+        debug("\n---- action_exec: start -----\n");
+        debug("EVENT: "); debug_event(event); debug("\n");
+    }
+
+    keyrecord_t record = { .event = event };
+
+    // pre-process on tapping
+    if (process_tapping(&record)) {
+        if (!IS_NOEVENT(record.event)) {
+            debug("processed: "); debug_record(record); debug("\n");
+        }
+    } else {
+        // enqueue
+        if (!waiting_buffer_enq(record)) {
+            // clear all in case of overflow.
+            debug("OVERFLOW: CLEAR ALL STATES\n");
+            clear_keyboard();
+            waiting_buffer_clear();
+            tapping_key = (keyrecord_t){};
+        }
+    }
+
+    // process waiting_buffer
+    if (!IS_NOEVENT(event) && waiting_buffer_head != waiting_buffer_tail) {
+        debug("---- action_exec: process waiting_buffer -----\n");
+    }
+
+    for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
+        if (process_tapping(&waiting_buffer[waiting_buffer_tail])) {
+            debug("processed: waiting_buffer["); debug_dec(waiting_buffer_tail); debug("] = ");
+            debug_record(waiting_buffer[waiting_buffer_tail]); debug("\n\n");
+        } else {
+            break;
+        }
+    }
+    if (!IS_NOEVENT(event)) {
+        debug("\n");
+    }
+}
+
+static void process_action(keyrecord_t *record)
+{
+    keyevent_t event = record->event;
+    uint8_t tap_count = record->tap_count;
+
+    if (IS_NOEVENT(event)) { return; }
+
+    action_t action = keymap_get_action(current_layer, event.key.pos.row, event.key.pos.col);
+    //debug("action: "); debug_hex16(action.code); if (event.pressed) debug("d\n"); else debug("u\n");
+    debug("ACTION: "); debug_action(action); debug("\n");
+
+    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) {
+                    uint8_t tmp_mods = host_get_mods();
+                    if (mods) {
+                        host_add_mods(mods);
+                        host_send_keyboard_report();
+                    }
+                    register_code(action.key.code);
+                    if (mods && action.key.code) {
+                        host_set_mods(tmp_mods);
+                        host_send_keyboard_report();
+                    }
+                } else {
+                    if (mods && !action.key.code) {
+                        host_del_mods(mods);
+                        host_send_keyboard_report();
+                    }
+                    unregister_code(action.key.code);
+                }
+            }
+            break;
+        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.code) {
+                    case 0x00:
+                        // Oneshot modifier
+                        if (event.pressed) {
+                            if (tap_count == 0) {
+                                debug("MODS_TAP: Oneshot: add_mods\n");
+                                add_mods(mods);
+                            }
+                            else if (tap_count == 1) {
+                                debug("MODS_TAP: Oneshot: start\n");
+                                oneshot_start(mods, event.time);
+                            }
+                            else if (tap_count == TAPPING_TOGGLE) {
+                                debug("MODS_TAP: Oneshot: toggle\n");
+                                oneshot_toggle();
+                            }
+                            else {
+                                debug("MODS_TAP: Oneshot: cancel&add_mods\n");
+                                // double tap cancels oneshot and works as normal modifier.
+                                oneshot_cancel();
+                                add_mods(mods);
+                            }
+                        } else {
+                            if (tap_count == 0) {
+                                debug("MODS_TAP: Oneshot: cancel/del_mods\n");
+                                // cancel oneshot by holding.
+                                oneshot_cancel();
+                                del_mods(mods);
+                            }
+                            else if (tap_count == 1) {
+                                debug("MODS_TAP: Oneshot: del_mods\n");
+                                // retain Oneshot
+                                del_mods(mods);
+                            }
+                            else {
+                                debug("MODS_TAP: Oneshot: del_mods\n");
+                                // cancel Mods
+                                del_mods(mods);
+                            }
+                        }
+                        break;
+                    default:
+                        if (event.pressed) {
+                            if (tap_count > 0) {
+                                if (waiting_buffer_has_anykey_pressed()) {
+                                    debug("MODS_TAP: Tap: Cancel: add_mods\n");
+                                    // ad hoc: set 0 to cancel tap
+                                    record->tap_count = 0;
+                                    add_mods(mods);
+                                } else {
+                                    debug("MODS_TAP: Tap: register_code\n");
+                                    register_code(action.key.code);
+                                }
+                            } else {
+                                debug("MODS_TAP: No tap: add_mods\n");
+                                add_mods(mods);
+                            }
+                        } else {
+                            if (tap_count > 0) {
+                                debug("MODS_TAP: Tap: unregister_code\n");
+                                unregister_code(action.key.code);
+                            } else {
+                                debug("MODS_TAP: No tap: add_mods\n");
+                                del_mods(mods);
+                            }
+                        }
+                        break;
+                }
+            }
+            break;
+
+        /* other HID usage */
+        case ACT_USAGE:
+#ifdef EXTRAKEY_ENABLE
+            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;
+            }
+#endif
+            break;
+
+        /* Mouse key */
+        case ACT_MOUSEKEY:
+#ifdef MOUSEKEY_ENABLE
+            if (event.pressed) {
+                mousekey_on(action.key.code);
+                mousekey_send();
+            } else {
+                mousekey_off(action.key.code);
+                mousekey_send();
+            }
+#endif
+            break;
+
+        /* Layer key */
+        case ACT_LAYER:
+            switch (action.layer.code) {
+                case LAYER_MOMENTARY:  /* momentary */
+                    if (event.pressed) {
+                        layer_switch(action.layer.val);
+                    }
+                    else {
+                        layer_switch(default_layer);
+                    }
+                    break;
+                case LAYER_ON_PRESS:
+                    if (event.pressed) {
+                        layer_switch(action.layer.val);
+                    }
+                    break;
+                case LAYER_ON_RELEASE:
+                    if (!event.pressed) {
+                        layer_switch(action.layer.val);
+                    }
+                    break;
+                case LAYER_DEFAULT:  /* default layer */
+                    switch (action.layer.val) {
+                        case DEFAULT_ON_BOTH:
+                            layer_switch(default_layer);
+                            break;
+                        case DEFAULT_ON_PRESS:
+                            if (event.pressed) {
+                                layer_switch(default_layer);
+                            }
+                            break;
+                        case DEFAULT_ON_RELEASE:
+                            if (!event.pressed) {
+                                layer_switch(default_layer);
+                            }
+                            break;
+                    }
+                    break;
+                case LAYER_TAP_TOGGLE:  /* switch on hold and toggle on several taps */
+                    if (event.pressed) {
+                        if (tap_count < TAPPING_TOGGLE) {
+                            layer_switch(action.layer.val);
+                        }
+                    } else {
+                        if (tap_count >= TAPPING_TOGGLE) {
+                            debug("LAYER_PRESSED: tap toggle.\n");
+                            layer_switch(action.layer.val);
+                        }
+                    }
+                    break;
+                case LAYER_CHANGE_DEFAULT:  /* change default layer */
+                    if (event.pressed) {
+                        default_layer = action.layer.val;
+                        layer_switch(default_layer);
+                    }
+                    break;
+                default:    /* switch layer on hold and key on tap*/
+                    if (event.pressed) {
+                       if (tap_count > 0) {
+                            debug("LAYER_PRESSED: Tap: register_code\n");
+                            register_code(action.layer.code);
+                       } else {
+                            debug("LAYER_PRESSED: No tap: layer_switch\n");
+                            layer_switch(action.layer.val);
+                       }
+                    } else {
+                        if (tap_count > 0) {
+                            debug("LAYER_PRESSED: Tap: unregister_code\n");
+                            unregister_code(action.layer.code);
+                        } else {
+                            //debug("LAYER_PRESSED: No tap: NO ACTION\n");
+//TODO: this is ok?
+                            debug("LAYER_PRESSED: No tap: return to default layer\n");
+                            layer_switch(default_layer);
+                        }
+                    }
+                    break;
+            }
+            break;
+        case ACT_LAYER_BIT:
+            switch (action.layer.code) {
+                case LAYER_MOMENTARY:  /* momentary */
+                    if (event.pressed) {
+                        layer_switch(current_layer ^ action.layer.val);
+                    } else {
+                        layer_switch(current_layer ^ action.layer.val);
+                    }
+                    break;
+                case LAYER_ON_PRESS:
+                    if (event.pressed) {
+                        layer_switch(current_layer ^ action.layer.val);
+                    }
+                    break;
+                case LAYER_ON_RELEASE:
+                    if (!event.pressed) {
+                        layer_switch(current_layer ^ action.layer.val);
+                    }
+                    break;
+                case LAYER_TAP_TOGGLE:  /* switch on hold and toggle on several taps */
+                    if (event.pressed) {
+                        if (tap_count < TAPPING_TOGGLE) {
+                            debug("LAYER_BIT: tap toggle(press).\n");
+                            layer_switch(current_layer ^ action.layer.val);
+                        }
+                    } else {
+                        if (tap_count <= TAPPING_TOGGLE) {
+                            debug("LAYER_BIT: tap toggle(release).\n");
+                            layer_switch(current_layer ^ action.layer.val);
+                        }
+                    }
+                    break;
+                case 0xFF:
+                    // change default layer
+                    if (event.pressed) {
+                        default_layer = current_layer ^ action.layer.val;
+                        layer_switch(default_layer);
+                    } else {
+                        default_layer = current_layer ^ action.layer.val;
+                        layer_switch(default_layer);
+                    }
+                    break;
+                default:
+                    // with tap key
+                    if (event.pressed) {
+                        if (IS_TAPPING_KEY(event.key) && tap_count > 0) {
+                            debug("LAYER_BIT: Tap: register_code\n");
+                            register_code(action.layer.code);
+                        } else {
+                            debug("LAYER_BIT: No tap: layer_switch(bit on)\n");
+                            layer_switch(current_layer ^ action.layer.val);
+                        }
+                    } else {
+                        if (IS_TAPPING_KEY(event.key) && tap_count > 0) {
+                            debug("LAYER_BIT: Tap: unregister_code\n");
+                            unregister_code(action.layer.code);
+                        } else {
+                            debug("LAYER_BIT: No tap: layer_switch(bit off)\n");
+                            layer_switch(current_layer ^ action.layer.val);
+                        }
+                    }
+                    break;
+            }
+            break;
+
+        /* Extentions */
+        case ACT_MACRO:
+            break;
+        case ACT_COMMAND:
+            break;
+        case ACT_FUNCTION:
+            // TODO
+            keymap_call_function(record, action.func.id, action.func.opt);
+            break;
+        default:
+            break;
+    }
+}
+
+/* Tapping
+ *
+ * Rule: Tap key is typed(pressed and released) within TAPPING_TERM.
+ *       (without interfering by typing other key)
+ */
+/* return true when key event is processed or consumed. */
+static bool process_tapping(keyrecord_t *keyp)
+{
+    keyevent_t event = keyp->event;
+
+    // if tapping
+    if (IS_TAPPING_PRESSED()) {
+        if (WITHIN_TAPPING_TERM(event)) {
+            if (tapping_key.tap_count == 0) {
+                if (IS_TAPPING_KEY(event.key) && !event.pressed) {
+                    // first tap!
+                    debug("Tapping: First tap(0->1).\n");
+                    tapping_key.tap_count = 1;
+                    debug_tapping_key();
+                    process_action(&tapping_key);
+
+                    // enqueue
+                    keyp->tap_count = tapping_key.tap_count;
+                    return false;
+                }
+#if TAPPING_TERM >= 500
+                /* This can prevent from typing some tap keys in a row at a time. */
+                else if (!event.pressed && waiting_buffer_typed(event)) {
+                    // other key typed. not tap.
+                    debug("Tapping: End. No tap. Interfered by typing key\n");
+                    process_action(&tapping_key);
+                    tapping_key = (keyrecord_t){};
+                    debug_tapping_key();
+
+                    // enqueue
+                    return false;
+                }
+#endif
+                else {
+                    // other key events shall be enq'd till tapping state settles.
+                    return false;
+                }
+            }
+            // tap_count > 0
+            else {
+                if (IS_TAPPING_KEY(event.key) && !event.pressed) {
+                    debug("Tapping: Tap release("); debug_dec(tapping_key.tap_count); debug(")\n");
+                    keyp->tap_count = tapping_key.tap_count;
+                    process_action(keyp);
+                    tapping_key = *keyp;
+                    debug_tapping_key();
+                    return true;
+                }
+                else if (is_tap_key(keyp->event.key) && event.pressed) {
+                    if (tapping_key.tap_count > 1) {
+                        debug("Tapping: Start new tap with releasing last tap(>1).\n");
+                        // unregister key
+                        process_action(&(keyrecord_t){
+                                .tap_count = tapping_key.tap_count,
+                                .event.key = tapping_key.event.key,
+                                .event.time = event.time,
+                                .event.pressed = false
+                        });
+                    } else {
+                        debug("Tapping: Start while last tap(1).\n");
+                    }
+                    tapping_key = *keyp;
+                    waiting_buffer_scan_tap();
+                    debug_tapping_key();
+                    return true;
+                }
+                else {
+                    if (!IS_NOEVENT(keyp->event)) {
+                        debug("Tapping: key event while last tap(>0).\n");
+                    }
+                    process_action(keyp);
+                    return true;
+                }
+            }
+        }
+        // after TAPPING_TERM
+        else {
+            if (tapping_key.tap_count == 0) {
+                debug("Tapping: End. Timeout. Not tap(0): ");
+                debug_event(event); debug("\n");
+                process_action(&tapping_key);
+                tapping_key = (keyrecord_t){};
+                debug_tapping_key();
+                return false;
+            }  else {
+                if (IS_TAPPING_KEY(event.key) && !event.pressed) {
+                    debug("Tapping: End. last timeout tap release(>0).");
+                    keyp->tap_count = tapping_key.tap_count;
+                    process_action(keyp);
+                    tapping_key = (keyrecord_t){};
+                    return true;
+                }
+                else if (is_tap_key(keyp->event.key) && event.pressed) {
+                    if (tapping_key.tap_count > 1) {
+                        debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
+                        // unregister key
+                        process_action(&(keyrecord_t){
+                                .tap_count = tapping_key.tap_count,
+                                .event.key = tapping_key.event.key,
+                                .event.time = event.time,
+                                .event.pressed = false
+                        });
+                    } else {
+                        debug("Tapping: Start while last timeout tap(1).\n");
+                    }
+                    tapping_key = *keyp;
+                    waiting_buffer_scan_tap();
+                    debug_tapping_key();
+                    return true;
+                }
+                else {
+                    if (!IS_NOEVENT(keyp->event)) {
+                        debug("Tapping: key event while last timeout tap(>0).\n");
+                    }
+                    process_action(keyp);
+                    return true;
+                }
+            }
+        }
+    } else if (IS_TAPPING_RELEASED()) {
+        if (WITHIN_TAPPING_TERM(event)) {
+            if (tapping_key.tap_count > 0 && IS_TAPPING_KEY(event.key) && event.pressed) {
+                // sequential tap.
+                keyp->tap_count = tapping_key.tap_count + 1;
+                debug("Tapping: Tap press("); debug_dec(keyp->tap_count); debug(")\n");
+                process_action(keyp);
+                tapping_key = *keyp;
+                debug_tapping_key();
+                return true;
+            } else if (event.pressed && is_tap_key(event.key)) {
+                // Sequential tap can be interfered with other tap key.
+                debug("Tapping: Start with interfering other tap.\n");
+                tapping_key = *keyp;
+                waiting_buffer_scan_tap();
+                debug_tapping_key();
+                return true;
+            } else {
+                if (!IS_NOEVENT(keyp->event)) debug("Tapping: other key just after tap.\n");
+                process_action(keyp);
+                return true;
+            }
+        } else {
+            // timeout. no sequential tap.
+            debug("Tapping: End(Timeout after releasing last tap): ");
+            debug_event(event); debug("\n");
+            tapping_key = (keyrecord_t){};
+            debug_tapping_key();
+            return false;
+        }
+    }
+    // not tapping satate
+    else {
+        if (event.pressed && is_tap_key(event.key)) {
+            debug("Tapping: Start(Press tap key).\n");
+            tapping_key = *keyp;
+            waiting_buffer_scan_tap();
+            debug_tapping_key();
+            return true;
+        } else {
+            process_action(keyp);
+            return true;
+        }
+    }
+}
+
+/* scan buffer for tapping */
+static void waiting_buffer_scan_tap(void)
+{
+    // tapping already is settled
+    if (tapping_key.tap_count > 0) return;
+    // invalid state: tapping_key released && tap_count == 0
+    if (!tapping_key.event.pressed) return;
+
+    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+        if (IS_TAPPING_KEY(waiting_buffer[i].event.key) &&
+                !waiting_buffer[i].event.pressed &&
+                WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
+            tapping_key.tap_count = 1;
+            waiting_buffer[i].tap_count = 1;
+            process_action(&tapping_key);
+
+            debug("waiting_buffer_scan_tap: found at ["); debug_dec(i); debug("]\n");
+            debug_waiting_buffer();
+            return;
+        }
+    }
+}
+
+
+
+/*
+ * Utilities for actions.
+ */
+void register_code(uint8_t code)
+{
+    if (code == KC_NO) {
+        return;
+    }
+    else if IS_KEY(code) {
+        // TODO: should push command_proc out of this block?
+        if (command_proc(code)) return;
+
+        if (oneshot_state.mods && oneshot_state.ready && !oneshot_state.disabled) {
+            uint8_t tmp_mods = host_get_mods();
+            host_add_mods(oneshot_state.mods);
+            host_add_key(code);
+            host_send_keyboard_report();
+
+            host_set_mods(tmp_mods);
+            oneshot_state.ready = false;
+        } else {
+            host_add_key(code);
+            host_send_keyboard_report();
+        }
+    }
+    else if IS_MOD(code) {
+        host_add_mods(MOD_BIT(code));
+        host_send_keyboard_report();
+    }
+}
+
+void unregister_code(uint8_t code)
+{
+    if IS_KEY(code) {
+        host_del_key(code);
+        host_send_keyboard_report();
+    }
+    else if IS_MOD(code) {
+        host_del_mods(MOD_BIT(code));
+        host_send_keyboard_report();
+    }
+}
+
+void add_mods(uint8_t mods)
+{
+    if (mods) {
+        host_add_mods(mods);
+        host_send_keyboard_report();
+    }
+}
+
+void del_mods(uint8_t mods)
+{
+    if (mods) {
+        host_del_mods(mods);
+        host_send_keyboard_report();
+    }
+}
+
+void set_mods(uint8_t mods)
+{
+    host_set_mods(mods);
+    host_send_keyboard_report();
+}
+
+void clear_keyboard(void)
+{
+    host_clear_mods();
+    clear_keyboard_but_mods();
+}
+
+void clear_keyboard_but_mods(void)
+{
+    host_clear_keys();
+    host_send_keyboard_report();
+#ifdef MOUSEKEY_ENABLE
+    mousekey_clear();
+    mousekey_send();
+#endif
+#ifdef EXTRAKEY_ENABLE
+    host_system_send(0);
+    host_consumer_send(0);
+#endif
+}
+
+bool sending_anykey(void)
+{
+    return (host_has_anykey() || host_mouse_in_use() ||
+            host_last_sysytem_report() || host_last_consumer_report());
+}
+
+void layer_switch(uint8_t new_layer)
+{
+    if (current_layer != new_layer) {
+        debug("Layer Switch: "); debug_hex(current_layer);
+        debug(" -> "); debug_hex(new_layer); debug("\n");
+
+        current_layer = new_layer;
+        clear_keyboard_but_mods(); // To avoid stuck keys
+        // NOTE: update mods with full scan of matrix? if modifier changes between layers
+    }
+}
+
+bool is_tap_key(key_t key)
+{
+    action_t action = keymap_get_action(current_layer, key.pos.row, key.pos.col);
+    switch (action.kind.id) {
+        case ACT_LMODS_TAP:
+        case ACT_RMODS_TAP:
+            return true;
+        case ACT_LAYER:
+        case ACT_LAYER_BIT:
+            switch (action.layer.code) {
+                case LAYER_MOMENTARY:
+                case LAYER_ON_PRESS:
+                case LAYER_ON_RELEASE:
+                case LAYER_DEFAULT:
+                    return false;
+                case LAYER_TAP_TOGGLE:
+                default:    /* tap key */
+                    return true;
+            }
+            return false;
+        case ACT_FUNCTION:
+            if (action.func.opt & FUNC_TAP) { return true; }
+            return false;
+    }
+    return false;
+}
+
+
+/*
+ * debug print
+ */
+static void debug_event(keyevent_t event)
+{
+    debug_hex16(event.key.raw);
+    if (event.pressed) debug("d("); else debug("u(");
+    debug_dec(event.time); debug(")");
+}
+static void debug_record(keyrecord_t record)
+{
+    debug_event(record.event); debug(":"); debug_dec(record.tap_count);
+}
+static void debug_action(action_t action)
+{
+    switch (action.kind.id) {
+        case ACT_LMODS:             debug("ACT_LMODS");             break;
+        case ACT_RMODS:             debug("ACT_RMODS");             break;
+        case ACT_LMODS_TAP:         debug("ACT_LMODS_TAP");         break;
+        case ACT_RMODS_TAP:         debug("ACT_RMODS_TAP");         break;
+        case ACT_USAGE:             debug("ACT_USAGE");             break;
+        case ACT_MOUSEKEY:          debug("ACT_MOUSEKEY");          break;
+        case ACT_LAYER:             debug("ACT_LAYER");     break;
+        case ACT_LAYER_BIT:         debug("ACT_LAYER_BIT");         break;
+        case ACT_MACRO:             debug("ACT_MACRO");             break;
+        case ACT_COMMAND:           debug("ACT_COMMAND");           break;
+        case ACT_FUNCTION:          debug("ACT_FUNCTION");          break;
+        default:                    debug("UNKNOWN");               break;
+    }
+    debug("[");
+    debug_hex4(action.kind.param>>8);
+    debug(":");
+    debug_hex8(action.kind.param & 0xff);
+    debug("]");
+}
+static void debug_tapping_key(void)
+{
+    debug("TAPPING_KEY="); debug_record(tapping_key); debug("\n");
+}
+static void debug_waiting_buffer(void)
+{
+    debug("{ ");
+    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+        debug("["); debug_dec(i); debug("]="); debug_record(waiting_buffer[i]); debug(" ");
+    }
+    debug("}\n");
+}
diff --git a/common/action.h b/common/action.h
new file mode 100644 (file)
index 0000000..9b559cb
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+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 "keyboard.h"
+#include "keycode.h"
+
+
+/* Execute action per keyevent */
+void action_exec(keyevent_t event);
+
+
+/* Struct to record event and tap count  */
+typedef struct {
+    keyevent_t  event;
+    uint8_t     tap_count;
+} keyrecord_t;
+
+/* Action struct.
+ *
+ * In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15). 
+ * AVR looks like a little endian in avr-gcc.
+ *
+ * NOTE: not portable across compiler/endianness?
+ * Byte order and bit order of 0x1234:
+ * Big endian:     15 ...  8 7 ... 210
+ *                |  0x12   |  0x34   |
+ *                 0001 0010 0011 0100
+ * Little endian:  012 ... 7  8 ... 15
+ *                |  0x34   |  0x12   |
+ *                 0010 1100 0100 1000
+ */
+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 {
+        uint8_t  code   :8;
+        uint8_t  val    :4;
+        uint8_t  kind   :4;
+    } layer;
+    struct action_usage {
+        uint16_t code   :10;
+        uint8_t  page   :2;
+        uint8_t  kind   :4;
+    } usage;
+    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;
+
+
+/*
+ * Utilities for actions.
+ */
+void register_code(uint8_t code);
+void unregister_code(uint8_t code);
+void add_mods(uint8_t mods);
+void del_mods(uint8_t mods);
+void set_mods(uint8_t mods);
+void clear_keyboard(void);
+void clear_keyboard_but_mods(void);
+bool sending_anykey(void);
+void layer_switch(uint8_t new_layer);
+bool is_tap_key(key_t key);
+bool waiting_buffer_has_anykey_pressed(void);
+
+
+
+
+/*
+ * Action codes
+ * ============
+ * 16bit code: action_kind(4bit) + action_parameter(12bit)
+ *
+Keyboard Keys
+-------------
+ACT_LMODS(0000):
+0000|0000|000000|00    No action
+0000|0000| keycode     Key
+0000|mods|000000|00    Left mods
+0000|mods| keycode     Key & Left mods
+
+ACT_RMODS(0001):
+0001|0000|000000|00    No action
+0001|0000| keycode     Key(no used)
+0001|mods|000000|00    Right mods
+0001|mods| keycode     Key & Right mods
+
+ACT_LMODS_TAP(0010):
+0010|mods|000000|00    Left mods OneShot
+0010|mods|000000|01    (reserved)
+0010|mods|000000|10    (reserved)
+0010|mods|000000|11    (reserved)
+0010|mods| keycode     Left mods + tap Key
+
+ACT_RMODS_TAP(0011):
+0011|mods|000000|00    Right mods OneShot
+0011|mods|000000|01    (reserved)
+0011|mods|000000|10    (reserved)
+0011|mods|000000|11    (reserved)
+0011|mods| keycode     Right mods + tap Key
+
+Other HID Usage
+---------------
+This action handles other usages than keyboard.
+ACT_USAGE(0100):
+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)
+
+
+Mouse Keys
+----------
+TODO: can be combined with 'Other HID Usage'? to save action kind id.
+ACT_MOUSEKEY(0110):
+0101|XXXX| keycode     Mouse key
+
+
+Layer Actions
+-------------
+ACT_LAYER(1000):            Set layer
+ACT_LAYER_BIT(1001):        Bit-op layer
+
+1000|LLLL|0000 0000   set L to layer on press and set default on release(momentary)
+1000|LLLL|0000 0001   set L to layer on press
+1000|LLLL|0000 0010   set L to layer on release
+1000|----|0000 0011   set default to layer on both(return to default layer)
+1000|LLLL|xxxx xxxx   set L to layer while hold and send key on tap
+1000|LLLL|1111 0000   set L to layer while hold and toggle on several taps
+1000|LLLL|1111 1111   set L to default and layer(on press)
+
+1001|BBBB|0000 0000   (not used)
+1001|BBBB|0000 0001   bit-xor layer with B on press
+1001|BBBB|0000 0010   bit-xor layer with B on release
+1001|BBBB|0000 0011   bit-xor layer with B on both(momentary)
+1001|BBBB|xxxx xxxx   bit-xor layer with B while hold and send key on tap
+1001|BBBB|1111 0000   bit-xor layer with B while hold and toggle on several taps
+1001|BBBB|1111 1111   bit-xor default with B and set layer(on press)
+
+
+
+Extensions(11XX)
+----------------
+NOTE: NOT FIXED
+
+ACT_MACRO(1100):
+1100|opt | id(8)      Macro play?
+1100|1111| id(8)      Macro record?
+
+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 {
+    ACT_LMODS           = 0b0000,
+    ACT_RMODS           = 0b0001,
+    ACT_LMODS_TAP       = 0b0010,
+    ACT_RMODS_TAP       = 0b0011,
+
+    ACT_USAGE           = 0b0100,
+    ACT_MOUSEKEY        = 0b0101,
+
+    ACT_LAYER           = 0b1000,
+    ACT_LAYER_BIT       = 0b1001,
+
+    ACT_MACRO           = 0b1100,
+    ACT_COMMAND         = 0b1110,
+    ACT_FUNCTION        = 0b1111
+};
+
+
+/* action utility */
+#define ACTION_NO                       0
+#define ACTION(kind, param)             ((kind)<<12 | (param))
+#define MODS4(mods)                     (((mods)>>4 | (mods)) & 0x0F)
+
+/* Key */
+#define ACTION_KEY(key)                 ACTION(ACT_LMODS,    key)
+/* Mods & key */
+#define ACTION_LMODS(mods)              ACTION(ACT_LMODS,    (mods)<<8 | 0x00)
+#define ACTION_LMODS_KEY(mods, key)     ACTION(ACT_LMODS,    (mods)<<8 | (key))
+#define ACTION_RMODS(mods)              ACTION(ACT_RMODS,    (mods)<<8 | 0x00)
+#define ACTION_RMODS_KEY(mods, key)     ACTION(ACT_RMODS,    (mods)<<8 | (key))
+/* Mod & key */
+#define ACTION_LMOD(mod)                ACTION(ACT_LMODS,    MODS4(MOD_BIT(mod))<<8 | 0x00)
+#define ACTION_LMOD_KEY(mod, key)       ACTION(ACT_LMODS,    MODS4(MOD_BIT(mod))<<8 | (key))
+#define ACTION_RMOD(mod)                ACTION(ACT_RMODS,    MODS4(MOD_BIT(mod))<<8 | 0x00)
+#define ACTION_RMOD_KEY(mod, key)       ACTION(ACT_RMODS,    MODS4(MOD_BIT(mod))<<8 | (key))
+
+/* Mods + Tap key */
+enum mods_codes {
+    MODS_ONESHOT           = 0x00,
+};
+#define ACTION_LMODS_TAP_KEY(mods, key) ACTION(ACT_LMODS_TAP, MODS4(mods)<<8 | (key))
+#define ACTION_LMODS_ONESHOT(mods)      ACTION(ACT_LMODS_TAP, MODS4(mods)<<8 | MODS_ONESHOT)
+#define ACTION_RMODS_TAP_KEY(mods, key) ACTION(ACT_RMODS_TAP, MODS4(mods)<<8 | (key))
+#define ACTION_RMODS_ONESHOT(mods)      ACTION(ACT_RMODS_TAP, MODS4(mods)<<8 | MODS_ONESHOT)
+/* Mod + Tap key */
+#define ACTION_LMOD_TAP_KEY(mod, key)   ACTION(ACT_LMODS_TAP, MODS4(MOD_BIT(mod))<<8 | (key))
+#define ACTION_LMOD_ONESHOT(mod)        ACTION(ACT_LMODS_TAP, MODS4(MOD_BIT(mod))<<8 | MODS_ONESHOT)
+#define ACTION_RMOD_TAP_KEY(mod, key)   ACTION(ACT_RMODS_TAP, MODS4(MOD_BIT(mod))<<8 | (key))
+#define ACTION_RMOD_ONESHOT(mod)        ACTION(ACT_RMODS_TAP, MODS4(MOD_BIT(mod))<<8 | MODS_ONESHOT)
+
+
+/* 
+ * Switch layer
+ */
+enum layer_codes {
+    LAYER_MOMENTARY = 0,
+    LAYER_ON_PRESS = 1,
+    LAYER_ON_RELEASE = 2,
+    LAYER_DEFAULT =3,
+    LAYER_TAP_TOGGLE = 0xF0,
+    LAYER_CHANGE_DEFAULT = 0xFF
+};
+enum layer_vals_default {
+    DEFAULT_ON_PRESS = 1,
+    DEFAULT_ON_RELEASE = 2,
+    DEFAULT_ON_BOTH = 3,
+};
+
+/* 
+ * return to default layer
+ */
+#define ACTION_LAYER_DEFAULT                    ACTION_LAYER_DEFAULT_R
+/* set default layer on press */
+#define ACTION_LAYER_DEFAULT_P                  ACTION(ACT_LAYER, DEFAULT_ON_PRESS<<8 | LAYER_DEFAULT)
+/* set default layer on release */
+#define ACTION_LAYER_DEFAULT_R                  ACTION(ACT_LAYER, DEFAULT_ON_RELEASE<<8 | LAYER_DEFAULT)
+/* change default layer and set layer */
+
+/*
+ * Set layer
+ */
+/* set layer on press and set default on release */
+#define ACTION_LAYER_SET(layer)                 ACTION_LAYER_SET_MOMENTARY(layer)
+#define ACTION_LAYER_SET_MOMENTARY(layer)       ACTION(ACT_LAYER, (layer)<<8 | LAYER_MOMENTARY)
+/* set layer on press and none on release */
+#define ACTION_LAYER_SET_TOGGLE(layer)          ACTION_LAYER_SET_R(layer)
+/* set layer while hold and send key on tap */
+#define ACTION_LAYER_SET_TAP_KEY(layer, key)    ACTION(ACT_LAYER, (layer)<<8 | (key))
+/* set layer on press */
+#define ACTION_LAYER_SET_P(layer)               ACTION(ACT_LAYER, (layer)<<8 | LAYER_ON_PRESS)
+/* set layer on release */
+#define ACTION_LAYER_SET_R(layer)               ACTION(ACT_LAYER, (layer)<<8 | LAYER_ON_RELEASE)
+/* set layer on hold and toggle on several taps */
+#define ACTION_LAYER_SET_TAP_TOGGLE(layer)      ACTION(ACT_LAYER, (layer)<<8 | LAYER_TAP_TOGGLE)
+/* set default layer on both press and release */
+#define ACTION_LAYER_SET_DEFAULT(layer)         ACTION(ACT_LAYER, (layer)<<8 | LAYER_CHANGE_DEFAULT)
+
+/* 
+ * Bit-op layer
+ */
+/* bit-xor on both press and release */
+#define ACTION_LAYER_BIT(bits)                  ACTION_LAYER_BIT_MOMENTARY(bits)
+#define ACTION_LAYER_BIT_MOMENTARY(bits)        ACTION(ACT_LAYER_BIT, (bits)<<8 | LAYER_MOMENTARY)
+/* bit-xor on press */
+#define ACTION_LAYER_BIT_TOGGLE(bits)           ACTION_LAYER_BIT_R(bits)
+/* bit-xor while hold and send key on tap */
+#define ACTION_LAYER_BIT_TAP_KEY(bits, key)     ACTION(ACT_LAYER_BIT, (bits)<<8 | (key))
+/* bit-xor on press */
+#define ACTION_LAYER_BIT_P(bits)                ACTION(ACT_LAYER_BIT, (bits)<<8 | LAYER_ON_PRESS)
+/* bit-xor on release */
+#define ACTION_LAYER_BIT_R(bits)                ACTION(ACT_LAYER_BIT, (bits)<<8 | LAYER_ON_RELEASE)
+/* bit-xor while hold and toggle on several taps */
+#define ACTION_LAYER_BIT_TAP_TOGGLE(bits)       ACTION(ACT_LAYER_BIT, (bits)<<8 | LAYER_TAP_TOGGLE)
+/* bit-xor default layer and set layer */
+#define ACTION_LAYER_BIT_DEFAULT(bits)          ACTION(ACT_LAYER, (bits)<<8 | LAYER_CHANGE_DEFAULT)
+
+
+/* HID Usage */
+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))
+
+/* Mousekey */
+#define ACTION_MOUSEKEY(key)            ACTION(ACT_MOUSEKEY, key)
+
+/* Macro */
+#define ACTION_MACRO(opt, id)           ACTION(ACT_FUNCTION, (opt)<<8 | (addr))
+
+/* Command */
+#define ACTION_COMMAND(opt, id)         ACTION(ACT_COMMAND,  (opt)<<8 | (addr))
+
+/* Function */
+enum function_opts {
+    FUNC_TAP        = 0x8,      /* indciates function is tappable */
+};
+#define ACTION_FUNCTION(id, opt)        ACTION(ACT_FUNCTION, (opt)<<8 | id)
+#define ACTION_FUNCTION_TAP(id)         ACTION(ACT_FUNCTION, FUNC_TAP<<8 | id)
+
+#endif  /* ACTION_H */
diff --git a/common/action_macro.c b/common/action_macro.c
new file mode 100644 (file)
index 0000000..72859c0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+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/>.
+*/
+#include <util/delay.h>
+#include "debug.h"
+#include "action.h"
+#include "action_macro.h"
+
+
+#define MACRO_READ()  (macro = pgm_read_byte(macro_p++))
+void action_macro_play(const prog_macro_t *macro_p)
+{
+    macro_t macro = END;
+    uint8_t interval = 0;
+
+    if (!macro_p) return;
+    while (true) {
+        switch (MACRO_READ()) {
+            case INTERVAL:
+                interval = MACRO_READ();
+                debug("INTERVAL("); debug_dec(interval); debug(")\n");
+                break;
+            case WAIT:
+                MACRO_READ();
+                debug("WAIT("); debug_dec(macro); debug(")\n");
+                { uint8_t ms = macro; while (ms--) _delay_ms(1); }
+                break;
+            case MODS_DOWN:
+                MACRO_READ();
+                debug("MODS_DOWN("); debug_hex(macro); debug(")\n");
+                debug("MODS_UP("); debug_hex(macro); debug(")\n");
+                add_mods(macro);
+                break;
+            case MODS_UP:
+                MACRO_READ();
+                debug("MODS_UP("); debug_hex(macro); debug(")\n");
+                del_mods(macro);
+                break;
+            case 0x04 ... 0x73:
+                debug("DOWN("); debug_hex(macro); debug(")\n");
+                register_code(macro);
+                break;
+            case 0x84 ... 0xF3:
+                debug("UP("); debug_hex(macro); debug(")\n");
+                unregister_code(macro&0x7F);
+                break;
+            case END:
+            default:
+                return;
+        }
+        // interval
+        { uint8_t ms = interval; while (ms--) _delay_ms(1); }
+    }
+}
diff --git a/common/action_macro.h b/common/action_macro.h
new file mode 100644 (file)
index 0000000..3833c7c
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+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_MACRO_H
+#define ACTION_MACRO_H
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+
+typedef uint8_t macro_t;
+typedef macro_t prog_macro_t PROGMEM;
+
+
+void action_macro_play(const prog_macro_t *macro);
+
+
+
+/* TODO: NOT FINISHED 
+normal mode command:
+    key(down):      0x04-7f/73(F24)
+    key(up):        0x84-ff
+command:        0x00-03, 0x80-83(0x74-7f, 0xf4-ff)
+    mods down   0x00
+    mods up     0x01
+    wait        0x02
+    interval    0x03
+    extkey down 0x80
+    extkey up   0x81
+    ext commad  0x82
+    ext mode    0x83
+    end         0xff
+
+extension mode command: NOT IMPLEMENTED
+    key down            0x00
+    key up              0x01
+    key down + wait
+    key up   + wait
+    mods push
+    mods pop
+    wait
+    interval
+    if
+    loop
+    push
+    pop
+    all up
+    end
+*/
+enum macro_command_id{
+    /* 0x00 - 0x03 */
+    END                 = 0x00,
+    MODS_DOWN           = 0x01,
+    MODS_UP             = 0x02,
+    MODS_SET,
+    MODS_PUSH,
+    MODS_POP,
+
+    WAIT                = 0x74,
+    INTERVAL,
+    /* 0x74 - 0x7f */
+    /* 0x80 - 0x84 */
+
+    EXT_DOWN,
+    EXT_UP,
+    EXT_WAIT,
+    EXT_INTERVAL,
+    COMPRESSION_MODE,
+
+    EXTENSION_MODE      = 0xff,
+};
+
+
+/* normal mode */
+#define DOWN(key)       (key)
+#define UP(key)         ((key) | 0x80)
+#define TYPE(key)       (key), (key | 0x80)
+#define MODS_DOWN(mods) MODS_DOWN, (mods)
+#define MODS_UP(mods)   MODS_UP, (mods)
+#define WAIT(ms)        WAIT, (ms)
+#define INTERVAL(ms)    INTERVAL, (ms)
+
+#define D(key)          DOWN(KC_##key)
+#define U(key)          UP(KC_##key)
+#define T(key)          TYPE(KC_##key)
+#define MD(key)         MODS_DOWN(MOD_BIT(KC_##key))
+#define MU(key)         MODS_UP(MOD_BIT(KC_##key))
+#define W(ms)           WAIT(ms)
+#define I(ms)           INTERVAL(ms)
+
+
+/* extension mode */
+
+
+#endif /* ACTION_MACRO_H */
index 5cdd168d46297dcbf1992bdce80f5ccc1181dfe9..6d4e4c642dbc34df5f70c4a3032c7784b0633867 100644 (file)
@@ -19,6 +19,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <util/delay.h>
 #include "keycode.h"
 #include "host.h"
+#include "keymap.h"
 #include "print.h"
 #include "debug.h"
 #include "util.h"
@@ -53,7 +54,6 @@ static void mousekey_console_help(void);
 
 static uint8_t numkey2num(uint8_t code);
 static void switch_layer(uint8_t layer);
-static void clear_keyboard(void);
 
 
 typedef enum { ONESHOT, CONSOLE, MOUSEKEY } cmdstate_t;
@@ -556,18 +556,3 @@ static void switch_layer(uint8_t layer)
     default_layer = layer;
     print("switch to "); print_val_hex8(layer);
 }
-
-static void clear_keyboard(void)
-{
-    host_clear_keys();
-    host_clear_mods();
-    host_send_keyboard_report();
-
-    host_system_send(0);
-    host_consumer_send(0);
-
-#ifdef MOUSEKEY_ENABLE
-    mousekey_clear();
-    mousekey_send();
-#endif
-}
index 648f0e096c71e1a4c987361be59c47d49ec1c7c9..e63d46f0e9e0dbd398da756b45a7d0218f939f8c 100644 (file)
@@ -36,6 +36,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 #define debug_dec(data)           do { if (debug_enable) print_dec(data); } while (0)
 #define debug_decs(data)          do { if (debug_enable) print_decs(data); } while (0)
+#define debug_hex4(data)          do { if (debug_enable) print_hex4(data); } while (0)
 #define debug_hex8(data)          do { if (debug_enable) print_hex8(data); } while (0)
 #define debug_hex16(data)         do { if (debug_enable) print_hex16(data); } while (0)
 #define debug_hex32(data)         do { if (debug_enable) print_hex32(data); } while (0)
index 261ec6472fa4f9e209260e6bd9afd24c9f3be891..6ed3d780f640affa88668ab11a303b40090200db 100644 (file)
@@ -127,14 +127,19 @@ void host_clear_keys(void)
     }
 }
 
-void host_add_mod_bit(uint8_t mod)
+uint8_t host_get_mods(void)
 {
-    keyboard_report->mods |= mod;
+    return keyboard_report->mods;
 }
 
-void host_del_mod_bit(uint8_t mod)
+void host_add_mods(uint8_t mods)
 {
-    keyboard_report->mods &= ~mod;
+    keyboard_report->mods |= mods;
+}
+
+void host_del_mods(uint8_t mods)
+{
+    keyboard_report->mods &= ~mods;
 }
 
 void host_set_mods(uint8_t mods)
index 8417987966d2962411cbdd855f153c9d8580e0fa..7c4f06601d9a0e682b77a38b56bd46cf0abfc4e4 100644 (file)
@@ -52,10 +52,13 @@ void host_consumer_send(uint16_t data);
 void host_add_key(uint8_t key);
 void host_del_key(uint8_t key);
 void host_clear_keys(void);
-void host_add_mod_bit(uint8_t mod);
-void host_del_mod_bit(uint8_t mod);
+
+uint8_t host_get_mods(void);
+void host_add_mods(uint8_t mods);
+void host_del_mods(uint8_t mods);
 void host_set_mods(uint8_t mods);
 void host_clear_mods(void);
+
 uint8_t host_has_anykey(void);
 uint8_t host_has_anymod(void);
 uint8_t host_get_first_key(void);
index 2dee51d4b817d0c282cf4102a50555cc1cdc94a1..5e9945baf450eb1f8ca66441c1800da1de35b7d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright 2011,2012 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
@@ -26,536 +26,39 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "command.h"
 #include "util.h"
 #include "sendchar.h"
+#include "bootloader.h"
 #ifdef MOUSEKEY_ENABLE
 #include "mousekey.h"
 #endif
 
 
-#define Kdebug(s)       do { if (debug_keyboard) debug(s); } while(0)
-#define Kdebug_P(s)     do { if (debug_keyboard) debug_P(s); } while(0)
-#define Kdebug_hex(s)   do { if (debug_keyboard) debug_hex(s); } while(0)
-
-#define LAYER_DELAY     250
-
-typedef enum keykind {
-    NONE,
-    FN_DOWN, FN_UP,
-    FNK_DOWN, FNK_UP,
-    KEY_DOWN, KEY_UP,
-    MOD_DOWN, MOD_UP,
-} keykind_t;
-
-typedef enum { IDLE, DELAYING, WAITING, PRESSING } kbdstate_t;
-
-
-#ifdef KEYMAP_DEFAULT_LAYER
-uint8_t default_layer = KEYMAP_DEFAULT_LAYER;
-uint8_t current_layer = KEYMAP_DEFAULT_LAYER;
-#else
-uint8_t default_layer = 0;
-uint8_t current_layer = 0;
-#endif
-
-/* keyboard internal states */
-static kbdstate_t kbdstate = IDLE;
-static uint8_t fn_state_bits = 0;
-static keyrecord_t delayed_fn;
-static keyrecord_t waiting_key;
-
-
-static const char *state_str(kbdstate_t state)
-{
-    if (state == IDLE)      return PSTR("IDLE");
-    if (state == DELAYING)  return PSTR("DELAYING");
-    if (state == WAITING)   return PSTR("WAITING");
-    if (state == PRESSING)  return PSTR("PRESSING");
-    return PSTR("UNKNOWN");
-}
-
-static inline keykind_t get_keykind(uint8_t code, bool pressed)
-{
-    if IS_KEY(code)         return (pressed ? KEY_DOWN : KEY_UP);
-    if IS_MOD(code)         return (pressed ? MOD_DOWN : MOD_UP);
-    if IS_FN(code) {
-        if (keymap_fn_keycode(FN_INDEX(code)))
-            return (pressed ? FNK_DOWN : FNK_UP);
-        else
-            return (pressed ? FN_DOWN : FN_UP);
-    }
-    if IS_MOUSEKEY(code)    return (pressed ? KEY_DOWN : KEY_UP);
-    if IS_SYSTEM(code)      return (pressed ? KEY_DOWN : KEY_UP);
-    if IS_CONSUMER(code)    return (pressed ? KEY_DOWN : KEY_UP);
-    return  NONE;
-}
-
-static void clear_keyboard(void)
-{
-    host_clear_keys();
-    host_clear_mods();
-    host_send_keyboard_report();
-
-    host_system_send(0);
-    host_consumer_send(0);
-
-#ifdef MOUSEKEY_ENABLE
-    mousekey_clear();
-    mousekey_send();
-#endif
-}
-
-static void clear_keyboard_but_mods(void)
-{
-    host_clear_keys();
-    host_send_keyboard_report();
-
-    host_system_send(0);
-    host_consumer_send(0);
-
-#ifdef MOUSEKEY_ENABLE
-    mousekey_clear();
-    mousekey_send();
-#endif
-}
-
-static bool anykey_sent_to_host(void)
-{
-    return (host_has_anykey() || host_mouse_in_use() ||
-            host_last_sysytem_report() || host_last_consumer_report());
-}
-
-static void layer_switch_on(uint8_t code)
-{
-    if (!IS_FN(code)) return;
-    fn_state_bits |= FN_BIT(code);
-    uint8_t new_layer = (fn_state_bits ? keymap_fn_layer(biton(fn_state_bits)) : default_layer);
-    if (current_layer != new_layer) {
-        Kdebug("Layer Switch(on): "); Kdebug_hex(current_layer);
-        Kdebug(" -> "); Kdebug_hex(new_layer); Kdebug("\n");
-
-        clear_keyboard_but_mods();
-        current_layer = new_layer;
-    }
-}
-
-static bool layer_switch_off(uint8_t code)
-{
-    if (!IS_FN(code)) return false;
-    fn_state_bits &= ~FN_BIT(code);
-    uint8_t new_layer = (fn_state_bits ? keymap_fn_layer(biton(fn_state_bits)) : default_layer);
-    if (current_layer != new_layer) {
-        Kdebug("Layer Switch(off): "); Kdebug_hex(current_layer);
-        Kdebug(" -> "); Kdebug_hex(new_layer); Kdebug("\n");
-
-        clear_keyboard_but_mods();
-        current_layer = new_layer;
-        return true;
-    }
-    return false;
-}
-
-static void register_code(uint8_t code)
-{
-    if IS_KEY(code) {
-        if (!command_proc(code)) {
-            host_add_key(code);
-            host_send_keyboard_report();
-        }
-    }
-    else if IS_MOD(code) {
-        host_add_mod_bit(MOD_BIT(code));
-        host_send_keyboard_report();
-    }
-    else if IS_FN(code) {
-        if (!command_proc(keymap_fn_keycode(FN_INDEX(code)))) {
-            host_add_key(keymap_fn_keycode(FN_INDEX(code)));
-            host_send_keyboard_report();
-        }
-    }
-    else if IS_MOUSEKEY(code) {
-#ifdef MOUSEKEY_ENABLE
-        mousekey_on(code);
-        mousekey_send();
-#endif
-    }
-    else if IS_CONSUMER(code) {
-        uint16_t usage = 0;
-        switch (code) {
-            case KC_AUDIO_MUTE:
-                usage = AUDIO_MUTE;
-                break;
-            case KC_AUDIO_VOL_UP:
-                usage = AUDIO_VOL_UP;
-                break;
-            case KC_AUDIO_VOL_DOWN:
-                usage = AUDIO_VOL_DOWN;
-                break;
-            case KC_MEDIA_NEXT_TRACK:
-                usage = TRANSPORT_NEXT_TRACK;
-                break;
-            case KC_MEDIA_PREV_TRACK:
-                usage = TRANSPORT_PREV_TRACK;
-                break;
-            case KC_MEDIA_STOP:
-                usage = TRANSPORT_STOP;
-                break;
-            case KC_MEDIA_PLAY_PAUSE:
-                usage = TRANSPORT_PLAY_PAUSE;
-                break;
-            case KC_MEDIA_SELECT:
-                usage = AL_CC_CONFIG;
-                break;
-            case KC_MAIL:
-                usage = AL_EMAIL;
-                break;
-            case KC_CALCULATOR:
-                usage = AL_CALCULATOR;
-                break;
-            case KC_MY_COMPUTER:
-                usage = AL_LOCAL_BROWSER;
-                break;
-            case KC_WWW_SEARCH:
-                usage = AC_SEARCH;
-                break;
-            case KC_WWW_HOME:
-                usage = AC_HOME;
-                break;
-            case KC_WWW_BACK:
-                usage = AC_BACK;
-                break;
-            case KC_WWW_FORWARD:
-                usage = AC_FORWARD;
-                break;
-            case KC_WWW_STOP:
-                usage = AC_STOP;
-                break;
-            case KC_WWW_REFRESH:
-                usage = AC_REFRESH;
-                break;
-            case KC_WWW_FAVORITES:
-                usage = AC_BOOKMARKS;
-                break;
-        }
-        host_consumer_send(usage);
-    }
-    else if IS_SYSTEM(code) {
-        uint16_t usage = 0;
-        switch (code) {
-            case KC_SYSTEM_POWER:
-                usage = SYSTEM_POWER_DOWN;
-                break;
-            case KC_SYSTEM_SLEEP:
-                usage = SYSTEM_SLEEP;
-                break;
-            case KC_SYSTEM_WAKE:
-                usage = SYSTEM_WAKE_UP;
-                break;
-        }
-        host_system_send(usage);
-    }
-
-}
-
-static void unregister_code(uint8_t code)
-{
-    if IS_KEY(code) {
-        host_del_key(code);
-        host_send_keyboard_report();
-    }
-    else if IS_MOD(code) {
-        host_del_mod_bit(MOD_BIT(code));
-        host_send_keyboard_report();
-    }
-    else if IS_FN(code) {
-        host_del_key(keymap_fn_keycode(FN_INDEX(code)));
-        host_send_keyboard_report();
-    }
-    else if IS_MOUSEKEY(code) {
-#ifdef MOUSEKEY_ENABLE
-        mousekey_off(code);
-        mousekey_send();
-#endif
-    }
-    else if IS_CONSUMER(code) {
-        host_consumer_send(0x0000);
-    }
-    else if IS_SYSTEM(code) {
-        host_system_send(0x0000);
-    }
-}
-
-/*
- *
- * Event/State|IDLE          PRESSING      DELAYING[f]      WAITING[f,k]         
- * -----------+------------------------------------------------------------------
- * Fn  Down   |(L+)          -*1           WAITING(Sk)      IDLE(Rf,Ps)*7        
- *     Up     |(L-)          IDLE(L-)*8    IDLE(L-)*8       IDLE(L-)*8           
- * Fnk Down   |DELAYING(Sf)* (Rf)          WAITING(Sk)      IDLE(Rf,Ps,Rf)       
- *     Up     |(L-)          IDLE(L-/Uf)*8 IDLE(Rf,Uf/L-)*3 IDLE(Rf,Ps,Uf/L-)*3  
- * Key Down   |PRESSING(Rk)  (Rk)          WAITING(Sk)      IDLE(Rf,Ps,Rk)       
- *     Up     |(Uk)          IDLE(Uk)*4    (Uk)             IDLE(L+,Ps,Pk)/(Uk)*a
- *            |
- * Delay      |-             -             IDLE(L+)         IDLE(L+,Ps)          
- * Magic Key  |COMMAND*5
- *
- * *1: ignore Fn if other key is down.
- * *2: register Fnk if any key is pressing
- * *3: register/unregister delayed Fnk and move to IDLE if code == delayed Fnk, else *8
- * *4: if no keys registered to host
- * *5: unregister all keys
- * *6: only if no keys down
- * *7: ignore Fn because Fnk key and stored key are down.
- * *8: move to IDLE if layer switch(off) occurs, else stay at current state
- * *9: repeat key if pressing Fnk twice quickly(move to PRESSING)
- * *a: layer switch and process waiting key and code if code == wainting key, else unregister key
- *
- * States:
- *      IDLE: No key is down except modifiers
- *      DELAYING: delay layer switch after pressing Fn with alt keycode
- *      WAITING: key is pressed during DELAYING
- *
- * Events:
- *      Fn: Fn key without alternative keycode
- *      Fnk: Fn key with alternative keycode
- *      -: ignore
- *      Delay: layer switch delay term is elapsed
- *
- * Actions:
- *      Rk: register key
- *      Uk: unregister key
- *      Rf: register Fn(alt keycode)
- *      Uf: unregister Fn(alt keycode)
- *      Rs: register stored key
- *      Us: unregister stored key
- *      Sk: Store key(waiting Key)
- *      Sf: Store Fn(delayed Fn)
- *      Ps: Process stored key
- *      Ps: Process key
- *      Is: Interpret stored keys in current layer
- *      L+: Switch to new layer(*unregister* all keys but modifiers)
- *      L-: Switch back to last layer(*unregister* all keys but modifiers)
- *      Ld: Switch back to default layer(*unregister* all keys but modifiers)
- */
-#define NEXT(state)     do { \
-    Kdebug("NEXT: "); Kdebug_P(state_str(kbdstate)); \
-    kbdstate = state; \
-    Kdebug(" -> "); Kdebug_P(state_str(kbdstate)); Kdebug("\n"); \
-} while (0)
-
-static inline void process_key(keyevent_t event)
-{
-    uint8_t code = keymap_get_keycode(current_layer, event.key.row, event.key.col);
-    keykind_t kind = get_keykind(code, event.pressed);
-
-    uint8_t tmp_mods;
-
-    Kdebug("state: "); Kdebug_P(state_str(kbdstate));
-    Kdebug(" kind: "); Kdebug_hex(kind);
-    Kdebug(" code: "); Kdebug_hex(code);
-    if (event.pressed) { Kdebug("d"); } else { Kdebug("u"); }
-    Kdebug("\n");
-
-    switch (kbdstate) {
-        case IDLE:
-            switch (kind) {
-                case FN_DOWN:
-                    layer_switch_on(code);
-                    break;
-                case FN_UP:
-                    layer_switch_off(code);
-                    break;
-                case FNK_DOWN:
-                    // repeat Fn alt key when press Fn key down, up then down again quickly
-                    if (KEYEQ(delayed_fn.event.key, event.key) &&
-                            timer_elapsed(delayed_fn.time) < LAYER_DELAY) {
-                        register_code(code);
-                        NEXT(PRESSING);
-                    } else {
-                        delayed_fn = (keyrecord_t) {
-                            .event = event,
-                            .code = code,
-                            .mods = keyboard_report->mods,
-                            .time = timer_read()
-                        };
-                        NEXT(DELAYING);
-                    }
-                    break;
-                case FNK_UP:
-                    layer_switch_off(code);
-                    break;
-                case KEY_DOWN:
-                    register_code(code);
-                    NEXT(PRESSING);
-                    break;
-                case MOD_DOWN:
-                    register_code(code);
-                    break;
-                case KEY_UP:
-                case MOD_UP:
-                    unregister_code(code);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        case PRESSING:
-            switch (kind) {
-                case FN_DOWN:
-                    // ignored when any key is pressed
-                    break;
-                case FN_UP:
-                    if (layer_switch_off(code))
-                        NEXT(IDLE);
-                    break;
-                case FNK_DOWN:
-                    register_code(code);
-                    break;
-                case FNK_UP:
-                    if (layer_switch_off(code)) {
-                        NEXT(IDLE);
-                    } else {
-                        unregister_code(code);
-                        if (!anykey_sent_to_host())
-                            NEXT(IDLE);
-                    }
-                    break;
-                case KEY_DOWN:
-                case MOD_DOWN:
-                    register_code(code);
-                    break;
-                case KEY_UP:
-                case MOD_UP:
-                    unregister_code(code);
-                    if (!anykey_sent_to_host())
-                        NEXT(IDLE);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        case DELAYING:
-            switch (kind) {
-                case FN_DOWN:
-                case FNK_DOWN:
-                case KEY_DOWN:
-                    waiting_key = (keyrecord_t) {
-                        .event = event,
-                        .code = code,
-                        .mods = keyboard_report->mods,
-                        .time = timer_read()
-                    };
-                    NEXT(WAITING);
-                    break;
-                case MOD_DOWN:
-                    register_code(code);
-                    break;
-                case FN_UP:
-                    if (layer_switch_off(code))
-                        NEXT(IDLE);
-                    break;
-                case FNK_UP:
-                    if (code == delayed_fn.code) {
-                        // type Fn with alt keycode
-                        // restore the mod status at the time of pressing Fn key
-                        tmp_mods = keyboard_report->mods;
-                        host_set_mods(delayed_fn.mods);
-                        register_code(delayed_fn.code);
-                        unregister_code(delayed_fn.code);
-                        host_set_mods(tmp_mods);
-                        NEXT(IDLE);
-                    } else {
-                        if (layer_switch_off(code))
-                            NEXT(IDLE);
-                    }
-                    break;
-                case KEY_UP:
-                case MOD_UP:
-                    unregister_code(code);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        case WAITING:
-            switch (kind) {
-                case FN_DOWN:
-                case FNK_DOWN:
-                case KEY_DOWN:
-                    tmp_mods = keyboard_report->mods;
-                    host_set_mods(delayed_fn.mods);
-                    register_code(delayed_fn.code);
-                    host_set_mods(waiting_key.mods);
-                    register_code(waiting_key.code);
-                    host_set_mods(tmp_mods);
-                    if (kind == FN_DOWN) {
-                        // ignore Fn
-                    } else if (kind == FNK_DOWN) {
-                        register_code(code);
-                    } else if (kind == KEY_DOWN) {
-                        register_code(code);
-                    }
-                    NEXT(IDLE);
-                    break;
-                case MOD_DOWN:
-                    register_code(code);
-                    break;
-                case FN_UP:
-                    if (layer_switch_off(code))
-                        NEXT(IDLE);
-                    break;
-                case FNK_UP:
-                    if (code == delayed_fn.code) {
-                        // alt down, key down, alt up
-                        tmp_mods = keyboard_report->mods;
-                        host_set_mods(delayed_fn.mods);
-                        register_code(delayed_fn.code);
-                        host_set_mods(waiting_key.mods);
-                        register_code(waiting_key.code);
-                        unregister_code(delayed_fn.code);
-                        host_set_mods(tmp_mods);
-                        NEXT(IDLE);
-                    } else {
-                        if (layer_switch_off(code))
-                            NEXT(IDLE);
-                    }
-                    break;
-                case KEY_UP:
-                    if (code == waiting_key.code) {
-                        layer_switch_on(delayed_fn.code);
-                        NEXT(IDLE);
-                        // process waiting_key
-                        tmp_mods = keyboard_report->mods;
-                        host_set_mods(waiting_key.mods);
-                        process_key(waiting_key.event);
-                        host_set_mods(tmp_mods);
-                        process_key(event);
-                    } else {
-                        unregister_code(code);
-                    }
-                    break;
-                case MOD_UP:
-                    unregister_code(code);
-                    break;
-                default:
-                    break;
-            }
-            break;
-    }
-}
-
 void keyboard_init(void)
 {
-    // TODO: to enable debug print magic key bind on boot time
-
     // TODO: configuration of sendchar impl
     print_sendchar_func = sendchar;
 
     timer_init();
     matrix_init();
+
+    /* boot magic keys goes here */
+    matrix_scan();
+#ifdef IS_BOOTMAGIC_BOOTLOADER
+    /* kick up bootloader */
+    if (IS_BOOTMAGIC_BOOTLOADER()) bootloader_jump();
+#endif
+#ifdef IS_BOOTMAGIC_DEBUG
+    if (IS_BOOTMAGIC_DEBUG()) debug_enable = true;
+#endif
+
 #ifdef PS2_MOUSE_ENABLE
     ps2_mouse_init();
 #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];
@@ -572,9 +75,10 @@ void keyboard_task(void)
 
             for (uint8_t c = 0; c < MATRIX_COLS; c++) {
                 if (matrix_change & ((matrix_row_t)1<<c)) {
-                    process_key((keyevent_t){
-                        .key = (key_t){ .row = r, .col = c },
-                        .pressed = (matrix_row & ((matrix_row_t)1<<c))
+                    action_exec((keyevent_t){
+                        .key.pos  = (keypos_t){ .row = r, .col = c },
+                        .pressed = (matrix_row & (1<<c)),
+                        .time = (timer_read() | 1) /* time should not be 0 */
                     });
                     // record a processed key
                     matrix_prev[r] ^= ((matrix_row_t)1<<c);
@@ -584,55 +88,19 @@ void keyboard_task(void)
             }
         }
     }
-    MATRIX_LOOP_END:
-
-    // layer switch when delay term elapses
-    if (kbdstate == DELAYING || kbdstate == WAITING) {
-        if (timer_elapsed(delayed_fn.time) > LAYER_DELAY) {
-            if (kbdstate == DELAYING) {
-                layer_switch_on(delayed_fn.code);
-                NEXT(IDLE);
-            }
-            if (kbdstate == WAITING) {
-                layer_switch_on(delayed_fn.code);
-                NEXT(IDLE);
-                uint8_t tmp_mods = keyboard_report->mods;
-                host_set_mods(waiting_key.mods);
-                process_key(waiting_key.event);
-                host_set_mods(tmp_mods);
-            }
-        }
-    }
+    // call with pseudo tick event when no real key event.
+    action_exec(TICK);
 
+MATRIX_LOOP_END:
 #ifdef MOUSEKEY_ENABLE
     // mousekey repeat & acceleration
     mousekey_task();
 #endif
-
-    // FAIL SAFE: clear all key if no key down
-    if (matrix_change) {
-        matrix_row_t is_matrix_on = 0;
-        for (int r = 0; r < MATRIX_ROWS; r++) {
-            is_matrix_on |= matrix_get_row(r);
-        }
-        if (!is_matrix_on) {
-            Kdebug("FAIL SAFE: clear all keys(default layer).\n");
-            clear_keyboard();
-            current_layer = default_layer;
-            fn_state_bits = 0;
-            delayed_fn = (keyrecord_t){};
-            waiting_key = (keyrecord_t){};
-            NEXT(IDLE);
-        }
-    }
-
     // update LED
     if (led_status != host_keyboard_leds()) {
         led_status = host_keyboard_leds();
         keyboard_set_leds(led_status);
     }
-
-    return;
 }
 
 void keyboard_set_leds(uint8_t leds)
index 2353805e172df3a8ff0cfa01ca36ea7814c23055..e1cab31194ccaee402aee1e7d99a3ede61b7d309 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright 2011 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
@@ -26,28 +26,44 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 extern "C" {
 #endif
 
+/* key matrix position */
 typedef struct {
-    uint8_t row;
     uint8_t col;
+    uint8_t row;
+} keypos_t;
+
+// TODO: need raw? keypos_t -> key_t?
+typedef union {
+    uint16_t raw;
+    keypos_t pos;
 } key_t;
 
+/* key event */
 typedef struct {
     key_t    key;
     bool     pressed;
+    uint16_t time;
 } keyevent_t;
 
-typedef struct {
-    keyevent_t  event;
-    uint8_t     code;
-    uint8_t     mods;
-    uint16_t    time;
-} keyrecord_t;
+/* equivalent test of key_t */
+#define KEYEQ(keya, keyb)       ((keya).raw == (keyb).raw)
 
-#define KEYEQ(keya, keyb)     (keya.row == keyb.row && keya.col == keyb.col)
+/* (time == 0) means no event and assumes matrix has no 255 line. */
+#define IS_NOEVENT(event)       ((event).time == 0 || ((event).key.pos.row == 255 && (event).key.pos.col == 255))
 
+#define NOEVENT                 (keyevent_t){           \
+    .key.pos = (keypos_t){ .row = 255, .col = 255 },    \
+    .pressed = false,                                   \
+    .time = 0                                           \
+}
+
+/* tick event */
+#define TICK                    (keyevent_t){           \
+    .key.pos = (keypos_t){ .row = 255, .col = 255 },    \
+    .pressed = false,                                   \
+    .time = (timer_read() | 1)                          \
+}
 
-extern uint8_t current_layer;
-extern uint8_t default_layer;
 
 void keyboard_init(void);
 void keyboard_task(void);
index f9331cdbf300839c841bdf8cc2c5cbce00d35f5a..4f57a5887c608816d86fa9d4639f9a20a5e0eae0 100644 (file)
@@ -28,14 +28,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define IS_KEY(code)             (KC_A         <= (code) && (code) <= KC_EXSEL)
 #define IS_MOD(code)             (KC_LCTRL     <= (code) && (code) <= KC_RGUI)
 
-#define IS_FN(code)              (KC_FN0       <= (code) && (code) <= KC_FN7)
+#define IS_FN(code)              (KC_FN0       <= (code) && (code) <= KC_FN31)
 #define IS_MOUSEKEY(code)        (KC_MS_UP     <= (code) && (code) <= KC_MS_ACCEL2)
 #define IS_MOUSEKEY_MOVE(code)   (KC_MS_UP     <= (code) && (code) <= KC_MS_RIGHT)
 #define IS_MOUSEKEY_BUTTON(code) (KC_MS_BTN1   <= (code) && (code) <= KC_MS_BTN5)
 #define IS_MOUSEKEY_WHEEL(code)  (KC_MS_WH_UP  <= (code) && (code) <= KC_MS_WH_RIGHT)
 #define IS_MOUSEKEY_ACCEL(code)  (KC_MS_ACCEL0 <= (code) && (code) <= KC_MS_ACCEL2)
 
-#define IS_SPECIAL(code)         ((0xB0 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF))
+#define IS_SPECIAL(code)         ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF))
 #define IS_CONSUMER(code)        (KC_MUTE      <= (code) && (code) <= KC_WFAV)
 #define IS_SYSTEM(code)          (KC_POWER     <= (code) && (code) <= KC_WAKE)
 
@@ -43,6 +43,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define MOD_INDEX(code) ((code) & 0x07)
 #define FN_BIT(code)    (1<<FN_INDEX(code))
 #define FN_INDEX(code)  ((code) - KC_FN0)
+#define FN_MIN          KC_FN0
+#define FN_MAX          KC_FN31
 
 
 /*
@@ -388,11 +390,10 @@ enum internal_special_keycodes {
     /* System Control */
     KC_SYSTEM_POWER     = 0xA5,
     KC_SYSTEM_SLEEP,
-    KC_SYSTEM_WAKE,     /* 0xA7 */
-                        /* 0xA8-AF */
+    KC_SYSTEM_WAKE,
 
-    /* Consumer Page */
-    KC_AUDIO_MUTE       = 0xB0,
+    /* Media Control */
+    KC_AUDIO_MUTE,
     KC_AUDIO_VOL_UP,
     KC_AUDIO_VOL_DOWN,
     KC_MEDIA_NEXT_TRACK,
@@ -408,21 +409,47 @@ enum internal_special_keycodes {
     KC_WWW_BACK,
     KC_WWW_FORWARD,
     KC_WWW_STOP,
-    KC_WWW_REFRESH,     /* 0xC0 */
-    KC_WWW_FAVORITES,   /* 0xC1 */
-                        /* 0xC2-DF vacant for future use */
+    KC_WWW_REFRESH,
+    KC_WWW_FAVORITES,   /* 0xB9 */
 
-    /* 0xE0-E7 for Modifiers. DO NOT USE. */
-
-    /* Layer Switching */
-    KC_FN0              = 0xE8,
+    /* Fn key */
+    KC_FN0              = 0xC0,
     KC_FN1,
     KC_FN2,
     KC_FN3,
     KC_FN4,
     KC_FN5,
     KC_FN6,
-    KC_FN7,             /* 0xEF */
+    KC_FN7,
+    KC_FN8,
+    KC_FN9,
+    KC_FN10,
+    KC_FN11,
+    KC_FN12,
+    KC_FN13,
+    KC_FN14,
+    KC_FN15,
+
+    KC_FN16             = 0xD0,
+    KC_FN17,
+    KC_FN18,
+    KC_FN19,
+    KC_FN20,
+    KC_FN21,
+    KC_FN22,
+    KC_FN23,
+    KC_FN24,
+    KC_FN25,
+    KC_FN26,
+    KC_FN27,
+    KC_FN28,
+    KC_FN29,
+    KC_FN30,
+    KC_FN31,            /* 0xDF */
+
+    /**************************************/
+    /* 0xE0-E7 for Modifiers. DO NOT USE. */
+    /**************************************/
 
     /* Mousekey */
     KC_MS_UP            = 0xF0,
diff --git a/common/keymap.c b/common/keymap.c
new file mode 100644 (file)
index 0000000..8302c27
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+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/>.
+*/
+#include "keymap.h"
+#include "report.h"
+#include "keycode.h"
+
+
+/* layer */
+uint8_t default_layer = 0;
+uint8_t current_layer = 0;
+
+
+#ifndef NO_LEGACY_KEYMAP_SUPPORT
+/* legacy support with weak reference */
+__attribute__ ((weak))
+action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col)
+{
+    /* convert from legacy keycode to action */
+    uint8_t key = keymap_get_keycode(layer, row, col);
+    action_t action;
+    switch (key) {
+        case KC_A ... KC_EXSEL:
+            action.code = ACTION_KEY(key);
+            break;
+        case KC_LCTRL ... KC_LGUI:
+            action.code = ACTION_LMOD(key);
+            break;
+        case KC_RCTRL ... KC_RGUI:
+            action.code = ACTION_RMOD(key);
+            break;
+        case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
+            action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(key));
+            break;
+        case KC_AUDIO_MUTE ... KC_WWW_FAVORITES:
+            action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(key));
+            break;
+        case KC_MS_UP ... KC_MS_ACCEL2:
+            action.code = ACTION_MOUSEKEY(key);
+            break;
+        case KC_FN0 ... KC_FN31:
+            {
+                uint8_t layer = keymap_fn_layer(FN_INDEX(key));
+                uint8_t code = keymap_fn_keycode(FN_INDEX(key));
+                action.code = ACTION_LAYER_SET_TAP_KEY(layer, code);
+            }
+            break;
+        case KC_NO ... KC_UNDEFINED:
+        default:
+            action.code = ACTION_NO;
+            break;
+    }
+    return action;
+}
+#endif
+
+__attribute__ ((weak))
+void keymap_call_function(keyrecord_t *event, uint8_t id, uint8_t opt)
+{
+}
index 7dfd6c2a1b66ba3bdbf6f2a23468823f79d08f48..30d73f797ff96ecb09d62aa59ac56a19bff772e4 100644 (file)
@@ -20,9 +20,26 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 #include <stdint.h>
 #include <stdbool.h>
+#include "action.h"
 
 
-/* keycode in specific layer */
+// TODO: move to action.h?
+/* layer used currently */
+extern uint8_t current_layer;
+/* layer to return or start with */
+extern uint8_t default_layer;
+
+
+/* action for key */
+// TODO: should use struct key_t?
+action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col);
+
+/* user defined special function */
+void keymap_call_function(keyrecord_t *record, uint8_t id, uint8_t opt);
+
+
+#ifndef NO_LEGACY_KEYMAP_SUPPORT
+/* keycode of key */
 uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col);
 
 /* layer to move during press Fn key */
@@ -30,5 +47,6 @@ uint8_t keymap_fn_layer(uint8_t fn_bits);
 
 /* keycode to send when release Fn key without using */
 uint8_t keymap_fn_keycode(uint8_t fn_bits);
+#endif
 
 #endif
index 84400a1df21ab2f33f85d75df7b203ac301f20e5..08d211f206a81a7b5b27ebe019e2263da76cf67a 100644 (file)
@@ -113,7 +113,6 @@ void print_decs(int16_t data)
 }
 
 
-static inline
 void print_hex4(uint8_t data)
 {
     sendchar(data + ((data < 10) ? '0' : 'A' - 10));
@@ -137,6 +136,12 @@ void print_hex32(uint32_t data)
     print_hex16(data);
 }
 
+void print_bin4(uint8_t data)
+{
+    for (int i = 4; i >= 0; i--) {
+        sendchar((data & (1<<i)) ? '1' : '0');
+    }
+}
 
 void print_bin8(uint8_t data)
 {
index 9c31b24a2edf48b1f4936fa36f9e71805b72e939..b22509477fb903175bc348512381f2a0f7f32281 100644 (file)
@@ -87,11 +87,13 @@ void print_dec(uint16_t data);
 void print_decs(int16_t data);
 
 /* hex */
+void print_hex4(uint8_t data);
 void print_hex8(uint8_t data);
 void print_hex16(uint16_t data);
 void print_hex32(uint32_t data);
 
 /* binary */
+void print_bin4(uint8_t data);
 void print_bin8(uint8_t data);
 void print_bin16(uint16_t data);
 void print_bin32(uint32_t data);
index a73e0aba180bfbc09588ad6a2386191e334c6b35..0995189b399087668dd3373ff50d85b39b5279ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright 2011 Jun Wako <wakojun@gmail.com>
+Copyright 2011,2012 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
@@ -19,6 +19,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define REPORT_H
 
 #include <stdint.h>
+#include "keycode.h"
 
 
 /* report id */
@@ -33,8 +34,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define MOUSE_BTN4 (1<<3)
 #define MOUSE_BTN5 (1<<4)
 
-// Consumer Page(0x0C)
-// following are supported by Windows: http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx
+/* Consumer Page(0x0C)
+ * following are supported by Windows: http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx
+ */
 #define AUDIO_MUTE              0x00E2
 #define AUDIO_VOL_UP            0x00E9
 #define AUDIO_VOL_DOWN          0x00EA
@@ -42,10 +44,12 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define TRANSPORT_PREV_TRACK    0x00B6
 #define TRANSPORT_STOP          0x00B7
 #define TRANSPORT_PLAY_PAUSE    0x00CD
+/* application launch */
 #define AL_CC_CONFIG            0x0183
 #define AL_EMAIL                0x018A
 #define AL_CALCULATOR           0x0192
 #define AL_LOCAL_BROWSER        0x0194
+/* application control */
 #define AC_SEARCH               0x0221
 #define AC_HOME                 0x0223
 #define AC_BACK                 0x0224
@@ -53,20 +57,20 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define AC_STOP                 0x0226
 #define AC_REFRESH              0x0227
 #define AC_BOOKMARKS            0x022A
-// supplement for Bluegiga iWRAP HID(not supported by Windows?)
+/* supplement for Bluegiga iWRAP HID(not supported by Windows?) */
 #define AL_LOCK                 0x019E
 #define TRANSPORT_RECORD        0x00B2
 #define TRANSPORT_REWIND        0x00B4
 #define TRANSPORT_EJECT         0x00B8
 #define AC_MINIMIZE             0x0206
 
-// Generic Desktop Page(0x01)
+/* Generic Desktop Page(0x01) - system power control */
 #define SYSTEM_POWER_DOWN       0x0081
 #define SYSTEM_SLEEP            0x0082
 #define SYSTEM_WAKE_UP          0x0083
 
 
-// key report size(NKRO or boot mode)
+/* key report size(NKRO or boot mode) */
 #if defined(HOST_PJRC)
 #   include "usb.h"
 #   if defined(KBD2_REPORT_KEYS) && KBD2_REPORT_KEYS > KBD_REPORT_KEYS
@@ -97,6 +101,34 @@ typedef struct {
     int8_t h;
 } __attribute__ ((packed)) report_mouse_t;
 
+
+/* keycode to system usage */
+#define KEYCODE2SYSTEM(key) \
+    (key == KC_SYSTEM_POWER ? SYSTEM_POWER_DOWN : \
+    (key == KC_SYSTEM_SLEEP ? SYSTEM_SLEEP : \
+    (key == KC_SYSTEM_WAKE  ? SYSTEM_WAKE_UP : 0)))
+
+/* keycode to consumer usage */
+#define KEYCODE2CONSUMER(key) \
+    (key == KC_AUDIO_MUTE       ?  AUDIO_MUTE : \
+    (key == KC_AUDIO_VOL_UP     ?  AUDIO_VOL_UP : \
+    (key == KC_AUDIO_VOL_DOWN   ?  AUDIO_VOL_DOWN : \
+    (key == KC_MEDIA_NEXT_TRACK ?  TRANSPORT_NEXT_TRACK : \
+    (key == KC_MEDIA_PREV_TRACK ?  TRANSPORT_PREV_TRACK : \
+    (key == KC_MEDIA_STOP       ?  TRANSPORT_STOP : \
+    (key == KC_MEDIA_PLAY_PAUSE ?  TRANSPORT_PLAY_PAUSE : \
+    (key == KC_MEDIA_SELECT     ?  AL_CC_CONFIG : \
+    (key == KC_MAIL             ?  AL_EMAIL : \
+    (key == KC_CALCULATOR       ?  AL_CALCULATOR : \
+    (key == KC_MY_COMPUTER      ?  AL_LOCAL_BROWSER : \
+    (key == KC_WWW_SEARCH       ?  AC_SEARCH : \
+    (key == KC_WWW_HOME         ?  AC_HOME : \
+    (key == KC_WWW_BACK         ?  AC_BACK : \
+    (key == KC_WWW_FORWARD      ?  AC_FORWARD : \
+    (key == KC_WWW_STOP         ?  AC_STOP : \
+    (key == KC_WWW_REFRESH      ?  AC_REFRESH : \
+    (key == KC_WWW_FAVORITES    ?  AC_BOOKMARKS : 0))))))))))))))))))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/doc/keycode.txt b/doc/keycode.txt
new file mode 100644 (file)
index 0000000..4137566
--- /dev/null
@@ -0,0 +1,261 @@
+Keycode Symbol Table
+====================
+Keycodes are defined in `common/keycode.h`.
+Range of 00-A4 and E0-E7 are identical with HID Usage:
+<http://www.usb.org/developers/devclass_docs/Hut1_11.pdf>
+Virtual keycodes are defined out of above range to support special actions.
+
+
+Keycode Symbol      Short name      Description
+--------------------------------------------------------------------------------
+KC_NO                               00 Reserved (no event indicated)
+KC_ROLL_OVER                        01 Keyboard ErrorRollOver
+KC_POST_FAIL                        02 Keyboard POSTFail
+KC_UNDEFINED                        03 Keyboard ErrorUndefined
+KC_A                                04 Keyboard a and A
+KC_B                                05 Keyboard b and B
+KC_C                                06 Keyboard c and C
+KC_D                                07 Keyboard d and D
+KC_E                                08 Keyboard e and E
+KC_F                                09 Keyboard f and F
+KC_G                                0A Keyboard g and G
+KC_H                                0B Keyboard h and H
+KC_I                                0C Keyboard i and I
+KC_J                                0D Keyboard j and J
+KC_K                                0E Keyboard k and K
+KC_L                                0F Keyboard l and L
+KC_M                                10 Keyboard m and M
+KC_N                                11 Keyboard n and N
+KC_O                                12 Keyboard o and O
+KC_P                                13 Keyboard p and P
+KC_Q                                14 Keyboard q and Q
+KC_R                                15 Keyboard r and R
+KC_S                                16 Keyboard s and S
+KC_T                                17 Keyboard t and T
+KC_U                                18 Keyboard u and U
+KC_V                                19 Keyboard v and V
+KC_W                                1A Keyboard w and W
+KC_X                                1B Keyboard x and X
+KC_Y                                1C Keyboard y and Y
+KC_Z                                1D Keyboard z and Z
+KC_1                                1E Keyboard 1 and !
+KC_2                                1F Keyboard 2 and @
+KC_3                                20 Keyboard 3 and #
+KC_4                                21 Keyboard 4 and $
+KC_5                                22 Keyboard 5 and %
+KC_6                                23 Keyboard 6 and ^
+KC_7                                24 Keyboard 7 and &
+KC_8                                25 Keyboard 8 and *
+KC_9                                26 Keyboard 9 and (
+KC_0                                27 Keyboard 0 and )
+KC_ENTER            KC_ENT          28 Keyboard Return (ENTER)
+KC_ESCAPE           KC_ESC          29 Keyboard ESCAPE
+KC_BSPACE           KC_BSPC         2A Keyboard DELETE (Backspace)
+KC_TAB                              2B Keyboard Tab
+KC_SPACE            KC_SPC          2C Keyboard Spacebar
+KC_MINUS            KC_MINS         2D Keyboard - and (underscore)
+KC_EQUAL            KC_EQL          2E Keyboard = and +
+KC_LBRACKET         KC_LBRC         2F Keyboard [ and {
+KC_RBRACKET         KC_RBRC         30 Keyboard ] and }
+KC_BSLASH           KC_BSLS         31 Keyboard \ and |
+KC_NONUS_HASH       KC_NUHS         32 Keyboard Non-US # and ~
+KC_SCOLON           KC_SCLN         33 Keyboard ; and :
+KC_QUOTE            KC_QUOT         34 Keyboard â€˜ and â€œ
+KC_GRAVE            KC_GRV          35 Keyboard Grave Accent and Tilde
+KC_COMMA            KC_COMM         36 Keyboard, and <
+KC_DOT                              37 Keyboard . and >
+KC_SLASH            KC_SLSH         38 Keyboard / and ?
+KC_CAPSLOCK         KC_CAPS         39 Keyboard Caps Lock
+KC_F1                               3A Keyboard F1
+KC_F2                               3B Keyboard F2
+KC_F3                               3C Keyboard F3
+KC_F4                               3D Keyboard F4
+KC_F5                               3E Keyboard F5
+KC_F6                               3F Keyboard F6
+KC_F7                               40 Keyboard F7
+KC_F8                               41 Keyboard F8
+KC_F9                               42 Keyboard F9
+KC_F10                              43 Keyboard F10
+KC_F11                              44 Keyboard F11
+KC_F12                              45 Keyboard F12
+KC_PSCREEN          KC_PSCR         46 Keyboard PrintScreen1
+KC_SCKLOCK          KC_SLCK         47 Keyboard Scroll Lock11
+KC_PAUSE            KC_PAUS         48 Keyboard Pause1
+KC_INSERT           KC_INT          49 Keyboard Insert1
+KC_HOME                             4A Keyboard Home1
+KC_PGUP                             4B Keyboard PageUp1
+KC_DELETE           KC_DELETE       4C Keyboard Delete Forward
+KC_END                              4D Keyboard End1
+KC_PGDOWN           KC_PGDN         4E Keyboard PageDown1
+KC_RIGHT            KC_RGHT         4F Keyboard RightArrow1
+KC_LEFT                             50 Keyboard LeftArrow1
+KC_DOWN                             51 Keyboard DownArrow1
+KC_UP                               52 Keyboard UpArrow1
+KC_NUMLOCK          KC_NLCK         53 Keypad Num Lock and Clear11
+KC_KP_SLASH         KC_PSLS         54 Keypad /1
+KC_KP_ASTERISK      KC_PAST         55 Keypad *
+KC_KP_MINUS         KC_PMNS         56 Keypad -
+KC_KP_PLUS          KC_PPLS         57 Keypad +
+KC_KP_ENTER         KC_PENT         58 Keypad ENTER5
+KC_KP_1             KC_P1           59 Keypad 1 and End
+KC_KP_2             KC_P2           5A Keypad 2 and Down Arrow
+KC_KP_3             KC_P3           5B Keypad 3 and PageDn
+KC_KP_4             KC_P4           5C Keypad 4 and Left Arrow
+KC_KP_5             KC_P5           5D Keypad 5
+KC_KP_6             KC_P6           5E Keypad 6 and Right Arrow
+KC_KP_7             KC_P7           5F Keypad 7 and Home
+KC_KP_8             KC_P8           60 Keypad 8 and Up Arrow
+KC_KP_9             KC_P9           61 Keypad 9 and PageUp
+KC_KP_0             KC_P0           62 Keypad 0 and Insert
+KC_KP_DOT           KC_PDOT         63 Keypad . and Delete
+KC_NONUS_BSLASH     KC_NUBS         64 Keyboard Non-US \ and |
+KC_APPLICATION      KC_APP          65 Keyboard Application10
+KC_POWER                            66 Keyboard Power9
+KC_KP_EQUAL         KC_PEQL         67 Keypad =
+KC_F13                              68 Keyboard F13
+KC_F14                              69 Keyboard F14
+KC_F15                              6A Keyboard F15
+KC_F16                              6B Keyboard F16
+KC_F17                              6C Keyboard F17
+KC_F18                              6D Keyboard F18
+KC_F19                              6E Keyboard F19
+KC_F20                              6F Keyboard F20
+KC_F21                              70 Keyboard F21
+KC_F22                              71 Keyboard F22
+KC_F23                              72 Keyboard F23
+KC_F24                              73 Keyboard F24
+KC_EXECUTE                          74 Keyboard Execute
+KC_HELP                             75 Keyboard Help
+KC_MENU                             76 Keyboard Menu
+KC_SELECT                           77 Keyboard Select
+KC_STOP                             78 Keyboard Stop
+KC_AGAIN                            79 Keyboard Again
+KC_UNDO                             7A Keyboard Undo
+KC_CUT                              7B Keyboard Cut
+KC_COPY                             7C Keyboard Copy
+KC_PASTE                            7D Keyboard Paste
+KC_FIND                             7E Keyboard Find
+KC__MUTE                            7F Keyboard Mute
+KC__VOLUP                           80 Keyboard Volume Up
+KC__VOLDOWN                         81 Keyboard Volume Down
+KC_LOCKING_CAPS                     82 Keyboard Locking Caps Lock12
+KC_LOCKING_NUM                      83 Keyboard Locking Num Lock12
+KC_LOCKING_SCROLL                   84 Keyboard Locking Scroll Lock12
+KC_KP_COMMA         KC_PCMM         85 Keypad Comma27
+KC_KP_EQUAL_AS400                   86 Keypad Equal Sign29
+KC_INT1             KC_RO           87 Keyboard International115,28
+KC_INT2             KC_KANA         88 Keyboard International216
+KC_INT3             KC_JYEN         89 Keyboard International317
+KC_INT4             KC_HENK         8A Keyboard International418
+KC_INT5             KC_MHEN         8B Keyboard International519
+KC_INT6                             8C Keyboard International620
+KC_INT7                             8D Keyboard International721
+KC_INT8                             8E Keyboard International822
+KC_INT9                             8F Keyboard International922
+KC_LANG1                            90 Keyboard LANG125
+KC_LANG2                            91 Keyboard LANG226
+KC_LANG3                            92 Keyboard LANG330
+KC_LANG4                            93 Keyboard LANG431
+KC_LANG5                            94 Keyboard LANG532
+KC_LANG6                            95 Keyboard LANG68
+KC_LANG7                            96 Keyboard LANG78
+KC_LANG8                            97 Keyboard LANG88
+KC_LANG9                            98 Keyboard LANG98
+KC_ALT_ERASE                        99 Keyboard Alternate Erase7
+KC_SYSREQ                           9A Keyboard SysReq/Attention1
+KC_CANCEL                           9B Keyboard Cancel
+KC_CLEAR                            9C Keyboard Clear
+KC_PRIOR                            9D Keyboard Prior
+KC_RETURN                           9E Keyboard Return
+KC_SEPARATOR                        9F Keyboard Separator
+KC_OUT                              A0 Keyboard Out
+KC_OPER                             A1 Keyboard Oper
+KC_CLEAR_AGAIN                      A2 Keyboard Clear/Again
+KC_CRSEL                            A3 Keyboard CrSel/Props
+KC_EXSEL                            A4 Keyboard ExSel
+/* Modifiers */
+KC_LCTRL            KC_LCTRL        E0 Keyboard LeftControl
+KC_LSHIFT           KC_LSFT         E1 Keyboard LeftShift
+KC_LALT                             E2 Keyboard LeftAlt
+KC_LGUI                             E3 Keyboard Left GUI(Windows/Apple/Meta key)
+KC_RCTRL            KC_RCTL         E4 Keyboard RightControl
+KC_RSHIFT           KC_RSFT         E5 Keyboard RightShift
+KC_RALT                             E6 Keyboard RightAlt
+KC_RGUI                             E7 Keyboard Right GUI(Windows/Apple/Meta key)
+
+/* 
+ * Virtual keycodes
+ */
+/* System Control */
+KC_SYSTEM_POWER     KC_PWR          System Power Down
+KC_SYSTEM_SLEEP     KC_SLEP         System Sleep
+KC_SYSTEM_WAKE      KC_WAKE         System Wake
+/* Consumer Page */
+KC_AUDIO_MUTE       KC_MUTE
+KC_AUDIO_VOL_UP     KC_VOLU
+KC_AUDIO_VOL_DOWN   KC_VOLD
+KC_MEDIA_NEXT_TRACK KC_MNXT
+KC_MEDIA_PREV_TRACK KC_MPRV
+KC_MEDIA_STOP       KC_MSTP
+KC_MEDIA_PLAY_PAUSE KC_MPLY
+KC_MEDIA_SELECT     KC_MSEL
+KC_MAIL             KC_MAIL
+KC_CALCULATOR       KC_CALC
+KC_MY_COMPUTER      KC_MYCM
+KC_WWW_SEARCH       KC_WSCH
+KC_WWW_HOME         KC_WHOM
+KC_WWW_BACK         KC_WBAK
+KC_WWW_FORWARD      KC_WFWD
+KC_WWW_STOP         KC_WSTP
+KC_WWW_REFRESH      KC_WREF
+KC_WWW_FAVORITES    KC_WFAV
+/* Mousekey */
+KC_MS_UP            KC_MS_U         Mouse Cursor Up
+KC_MS_DOWN          KC_MS_D         Mouse Cursor Down
+KC_MS_LEFT          KC_MS_L         Mouse Cursor Left
+KC_MS_RIGHT         KC_MS_R         Mouse Cursor Right
+KC_MS_BTN1          KC_BTN1         Mouse Button 1
+KC_MS_BTN2          KC_BTN2         Mouse Button 2
+KC_MS_BTN3          KC_BTN3         Mouse Button 3
+KC_MS_BTN4          KC_BTN4         Mouse Button 4
+KC_MS_BTN5          KC_BTN5         Mouse Button 5
+KC_MS_WH_UP         KC_WH_U         Mouse Wheel Up
+KC_MS_WH_DOWN       KC_WH_D         Mouse Wheel Down
+KC_MS_WH_LEFT       KC_WH_L         Mouse Wheel Left
+KC_MS_WH_RIGHT      KC_WH_R         Mouse Wheel Right
+KC_MS_ACCEL0        KC_ACL0         Mouse Acceleration 0
+KC_MS_ACCEL1        KC_ACL1         Mouse Acceleration 1
+KC_MS_ACCEL2        KC_ACL2         Mouse Acceleration 2
+/* Fn key */
+KC_FN0
+KC_FN1
+KC_FN2
+KC_FN3
+KC_FN4
+KC_FN5
+KC_FN6
+KC_FN7
+KC_FN8
+KC_FN9
+KC_FN10
+KC_FN11
+KC_FN12
+KC_FN13
+KC_FN14
+KC_FN15
+KC_FN16
+KC_FN17
+KC_FN18
+KC_FN19
+KC_FN20
+KC_FN21
+KC_FN22
+KC_FN23
+KC_FN24
+KC_FN25
+KC_FN26
+KC_FN27
+KC_FN28
+KC_FN29
+KC_FN30
+KC_FN31
index 5acc93a23ccade3456d9c1229e5ac3d0a5e03182..afd413d019561b63a69693a8a67e36d1eeb579a0 100644 (file)
@@ -121,3 +121,6 @@ VPATH += $(TOP_DIR)
 include $(TOP_DIR)/protocol/lufa.mk
 include $(TOP_DIR)/common.mk
 include $(TOP_DIR)/rules.mk
+
+debug-on: EXTRAFLAGS += -DDEBUG
+debug-on: all
index 8caf234971ea9bb14856c7903f964d88a495339a..0e0e4a8cd67ad823a330a5783c82782c6df3dd07 100644 (file)
@@ -89,3 +89,6 @@ VPATH += $(TOP_DIR)
 include $(TOP_DIR)/protocol/vusb.mk
 include $(TOP_DIR)/common.mk
 include $(TOP_DIR)/rules.mk
+
+debug-on: EXTRAFLAGS += -DDEBUG
+debug-on: all
index cca75f2434d9692d2ea09cc53ed5095d3e008aa9..5fcec95eb28e55c15f510e3bab36d93cc9cfd3fb 100644 (file)
@@ -37,6 +37,20 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define MATRIX_COLS 8
 
 
+/* 
+ * Boot magic keys
+ * call some function by pressing key when pluging cable or powering on.
+ */
+/* key position on matrix(ROW:COL) */
+#define KEY_FN          0x54
+#define KEY_D           0x14
+#define KEY_IS_ON(key)  matrix_is_on((key)>>4, (key)&0xF)
+/* kick up bootloader */
+#define IS_BOOTMAGIC_BOOTLOADER()       KEY_IS_ON(KEY_FN)
+/* debug on */
+#define IS_BOOTMAGIC_DEBUG()            KEY_IS_ON(KEY_D)
+
+
 /* key combination for command */
 #define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT))) 
 
@@ -45,6 +59,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #   define MOUSEKEY_DELAY_TIME 100
 #endif
 
+/* period of tapping(ms) */
+#define TAPPING_TERM    200
+/* tap count needed for toggling a feature */
+#define TAPPING_TOGGLE  5
 
 /* PS/2 mouse */
 #ifdef PS2_MOUSE_ENABLE
index 5dc5582ec792e499da70a016787d3ab019a10841..65ef89ad77da326d840ead3db02e1dda88b20d63 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright 2011 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
@@ -21,16 +21,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <stdint.h>
 #include <stdbool.h>
 #include <avr/pgmspace.h>
-#include "host.h"
 #include "keycode.h"
-#include "print.h"
+#include "action.h"
+#include "action_macro.h"
+#include "host.h"
 #include "debug.h"
-#include "util.h"
 #include "keymap.h"
 
 
-// Convert physical keyboard layout to matrix array.
-// This is a macro to define keymap easily in keyboard layout form.
 #define KEYMAP( \
     K31, K30, K00, K10, K11, K20, K21, K40, K41, K60, K61, K70, K71, K50, K51, \
     K32, K01, K02, K13, K12, K23, K22, K42, K43, K62, K63, K73, K72, K52, \
@@ -49,34 +47,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
     { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_NO    } \
 }
 
-#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
-
-
-// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed.
-static const uint8_t PROGMEM fn_layer[] = {
-    0,              // Fn0
-    1,              // Fn1
-    2,              // Fn2
-    3,              // Fn3
-    3,              // Fn4
-    5,              // Fn5
-    0,              // Fn6
-    0               // Fn7
-};
-
-// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer.
-// See layer.c for details.
-static const uint8_t PROGMEM fn_keycode[] = {
-    KC_NO,          // Fn0
-    KC_NO,          // Fn1
-    KC_SLSH,        // Fn2
-    KC_SCLN,        // Fn3
-    KC_NO,          // Fn4
-    KC_SPC,         // Fn5
-    KC_NO,          // Fn6
-    KC_NO           // Fn7
-};
 
+// TODO: use [1] = KEYMAP(...) to prevent from changing index of element?
 static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
     /* Layer 0: Default Layer
      * ,-----------------------------------------------------------.
@@ -84,18 +56,18 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
      * |-----------------------------------------------------------|
      * |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  [|  ]|Backs|
      * |-----------------------------------------------------------|
-     * |Contro|  A|  S|  D|  F|  G|  H|  J|  K|  L|Fn3|  '|Return  |
+     * |Fn6   |  A|  S|  D|  F|  G|  H|  J|  K|  L|Fn3|  '|Return  |
      * |-----------------------------------------------------------|
-     * |Shift   |  Z|  X|  C|  V|  B|  N|  M|  ,|  .|Fn2|Shift |Fn1|
+     * |Fn8     |  Z|  X|  C|  V|  B|  N|  M|  ,|  .|Fn2|Fn12  |Fn1|
      * `-----------------------------------------------------------'
-     *       |Gui|Alt  |Fn5                    |Alt  |Fn4|
+     *       |Gui|Alt  |          Fn5          |Alt  |Fn4|
      *       `-------------------------------------------'
      */
     KEYMAP(ESC, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSLS,GRV, \
            TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSPC, \
-           LCTL,A,   S,   D,   F,   G,   H,   J,   K,   L,   FN3, QUOT,ENT, \
-           LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, FN2, RSFT,FN1, \
-                LGUI,LALT,          FN5,                RALT,FN4),
+           FN6, A,   S,   D,   F,   G,   H,   J,   K,   L,   FN3, QUOT,FN7, \
+           FN8, Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, FN2, FN12,FN9, \
+                LGUI,LALT,          FN5,                FN13,FN4),
 
     /* Layer 1: HHKB mode (HHKB Fn)
      * ,-----------------------------------------------------------.
@@ -105,16 +77,16 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
      * |-----------------------------------------------------------|
      * |Contro|VoD|VoU|Mut|   |   |  *|  /|Hom|PgU|Lef|Rig|Enter   |
      * |-----------------------------------------------------------|
-     * |Shift   |   |   |   |   |   |  +|  -|End|PgD|Dow|Shift |xxx|
+     * |Shift   |   |   |   |   |   |  +|  -|End|PgD|Dow|Shift |Fn0|
      * `-----------------------------------------------------------'
-     *      |Gui |Alt  |Space                  |Alt  |xxx|
-     *      `--------------------------------------------'
+     *       |Gui|Alt  |         Space         |Alt  |Gui|
+     *       `-------------------------------------------'
      */ 
     KEYMAP(PWR, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
-           CAPS,NO,  NO,  NO,  NO,  NO,  NO,  NO,  PSCR,SLCK,BRK, UP,  NO,  BSPC, \
+           CAPS,NO,  NO,  NO,  NO,  NO,  NO,  NO,  PSCR,SLCK,PAUS, UP,  NO,  BSPC, \
            LCTL,VOLD,VOLU,MUTE,NO,  NO,  PAST,PSLS,HOME,PGUP,LEFT,RGHT,ENT, \
-           LSFT,NO,  NO,  NO,  NO,  NO,  PPLS,PMNS,END, PGDN,DOWN,RSFT,FN1, \
-                LGUI,LALT,          SPC,                RALT,FN7),
+           LSFT,NO,  NO,  NO,  NO,  NO,  PPLS,PMNS,END, PGDN,DOWN,RSFT,FN0, \
+                LGUI,LALT,          SPC,                RALT,RGUI),
 
     /* Layer 2: Vi mode (Slash)
      * ,-----------------------------------------------------------.
@@ -124,49 +96,36 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
      * |-----------------------------------------------------------|
      * |Contro|   |Lef|Dow|Rig|   |Lef|Dow|Up |Rig|   |   |Return  |
      * |-----------------------------------------------------------|
-     * |Shift   |   |   |   |   |   |Hom|PgD|PgUlEnd|xxx|Shift |   |
+     * |Shift   |   |   |   |   |   |Hom|PgD|PgUlEnd|Fn0|Shift |   |
      * `-----------------------------------------------------------'
-     *       |Gui|Alt  |Space                  |Alt  |Gui|
+     *       |Gui|Alt  |          Space        |Alt  |Gui|
      *       `-------------------------------------------'
      */
     KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
            TAB, HOME,PGDN,UP,  PGUP,END, HOME,PGDN,PGUP,END, NO,  NO,  NO,  BSPC, \
            LCTL,NO,  LEFT,DOWN,RGHT,NO,  LEFT,DOWN,UP,  RGHT,NO,  NO,  ENT, \
-           LSFT,NO,  NO,  NO,  NO,  NO,  HOME,PGDN,PGUP,END, FN2, RSFT,NO, \
+           LSFT,NO,  NO,  NO,  NO,  NO,  HOME,PGDN,PGUP,END, FN0, RSFT,NO, \
                 LGUI,LALT,          SPC,                RALT,RGUI),
 
     /* Layer 3: Mouse mode (Semicolon)
      * ,-----------------------------------------------------------.
      * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
      * |-----------------------------------------------------------|
-     * |Tab  |MwL|MwU|McU|MwD|MwR|MwL|MwD|MwU|MwR|   |   |   |Backs|
+     * |Tab  |   |   |   |   |   |MwL|MwD|MwU|MwR|   |   |   |Backs|
      * |-----------------------------------------------------------|
-     * |Contro|   |McL|McD|McR|   |McL|McD|McU|McR|xxx|   |Return  |
+     * |Contro|   |   |   |   |   |McL|McD|McU|McR|Fn0|   |Return  |
      * |-----------------------------------------------------------|
-     * |Shift   |Mb4|Mb5|Mb1|Mb2|Mb3|Mb2|Mb1|Mb4|Mb5|   |Shift |   |
+     * |Shift   |   |   |   |   |Mb3|Mb2|Mb1|Mb4|Mb5|   |Shift |   |
      * `-----------------------------------------------------------'
-     *      |Gui |Alt  |Mb1                    |Alt  |Gui|
+     *      |Gui |Alt  |          Mb1          |Alt  |Fn0|
      *      `--------------------------------------------'
      * Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel 
      */
-#ifdef HOST_IWRAP
-// iWRAP does not support mouse wheel, use these keycodes to remap as wheel
-#define KC_KPPL KC_KP_PLUS
-#define KC_KPMI KC_KP_MINUS
-#define KC_KPAS KC_KP_ASTERISK
-#define KC_KPSL KC_KP_SLASH
-    KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
-           TAB, KPAS,KPPL,MS_U,KPMI,KPSL,KPAS,KPPL,KPMI,KPSL,NO,  NO,  NO,  BSPC, \
-           LCTL,NO,  MS_L,MS_D,MS_R,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
-           LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,NO,  NO,  NO,  RSFT,NO, \
-                LGUI,LALT,          BTN1,               RALT,FN4),
-#else
     KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
            TAB, NO,  NO,  NO,  NO,  NO,  WH_L,WH_D,WH_U,WH_R,NO,  NO,  NO,  BSPC, \
-           LCTL,NO,  ACL0,ACL1,ACL2,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
-           LSFT,NO,  NO,  NO,  NO,  BTN3,BTN2,BTN1,BTN4,BTN5,NO,  RSFT,NO, \
-                LGUI,LALT,          BTN1,               RALT,FN4),
-#endif
+           LCTL,NO,  ACL0,ACL1,ACL2,NO,  MS_L,MS_D,MS_U,MS_R,FN0, QUOT,ENT, \
+           LSFT,NO,  NO,  NO,  NO,  BTN3,BTN2,BTN1,BTN4,BTN5,SLSH,RSFT,NO, \
+                LGUI,LALT,          BTN1,               RALT,FN0),
 
     /* Layer 4: Matias half keyboard style (Space)
      * ,-----------------------------------------------------------.
@@ -178,43 +137,212 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
      * |-----------------------------------------------------------|
      * |Shift   |  /|  .|  ,|  M|  N|  B|  V|  C|  X|  Z|Shift |   |
      * `-----------------------------------------------------------'
-     *      |Gui |Alt  |xxxxxxxxxxxxxxxxxxxxxxx|Alt  |Gui|
+     *      |Gui |Alt  |          Fn0          |Alt  |Gui|
      *      `--------------------------------------------'
      */
     KEYMAP(MINS,0,   9,   8,   7,   6,   5,   4,   3,   2,   1,   NO,  NO,  NO,  ESC, \
            BSPC,P,   O,   I,   U,   Y,   T,   R,   E,   W,   Q,   NO,  NO,  TAB, \
            LCTL,SCLN,L,   K,   J,   H,   G,   F,   D,   S,   A,   RCTL,RCTL, \
            LSFT,SLSH,DOT, COMM,M,   N,   B,   V,   C,   X,   Z,   RSFT,NO, \
-                LGUI,LALT,          FN5,                RALT,RGUI),
+                LGUI,LALT,          FN0,                RALT,RGUI),
 
-    /* Layer5: another Mouse mode (Space) */
-#ifdef HOST_IWRAP
-    KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
-           TAB, KPAS,KPPL,MS_U,KPMI,KPSL,KPAS,KPPL,KPMI,KPSL,NO,  NO,  NO,  BSPC, \
-           LCTL,NO,  MS_L,MS_D,MS_R,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
-           LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,BTN4,BTN5,NO,  RSFT,NO, \
-                LGUI,LALT,          FN5,                RALT,RGUI),
-#else
+    /* Layer5: another Mouse mode (Space)
+     * ,-----------------------------------------------------------.
+     * |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
+     * |-----------------------------------------------------------|
+     * |Tab  |   |   |   |   |   |MwL|MwD|MwU|MwR|   |   |   |Backs|
+     * |-----------------------------------------------------------|
+     * |Contro|   |   |   |   |   |McL|McD|McU|McR|Fn0|   |Return  |
+     * |-----------------------------------------------------------|
+     * |Shift   |   |   |   |   |Mb3|Mb2|Mb1|Mb4|Mb5|   |Shift |   |
+     * `-----------------------------------------------------------'
+     *      |Gui |Alt  |          Fn0          |Alt  |Fn0|
+     *      `--------------------------------------------'
+     * Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel 
+     */
     KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
            TAB, NO,  NO,  NO,  NO,  NO,  WH_L,WH_D,WH_U,WH_R,NO,  NO,  NO,  BSPC, \
-           LCTL,NO,  ACL0,ACL1,ACL2,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
+           LCTL,NO,  ACL0,ACL1,ACL2,NO,  MS_L,MS_D,MS_U,MS_R,NO,  NO,  ENT, \
            LSFT,NO,  NO,  NO,  NO,  BTN3,BTN2,BTN1,BTN4,BTN5,NO,  RSFT,NO, \
-                LGUI,LALT,          FN5,                RALT,RGUI),
-#endif
+                LGUI,LALT,          FN0,                RALT,RGUI),
+};
+
+
+
+/* id for user defined functions */
+enum function_id {
+    LSHIFT_LPAREN,
+    RSHIFT_RPAREN,
+    MACRO                   = 0xff
+};
+
+
+/*
+ * Fn action definition
+ */
+// TODO: use [1] = KEYMAP(...) to prevent from changing index of element?
+static const uint16_t PROGMEM fn_actions[] = {
+    ACTION_LAYER_DEFAULT,                           // FN0
+    ACTION_LAYER_SET(1),                            // FN1
+    ACTION_LAYER_SET_TAP_KEY(2, KC_SLASH),          // FN2  Layer with Slash
+    ACTION_LAYER_SET_TAP_KEY(3, KC_SCLN),           // FN3  Layer with Semicolon
+
+    ACTION_LAYER_SET(3),                            // FN4
+//  ACTION_LAYER_SET_TOGGLE(3),                     // FN4
+//  ACTION_FUNCTION(MACRO, 0),                      // FN4
+    ACTION_LAYER_SET_TAP_KEY(5, KC_SPC),            // FN5
+//  ACTION_LMOD_TAP_KEY(KC_LCTL, KC_BSPC),          // FN6  Control with tap Backspace
+    ACTION_LMOD_TAP_KEY(KC_LCTL, KC_ESC),           // FN6  Control with tap Backspace
+    ACTION_RMOD_TAP_KEY(KC_RCTL, KC_ENT),           // FN7  Control with tap Enter
+    ACTION_LMOD_ONESHOT(KC_LSFT),                   // FN8  Oneshot Shift
+    ACTION_LAYER_SET_TAP_TOGGLE(1),                 // FN9
+    ACTION_LAYER_BIT_TAP_KEY(1, KC_GRV),            // FN10 Layer with Grave
+    //ACTION_LAYER_BIT(1),                          // FN10
+    //ACTION_LAYER_BIT_TAP_TOGGLE(1),               // FN10
+    ACTION_FUNCTION_TAP(LSHIFT_LPAREN),             // FN11 Function: LShift with tap '('
+    ACTION_FUNCTION_TAP(RSHIFT_RPAREN),             // FN12 Function: RShift with tap ')'
+    ACTION_FUNCTION(MACRO, 1),                      // FN13 Macro:
 };
 
 
-uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
+/*
+ * Macro definition
+ */
+#define MACRO(...) ({ static prog_macro_t _m[] PROGMEM = { __VA_ARGS__ }; _m; })
+#define MACRO_NONE  0
+static const prog_macro_t *get_macro(uint8_t id, bool pressed)
 {
-    return KEYCODE(layer, row, col);
+    switch (id) {
+        case 0:
+            return (pressed ?
+                    MACRO( MD(LSHIFT), D(D), END ) :
+                    MACRO( U(D), MU(LSHIFT), END ) );
+        case 1:
+            return (pressed ?
+                    MACRO( I(255), T(H), T(E), T(L), T(L), W(255), T(O), END ) :
+                    MACRO_NONE );
+    }
+    return 0;
 }
 
-uint8_t keymap_fn_layer(uint8_t index)
+
+
+/*
+ * user defined action function
+ */
+void keymap_call_function(keyrecord_t *record, uint8_t id, uint8_t opt)
 {
-    return pgm_read_byte(&fn_layer[index]);
+    keyevent_t event = record->event;
+    uint8_t tap_count = record->tap_count;
+
+    debug("action_call_function: ");
+    if (event.pressed) debug("pressed"); else debug("released");
+    debug(" id: "); debug_hex(id);
+    debug(" tap_count: "); debug_dec(tap_count);
+    debug("\n");
+
+    switch (id) {
+        case LSHIFT_LPAREN:
+            // LShft + tap '('
+            if (event.pressed) {
+                if (tap_count == 0) {
+                    add_mods(MOD_BIT(KC_LSHIFT));
+                } else {
+                    if (waiting_buffer_has_anykey_pressed()) {
+                        // ad hoc: set 0 to cancel tap
+                        record->tap_count = 0;
+                        add_mods(MOD_BIT(KC_LSHIFT));
+                    } else {
+                        // NOTE to avoid conflicting command key bind(LShift+RShift)
+                        //register_code(KC_LSHIFT);
+                        //register_code(KC_9);
+                        host_add_mods(MOD_BIT(KC_LSHIFT));
+                        host_add_key(KC_9);
+                        host_send_keyboard_report();
+                    }
+                }
+            } else {
+                if (tap_count == 0) {
+                    del_mods(MOD_BIT(KC_LSHIFT));
+                } else {
+                    //unregister_code(KC_9);
+                    //unregister_code(KC_LSHIFT);
+                    host_del_mods(MOD_BIT(KC_LSHIFT));
+                    host_del_key(KC_9);
+                    host_send_keyboard_report();
+                }
+            }
+            break;
+        case RSHIFT_RPAREN:
+            // RShift + tap ')'
+            if (event.pressed) {
+                if (tap_count == 0) {
+                    add_mods(MOD_BIT(KC_RSHIFT));
+                } else {
+                    if (waiting_buffer_has_anykey_pressed()) {
+                        // ad hoc: set 0 to cancel tap
+                        record->tap_count = 0;
+                        add_mods(MOD_BIT(KC_RSHIFT));
+                    } else {
+                        //register_code(KC_RSHIFT);
+                        //register_code(KC_0);
+                        host_add_mods(MOD_BIT(KC_RSHIFT));
+                        host_add_key(KC_0);
+                        host_send_keyboard_report();
+                    }
+                }
+            } else {
+                if (tap_count == 0) {
+                    del_mods(MOD_BIT(KC_RSHIFT));
+                } else {
+                    //unregister_code(KC_0);
+                    //unregister_code(KC_RSHIFT);
+                    host_del_mods(MOD_BIT(KC_RSHIFT));
+                    host_del_key(KC_0);
+                    host_send_keyboard_report();
+                }
+            }
+            break;
+        case MACRO:
+            action_macro_play(get_macro(opt, event.pressed));
+            break;
+    }
 }
 
-uint8_t keymap_fn_keycode(uint8_t index)
-{
-    return pgm_read_byte(&fn_keycode[index]);
+/* convert keycode to action */
+action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col) {
+    uint8_t key = (pgm_read_byte(&keymaps[(layer)][(row)][(col)]));
+    action_t action;
+    switch (key) {
+        case KC_A ... KC_EXSEL:
+            action.code = ACTION_KEY(key);
+            break;
+        case KC_LCTRL ... KC_LGUI:
+            action.code = ACTION_LMOD(key);
+            break;
+        case KC_RCTRL ... KC_RGUI:
+            action.code = ACTION_RMOD(key);
+            break;
+        case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
+            action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(key));
+            break;
+        case KC_AUDIO_MUTE ... KC_WWW_FAVORITES:
+            action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(key));
+            break;
+        case KC_MS_UP ... KC_MS_ACCEL2:
+            action.code = ACTION_MOUSEKEY(key);
+            break;
+        case KC_FN0 ... KC_FN31:
+            if (FN_INDEX(key) < sizeof(fn_actions) / sizeof(fn_actions[0])) {
+                action.code = pgm_read_word(&fn_actions[FN_INDEX(key)]);
+            } else {
+                action.code = ACTION_NO;
+            }
+            break;
+        case KC_NO ... KC_UNDEFINED:
+        default:
+            action.code = ACTION_NO;
+            break;
+    }
+    return action;
 }
index fd0d6f97f6a47b6fbe12945d576ade51004c7c1e..f53e36dbe0acd4d23e83de136408681f0f314a20 100644 (file)
@@ -24,6 +24,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <avr/interrupt.h>
 #include <util/delay.h>
 #include "print.h"
+#include "debug.h"
 #include "util.h"
 #include "timer.h"
 #include "matrix.h"
@@ -135,6 +136,12 @@ uint8_t matrix_cols(void)
 
 void matrix_init(void)
 {
+#ifdef DEBUG
+    print_enable = true;
+    debug_enable = true;
+    debug_keyboard = true;
+#endif
+
     KEY_INIT();
 
     // initialize matrix state: all keys off