extended `key_functions__type_string()` to use keycodes
when possible, and "unicode sequences" otherwise. made the function enormous, but also much more useful :)partial-rewrite
parent
a89e6528f2
commit
952c2792ed
|
@ -29,9 +29,9 @@ void key_functions__toggle (uint8_t keycode);
|
|||
void key_functions__jump_to_bootloader (void);
|
||||
|
||||
// special
|
||||
void key_functions__toggle_capslock (void);
|
||||
void key_functions__type_byte_hex (uint8_t byte);
|
||||
void key_functions__send_unicode_sequence (const char * string);
|
||||
void key_functions__toggle_capslock (void);
|
||||
void key_functions__type_byte_hex (uint8_t byte);
|
||||
void key_functions__type_string (const char * string);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -105,25 +105,38 @@ void key_functions__send_unicode_sequence (const char * string);
|
|||
* - `byte`: The byte to send a representation of
|
||||
*/
|
||||
|
||||
// === key_functions__send_unicode_sequence() ===
|
||||
/** functions/key_functions__send_unicode_sequence/description
|
||||
* Send the "unicode sequence" for each character in `string`
|
||||
*
|
||||
* This function is, relative to the rest of life, extremely unportable. Sorry
|
||||
* about that: I looked, but I couldn't find a better way to do it. I'm
|
||||
* including it in the hope that it will be useful anyway.
|
||||
// === key_functions__type_string() ===
|
||||
/** functions/key_functions__type_string/description
|
||||
* Type the keycode (or "unicode sequence") for each character in `string`
|
||||
*
|
||||
* Arguments:
|
||||
* - `string`: A pointer to a valid UTF-8 string in PROGMEM
|
||||
*
|
||||
*
|
||||
* Operating system considerations:
|
||||
* Notes:
|
||||
*
|
||||
* - This function should work on OS X and Windows (after enabling "hexidecimal
|
||||
* code input" in the OS), but probably will not work on Linux (2 out of 3 of
|
||||
* the major OSs is better than nothing...). If you're using Linux and you
|
||||
* want to flip that around :) please modify the function to send Linux
|
||||
* friendly start and end sequences. See [this Wikipedia article]
|
||||
* - A "unicode sequence" is holding down "alt", typing "+", typing the 4
|
||||
* character hexadecimal unicode code for the specified character, then
|
||||
* releasing "alt". This is done for every character in `string` for which a
|
||||
* dedicated USB keycode has not been specified.
|
||||
*
|
||||
* - This function is, relative to the rest of life, extremely unportable.
|
||||
* Sorry about that: I looked for a better way to do things, but I couldn't
|
||||
* find one. It may be very convenient under certain circumstances though,
|
||||
* if one is willing to take a little time to understand what it's actually
|
||||
* doing, so I'm including it in the hope that it will be. Please see the
|
||||
* implementation (in the '.c' file) for which keycodes are being sent for a
|
||||
* given character.
|
||||
*
|
||||
*
|
||||
* Operating system considerations (for typing "unicode sequences"):
|
||||
*
|
||||
* - "Unicode sequences", as implemented, should work on OS X and Windows
|
||||
* (after enabling "hexidecimal code input" in the OS), but probably will not
|
||||
* work on Linux (2 out of 3 of the major OSs is better than nothing...). If
|
||||
* you're using Linux and you want to flip that around :) please modify the
|
||||
* function to send Linux friendly start and end sequences. See [this
|
||||
* Wikipedia article]
|
||||
* (http://en.wikipedia.org/wiki/Unicode_input#Hexadecimal_code_input) for
|
||||
* more information.
|
||||
*
|
||||
|
@ -144,34 +157,29 @@ void key_functions__send_unicode_sequence (const char * string);
|
|||
*
|
||||
* Usage notes:
|
||||
*
|
||||
* - This function disables all modifier keys on entry, and restores their
|
||||
* state on exit.
|
||||
*
|
||||
* - A "unicode sequence" is holding down "alt", typing "+", typing the 4
|
||||
* character unicode code for the specified character, then releasing "alt".
|
||||
* This is done for every character in `string`, even the ones with a
|
||||
* dedicated USB keycode.
|
||||
*
|
||||
* - Characters (and strings) sent with this function do not automatically
|
||||
* repeat (as normal keys do).
|
||||
*
|
||||
* - If you're holding down any of `[0-9A-F]` when this function is called, it
|
||||
* may not do what you want.
|
||||
* - Please pay very special attention to what this function is actually typing
|
||||
* if you are using any language besides English as the default in your OS,
|
||||
* or if you have characters that aren't 7-bit ASCII in your string and have
|
||||
* not enabled "hexidecimal code input" in your OS.
|
||||
*
|
||||
* - This function does not disable modifier keys, or any other keys, on entry:
|
||||
* keys are pressed and released as they would be if one was typing them
|
||||
* starting with no keys pressed. If you are holding down any keys when this
|
||||
* function is called, it *may* not do what you expect, depending on which
|
||||
* keys are being held down and which keys this function is trying to press
|
||||
* and release.
|
||||
*
|
||||
* - An easy way to pass a PROGMEM string to this function is to use the
|
||||
* `PSTR()` macro in `<avr/pgmspace.h>`, as in
|
||||
*
|
||||
* key_functions__send_unicode_sequence( PSTR ( "❄" ) );
|
||||
* key_functions__type_string( PSTR( "❄" ) );
|
||||
*
|
||||
* or
|
||||
*
|
||||
* key_functions__send_unicode_sequence( PSTR (
|
||||
* key_functions__type_string( PSTR(
|
||||
* "こんにちは世界 γειά σου κόσμε hello world ^_^" ) );
|
||||
*
|
||||
* - It's probably better to define a proper macro key than to use this
|
||||
* function for sending sequences of "normal" characters, despite the
|
||||
* relative inconvenience. But... if you're not concerned about portability,
|
||||
* or other factors that might arise because of what this function is
|
||||
* *actually* typing... it's possible to do it this way to... :) lol
|
||||
*/
|
||||
|
||||
|
|
|
@ -6,13 +6,6 @@
|
|||
|
||||
/** description
|
||||
* Implements the "special" section of "../key-functions.h"
|
||||
*
|
||||
* Notes:
|
||||
* - If the USB keyboard modifier state functions turn out to be something that
|
||||
* would be generally useful, the functionality should be reimplemented in
|
||||
* ".../firmware/lib/usb" (and removed from here). For now I'm leaving them
|
||||
* here because it seems better not to encourage messing with modifiers as a
|
||||
* special group of keys, except for special purposes.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -25,70 +18,18 @@
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** types/modifier_state_t/description
|
||||
* A struct representing the state of the keyboard modifier keys
|
||||
*/
|
||||
struct modifier_state_t {
|
||||
bool left_control : 1;
|
||||
bool left_shift : 1;
|
||||
bool left_alt : 1;
|
||||
bool left_gui : 1;
|
||||
bool right_control : 1;
|
||||
bool right_shift : 1;
|
||||
bool right_alt : 1;
|
||||
bool right_gui : 1;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** functions/read_modifier_state/description
|
||||
* Return the state of the modifier keys
|
||||
*
|
||||
* Returns:
|
||||
* - success: A `modifier_state_t`
|
||||
*/
|
||||
static struct modifier_state_t read_modifier_state(void) {
|
||||
return (struct modifier_state_t) {
|
||||
.left_control = usb__kb__read_key( KEYBOARD__LeftControl ),
|
||||
.left_shift = usb__kb__read_key( KEYBOARD__LeftShift ),
|
||||
.left_alt = usb__kb__read_key( KEYBOARD__LeftAlt ),
|
||||
.left_gui = usb__kb__read_key( KEYBOARD__LeftGUI ),
|
||||
.right_control = usb__kb__read_key( KEYBOARD__RightControl ),
|
||||
.right_shift = usb__kb__read_key( KEYBOARD__RightShift ),
|
||||
.right_alt = usb__kb__read_key( KEYBOARD__RightAlt ),
|
||||
.right_gui = usb__kb__read_key( KEYBOARD__RightGUI ),
|
||||
};
|
||||
}
|
||||
|
||||
/** functions/set_modifier_state/description
|
||||
* Set the state of the modifier keys to `state`
|
||||
*
|
||||
* Arguments:
|
||||
* - `state`: A `modifier_state_t`
|
||||
*/
|
||||
static void set_modifier_state(struct modifier_state_t state) {
|
||||
usb__kb__set_key( state.left_control , KEYBOARD__LeftControl );
|
||||
usb__kb__set_key( state.left_shift , KEYBOARD__LeftShift );
|
||||
usb__kb__set_key( state.left_alt , KEYBOARD__LeftAlt );
|
||||
usb__kb__set_key( state.left_gui , KEYBOARD__LeftGUI );
|
||||
usb__kb__set_key( state.right_control , KEYBOARD__RightControl );
|
||||
usb__kb__set_key( state.right_shift , KEYBOARD__RightShift );
|
||||
usb__kb__set_key( state.right_alt , KEYBOARD__RightAlt );
|
||||
usb__kb__set_key( state.right_gui , KEYBOARD__RightGUI );
|
||||
|
||||
usb__kb__send_report();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void key_functions__toggle_capslock(void) {
|
||||
struct modifier_state_t state = read_modifier_state();
|
||||
// -------
|
||||
struct modifier_state_t temp_state = state;
|
||||
temp_state.left_shift = false;
|
||||
temp_state.right_shift = false;
|
||||
// -------
|
||||
set_modifier_state(temp_state);
|
||||
// save the state of both shifts, and disable them
|
||||
struct {
|
||||
bool left_shift : 1;
|
||||
bool right_shift : 1;
|
||||
} state = {
|
||||
.left_shift = usb__kb__read_key( KEYBOARD__LeftShift ),
|
||||
.right_shift = usb__kb__read_key( KEYBOARD__RightShift ),
|
||||
};
|
||||
usb__kb__set_key( false, KEYBOARD__LeftShift );
|
||||
usb__kb__set_key( false, KEYBOARD__RightShift );
|
||||
usb__kb__send_report();
|
||||
|
||||
// toggle capslock
|
||||
usb__kb__set_key(true, KEYBOARD__CapsLock);
|
||||
|
@ -96,7 +37,10 @@ void key_functions__toggle_capslock(void) {
|
|||
usb__kb__set_key(false, KEYBOARD__CapsLock);
|
||||
usb__kb__send_report();
|
||||
|
||||
set_modifier_state(state);
|
||||
// restore the state of both shifts
|
||||
usb__kb__set_key( state.left_shift, KEYBOARD__LeftShift );
|
||||
usb__kb__set_key( state.right_shift, KEYBOARD__RightShift );
|
||||
usb__kb__send_report();
|
||||
}
|
||||
|
||||
void key_functions__type_byte_hex(uint8_t byte) {
|
||||
|
@ -115,7 +59,7 @@ void key_functions__type_byte_hex(uint8_t byte) {
|
|||
usb__kb__send_report();
|
||||
}
|
||||
|
||||
/** functions/key_functions__send_unicode_sequence/description
|
||||
/** functions/key_functions__type_string/description
|
||||
* Implementation notes:
|
||||
*
|
||||
* - We use `uint8_t` instead of `char` when iterating over `string` because
|
||||
|
@ -137,14 +81,8 @@ void key_functions__type_byte_hex(uint8_t byte) {
|
|||
* 0x0800 - 0xFFFF 16 1110xxxx 10xxxxxx 10xxxxxx
|
||||
* 0x010000 - 0x10FFFF 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
* ----------------------------------------------------------------------
|
||||
*
|
||||
* TODO: change the name of this function, and extend it to type printable
|
||||
* non-extended ASCII directly
|
||||
*/
|
||||
void key_functions__send_unicode_sequence(const char * string) {
|
||||
struct modifier_state_t state = read_modifier_state();
|
||||
set_modifier_state( (struct modifier_state_t){} );
|
||||
|
||||
void key_functions__type_string(const char * string) {
|
||||
uint8_t c; // for storing the current byte of the character
|
||||
uint16_t c_full; // for storing the full character
|
||||
|
||||
|
@ -154,7 +92,7 @@ void key_functions__send_unicode_sequence(const char * string) {
|
|||
// get character
|
||||
if (c >> 7 == 0b0) {
|
||||
// a 1-byte utf-8 character
|
||||
c_full = c & 0x7F;
|
||||
c_full = c;
|
||||
|
||||
} else if (c >> 5 == 0b110) {
|
||||
// beginning of a 2-byte utf-8 character
|
||||
|
@ -182,6 +120,119 @@ void key_functions__send_unicode_sequence(const char * string) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// --- (if possible) send regular keycode ---
|
||||
|
||||
if (c == c_full) {
|
||||
bool shifted = false;
|
||||
uint8_t keycode = 0;
|
||||
|
||||
if (c == 0x30) {
|
||||
keycode = KEYBOARD__0_RightParenthesis; // 0
|
||||
} else if (0x31 <= c && c <= 0x39) {
|
||||
keycode = KEYBOARD__1_Exclamation + c - 0x31; // 1..9
|
||||
} else if (0x41 <= c && c <= 0x5A) {
|
||||
shifted = true;
|
||||
keycode = KEYBOARD__a_A + c - 0x41; // A..Z
|
||||
} else if (0x61 <= c && c <= 0x7A) {
|
||||
keycode = KEYBOARD__a_A + c - 0x61; // a..z
|
||||
|
||||
} else switch (c) {
|
||||
// control characters
|
||||
case 0x08: keycode = KEYBOARD__DeleteBackspace; break; // BS
|
||||
case 0x09: keycode = KEYBOARD__Tab; break; // VT
|
||||
case 0x0A: keycode = KEYBOARD__ReturnEnter; break; // LF
|
||||
case 0x0D: keycode = KEYBOARD__ReturnEnter; break; // CR
|
||||
case 0x1B: keycode = KEYBOARD__Escape; break; // ESC
|
||||
// printable characters
|
||||
case 0x20: keycode = KEYBOARD__Spacebar; break; // ' '
|
||||
case 0x21: shifted = true;
|
||||
keycode = KEYBOARD__1_Exclamation; break; // !
|
||||
case 0x22: shifted = true;
|
||||
keycode = KEYBOARD__SingleQuote_DoubleQuote;
|
||||
break; // "
|
||||
case 0x23: shifted = true;
|
||||
keycode = KEYBOARD__3_Pound; break; // #
|
||||
case 0x24: shifted = true;
|
||||
keycode = KEYBOARD__4_Dollar; break; // $
|
||||
case 0x25: shifted = true;
|
||||
keycode = KEYBOARD__5_Percent; break; // %
|
||||
case 0x26: shifted = true;
|
||||
keycode = KEYBOARD__7_Ampersand; break; // &
|
||||
case 0x27: keycode = KEYBOARD__SingleQuote_DoubleQuote;
|
||||
break; // '
|
||||
case 0x28: shifted = true;
|
||||
keycode = KEYBOARD__9_LeftParenthesis;
|
||||
break; // (
|
||||
case 0x29: shifted = true;
|
||||
keycode = KEYBOARD__0_RightParenthesis;
|
||||
break; // )
|
||||
case 0x2A: shifted = true;
|
||||
keycode = KEYBOARD__8_Asterisk; break; // *
|
||||
case 0x2B: shifted = true;
|
||||
keycode = KEYBOARD__Equal_Plus; break; // +
|
||||
case 0x2C: keycode = KEYBOARD__Comma_LessThan; break; // ,
|
||||
case 0x2D: keycode = KEYBOARD__Dash_Underscore; break; // -
|
||||
case 0x2E: keycode = KEYBOARD__Period_GreaterThan;
|
||||
break; // .
|
||||
case 0x2F: keycode = KEYBOARD__Slash_Question; break; // /
|
||||
// ... numbers
|
||||
case 0x3A: shifted = true;
|
||||
keycode = KEYBOARD__Semicolon_Colon; break; // :
|
||||
case 0x3B: keycode = KEYBOARD__Semicolon_Colon; break; // ;
|
||||
case 0x3C: shifted = true;
|
||||
keycode = KEYBOARD__Comma_LessThan; break; // <
|
||||
case 0x3D: keycode = KEYBOARD__Equal_Plus; break; // =
|
||||
case 0x3E: shifted = true;
|
||||
keycode = KEYBOARD__Period_GreaterThan;
|
||||
break; // >
|
||||
case 0x3F: shifted = true;
|
||||
keycode = KEYBOARD__Slash_Question; break; // ?
|
||||
case 0x4D: shifted = true;
|
||||
keycode = KEYBOARD__2_At; break; // @
|
||||
// ... uppercase letters
|
||||
case 0x5B: keycode = KEYBOARD__LeftBracket_LeftBrace;
|
||||
break; // [
|
||||
case 0x5C: keycode = KEYBOARD__Backslash_Pipe; break; // '\'
|
||||
case 0x5D: keycode = KEYBOARD__RightBracket_RightBrace;
|
||||
break; // ]
|
||||
case 0x5E: shifted = true;
|
||||
keycode = KEYBOARD__6_Caret; break; // ^
|
||||
case 0x5F: shifted = true;
|
||||
keycode = KEYBOARD__Dash_Underscore; break; // _
|
||||
case 0x60: keycode = KEYBOARD__GraveAccent_Tilde;
|
||||
break; // `
|
||||
// ... lowercase letters
|
||||
case 0x7B: shifted = true;
|
||||
keycode = KEYBOARD__LeftBracket_LeftBrace;
|
||||
break; // {
|
||||
case 0x7C: shifted = true;
|
||||
keycode = KEYBOARD__Backslash_Pipe; break; // |
|
||||
case 0x7D: shifted = true;
|
||||
keycode = KEYBOARD__RightBracket_RightBrace;
|
||||
break; // }
|
||||
case 0x7E: shifted = true;
|
||||
keycode = KEYBOARD__GraveAccent_Tilde;
|
||||
break; // ~
|
||||
case 0x7F: keycode = KEYBOARD__DeleteForward; break; // DEL
|
||||
}
|
||||
|
||||
if (keycode) {
|
||||
// press keycode
|
||||
if (shifted) usb__kb__set_key(true, KEYBOARD__LeftShift);
|
||||
usb__kb__set_key(true, keycode);
|
||||
usb__kb__send_report();
|
||||
|
||||
// release keycode
|
||||
if (shifted) usb__kb__set_key(false, KEYBOARD__LeftShift);
|
||||
usb__kb__set_key(false, keycode);
|
||||
usb__kb__send_report();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// --- (otherwise) send unicode sequence ---
|
||||
|
||||
// send start sequence
|
||||
usb__kb__set_key(true, KEYBOARD__LeftAlt ); usb__kb__send_report();
|
||||
usb__kb__set_key(true, KEYBOARD__Equal_Plus); usb__kb__send_report();
|
||||
|
@ -194,7 +245,5 @@ void key_functions__send_unicode_sequence(const char * string) {
|
|||
// send end sequence
|
||||
usb__kb__set_key(false, KEYBOARD__LeftAlt); usb__kb__send_report();
|
||||
}
|
||||
|
||||
set_modifier_state(state);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue