1

I currently use slock to lock the screen. It intercepts all keystrokes, preventing them from reaching the window manager (in my case Fluxbox). This is a good thing.

However, I want to be able to use a particular custom-defined keyboard shortcut even when the screen is locked (without unlocking the screen). The shortcut runs a script that I wrote.

I considered modifying slock's source code to hardcode the shortcut. However, it is not totally trivial because slock runs setuid. I hope that there is a ready-made solution.

(The solution can involve switching a screen locker; I am not set on slock.)

  • 1
    You might look at whether evtest is still able to read events from /dev/input/event... while slock is running. – meuh Oct 17 '17 at 18:06
  • @meuh Yes, it is able. Interesting. As far as I can tell, this does not offer a solution by itself since it requires root privileges to run. I think I will go with PawkyPenguin's solution. – Boris Bukh Oct 18 '17 at 12:59
2

Unfortunately, you'll have to hardcode such a keyboard shortcut. Screenlockers always grab control of the keyboard, meaning they are the only running X client that get the keypresses. If they didn't do that, it would mean that other applications would receive keypresses which is the exact thing you wouldn't want to happen with a keylocker. The grabbing happens with the XGrabKeyboard function that is implemented in Xlib (which is the library that slock uses). In general, Xlib is pretty well-documented and you probably even have manpages installed for it if you're interested - for example man XGrabKeyboard. The other manpages are similarly prefixed with "X" for various other library functions.

As far as I understand, you're worried that setuid messes up your script, right? If so, my first instinct would be to fork() slock on startup and probably use pipes to communicate between parent and child. Looking at the source code, you could probably fork on line 340 or so (before the setuid and set up a pipe. Once you have programmed your shortcut, you can use the pipe to communicate between parent and child. Essentially all you would have to do is send a message that lets the child, resp. parent know when to execute your own script. Pipes are fairly easy in C, so they are suitable if you don't want to fiddle with the implementation too much. Here's a full pipe example taken from this site:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
        int     fd[2], nbytes;
        pid_t   childpid;
        char    string[] = "Hello, world!\n";
        char    readbuffer[80];

        pipe(fd);

        if((childpid = fork()) == -1)
        {
                perror("fork");
                exit(1);
        }

        if(childpid == 0)
        {
                /* Child process closes up input side of pipe */
                close(fd[0]);

                /* Send "string" through the output side of pipe */
                write(fd[1], string, (strlen(string)+1));
                exit(0);
        }
        else
        {
                /* Parent process closes up output side of pipe */
                close(fd[1]);

                /* Read in a string from the pipe */
                nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
                printf("Received string: %s", readbuffer);
        }

        return(0);
}
  • Thanks for the suggestion. Fork, then in the child set effective uid to to real uid (=drop priveledge) and then use pipe to communicate. Yep. If no better solution comes along, I will accept your answer. (There is no elegant way to intercept keystrokes before they reach the X server, right? Was there really no way to set global keyboard shortcuts before X came along?) – Boris Bukh Oct 17 '17 at 13:49
  • I have implemented your solution. It is a hack, but it works. – Boris Bukh Nov 22 '17 at 17:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.