feat(x11): add XDrawer global phone controls drawer, softkey chord detection, and st/T9 scrollback
This commit is contained in:
+174
-39
@@ -4,6 +4,7 @@
|
||||
#define _EVDEVK(_v) (0x10081000 + (_v))
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -556,11 +557,12 @@ insert:
|
||||
sel = matchend;
|
||||
break;
|
||||
case XK_Escape:
|
||||
case XF86XK_Back:
|
||||
case XF86XK_KbdLcdMenu2:
|
||||
case XF86XK_PowerOff:
|
||||
cleanup();
|
||||
exit(1);
|
||||
case XF86XK_Back:
|
||||
case XF86XK_KbdLcdMenu2:
|
||||
return;
|
||||
case XK_Home:
|
||||
if (sel == matches) {
|
||||
cursor = 0;
|
||||
@@ -610,6 +612,7 @@ insert:
|
||||
break;
|
||||
case XK_Menu:
|
||||
case XF86XK_KbdLcdMenu1:
|
||||
return;
|
||||
case XF86XK_Phone:
|
||||
case XF86XK_PickupPhone:
|
||||
case XK_Return:
|
||||
@@ -910,6 +913,8 @@ readstdin(void)
|
||||
lines = MIN(lines, i);
|
||||
}
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
static int
|
||||
issoftkey(unsigned int keycode)
|
||||
{
|
||||
@@ -917,51 +922,181 @@ issoftkey(unsigned int keycode)
|
||||
return keycode == 124 || keycode == 135 || keycode == 166 || keycode == 177;
|
||||
}
|
||||
|
||||
static long long
|
||||
dmenu_now_ms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (long long)ts.tv_sec * 1000LL + (long long)(ts.tv_nsec / 1000000L);
|
||||
}
|
||||
|
||||
static void
|
||||
write_softkey_suppress(long long until_ms)
|
||||
{
|
||||
char buf[32];
|
||||
int fd = open("/tmp/sxmo_softkey_suppress", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
|
||||
if (fd >= 0) {
|
||||
int len = snprintf(buf, sizeof(buf), "%lld\n", until_ms);
|
||||
(void)write(fd, buf, len);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
query_softkeys_down(void)
|
||||
{
|
||||
char km[32];
|
||||
int mask = 0;
|
||||
if (!XQueryKeymap(dpy, km))
|
||||
return 0;
|
||||
if (km[135 / 8] & (1 << (135 % 8)))
|
||||
mask |= 1;
|
||||
if (km[166 / 8] & (1 << (166 % 8)))
|
||||
mask |= 2;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_xdrawer_and_exit(void)
|
||||
{
|
||||
write_softkey_suppress(dmenu_now_ms() + 500);
|
||||
cleanup();
|
||||
if (fork() == 0) {
|
||||
int nullfd = open("/dev/null", O_RDWR);
|
||||
if (nullfd >= 0) {
|
||||
dup2(nullfd, 0);
|
||||
dup2(nullfd, 1);
|
||||
dup2(nullfd, 2);
|
||||
if (nullfd > 2)
|
||||
close(nullfd);
|
||||
}
|
||||
setsid();
|
||||
execlp("xdrawer", "xdrawer", (char *)NULL);
|
||||
execl("/home/user/.local/bin/xdrawer", "xdrawer", (char *)NULL);
|
||||
execl("/usr/bin/xdrawer", "xdrawer", (char *)NULL);
|
||||
_exit(0);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
run(void)
|
||||
{
|
||||
XEvent ev;
|
||||
int soft_pending = 0;
|
||||
long long soft_first_ms = 0;
|
||||
long long soft_deadline = 0;
|
||||
long long start_ignore = dmenu_now_ms() + 40;
|
||||
int initial_released = (query_softkeys_down() == 0);
|
||||
int xfd = ConnectionNumber(dpy);
|
||||
|
||||
while (!XNextEvent(dpy, &ev)) {
|
||||
if (ev.type == KeyPress || ev.type == KeyRelease) {
|
||||
if (!issoftkey(ev.xkey.keycode)) {
|
||||
ev.xkey.window = win;
|
||||
if (XFilterEvent(&ev, None))
|
||||
for (;;) {
|
||||
if (!initial_released && query_softkeys_down() == 0)
|
||||
initial_released = 1;
|
||||
while (XPending(dpy)) {
|
||||
if (XNextEvent(dpy, &ev))
|
||||
return;
|
||||
if (!initial_released && query_softkeys_down() == 0)
|
||||
initial_released = 1;
|
||||
if (ev.type == KeyPress || ev.type == KeyRelease) {
|
||||
KeySym ks = XLookupKeysym(&ev.xkey, 0);
|
||||
int is_left = (ks == XK_Menu || ks == XF86XK_KbdLcdMenu1 || ev.xkey.keycode == 135);
|
||||
int is_right = (ks == XF86XK_Back || ks == XF86XK_KbdLcdMenu2 || ev.xkey.keycode == 166);
|
||||
if (is_left || is_right) {
|
||||
long long now = dmenu_now_ms();
|
||||
if (ev.type == KeyRelease) {
|
||||
initial_released = 1;
|
||||
if (soft_pending != 0 && soft_pending != 3) {
|
||||
long long grace = now + 65;
|
||||
if (grace > soft_deadline)
|
||||
soft_deadline = grace;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!initial_released || now < start_ignore)
|
||||
continue;
|
||||
if (is_left)
|
||||
soft_pending |= 1;
|
||||
if (is_right)
|
||||
soft_pending |= 2;
|
||||
soft_pending |= query_softkeys_down();
|
||||
if (soft_pending == 3)
|
||||
spawn_xdrawer_and_exit();
|
||||
if (soft_deadline == 0) {
|
||||
soft_first_ms = now;
|
||||
soft_deadline = now + 200;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!issoftkey(ev.xkey.keycode)) {
|
||||
ev.xkey.window = win;
|
||||
if (XFilterEvent(&ev, None))
|
||||
continue;
|
||||
}
|
||||
} else if (XFilterEvent(&ev, None)) {
|
||||
continue;
|
||||
}
|
||||
} else if (XFilterEvent(&ev, None)) {
|
||||
continue;
|
||||
}
|
||||
switch(ev.type) {
|
||||
case MotionNotify:
|
||||
motionnotify(&ev);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
buttonpress(&ev);
|
||||
break;
|
||||
case DestroyNotify:
|
||||
if (ev.xdestroywindow.window != win)
|
||||
switch(ev.type) {
|
||||
case MotionNotify:
|
||||
motionnotify(&ev);
|
||||
break;
|
||||
cleanup();
|
||||
exit(1);
|
||||
case Expose:
|
||||
if (ev.xexpose.count == 0)
|
||||
drw_map(drw, win, 0, 0, mw, mh);
|
||||
break;
|
||||
case FocusIn:
|
||||
/* regrab focus from parent window */
|
||||
if (ev.xfocus.window != win)
|
||||
grabfocus();
|
||||
if (xic)
|
||||
XSetICFocus(xic);
|
||||
break;
|
||||
case KeyPress:
|
||||
keypress(&ev.xkey);
|
||||
break;
|
||||
case SelectionNotify:
|
||||
if (ev.xselection.property == utf8)
|
||||
paste();
|
||||
break;
|
||||
case ButtonRelease:
|
||||
buttonpress(&ev);
|
||||
break;
|
||||
case DestroyNotify:
|
||||
if (ev.xdestroywindow.window != win)
|
||||
break;
|
||||
cleanup();
|
||||
exit(1);
|
||||
case Expose:
|
||||
if (ev.xexpose.count == 0)
|
||||
drw_map(drw, win, 0, 0, mw, mh);
|
||||
break;
|
||||
case FocusIn:
|
||||
/* regrab focus from parent window */
|
||||
if (ev.xfocus.window != win)
|
||||
grabfocus();
|
||||
if (xic)
|
||||
XSetICFocus(xic);
|
||||
break;
|
||||
case KeyPress:
|
||||
keypress(&ev.xkey);
|
||||
break;
|
||||
case SelectionNotify:
|
||||
if (ev.xselection.property == utf8)
|
||||
paste();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (soft_pending && soft_deadline > 0) {
|
||||
long long now = dmenu_now_ms();
|
||||
int hw_down = query_softkeys_down();
|
||||
soft_pending |= hw_down;
|
||||
if (soft_pending == 3)
|
||||
spawn_xdrawer_and_exit();
|
||||
long long rem = soft_deadline - now;
|
||||
if (rem <= 0) {
|
||||
if (hw_down != 0 && (now - soft_first_ms) < 480) {
|
||||
soft_deadline = now + 25;
|
||||
rem = 25;
|
||||
} else {
|
||||
write_softkey_suppress(now + 400);
|
||||
if (soft_pending == 1) {
|
||||
puts((sel) ? sel->text : text);
|
||||
cleanup();
|
||||
exit(0);
|
||||
} else {
|
||||
cleanup();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
struct pollfd pfd = { xfd, POLLIN, 0 };
|
||||
poll(&pfd, 1, (int)rem);
|
||||
} else {
|
||||
struct pollfd pfd = { xfd, POLLIN, 0 };
|
||||
poll(&pfd, 1, initial_released ? -1 : 40);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user