input: add new Unicode input mode

This mode is activated through the new key-bindings.unicode-input and
search-bindings.unicode-input key bindings.

When active, the user can “build” a Unicode codepoint by typing its
hexadecimal value.

Note that there’s no visual feedback in this mode. This is
intentional. This mode is intended to be a fallback for users that
don’t use an IME.

Closes #1116
This commit is contained in:
Daniel Eklöf 2022-07-28 18:09:16 +02:00
parent fa2d9f8699
commit 8967dd9cfe
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
11 changed files with 167 additions and 2 deletions

View file

@ -52,11 +52,16 @@
`ctrl`+`shift`+`x` respectively ([#30][30]).
* `colors.search-box-no-match` and `colors.search-box-match` options
to `foot.ini` ([#1112][1112]).
* Very basic Unicode input mode via the new
`key-bindings.unicode-input` and `search-bindings.unicode-input` key
bindings. Note that there is no visual feedback, as the preferred
way of entering Unicode characters is with an IME ([#1116][1116]).
[1058]: https://codeberg.org/dnkl/foot/issues/1058
[1070]: https://codeberg.org/dnkl/foot/issues/1070
[30]: https://codeberg.org/dnkl/foot/issues/30
[1112]: https://codeberg.org/dnkl/foot/issues/1112
[1116]: https://codeberg.org/dnkl/foot/issues/1116
### Changed

View file

@ -117,6 +117,7 @@ static const char *const binding_action_map[] = {
[BIND_ACTION_TEXT_BINDING] = "text-binding",
[BIND_ACTION_PROMPT_PREV] = "prompt-prev",
[BIND_ACTION_PROMPT_NEXT] = "prompt-next",
[BIND_ACTION_UNICODE_INPUT] = "unicode-input",
/* Mouse-specific actions */
[BIND_ACTION_SELECT_BEGIN] = "select-begin",
@ -148,6 +149,7 @@ static const char *const search_binding_action_map[] = {
[BIND_ACTION_SEARCH_EXTEND_WORD_WS] = "extend-to-next-whitespace",
[BIND_ACTION_SEARCH_CLIPBOARD_PASTE] = "clipboard-paste",
[BIND_ACTION_SEARCH_PRIMARY_PASTE] = "primary-paste",
[BIND_ACTION_SEARCH_UNICODE_INPUT] = "unicode-input",
};
static const char *const url_binding_action_map[] = {

View file

@ -791,6 +791,32 @@ e.g. *search-start=none*.
Jump the next prompt (requires shell integration, see
*foot*(1)). Default: _Control+Shift+x_.
*unicode-input*
Input a Unicode character by typing its codepoint in hexadecimal,
followed by *Enter* or *Space*.
For example, to input the character _ö_ (LATIN SMALL LETTER O WITH
DIAERESIS, Unicode codepoint 0xf6), you would first activate this
key binding, then type: *f*, *6*, *Enter*.
Another example: to input 😍 (SMILING FACE WITH HEART-SHAPED EYES,
Unicode codepoint 0x1f60d), activate this key binding, then type:
*1*, *f*, *6*, *0*, *d*, *Enter*.
Recognized key bindings in Unicode input mode:
- Enter, Space: commit the Unicode character, then exit this mode.
- Escape, Ctrl+c, Ctrl+d, Ctrl+g: abort input, then exit this mode.
- 0-9, a-f: append next digit to the Unicode's codepoint.
- Backspace: undo the last digit.
Note that there is no visual feedback while in this mode. This is
by design; foot's Unicode input mode is considered to be a
fallback. The preferred way of entering Unicode characters, emojis
etc is by using an IME.
Default: _none_.
# SECTION: search-bindings
This section lets you override the default key bindings used in
@ -869,6 +895,10 @@ scrollback search mode. The syntax is exactly the same as the regular
Paste from the _primary selection_ into the search
buffer. Default: _Shift+Insert_.
*unicode-input*
Unicode input mode. See _key-bindings.unicode-input_ for
details. Default: _none_.
# SECTION: url-bindings
This section lets you override the default key bindings used in URL

View file

@ -150,6 +150,7 @@
# show-urls-persistent=none
# prompt-prev=Control+Shift+z
# prompt-next=Control+Shift+x
# unicode-input=none
# noop=none
[search-bindings]
@ -171,6 +172,7 @@
# extend-to-next-whitespace=Control+Shift+w
# clipboard-paste=Control+v Control+Shift+v Control+y XF86Paste
# primary-paste=Shift+Insert
# unicode-input=none
[url-bindings]
# cancel=Control+g Control+c Control+d Escape

69
input.c
View file

@ -36,6 +36,7 @@
#include "spawn.h"
#include "terminal.h"
#include "tokenize.h"
#include "unicode-mode.h"
#include "url-mode.h"
#include "util.h"
#include "vt.h"
@ -416,6 +417,10 @@ execute_binding(struct seat *seat, struct terminal *term,
return true;
}
case BIND_ACTION_UNICODE_INPUT:
unicode_mode_activate(seat);
return true;
case BIND_ACTION_SELECT_BEGIN:
selection_start(
term, seat->mouse.col, seat->mouse.row, SELECTION_CHAR_WISE, false);
@ -1405,7 +1410,69 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
xassert(bindings != NULL);
if (pressed) {
if (term->is_searching) {
if (seat->unicode_mode.active) {
if (sym == XKB_KEY_Return ||
sym == XKB_KEY_space ||
sym == XKB_KEY_KP_Enter ||
sym == XKB_KEY_KP_Space)
{
char utf8[MB_CUR_MAX];
size_t chars = c32rtomb(
utf8, seat->unicode_mode.character, &(mbstate_t){0});
LOG_DBG("Unicode input: 0x%06x -> %.*s",
seat->unicode_mode.character, (int)chars, utf8);
if (chars != (size_t)-1) {
if (term->is_searching)
search_add_chars(term, utf8, chars);
else
term_to_slave(term, utf8, chars);
}
unicode_mode_deactivate(seat);
}
else if (sym == XKB_KEY_Escape ||
(seat->kbd.ctrl && (sym == XKB_KEY_c ||
sym == XKB_KEY_d ||
sym == XKB_KEY_g)))
{
unicode_mode_deactivate(seat);
}
else if (sym == XKB_KEY_BackSpace) {
if (seat->unicode_mode.count > 0) {
seat->unicode_mode.character >>= 4;
seat->unicode_mode.count--;
unicode_mode_updated(seat);
}
}
else if (seat->unicode_mode.count < 6) {
int digit = -1;
/* 0-9, a-f, A-F */
if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9)
digit = sym - XKB_KEY_0;
else if (sym >= XKB_KEY_a && sym <= XKB_KEY_f)
digit = 0xa + (sym - XKB_KEY_a);
else if (sym >= XKB_KEY_A && sym <= XKB_KEY_F)
digit = 0xa + (sym - XKB_KEY_A);
if (digit >= 0) {
xassert(digit >= 0 && digit <= 0xf);
seat->unicode_mode.character <<= 4;
seat->unicode_mode.character |= digit;
seat->unicode_mode.count++;
unicode_mode_updated(seat);
}
}
return;
}
else if (term->is_searching) {
if (should_repeat)
start_repeater(seat, key);

View file

@ -38,6 +38,7 @@ enum bind_action_normal {
BIND_ACTION_TEXT_BINDING,
BIND_ACTION_PROMPT_PREV,
BIND_ACTION_PROMPT_NEXT,
BIND_ACTION_UNICODE_INPUT,
/* Mouse specific actions - i.e. they require a mouse coordinate */
BIND_ACTION_SELECT_BEGIN,
@ -48,7 +49,7 @@ enum bind_action_normal {
BIND_ACTION_SELECT_WORD_WS,
BIND_ACTION_SELECT_ROW,
BIND_ACTION_KEY_COUNT = BIND_ACTION_PROMPT_NEXT + 1,
BIND_ACTION_KEY_COUNT = BIND_ACTION_UNICODE_INPUT + 1,
BIND_ACTION_COUNT = BIND_ACTION_SELECT_ROW + 1,
};
@ -72,6 +73,7 @@ enum bind_action_search {
BIND_ACTION_SEARCH_EXTEND_WORD_WS,
BIND_ACTION_SEARCH_CLIPBOARD_PASTE,
BIND_ACTION_SEARCH_PRIMARY_PASTE,
BIND_ACTION_SEARCH_UNICODE_INPUT,
BIND_ACTION_SEARCH_COUNT,
};

View file

@ -222,6 +222,7 @@ executable(
'slave.c', 'slave.h',
'spawn.c', 'spawn.h',
'tokenize.c', 'tokenize.h',
'unicode-mode.c', 'unicode-mode.h',
'url-mode.c', 'url-mode.h',
'user-notification.c', 'user-notification.h',
'wayland.c', 'wayland.h', 'shm-formats.h',

View file

@ -18,6 +18,7 @@
#include "render.h"
#include "selection.h"
#include "shm.h"
#include "unicode-mode.h"
#include "util.h"
#include "xmalloc.h"
@ -993,6 +994,10 @@ execute_binding(struct seat *seat, struct terminal *term,
*update_search_result = *redraw = true;
return true;
case BIND_ACTION_SEARCH_UNICODE_INPUT:
unicode_mode_activate(seat);
return true;
case BIND_ACTION_SEARCH_COUNT:
BUG("Invalid action type");
return true;

38
unicode-mode.c Normal file
View file

@ -0,0 +1,38 @@
#include "unicode-mode.h"
#include "render.h"
void
unicode_mode_activate(struct seat *seat)
{
if (seat->unicode_mode.active)
return;
seat->unicode_mode.active = true;
seat->unicode_mode.character = u'\0';
seat->unicode_mode.count = 0;
unicode_mode_updated(seat);
}
void
unicode_mode_deactivate(struct seat *seat)
{
if (!seat->unicode_mode.active)
return;
seat->unicode_mode.active = false;
unicode_mode_updated(seat);
}
void
unicode_mode_updated(struct seat *seat)
{
struct terminal *term = seat->kbd_focus;
if (term == NULL)
return;
if (term->is_searching)
render_refresh_search(term);
else
render_refresh(term);
}

7
unicode-mode.h Normal file
View file

@ -0,0 +1,7 @@
#pragma once
#include "wayland.h"
void unicode_mode_activate(struct seat *seat);
void unicode_mode_deactivate(struct seat *seat);
void unicode_mode_updated(struct seat *seat);

View file

@ -206,6 +206,12 @@ struct seat {
uint32_t serial;
} ime;
#endif
struct {
bool active;
int count;
char32_t character;
} unicode_mode;
};
enum csd_surface {