host_add_mods(MOD_BIT(code)); | host_add_mods(MOD_BIT(code)); | ||||
host_send_keyboard_report(); | host_send_keyboard_report(); | ||||
} | } | ||||
else if IS_SYSTEM(code) { | |||||
host_system_send(KEYCODE2SYSTEM(code)); | |||||
} | |||||
else if IS_CONSUMER(code) { | |||||
host_consumer_send(KEYCODE2CONSUMER(code)); | |||||
} | |||||
} | } | ||||
void unregister_code(uint8_t code) | void unregister_code(uint8_t code) | ||||
host_del_mods(MOD_BIT(code)); | host_del_mods(MOD_BIT(code)); | ||||
host_send_keyboard_report(); | host_send_keyboard_report(); | ||||
} | } | ||||
else if IS_SYSTEM(code) { | |||||
host_system_send(0); | |||||
} | |||||
else if IS_CONSUMER(code) { | |||||
host_consumer_send(0); | |||||
} | |||||
} | } | ||||
void add_mods(uint8_t mods) | void add_mods(uint8_t mods) |
* r: Left/Right flag(Left:0, Right:1) | * r: Left/Right flag(Left:0, Right:1) | ||||
* | * | ||||
* ACT_MODS_TAP(001r): | * ACT_MODS_TAP(001r): | ||||
* 0010|mods|0000 0000 Modifiers with OneShot | |||||
* 0010|mods|0000 00xx (reserved) | |||||
* 0010|mods| keycode Modifiers with Tap Key | |||||
* 001r|mods|0000 0000 Modifiers with OneShot | |||||
* 001r|mods|0000 00xx (reserved) | |||||
* 001r|mods| keycode Modifiers with Tap Key | |||||
* | * | ||||
* | * | ||||
* Other Keys(01xx) | * Other Keys(01xx) |
if (!macro_p) return; | if (!macro_p) return; | ||||
while (true) { | while (true) { | ||||
switch (MACRO_READ()) { | switch (MACRO_READ()) { | ||||
case INTERVAL: | |||||
interval = MACRO_READ(); | |||||
debug("INTERVAL("); debug_dec(interval); debug(")\n"); | |||||
break; | |||||
case WAIT: | |||||
case KEY_DOWN: | |||||
MACRO_READ(); | MACRO_READ(); | ||||
debug("WAIT("); debug_dec(macro); debug(")\n"); | |||||
{ uint8_t ms = macro; while (ms--) _delay_ms(1); } | |||||
dprintf("KEY_DOWN(%02X)\n", macro); | |||||
register_code(macro); | |||||
break; | break; | ||||
case MODS_DOWN: | |||||
case KEY_UP: | |||||
MACRO_READ(); | MACRO_READ(); | ||||
debug("MODS_DOWN("); debug_hex(macro); debug(")\n"); | |||||
add_mods(macro); | |||||
dprintf("KEY_UP(%02X)\n", macro); | |||||
unregister_code(macro); | |||||
break; | break; | ||||
case MODS_UP: | |||||
case WAIT: | |||||
MACRO_READ(); | MACRO_READ(); | ||||
debug("MODS_UP("); debug_hex(macro); debug(")\n"); | |||||
del_mods(macro); | |||||
dprintf("WAIT(%u)\n", macro); | |||||
{ uint8_t ms = macro; while (ms--) _delay_ms(1); } | |||||
break; | |||||
case INTERVAL: | |||||
interval = MACRO_READ(); | |||||
dprintf("INTERVAL(%u)\n", interval); | |||||
break; | break; | ||||
case 0x04 ... 0x73: | case 0x04 ... 0x73: | ||||
debug("DOWN("); debug_hex(macro); debug(")\n"); | |||||
dprintf("DOWN(%02X)\n", macro); | |||||
register_code(macro); | register_code(macro); | ||||
break; | break; | ||||
case 0x84 ... 0xF3: | case 0x84 ... 0xF3: | ||||
debug("UP("); debug_hex(macro); debug(")\n"); | |||||
dprintf("UP(%02X)\n", macro); | |||||
unregister_code(macro&0x7F); | unregister_code(macro&0x7F); | ||||
break; | break; | ||||
case END: | case END: |
/* 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 | |||||
*/ | |||||
/* Macro commands | |||||
* code(0x04-73) // key down(1byte) | |||||
* code(0x04-73) | 0x80 // key up(1byte) | |||||
* { KEY_DOWN, code(0x04-0xff) } // key down(2bytes) | |||||
* { KEY_UP, code(0x04-0xff) } // key up(2bytes) | |||||
* WAIT // wait milli-seconds | |||||
* INTERVAL // set interval between macro commands | |||||
* END // stop macro execution | |||||
* | |||||
* Ideas(Not implemented): | |||||
* modifiers | |||||
* system usage | |||||
* consumer usage | |||||
* unicode usage | |||||
* function call | |||||
* conditionals | |||||
* loop | |||||
*/ | |||||
enum macro_command_id{ | enum macro_command_id{ | ||||
/* 0x00 - 0x03 */ | /* 0x00 - 0x03 */ | ||||
END = 0x00, | END = 0x00, | ||||
MODS_DOWN = 0x01, | |||||
MODS_UP = 0x02, | |||||
MODS_SET, | |||||
MODS_PUSH, | |||||
MODS_POP, | |||||
KEY_DOWN, | |||||
KEY_UP, | |||||
/* 0x04 - 0x73 (reserved for keycode down) */ | |||||
/* 0x74 - 0x83 */ | |||||
WAIT = 0x74, | WAIT = 0x74, | ||||
INTERVAL, | INTERVAL, | ||||
/* 0x74 - 0x7f */ | |||||
/* 0x80 - 0x84 */ | |||||
EXT_DOWN, | |||||
EXT_UP, | |||||
EXT_WAIT, | |||||
EXT_INTERVAL, | |||||
COMPRESSION_MODE, | |||||
/* 0x84 - 0xf3 (reserved for keycode up) */ | |||||
EXTENSION_MODE = 0xff, | |||||
/* 0xf4 - 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) | |||||
/* TODO: keycode:0x04-0x73 can be handled by 1byte command else 2bytes are needed | |||||
* if keycode between 0x04 and 0x73 | |||||
* keycode / (keycode|0x80) | |||||
* else | |||||
* {KEY_DOWN, keycode} / {KEY_UP, keycode} | |||||
*/ | |||||
#define DOWN(key) KEY_DOWN, (key) | |||||
#define UP(key) KEY_UP, (key) | |||||
#define TYPE(key) DOWN(key), UP(key) | |||||
#define WAIT(ms) WAIT, (ms) | #define WAIT(ms) WAIT, (ms) | ||||
#define INTERVAL(ms) INTERVAL, (ms) | #define INTERVAL(ms) INTERVAL, (ms) | ||||
/* key down */ | |||||
#define D(key) DOWN(KC_##key) | #define D(key) DOWN(KC_##key) | ||||
/* key up */ | |||||
#define U(key) UP(KC_##key) | #define U(key) UP(KC_##key) | ||||
/* key type */ | |||||
#define T(key) TYPE(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)) | |||||
/* wait */ | |||||
#define W(ms) WAIT(ms) | #define W(ms) WAIT(ms) | ||||
/* interval */ | |||||
#define I(ms) INTERVAL(ms) | #define I(ms) INTERVAL(ms) | ||||
/* extension mode */ | |||||
/* for backward comaptibility */ | |||||
#define MD(key) DOWN(KC_##key) | |||||
#define MU(key) UP(KC_##key) | |||||
#endif /* ACTION_MACRO_H */ | #endif /* ACTION_MACRO_H */ |
#define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) | #define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) | ||||
#define IS_SYSTEM(code) (KC_POWER <= (code) && (code) <= KC_WAKE) | |||||
#define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE) | |||||
#define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_WFAV) | #define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_WFAV) | ||||
#define IS_FN(code) (KC_FN0 <= (code) && (code) <= KC_FN31) | #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(code) (KC_MS_UP <= (code) && (code) <= KC_MS_ACCEL2) |
`Macro` action indicates complex key strokes. | `Macro` action indicates complex key strokes. | ||||
MACRO( MD(LSHIFT), D(D), END ) | |||||
MACRO( U(D), MU(LSHIFT), END ) | |||||
MACRO( D(LSHIFT), D(D), END ) | |||||
MACRO( U(D), U(LSHIFT), END ) | |||||
MACRO( I(255), T(H), T(E), T(L), T(L), W(255), T(O), END ) | MACRO( I(255), T(H), T(E), T(L), T(L), W(255), T(O), END ) | ||||
#### 2.3.1 Normal mode | |||||
#### 2.3.1 Macro Commands | |||||
- **I()** change interavl of stroke. | - **I()** change interavl of stroke. | ||||
- **D()** press key | - **D()** press key | ||||
- **U()** release key | - **U()** release key | ||||
- **T()** type key(press and release) | - **T()** type key(press and release) | ||||
- **W()** wait | - **W()** wait | ||||
- **MD()** modifier down | |||||
- **MU()** modifier up | |||||
- **END** end mark | - **END** end mark | ||||
#### 2.3.2 Extended mode | |||||
#### 2.3.2 Examples | |||||
***TODO: sample impl*** | ***TODO: sample impl*** | ||||
See `keyboard/hhkb/keymap.c` for sample. | See `keyboard/hhkb/keymap.c` for sample. |
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ | 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,FN4, \ | LCTL,A, S, D, F, G, H, J, K, L, FN3, QUOT,FN4, \ | ||||
FN5,Z, X, C, V, B, N, M, COMM,DOT, FN2, RSFT,FN1, \ | FN5,Z, X, C, V, B, N, M, COMM,DOT, FN2, RSFT,FN1, \ | ||||
LGUI,LALT, FN6, RALT,NO), | |||||
LGUI,LALT, FN6, RALT,RGUI), | |||||
/* Layer 1: HHKB mode (HHKB Fn) | /* Layer 1: HHKB mode (HHKB Fn) | ||||
* ,-----------------------------------------------------------. | * ,-----------------------------------------------------------. | ||||
LSHIFT_PAREN, | LSHIFT_PAREN, | ||||
RSHIFT_PAREN, | RSHIFT_PAREN, | ||||
HELLO, | HELLO, | ||||
VOLUP, | |||||
}; | }; | ||||
// [13] = ACTION_MACRO_TAP(LSHIFT_PAREN), // Macro: LShift with tap '(' | // [13] = ACTION_MACRO_TAP(LSHIFT_PAREN), // Macro: LShift with tap '(' | ||||
// [14] = ACTION_MACRO_TAP(RSHIFT_PAREN), // Macro: RShift with tap ')' | // [14] = ACTION_MACRO_TAP(RSHIFT_PAREN), // Macro: RShift with tap ')' | ||||
// [15] = ACTION_MACRO(HELLO), // Macro: say hello | // [15] = ACTION_MACRO(HELLO), // Macro: say hello | ||||
// [9] = ACTION_MACRO(VOLUP), // Macro: media key | |||||
}; | }; | ||||
case LSHIFT_PAREN: | case LSHIFT_PAREN: | ||||
if (tap.count > 0 && !tap.interrupted) { | if (tap.count > 0 && !tap.interrupted) { | ||||
return (event.pressed ? | return (event.pressed ? | ||||
MACRO( MD(LSHIFT), D(9), U(9), MU(LSHIFT), END ) : MACRO_NONE); | |||||
MACRO( D(LSHIFT), D(9), U(9), U(LSHIFT), END ) : MACRO_NONE); | |||||
} else { | } else { | ||||
return (event.pressed ? | return (event.pressed ? | ||||
MACRO( MD(LSHIFT), END ) : MACRO( MU(LSHIFT), END ) ); | |||||
MACRO( D(LSHIFT), END ) : MACRO( U(LSHIFT), END ) ); | |||||
} | } | ||||
case RSHIFT_PAREN: | case RSHIFT_PAREN: | ||||
if (tap.count > 0 && !tap.interrupted) { | if (tap.count > 0 && !tap.interrupted) { | ||||
return (event.pressed ? | return (event.pressed ? | ||||
MACRO( MD(RSHIFT), D(0), U(0), MU(RSHIFT), END ) : MACRO_NONE); | |||||
MACRO( D(RSHIFT), D(0), U(0), U(RSHIFT), END ) : MACRO_NONE); | |||||
} else { | } else { | ||||
return (event.pressed ? | return (event.pressed ? | ||||
MACRO( MD(RSHIFT), END ) : MACRO( MU(RSHIFT), END ) ); | |||||
MACRO( D(RSHIFT), END ) : MACRO( U(RSHIFT), END ) ); | |||||
} | } | ||||
case HELLO: | case HELLO: | ||||
return (event.pressed ? | return (event.pressed ? | ||||
MACRO( I(0), T(H), T(E), T(L), T(L), W(255), T(O), END ) : | MACRO( I(0), T(H), T(E), T(L), T(L), W(255), T(O), END ) : | ||||
MACRO_NONE ); | MACRO_NONE ); | ||||
case VOLUP: | |||||
return (event.pressed ? | |||||
MACRO( D(VOLU), U(VOLU), END ) : | |||||
MACRO_NONE ); | |||||
} | } | ||||
return MACRO_NONE; | return MACRO_NONE; | ||||
} | } |