add type-to-select support

This commit is contained in:
phillbush 2020-12-29 22:26:48 -03:00
parent 6bbc0e45ea
commit b33886d7a2
2 changed files with 81 additions and 17 deletions

91
xmenu.c
View File

@ -1140,20 +1140,61 @@ isclickbutton(unsigned int button)
return 0;
}
/* append buf into text */
static int
append(char *text, char *buf, size_t textsize, size_t buflen)
{
size_t textlen;
textlen = strlen(text);
if (iscntrl(*buf))
return 0;
if (textlen + buflen > textsize - 1)
return 0;
if (buflen < 1)
return 0;
memcpy(text + textlen, buf, buflen);
text[textlen + buflen] = '\0';
return 1;
}
/* get item in menu matching text */
static struct Item *
matchitem(struct Menu *menu, char *text)
{
struct Item *item;
char *s;
size_t textlen;
textlen = strlen(text);
for (item = menu->list; item; item = item->next)
for (s = item->label; s && *s; s++)
if (strncasecmp(s, text, textlen) == 0)
return item;
return NULL;
}
/* run event loop */
static void
run(struct Menu *currmenu)
{
char text[BUFSIZ];
char buf[32];
struct Menu *menu;
struct Item *item;
struct Item *previtem = NULL;
struct Item *lastitem;
struct Item *lastitem, *select;
KeySym ksym;
Status status;
XEvent ev;
int action;
int len;
text[0] = '\0';
mapmenu(currmenu);
while (!XNextEvent(dpy, &ev)) {
if (XFilterEvent(&ev, None))
continue;
action = ACTION_NOP;
switch(ev.type) {
case Expose:
@ -1166,14 +1207,14 @@ run(struct Menu *currmenu)
if (menu == NULL || item == NULL || previtem == item)
break;
previtem = item;
menu->selected = item;
select = menu->selected = item;
if (item->submenu != NULL) {
currmenu = item->submenu;
currmenu->selected = NULL;
select = NULL;
} else {
currmenu = menu;
}
action = ACTION_MAP | ACTION_DRAW;
action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
break;
case ButtonRelease:
if (!isclickbutton(ev.xbutton.button))
@ -1182,7 +1223,7 @@ run(struct Menu *currmenu)
item = getitem(menu, ev.xbutton.y);
if (menu == NULL || item == NULL)
break;
selectitem:
enteritem:
if (item->label == NULL)
break; /* ignore separators */
if (item->submenu != NULL) {
@ -1191,8 +1232,8 @@ selectitem:
printf("%s\n", item->output);
return;
}
currmenu->selected = currmenu->list;
action = ACTION_MAP | ACTION_DRAW;
select = currmenu->list;
action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
break;
case ButtonPress:
menu = getmenu(currmenu, ev.xbutton.window);
@ -1200,7 +1241,16 @@ selectitem:
return;
break;
case KeyPress:
ksym = XkbKeycodeToKeysym(dpy, ev.xkey.keycode, 0, 0);
len = XmbLookupString(currmenu->xic, &ev.xkey, buf, sizeof buf, &ksym, &status);
switch(status) {
default: /* XLookupNone, XBufferOverflow */
continue;
case XLookupChars:
goto append;
case XLookupKeySym: /* FALLTHROUGH */
case XLookupBoth:
break;
}
/* esc closes xmenu when current menu is the root menu */
if (ksym == XK_Escape && currmenu->parent == NULL)
@ -1230,21 +1280,30 @@ selectitem:
} else if ((ksym == XK_Return || ksym == XK_Right || ksym == KSYMRIGHT) &&
currmenu->selected != NULL) {
item = currmenu->selected;
goto selectitem;
goto enteritem;
} else if ((ksym == XK_Escape || ksym == XK_Left || ksym == KSYMLEFT) &&
currmenu->parent != NULL) {
item = currmenu->parent->selected;
currmenu = currmenu->parent;
action = ACTION_MAP;
} else
} else {
append:
if (append(text, buf, sizeof text, len)) {
currmenu->selected = matchitem(currmenu, text);
action = ACTION_DRAW;
} else {
select = NULL;
action = ACTION_SELECT | ACTION_DRAW;
}
break;
currmenu->selected = item;
action |= ACTION_DRAW;
}
select = item;
action |= ACTION_SELECT | ACTION_DRAW;
break;
case LeaveNotify:
previtem = NULL;
currmenu->selected = NULL;
action = ACTION_DRAW;
select = NULL;
action = ACTION_SELECT | ACTION_DRAW;
break;
case ConfigureNotify:
menu = getmenu(currmenu, ev.xconfigure.window);
@ -1264,6 +1323,10 @@ selectitem:
action = ACTION_MAP;
break;
}
if (action & ACTION_SELECT) {
currmenu->selected = select;
text[0] = '\0';
}
if (action & ACTION_MAP)
mapmenu(currmenu);
if (action & ACTION_DRAW)

View File

@ -1,9 +1,10 @@
#define PROGNAME "xmenu"
/* Actions for the main loop */
#define ACTION_NOP 0
#define ACTION_MAP 1<<0
#define ACTION_DRAW 1<<1
#define ACTION_NOP 0
#define ACTION_SELECT 1<<0 /* select item and clear text */
#define ACTION_MAP 1<<1 /* remap menu windows */
#define ACTION_DRAW 1<<2 /* redraw menu windows */
/* enum for keyboard menu navigation */
enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };