ephyr: Add -host-grab to set custom grab shortcut
Allows for calling Xephyr with `-host-grab [keys]` to customize the keyboard shortcut for grabbing/releasing keyboard and mouse input. Fully backwards compatible: Omitting `-host-grab` defaults to ctrl+shift. `-no-host-grab` acts the same as before. Closes: #134 Signed-off-by: Steven Van Dorp <steven@vandorp.lu>
This commit is contained in:
parent
61accf16e2
commit
b393d5fc02
|
@ -61,7 +61,12 @@ typedef struct _EphyrInputPrivate {
|
|||
|
||||
Bool EphyrWantGrayScale = 0;
|
||||
Bool EphyrWantResize = 0;
|
||||
Bool EphyrWantNoHostGrab = 0;
|
||||
|
||||
static xcb_mod_mask_t EphyrKeybindToggleHostGrabModMask;
|
||||
static uint32_t EphyrKeybindToggleHostGrabKey;
|
||||
static char const* EphyrTitleHostGrabKeyComboHint;
|
||||
static uint8_t EphyrTitleHostGrabKeyComboHintLen;
|
||||
static Bool EphyrHostGrabSet = FALSE;
|
||||
|
||||
Bool
|
||||
ephyrInitialize(KdCardInfo * card, EphyrPriv * priv)
|
||||
|
@ -649,6 +654,114 @@ ephyrCreateColormap(ColormapPtr pmap)
|
|||
return fbInitializeColormap(pmap);
|
||||
}
|
||||
|
||||
Bool
|
||||
ephyrSetGrabShortcut(char const* const desc)
|
||||
{
|
||||
if (desc == NULL || !strcmp(desc, "NULL")) {
|
||||
EphyrKeybindToggleHostGrabModMask = 0;
|
||||
EphyrKeybindToggleHostGrabKey = 0;
|
||||
EphyrTitleHostGrabKeyComboHint = NULL;
|
||||
EphyrTitleHostGrabKeyComboHintLen = 0;
|
||||
}
|
||||
else {
|
||||
const uint8_t fixed_bound = 255;
|
||||
char buf[16];
|
||||
uint8_t j = 0;
|
||||
for (uint8_t i = 0;; ++i) {
|
||||
assert(i < fixed_bound);
|
||||
char const c = desc[i];
|
||||
if (c == 0 || (j != 0 && c == '+')) {
|
||||
buf[j] = 0;
|
||||
if (j == 1) {
|
||||
EphyrKeybindToggleHostGrabKey = buf[0];
|
||||
}
|
||||
else if (!strcmp(buf, "ctrl")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_CONTROL;
|
||||
}
|
||||
else if (!strcmp(buf, "shift")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_SHIFT;
|
||||
}
|
||||
else if (!strcmp(buf, "lock")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_LOCK;
|
||||
}
|
||||
else if (!strcmp(buf, "mod1")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_1;
|
||||
}
|
||||
else if (!strcmp(buf, "mod2")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_2;
|
||||
}
|
||||
else if (!strcmp(buf, "mod3")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_3;
|
||||
}
|
||||
else if (!strcmp(buf, "mod4")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_4;
|
||||
}
|
||||
else if (!strcmp(buf, "mod5")) {
|
||||
EphyrKeybindToggleHostGrabModMask |= XCB_MOD_MASK_5;
|
||||
}
|
||||
else {
|
||||
ErrorF("ephyr: -host-grab: "
|
||||
"Unrecognized key: '%s'\n", buf);
|
||||
return FALSE;
|
||||
}
|
||||
if (c == 0) break;
|
||||
j = 0;
|
||||
}
|
||||
else {
|
||||
buf[j] = c;
|
||||
++j;
|
||||
assert(j < sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
EphyrTitleHostGrabKeyComboHint = desc;
|
||||
EphyrTitleHostGrabKeyComboHintLen = strlen(desc);
|
||||
}
|
||||
|
||||
EphyrHostGrabSet = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrPrintGrabShortcut(char* const out, size_t const out_size,
|
||||
Bool const currently_grabbed)
|
||||
{
|
||||
if (
|
||||
(
|
||||
EphyrKeybindToggleHostGrabModMask == 0 &&
|
||||
EphyrKeybindToggleHostGrabKey == 0
|
||||
) || (
|
||||
EphyrTitleHostGrabKeyComboHint == 0 ||
|
||||
EphyrTitleHostGrabKeyComboHint == 0
|
||||
)
|
||||
) {
|
||||
/* grabbing disabled */
|
||||
out[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
char const* const suffix = currently_grabbed
|
||||
? " releases mouse and keyboard)"
|
||||
: " grabs mouse and keyboard)";
|
||||
size_t const suffix_len = strlen(suffix);
|
||||
|
||||
assert(out_size > 1 + EphyrTitleHostGrabKeyComboHintLen + suffix_len + 1);
|
||||
assert(out != NULL);
|
||||
|
||||
out[0] = '(';
|
||||
memcpy(out + 1, EphyrTitleHostGrabKeyComboHint, EphyrTitleHostGrabKeyComboHintLen);
|
||||
|
||||
memcpy(out + EphyrTitleHostGrabKeyComboHintLen + 1, suffix, suffix_len + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
ephyrUpdateWindowTitle(KdScreenInfo* const screen, Bool const currently_grabbed)
|
||||
{
|
||||
char title_buf[128];
|
||||
ephyrPrintGrabShortcut(title_buf, sizeof(title_buf), currently_grabbed);
|
||||
hostx_set_win_title(screen, title_buf);
|
||||
}
|
||||
|
||||
Bool
|
||||
ephyrInitScreen(ScreenPtr pScreen)
|
||||
{
|
||||
|
@ -657,11 +770,10 @@ ephyrInitScreen(ScreenPtr pScreen)
|
|||
|
||||
EPHYR_LOG("pScreen->myNum:%d\n", pScreen->myNum);
|
||||
hostx_set_screen_number(screen, pScreen->myNum);
|
||||
if (EphyrWantNoHostGrab) {
|
||||
hostx_set_win_title(screen, "xephyr");
|
||||
} else {
|
||||
hostx_set_win_title(screen, "(ctrl+shift grabs mouse and keyboard)");
|
||||
if (!EphyrHostGrabSet) {
|
||||
ephyrSetGrabShortcut("ctrl+shift");
|
||||
}
|
||||
ephyrUpdateWindowTitle(screen, FALSE);
|
||||
pScreen->CreateColormap = ephyrCreateColormap;
|
||||
|
||||
#ifdef XV
|
||||
|
@ -1019,22 +1131,32 @@ ephyrProcessKeyPress(xcb_generic_event_t *xev)
|
|||
static void
|
||||
ephyrProcessKeyRelease(xcb_generic_event_t *xev)
|
||||
{
|
||||
xcb_connection_t *conn = hostx_get_xcbconn();
|
||||
xcb_key_release_event_t *key = (xcb_key_release_event_t *)xev;
|
||||
if (EphyrKeybindToggleHostGrabModMask != 0 ||
|
||||
EphyrKeybindToggleHostGrabKey != 0) {
|
||||
|
||||
xcb_connection_t *conn = hostx_get_xcbconn();
|
||||
static xcb_key_symbols_t *keysyms;
|
||||
static int grabbed_screen = -1;
|
||||
int mod1_down = ephyrUpdateGrabModifierState(key->state);
|
||||
|
||||
if (!keysyms)
|
||||
keysyms = xcb_key_symbols_alloc(conn);
|
||||
|
||||
if (!EphyrWantNoHostGrab &&
|
||||
(((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_L
|
||||
|| xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_R)
|
||||
&& (key->state & XCB_MOD_MASK_CONTROL)) ||
|
||||
((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_L
|
||||
|| xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_R)
|
||||
&& (key->state & XCB_MOD_MASK_SHIFT)))) {
|
||||
int const keysym =
|
||||
xcb_key_symbols_get_keysym(keysyms, key->detail, 0);
|
||||
|
||||
if (
|
||||
(
|
||||
(key->state & EphyrKeybindToggleHostGrabModMask) ==
|
||||
EphyrKeybindToggleHostGrabModMask
|
||||
) && (
|
||||
/* NOTE: mod-key keysyms are > 0xfe00. We do this so when the
|
||||
shortcut is only mod-keys (e.g. ctrl+shift) and the user
|
||||
releases any other key, input doesn't get grabbed */
|
||||
(EphyrKeybindToggleHostGrabKey == 0 && keysym > 0xfe00) ||
|
||||
keysym == EphyrKeybindToggleHostGrabKey
|
||||
)
|
||||
) {
|
||||
KdScreenInfo *screen = screen_from_window(key->event);
|
||||
assert(screen);
|
||||
EphyrScrPriv *scrpriv = screen->driver;
|
||||
|
@ -1043,10 +1165,8 @@ ephyrProcessKeyRelease(xcb_generic_event_t *xev)
|
|||
xcb_ungrab_keyboard(conn, XCB_TIME_CURRENT_TIME);
|
||||
xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME);
|
||||
grabbed_screen = -1;
|
||||
hostx_set_win_title(screen,
|
||||
"(ctrl+shift grabs mouse and keyboard)");
|
||||
}
|
||||
else if (!mod1_down) {
|
||||
else {
|
||||
/* Attempt grab */
|
||||
xcb_grab_keyboard_cookie_t kbgrabc =
|
||||
xcb_grab_keyboard(conn,
|
||||
|
@ -1079,12 +1199,11 @@ ephyrProcessKeyRelease(xcb_generic_event_t *xev)
|
|||
XCB_TIME_CURRENT_TIME);
|
||||
} else {
|
||||
grabbed_screen = scrpriv->mynum;
|
||||
hostx_set_win_title
|
||||
(screen,
|
||||
"(ctrl+shift releases mouse and keyboard)");
|
||||
}
|
||||
}
|
||||
}
|
||||
ephyrUpdateWindowTitle(screen, grabbed_screen != -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ephyrKbd ||
|
||||
|
|
|
@ -167,6 +167,14 @@ Bool
|
|||
Bool
|
||||
ephyrCreateColormap(ColormapPtr pmap);
|
||||
|
||||
/**
|
||||
* @param desc examples: "ctrl+shift", "ctrl+mod1+a", "a",
|
||||
* NULL (disables host grab)
|
||||
* @return TRUE if success, otherwise FALSE
|
||||
*/
|
||||
Bool
|
||||
ephyrSetGrabShortcut(char const* const desc);
|
||||
|
||||
#ifdef RANDR
|
||||
Bool
|
||||
ephyrRandRGetInfo(ScreenPtr pScreen, Rotation * rotations);
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
extern Window EphyrPreExistingHostWin;
|
||||
extern Bool EphyrWantGrayScale;
|
||||
extern Bool EphyrWantResize;
|
||||
extern Bool EphyrWantNoHostGrab;
|
||||
extern Bool kdHasPointer;
|
||||
extern Bool kdHasKbd;
|
||||
extern Bool ephyr_glamor, ephyr_glamor_gles2, ephyr_glamor_skip_present;
|
||||
|
@ -144,6 +143,8 @@ ddxUseMsg(void)
|
|||
ErrorF
|
||||
("-title [title] set the window title in the WM_NAME property\n");
|
||||
ErrorF("-no-host-grab Disable grabbing the keyboard and mouse.\n");
|
||||
ErrorF
|
||||
("-host-grab [keys] set shortcut to grab the keyboard and mouse (default: ctrl+shift)\n");
|
||||
ErrorF("\n");
|
||||
}
|
||||
|
||||
|
@ -343,9 +344,21 @@ ddxProcessArgument(int argc, char **argv, int i)
|
|||
}
|
||||
/* end Xnest compat */
|
||||
else if (!strcmp(argv[i], "-no-host-grab")) {
|
||||
EphyrWantNoHostGrab = 1;
|
||||
ephyrSetGrabShortcut(NULL);
|
||||
return 1;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-host-grab")) {
|
||||
if (i + 1 >= argc) {
|
||||
ErrorF(
|
||||
"ephyr: -host-grab requires an argument e.g. ctrl+shift+x\n");
|
||||
exit(1);
|
||||
}
|
||||
else if (!ephyrSetGrabShortcut(argv[i + 1])) {
|
||||
/* specific error message is printed in ephyrSetGrabShortcut */
|
||||
exit(1);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-sharevts") ||
|
||||
!strcmp(argv[i], "-novtswitch")) {
|
||||
return 1;
|
||||
|
|
|
@ -67,6 +67,31 @@ window. By default, the Xephyr window has a fixed size.
|
|||
.TP 8
|
||||
.B \-no\-host\-grab
|
||||
Disable grabbing the keyboard and mouse.
|
||||
.TP 8
|
||||
.BI \-host\-grab " keys"
|
||||
Set the keyboard shortcut for Xephyr to grab keyboard and mouse
|
||||
input. Possible values for mod-keys are: ctrl, shift, lock,
|
||||
mod1, mod2, mod3, mod4, mod5. Up to one ascii character (lower-case) can
|
||||
be used by itself or in conjunction with mod-keys. Keys are concatenated
|
||||
with
|
||||
.I +\fP. If omitted, defaults to
|
||||
.I ctrl+shift\fP.
|
||||
|
||||
Examples:
|
||||
.RS
|
||||
.IP \[bu] 2
|
||||
.I ctrl+mod1
|
||||
.IP \[bu] 2
|
||||
.I ctrl+shift++
|
||||
(note that the
|
||||
.I +
|
||||
at the end is interpreted as the ascii character '+')
|
||||
.IP \[bu] 2
|
||||
.I a
|
||||
(mod-keys are optional, this will grab/release whenever the
|
||||
.I a
|
||||
key is pressed)
|
||||
.RE
|
||||
.SH "SIGNALS"
|
||||
Send a SIGUSR1 to the server (e.g. pkill \-USR1 Xephyr) to
|
||||
toggle the debugging mode.
|
||||
|
|
Loading…
Reference in New Issue