static unsigned int using_vi_mode = 0; void vi_keypress(KeySym ksym, const XKeyEvent *ev) { static const size_t quit_len = LENGTH(quit_keys); if (ev->state & ControlMask) { switch(ksym) { /* movement */ case XK_d: /* fallthrough */ if (next) { sel = curr = next; calcoffsets(); goto draw; } else ksym = XK_G; break; case XK_u: if (prev) { sel = curr = prev; calcoffsets(); goto draw; } else ksym = XK_g; break; case XK_p: /* fallthrough */ case XK_P: break; case XK_c: cleanup(); exit(1); case XK_Return: /* fallthrough */ case XK_KP_Enter: break; default: return; } } switch(ksym) { /* movement */ case XK_0: cursor = 0; break; case XK_dollar: if (text[cursor + 1] != '\0') { cursor = strlen(text) - 1; break; } break; case XK_b: movewordedge(-1); break; case XK_e: cursor = nextrune(+1); movewordedge(+1); if (text[cursor] == '\0') --cursor; else cursor = nextrune(-1); break; case XK_g: if (sel == matches) { break; } sel = curr = matches; calcoffsets(); break; case XK_G: if (next) { /* jump to end of list and position items in reverse */ curr = matchend; calcoffsets(); curr = prev; calcoffsets(); while (next && (curr = curr->right)) calcoffsets(); } sel = matchend; break; case XK_h: if (cursor) cursor = nextrune(-1); break; case XK_j: if (sel && sel->right && (sel = sel->right) == next) { curr = next; calcoffsets(); } break; case XK_k: if (sel && sel->left && (sel = sel->left)->right == curr) { curr = prev; calcoffsets(); } break; case XK_l: if (text[cursor] != '\0' && text[cursor + 1] != '\0') cursor = nextrune(+1); else if (text[cursor] == '\0' && cursor) --cursor; break; case XK_w: movewordedge(+1); if (text[cursor] != '\0' && text[cursor + 1] != '\0') cursor = nextrune(+1); else if (cursor) --cursor; break; /* insertion */ case XK_a: cursor = nextrune(+1); /* fallthrough */ case XK_i: using_vi_mode = 0; break; case XK_A: if (text[cursor] != '\0') cursor = strlen(text); using_vi_mode = 0; break; case XK_I: cursor = using_vi_mode = 0; break; case XK_p: if (text[cursor] != '\0') cursor = nextrune(+1); XConvertSelection(dpy, (ev->state & ControlMask) ? clip : XA_PRIMARY, utf8, utf8, win, CurrentTime); return; case XK_P: XConvertSelection(dpy, (ev->state & ControlMask) ? clip : XA_PRIMARY, utf8, utf8, win, CurrentTime); return; /* deletion */ case XK_D: text[cursor] = '\0'; if (cursor) cursor = nextrune(-1); match(); break; case XK_x: cursor = nextrune(+1); insert(NULL, nextrune(-1) - cursor); if (text[cursor] == '\0' && text[0] != '\0') --cursor; match(); break; /* misc. */ case XK_Return: case XK_KP_Enter: #if RESTRICT_RETURN_PATCH if (restrict_return && (!sel || ev->state & (ShiftMask | ControlMask))) break; #endif // RESTRICT_RETURN_PATCH #if !MULTI_SELECTION_PATCH printcurrent(ev->state); #endif // MULTI_SELECTION_PATCH if (!(ev->state & ControlMask)) { #if MULTI_SELECTION_PATCH printselected(ev->state); #endif // MULTI_SELECTION_PATCH cleanup(); exit(0); } #if !MULTI_SELECTION_PATCH if (sel) sel->out = 1; #endif // MULTI_SELECTION_PATCH break; break; case XK_Tab: if (!sel) return; strncpy(text, sel->text, sizeof text - 1); text[sizeof text - 1] = '\0'; cursor = strlen(text) - 1; match(); break; default: for (size_t i = 0; i < quit_len; ++i) if (quit_keys[i].ksym == ksym && (quit_keys[i].state & ev->state) == quit_keys[i].state) { cleanup(); exit(1); } } draw: drawmenu(); }