Skip to content

Instantly share code, notes, and snippets.

@twaik
Created October 22, 2021 18:16
Show Gist options
  • Save twaik/1d04482c4dc5e92ecadbf6e0e2eeb54d to your computer and use it in GitHub Desktop.
Save twaik/1d04482c4dc5e92ecadbf6e0e2eeb54d to your computer and use it in GitHub Desktop.
Restore showing Application Menu with Super key using libinput. Needs a user to be in `input` group. Based on `libinput-debug-events.c` code.
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
// gcc -o libinput-superkey-menu libinput-superkey-menu.c -linput `pkg-config libevdev --libs --cflags` -ludev
#include <errno.h>
#include <inttypes.h>
#include <getopt.h>
#include <poll.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <linux/input.h>
#include <libinput.h>
#include <libevdev/libevdev.h>
static uint32_t start_time;
static const uint32_t screen_width = 100;
static const uint32_t screen_height = 100;
static bool show_keycodes;
static volatile sig_atomic_t stop = 0;
static bool be_quiet = false;
#define printq(...) ({ if (!be_quiet) printf(__VA_ARGS__); })
static void
print_key_event(struct libinput_event *ev)
{
struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
enum libinput_key_state state;
uint32_t key;
const char *keyname;
state = libinput_event_keyboard_get_key_state(k);
key = libinput_event_keyboard_get_key(k);
if (!show_keycodes && (key >= KEY_ESC && key < KEY_ZENKAKUHANKAKU)) {
keyname = "***";
key = -1;
} else {
keyname = libevdev_event_code_get_name(EV_KEY, key);
keyname = keyname ? keyname : "???";
}
printq("%s (%d) %s\n",
keyname,
key,
state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released");
}
static bool leftmeta_pressed = false;
static int
handle_and_print_events(struct libinput *li)
{
int rc = -1;
struct libinput_event *ev;
libinput_dispatch(li);
while ((ev = libinput_get_event(li))) {
enum libinput_event_type type = libinput_event_get_type(ev);
if (type != LIBINPUT_EVENT_KEYBOARD_KEY)
continue;
struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
uint32_t key = libinput_event_keyboard_get_key(k);
enum libinput_key_state state = libinput_event_keyboard_get_key_state(k);
if (key == KEY_LEFTMETA && state == LIBINPUT_KEY_STATE_RELEASED &&
leftmeta_pressed)
system("qdbus org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.activateLauncherMenu");
leftmeta_pressed = (key == KEY_LEFTMETA && state == LIBINPUT_KEY_STATE_PRESSED);
libinput_event_destroy(ev);
rc = 0;
}
return rc;
}
static void
sighandler(int signal, siginfo_t *siginfo, void *userdata)
{
stop = 1;
}
static void
mainloop(struct libinput *li)
{
struct pollfd fds;
fds.fd = libinput_get_fd(li);
fds.events = POLLIN;
fds.revents = 0;
/* Handle already-pending device added events */
handle_and_print_events(li);
/* time offset starts with our first received event */
if (poll(&fds, 1, -1) > -1) {
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
start_time = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
do {
handle_and_print_events(li);
} while (!stop && poll(&fds, 1, -1) > -1);
}
printf("\n");
}
static void
usage(void) {
printf("Usage: libinput debug-events [options] [--udev <seat>|--device /dev/input/event0 ...]\n");
}
static int
open_restricted(const char *path, int flags, void *user_data)
{
bool *grab = user_data;
int fd = open(path, flags);
if (fd < 0)
fprintf(stderr, "Failed to open %s (%s)\n",
path, strerror(errno));
else if (grab && *grab && ioctl(fd, EVIOCGRAB, (void*)1) == -1)
fprintf(stderr, "Grab requested, but failed for %s (%s)\n",
path, strerror(errno));
return fd < 0 ? -errno : fd;
}
static void
close_restricted(int fd, void *user_data)
{
close(fd);
}
static const struct libinput_interface interface = {
.open_restricted = open_restricted,
.close_restricted = close_restricted,
};
static struct libinput *
tools_open_udev(const char *seat, bool verbose)
{
struct libinput *li;
struct udev *udev = udev_new();
if (!udev) {
fprintf(stderr, "Failed to initialize udev\n");
return NULL;
}
bool grab = false;
li = libinput_udev_create_context(&interface, &grab, udev);
if (!li) {
fprintf(stderr, "Failed to initialize context from udev\n");
goto out;
}
if (libinput_udev_assign_seat(li, seat)) {
fprintf(stderr, "Failed to set seat\n");
libinput_unref(li);
li = NULL;
goto out;
}
out:
udev_unref(udev);
return li;
}
int
main(int argc, char **argv)
{
struct libinput *li;
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGINT, &act, NULL) == -1) {
fprintf(stderr, "Failed to set up signal handling (%s)\n",
strerror(errno));
return EXIT_FAILURE;
}
li = tools_open_udev("seat0", false);
if (!li)
return EXIT_FAILURE;
mainloop(li);
libinput_unref(li);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment