ledit

Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 0ac206aa676b56346dd45906fe0379a1e845fb80
parent 25deb9532df29d093281a2b542be2463809d7379
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 20 May 2021 21:37:00 +0200

Add support for Ctrl-c and Ctrl-v

Diffstat:
MMakefile | 2+-
Mbuffer.c | 54++++++++++++++++++++++++++++++++++++++++++++++--------
Mbuffer.h | 6++++++
Mledit.c | 203+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
4 files changed, 170 insertions(+), 95 deletions(-)

diff --git a/Makefile b/Makefile @@ -12,7 +12,7 @@ MAN1 = ${BIN:=.1} OBJ = ${BIN:=.o} cache.o buffer.o memory.o HDR = cache.h buffer.h memory.h common.h -CFLAGS_LEDIT = ${CFLAGS} -g -Wall -Wextra -D_POSIX_C_SOURCE=200809L `pkg-config --cflags x11 xkbfile pangoxft xext` +CFLAGS_LEDIT = -g -Wall -Wextra -D_POSIX_C_SOURCE=200809L `pkg-config --cflags x11 xkbfile pangoxft xext` LDFLAGS_LEDIT = ${LDFLAGS} `pkg-config --libs x11 xkbfile pangoxft xext` -lm all: ${BIN} diff --git a/buffer.c b/buffer.c @@ -1,3 +1,7 @@ +/* FIXME: shrink buffers when text length less than a fourth of the size */ + +#include <string.h> + #include <X11/Xlib.h> #include <X11/Xutil.h> #include <pango/pangoxft.h> @@ -101,20 +105,49 @@ ledit_insert_text(ledit_buffer *buffer, int line_index, int index, char *text, i ledit_line *line = &buffer->lines[line_index]; if (len == -1) len = strlen(text); - if (line->len + len > line->cap) { - line->cap *= 2; - if (line->cap == 0) - line->cap = 2; + if (line->len + len > line->cap || line->text == NULL) { + /* FIXME: read up on what the best values are here */ + line->cap = line->cap * 2 > line->len + len ? line->cap * 2 : line->len + len; line->text = ledit_realloc(line->text, line->cap); } memmove(line->text + index + len, line->text + index, line->len - index); memcpy(line->text + index, text, len); line->len += len; pango_layout_set_text(line->layout, line->text, line->len); - recalc_single_line_size(buffer, line_index); + /*recalc_single_line_size(buffer, line_index);*/ line->dirty = 1; } +static void append_line_impl(ledit_buffer *buffer, int line_index, int text_index); + +void +ledit_insert_text_with_newlines( + ledit_buffer *buffer, + int line_index, int index, + char *text, int len, + int *end_line_ret, int *end_char_ret) { + if (len == -1) + len = strlen(text); + char *cur, *last = text; + int cur_line = line_index; + int cur_index = index; + while ((cur = strchr(last, '\n'))) { + ledit_insert_text(buffer, cur_line, cur_index, last, cur - last); + /* FIXME: inefficient because there's no gap buffer yet */ + append_line_impl(buffer, cur_line, -1); + cur_index = 0; + cur_line++; + last = cur + 1; + } + /* FIXME: check how legal this casting between pointers and ints is */ + ledit_insert_text(buffer, cur_line, cur_index, last, text + len - last); + if (end_line_ret) + *end_line_ret = cur_line; + if (end_char_ret) + *end_char_ret = cur_index + text + len - last; + recalc_line_size_absolute(buffer); /* FIXME: make this more efficient */ +} + void ledit_render_line(ledit_buffer *buffer, int line_index) { /* FIXME: check for <= 0 on size */ @@ -171,8 +204,8 @@ init_line(ledit_buffer *buffer, ledit_line *line) { } /* FIXME: error checking (index out of bounds, etc.) */ -void -ledit_append_line(ledit_buffer *buffer, int line_index, int text_index) { +static void +append_line_impl(ledit_buffer *buffer, int line_index, int text_index) { if (buffer->lines_num >= buffer->lines_cap) { buffer->lines_cap *= 2; if (buffer->lines_cap == 0) @@ -201,6 +234,11 @@ ledit_append_line(ledit_buffer *buffer, int line_index, int text_index) { pango_layout_set_text(l->layout, l->text, l->len); /* FIXME: set height here */ } +} + +void +ledit_append_line(ledit_buffer *buffer, int line_index, int text_index) { + append_line_impl(buffer, line_index, text_index); recalc_line_size_absolute(buffer); } @@ -281,7 +319,7 @@ ledit_delete_unicode_char(ledit_buffer *buffer, int line_index, int byte_index, ledit_line *l = ledit_get_line(buffer, line_index); int new_index = byte_index; if (dir < 0) { - int i = buffer->cur_index - 1; + int i = byte_index - 1; /* find valid utf8 char - this probably needs to be improved */ while (i > 0 && ((l->text[i] & 0xC0) == 0x80)) i--; diff --git a/buffer.h b/buffer.h @@ -44,6 +44,12 @@ void ledit_set_line_selection(ledit_buffer *buffer, int line, int start_byte, in void ledit_set_line_cursor_attrs(ledit_buffer *buffer, int line, int index); void ledit_wipe_line_cursor_attrs(ledit_buffer *buffer, int line); void ledit_insert_text(ledit_buffer *buffer, int line_index, int index, char *text, int len); +void ledit_insert_text_with_newlines( + ledit_buffer *buffer, + int line_index, int index, + char *text, int len, + int *end_line_ret, int *end_char_ret +); void ledit_render_line(ledit_buffer *buffer, int line_index); void ledit_append_line(ledit_buffer *buffer, int line_index, int text_index); void ledit_delete_line_entries(ledit_buffer *buffer, int index1, int index2); diff --git a/ledit.c b/ledit.c @@ -1,3 +1,4 @@ +/* FIXME: Fix lag when selecting with mouse */ /* FIXME: Use PANGO_PIXELS() */ /* FIXME: Fix cursor movement, especially buffer->trailing and writing at end of line */ /* FIXME: horizontal scrolling (also need cache to avoid too large pixmaps) */ @@ -43,6 +44,7 @@ enum key_type { struct key { char *text; /* for keys that correspond with text */ + unsigned int mods; /* modifier mask */ KeySym keysym; /* for other keys, e.g. arrow keys */ enum ledit_mode modes; /* modes in which this keybinding is functional */ enum key_type prev_keys; /* allowed previous keys */ @@ -240,23 +242,12 @@ selnotify(XEvent *e) continue; } - /* FIXME: Is this needed for ledit? I don't think so, right? */ - /* - * As seen in getsel: - * Line endings are inconsistent in the terminal and GUI world - * copy and pasting. When receiving some selection data, - * replace all '\n' with '\r'. - * FIXME: Fix the computer world. - */ - /* - repl = data; - last = data + nitems * format / 8; - while ((repl = memchr(repl, '\n', last - repl))) { - *repl++ = '\r'; - } - */ - - printf("%.*s\n", (int)(nitems * format / 8), (char*)data); + ledit_insert_text_with_newlines( + buffer, + buffer->cur_line, buffer->cur_index, + (char*)data, (int)(nitems * format / 8), + &buffer->cur_line, &buffer->cur_index + ); XFree(data); /* number of 32-bit chunks returned */ ofs += nitems * format / 32; @@ -670,9 +661,11 @@ mainloop(void) { running = 0; break; case SelectionNotify: + need_redraw = 1; selnotify(&event); break; case PropertyNotify: + need_redraw = 1; propnotify(&event); break; case SelectionRequest: @@ -1011,6 +1004,7 @@ sort_selection(int *line1, int *byte1, int *line2, int *byte2) { } } +/* FIXME: don't reset selection when selection is clicked away */ /* FIXME: when selecting with mouse, only call this when button is released */ /* lines and bytes need to be sorted already! */ static void @@ -1240,9 +1234,10 @@ backspace(void) { ledit_line *l1 = ledit_get_line(buffer, buffer->cur_line - 1); ledit_line *l2 = ledit_get_line(buffer, buffer->cur_line); int old_len = l1->len; - ledit_insert_text( + ledit_insert_text_with_newlines( buffer, buffer->cur_line - 1, - l1->len, l2->text, l2->len + l1->len, l2->text, l2->len, + NULL, NULL ); ledit_delete_line_entry(buffer, buffer->cur_line); buffer->cur_line--; @@ -1267,9 +1262,10 @@ delete_key(void) { buffer, buffer->cur_line + 1 ); int old_len = cur_line->len; - ledit_insert_text( + ledit_insert_text_with_newlines( buffer, buffer->cur_line, cur_line->len, - next_line->text, next_line->len + next_line->text, next_line->len, + NULL, NULL ); ledit_delete_line_entry(buffer, buffer->cur_line + 1); buffer->cur_index = old_len; @@ -1338,7 +1334,7 @@ move_cursor_left_right(int dir) { new_index = cur_line->len; } } - if (e != NULL & e->motion_cb != NULL) { + if (e != NULL && e->motion_cb != NULL) { e->motion_cb(buffer->cur_line, new_index, KEY_MOTION_CHAR); } else { buffer->cur_index = new_index; @@ -1473,7 +1469,7 @@ static void cursor_to_beginning(void) { struct key_stack_elem *e = pop_key_stack(); /* FIXME: error when no callback? */ - if (e != NULL & e->motion_cb != NULL) { + if (e != NULL && e->motion_cb != NULL) { e->motion_cb(buffer->cur_line, 0, KEY_MOTION_CHAR); } else { buffer->cur_index = 0; @@ -1508,71 +1504,75 @@ switch_selection_end(void) { buffer->cur_index = buffer->sel.byte2; } +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 + static struct key keys_en[] = { - {NULL, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace}, - {NULL, XK_Left, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left}, - {NULL, XK_Right, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right}, - {NULL, XK_Up, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up}, - {NULL, XK_Down, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down}, - {NULL, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key}, - {NULL, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key}, - {NULL, XK_Escape, VISUAL|INSERT, KEY_ANY, KEY_ANY, &escape_key}, - {"i", 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_insert}, - {"h", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, - {"l", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, - {"j", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, - {"k", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, - {"0", 0, NORMAL|VISUAL, ~KEY_NUMBER, KEY_ANY, &cursor_to_beginning}, - {"0", 0, NORMAL|VISUAL, KEY_NUMBER, KEY_NUMBER, &push_0}, - {"1", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_1}, - {"2", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_2}, - {"3", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_3}, - {"4", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_4}, - {"5", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_5}, - {"6", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_6}, - {"7", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_7}, - {"8", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_8}, - {"9", 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_9}, - {"x", 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &key_x}, - {"d", 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &key_d}, - {"v", 0, NORMAL, KEY_ANY, KEY_ANY, &enter_visual}, - {"o", 0, VISUAL, KEY_ANY, KEY_ANY, &switch_selection_end}, - {"y", 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &clipcopy}, - {"p", 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &clippaste} + {NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace}, + {NULL, 0, XK_Left, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left}, + {NULL, 0, XK_Right, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right}, + {NULL, 0, XK_Up, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up}, + {NULL, 0, XK_Down, VISUAL|INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down}, + {NULL, 0, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key}, + {NULL, 0, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key}, + {NULL, 0, XK_Escape, VISUAL|INSERT, KEY_ANY, KEY_ANY, &escape_key}, + {"i", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_ANY, &enter_insert}, + {"h", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, + {"l", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, + {"j", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, + {"k", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, + {"0", 0, 0, NORMAL|VISUAL, ~KEY_NUMBER, KEY_ANY, &cursor_to_beginning}, + {"0", 0, 0, NORMAL|VISUAL, KEY_NUMBER, KEY_NUMBER, &push_0}, + {"1", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_1}, + {"2", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_2}, + {"3", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_3}, + {"4", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_4}, + {"5", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_5}, + {"6", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_6}, + {"7", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_7}, + {"8", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_8}, + {"9", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_NUMBER, &push_9}, + {"x", 0, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &key_x}, + {"d", 0, 0, NORMAL|VISUAL, KEY_ANY, KEY_MOTION|KEY_NUMBERALLOWED, &key_d}, + {"v", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &enter_visual}, + {"o", 0, 0, VISUAL, KEY_ANY, KEY_ANY, &switch_selection_end}, + {"c", ControlMask, 0, INSERT|VISUAL, KEY_ANY, KEY_ANY, &clipcopy}, + {"v", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &clippaste} }; static struct key keys_ur[] = { - {NULL, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace}, - {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left}, - {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right}, - {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up}, - {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down}, - {NULL, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key}, - {NULL, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key}, - {NULL, XK_Escape, INSERT, KEY_ANY, KEY_ANY, &escape_key}, - {"ی", 0, NORMAL, KEY_ANY, KEY_ANY, &enter_insert}, - {"ح", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, - {"ل", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, - {"ج", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, - {"ک", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, - {"0", 0, NORMAL, KEY_ANY, KEY_ANY, &cursor_to_beginning} + {NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace}, + {NULL, 0, XK_Left, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left}, + {NULL, 0, XK_Right, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right}, + {NULL, 0, XK_Up, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up}, + {NULL, 0, XK_Down, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down}, + {NULL, 0, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key}, + {NULL, 0, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key}, + {NULL, 0, XK_Escape, INSERT, KEY_ANY, KEY_ANY, &escape_key}, + {"ی", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &enter_insert}, + {"ح", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, + {"ل", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, + {"ج", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, + {"ک", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, + {"0", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &cursor_to_beginning}, + {"چ", ControlMask, 0, INSERT|VISUAL, KEY_ANY, KEY_ANY, &clipcopy} }; static struct key keys_hi[] = { - {NULL, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace}, - {NULL, XK_Left, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left}, - {NULL, XK_Right, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right}, - {NULL, XK_Up, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up}, - {NULL, XK_Down, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down}, - {NULL, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key}, - {NULL, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key}, - {NULL, XK_Escape, INSERT, KEY_ANY, KEY_ANY, &escape_key}, - {"ि", 0, NORMAL, KEY_ANY, KEY_ANY, &enter_insert}, - {"ह", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, - {"ल", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, - {"ज", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, - {"क", 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, - {"0", 0, NORMAL, KEY_ANY, KEY_ANY, &cursor_to_beginning} + {NULL, 0, XK_BackSpace, INSERT, KEY_ANY, KEY_ANY, &backspace}, + {NULL, 0, XK_Left, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_left}, + {NULL, 0, XK_Right, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_right}, + {NULL, 0, XK_Up, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_up}, + {NULL, 0, XK_Down, INSERT|NORMAL, KEY_ANY, KEY_ANY, &cursor_down}, + {NULL, 0, XK_Return, INSERT, KEY_ANY, KEY_ANY, &return_key}, + {NULL, 0, XK_Delete, INSERT, KEY_ANY, KEY_ANY, &delete_key}, + {NULL, 0, XK_Escape, INSERT, KEY_ANY, KEY_ANY, &escape_key}, + {"ि", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &enter_insert}, + {"ह", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_left}, + {"ल", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_right}, + {"ज", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_down}, + {"क", 0, 0, NORMAL, KEY_ANY, KEY_MOTION | KEY_NUMBERALLOWED, &cursor_up}, + {"0", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &cursor_to_beginning} }; #define LENGTH(X) (sizeof(X) / sizeof(X[0])) @@ -1602,10 +1602,37 @@ static void change_keyboard(char *lang) { } } +/* FIXME: Does this break anything? */ +static unsigned int importantmod = ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask; + +static int +match(unsigned int mask, unsigned int state) +{ + return mask == XK_ANY_MOD || mask == (state & importantmod); +} + static void key_press(XEvent event) { char buf[32]; KeySym sym; + /* + * FIXME: I don't understand how key handling works with different keymaps. + * If, for instance, you run "setxkbmap pk" and then type "Ctrl+c", the + * keysym will be "0x1000686, Arabic_tcheh" and the appropriate string will + * be returned by XmbLookupString (tested also using xev). + * If, however, you run "setxkbmap -layout "us,pk" -option grp:shifts_toggle" + * and type "Ctrl+c" after switching to the pk layout, the keysym will just + * be "0x63, c" and XmbLookupString will return the control code sent by + * Ctrl+c (ascii 03). This means the handling is different depending on how + * the keymap is switched to, and I have no clue what the proper way to + * handle this would be, since the shortcuts are explicitly supposed to work + * properly in all language maps. My current solution is to just ignore the + * control key in the state so the text found by Xutf8LookupString is correct + * and the modifier mask can be checked separately. Please tell me if you + * know the proper way to do this. + */ + unsigned int key_state = event.xkey.state; + event.xkey.state &= ~ControlMask; /* FIXME: X_HAVE_UTF8_STRING See XmbLookupString(3) */ int n = Xutf8LookupString( state.xic, &event.xkey, buf, sizeof(buf), &sym, NULL @@ -1617,12 +1644,14 @@ key_press(XEvent event) { if (n > 0 && (cur_keys->keys[i].modes & state.mode) && (!e || (e->key & cur_keys->keys[i].prev_keys)) && - !strncmp(cur_keys->keys[i].text, buf, n)) { + !strncmp(cur_keys->keys[i].text, buf, n) && + match(cur_keys->keys[i].mods, key_state)) { cur_keys->keys[i].func(); found = 1; } } else if ((cur_keys->keys[i].modes & state.mode) && - cur_keys->keys[i].keysym == sym) { + cur_keys->keys[i].keysym == sym && + match(cur_keys->keys[i].mods, key_state)) { cur_keys->keys[i].func(); found = 1; } @@ -1631,10 +1660,12 @@ key_press(XEvent event) { } if (state.mode == INSERT && !found && n > 0) { delete_selection(); - ledit_insert_text( - buffer, buffer->cur_line, buffer->cur_index, buf, n + ledit_insert_text_with_newlines( + buffer, + buffer->cur_line, buffer->cur_index, + buf, n, + &buffer->cur_line, &buffer->cur_index ); - buffer->cur_index += n; } ensure_cursor_shown(); }