~ruther/qmk_firmware

8c80deb775ac151001dc1592a2e94e8677b49964 — tmk 12 years ago 4701b08 + 39d0933
Merge branch 'keymap2'

Conflicts:
	common/keyboard.c
M README.md => README.md +544 -68
@@ 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.

M common.mk => common.mk +3 -0
@@ 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 \

A common/action.c => common/action.c +883 -0
@@ 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");
}

A common/action.h => common/action.h +331 -0
@@ 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 */

A common/action_macro.c => common/action_macro.c +67 -0
@@ 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); }
    }
}

A common/action_macro.h => common/action_macro.h +107 -0
@@ 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 */

M common/command.c => common/command.c +1 -16
@@ 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
}

M common/debug.h => common/debug.h +1 -0
@@ 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)

M common/host.c => common/host.c +9 -4
@@ 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)

M common/host.h => common/host.h +5 -2
@@ 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);

M common/keyboard.c => common/keyboard.c +24 -556
@@ 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)

M common/keyboard.h => common/keyboard.h +27 -11
@@ 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);

M common/keycode.h => common/keycode.h +41 -14
@@ 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,

A common/keymap.c => common/keymap.c +73 -0
@@ 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)
{
}

M common/keymap.h => common/keymap.h +19 -1
@@ 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

M common/print.c => common/print.c +6 -1
@@ 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)
{

M common/print.h => common/print.h +2 -0
@@ 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);

M common/report.h => common/report.h +38 -6
@@ 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

A doc/keycode.txt => doc/keycode.txt +261 -0
@@ 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

M keyboard/hhkb/Makefile.lufa => keyboard/hhkb/Makefile.lufa +3 -0
@@ 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

M keyboard/hhkb/Makefile.vusb => keyboard/hhkb/Makefile.vusb +3 -0
@@ 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

M keyboard/hhkb/config.h => keyboard/hhkb/config.h +18 -0
@@ 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

M keyboard/hhkb/keymap.c => keyboard/hhkb/keymap.c +216 -88
@@ 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;
}

M keyboard/hhkb/matrix.c => keyboard/hhkb/matrix.c +7 -0
@@ 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