i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
commit 4ff79c0e8f8ee119c7533641ecc85d2a9693563b
parent 8da502a4a20b691f8bd616b965322b0f15c03fb8
Author: Raymond Li <hi@raymond.li>
Date:   Mon,  9 Aug 2021 17:55:48 -0400

Merge pull request #231 from JezerM/passKeys

--pass-*-keys options (#136)
Diffstat:
M.github/workflows/Build Test.yml | 2+-
M.github/workflows/codeql-analysis.yml | 2+-
MREADME.md | 4++--
Mconfigure.ac | 2+-
Mi3lock.1 | 12++++++++++++
Mi3lock.c | 41+++++++++++++++++++++++++++++++++++++----
6 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/Build Test.yml b/.github/workflows/Build Test.yml
@@ -9,7 +9,7 @@ jobs:
     - name: Install deps
       run: |
         sudo apt update
-        sudo apt install pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util-dev libxcb-xrm-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
+        sudo apt install pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util-dev libxcb-xrm-dev libxcb-xtest0-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
     - name: Build
       run: ./build.sh
     - name: Check and distcheck
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
@@ -66,7 +66,7 @@ jobs:
 
     - run: |
         sudo apt-get update
-        sudo apt install autoconf gcc make pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util-dev libxcb-xrm-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
+        sudo apt install autoconf gcc make pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util-dev libxcb-xrm-dev libxcb-xtest0-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
         ./build.sh
 
     - name: Perform CodeQL Analysis
diff --git a/README.md b/README.md
@@ -81,7 +81,7 @@ The following dependencies will need to be installed for a successful build, dep
 ### Debian
 Run this command to install all dependencies:
 ```
-sudo apt install autoconf gcc make pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util0-dev libxcb-xrm-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
+sudo apt install autoconf gcc make pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util0-dev libxcb-xrm-dev libxcb-xtest0-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
 ```
 If you still see missing packages during build after installing all of these dependencies, try following the steps [here](https://github.com/Raymo111/i3lock-color/issues/211#issuecomment-809891727).
 
@@ -95,7 +95,7 @@ sudo dnf install -y autoconf automake cairo-devel fontconfig gcc libev-devel lib
 ### Ubuntu 18/20.04 LTS
 Run this command to install all dependencies:
 ```
-sudo apt install autoconf gcc make pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util-dev libxcb-xrm-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
+sudo apt install autoconf gcc make pkg-config libpam0g-dev libcairo2-dev libfontconfig1-dev libxcb-composite0-dev libev-dev libx11-xcb-dev libxcb-xkb-dev libxcb-xinerama0-dev libxcb-randr0-dev libxcb-image0-dev libxcb-util-dev libxcb-xrm-dev libxcb-xtest0-dev libxkbcommon-dev libxkbcommon-x11-dev libjpeg-dev
 ```
 
 ## Building i3lock-color
diff --git a/configure.ac b/configure.ac
@@ -97,7 +97,7 @@ AC_SEARCH_LIBS([iconv_open], [iconv], , [AC_MSG_FAILURE([cannot find the require
 
 dnl Each prefix corresponds to a source tarball which users might have
 dnl downloaded in a newer version and would like to overwrite.
-PKG_CHECK_MODULES([XCB], [xcb xcb-xkb xcb-xinerama xcb-randr xcb-composite])
+PKG_CHECK_MODULES([XCB], [xcb xcb-xkb xcb-xinerama xcb-randr xcb-composite xcb-xtest])
 PKG_CHECK_MODULES([XCB_IMAGE], [xcb-image])
 PKG_CHECK_MODULES([XCB_UTIL], [xcb-event xcb-util xcb-atom])
 PKG_CHECK_MODULES([XCB_UTIL_XRM], [xcb-xrm])
diff --git a/i3lock.1 b/i3lock.1
@@ -389,6 +389,18 @@ volume - XF86AudioMute, XF86AudioLowerVolume, XF86AudioRaiseVolume
 .RE
 
 .TP
+.B \-\-special\-passthrough
+Allows special keys to pass through the locked screen, with \-\-pass\-{media, screen,
+power, volume}\-keys. Keystrokes are forcibly sent to the window manager or desktop
+environment in three steps: un-grab keyboard, send key, and re-grab the keyboard.
+No other keys will be sent to the WM/DE.
+
+Note: ONLY use this option if the special keys are NOT passed through without it.
+This could be less safe than the default behavior since the keyboard is ungrabbed for
+the keys to be passed through. This HAS been tested though, so there SHOULDN'T be any
+security issues.
+
+.TP
 .B \-\-bar\-indicator
 Replaces the usual ring indicator with a bar indicator. Comes with perks.
 
diff --git a/i3lock.c b/i3lock.c
@@ -49,6 +49,8 @@
 #endif
 #include <xcb/xcb_aux.h>
 #include <xcb/randr.h>
+#include <xcb/xtest.h>
+#include <time.h>
 
 #include "i3lock.h"
 #include "xcb.h"
@@ -257,6 +259,7 @@ bool pass_media_keys = false;
 bool pass_screen_keys = false;
 bool pass_power_keys = false;
 bool pass_volume_keys = false;
+bool special_passthrough = false;
 
 // for the rendering thread, so we can clean it up
 pthread_t draw_thread;
@@ -651,6 +654,32 @@ static bool skip_without_validation(void) {
 }
 
 /*
+ * Sends key press event to root/wm
+ * Releases the keyboard, sends the event, and
+ * grabs the keyboard again
+ * */
+static void send_key_to_root(xcb_key_press_event_t *event, bool twice) {
+    if (!special_passthrough) {
+        xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
+        return;
+    }
+
+    xcb_ungrab_keyboard(conn, XCB_CURRENT_TIME);
+    DEBUG("Received: %d at %ld\n", event->detail, time(0));
+
+    xcb_test_fake_input(conn, XCB_KEY_PRESS, event->detail, XCB_CURRENT_TIME, screen->root, 0, 0, 0);
+    xcb_test_fake_input(conn, XCB_KEY_RELEASE, event->detail, XCB_CURRENT_TIME, screen->root, 0, 0, 0);
+
+    if (twice) {
+        xcb_test_fake_input(conn, XCB_KEY_PRESS, event->detail, XCB_CURRENT_TIME, screen->root, 0, 0, 0);
+        xcb_test_fake_input(conn, XCB_KEY_RELEASE, event->detail, XCB_CURRENT_TIME, screen->root, 0, 0, 0);
+    }
+
+    xcb_grab_keyboard(conn, true, screen->root, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+    xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, win, XCB_CURRENT_TIME);
+}
+
+/*
  * Handle key presses. Fixes state, then looks up the key symbol for the
  * given keycode, then looks up the key symbol (as UCS-2), converts it to
  * UTF-8 and stores it in the password array.
@@ -709,7 +738,7 @@ static void handle_key_press(xcb_key_press_event_t *event) {
             case XKB_KEY_XF86AudioMute:
             case XKB_KEY_XF86AudioLowerVolume:
             case XKB_KEY_XF86AudioRaiseVolume:
-                xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
+                send_key_to_root(event, true);
                 return;
         }
     }
@@ -719,7 +748,7 @@ static void handle_key_press(xcb_key_press_event_t *event) {
         switch(ksym) {
             case XKB_KEY_XF86MonBrightnessUp:
             case XKB_KEY_XF86MonBrightnessDown:
-                xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
+                send_key_to_root(event, false);
                 return;
         }
     }
@@ -730,7 +759,7 @@ static void handle_key_press(xcb_key_press_event_t *event) {
             case XKB_KEY_XF86PowerDown:
             case XKB_KEY_XF86PowerOff:
             case XKB_KEY_XF86Sleep:
-                xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
+                send_key_to_root(event, false);
                 return;
         }
     }
@@ -741,7 +770,7 @@ static void handle_key_press(xcb_key_press_event_t *event) {
             case XKB_KEY_XF86AudioMute:
             case XKB_KEY_XF86AudioLowerVolume:
             case XKB_KEY_XF86AudioRaiseVolume:
-                xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
+                send_key_to_root(event, true);
                 return;
         }
     }
@@ -1543,6 +1572,7 @@ int main(int argc, char *argv[]) {
         {"pass-screen-keys", no_argument, NULL, 602},
         {"pass-power-keys", no_argument, NULL, 603},
         {"pass-volume-keys", no_argument, NULL, 604},
+        {"special-passthrough", no_argument, NULL, 605},
 
         // bar indicator stuff
         {"bar-indicator", no_argument, NULL, 700},
@@ -2104,6 +2134,9 @@ int main(int argc, char *argv[]) {
             case 604:
                 pass_volume_keys = true;
                 break;
+            case 605:
+                special_passthrough = true;
+                break;
 
             // Bar indicator
             case 700: