Skip to content

Instantly share code, notes, and snippets.

@CyberShadow
Created March 30, 2016 17:55
Show Gist options
  • Save CyberShadow/6412d11aea64144f8905cc0b8196f38e to your computer and use it in GitHub Desktop.
Save CyberShadow/6412d11aea64144f8905cc0b8196f38e to your computer and use it in GitHub Desktop.
#!/bin/env rdmd
module xorg_show_grabs;
import std.algorithm;
import std.conv;
import std.exception;
import std.getopt;
import std.stdio;
import std.string;
void main(string[] args)
{
const defaultLogFileName = "/var/log/Xorg.0.log";
string logFileName = defaultLogFileName;
auto help = getopt(args,
"xorg-log", "Path to the Xorg log file, by default: " ~ defaultLogFileName, &logFileName,
);
if (help.helpWanted)
return defaultGetoptPrinter("xorg-show-grabs - Extract and display key grabs from Xorg log in a human-readable way.
Usage:
1. Run:
xdotool key XF86LogGrabInfo
2. Run this program.
Options:
",
help.options);
bool[string][string] results;
string currentClient;
bool currentGrab;
int currentKey, currentMod;
foreach (l; File(logFileName).byLine())
{
auto line = l.findSplit("] ")[2];
if (!line.length)
continue;
if (line == "Printing all currently registered grabs")
results = null;
else
if (line.skipOver(" Printing all registered grabs of client pid "))
currentClient = line.idup.strip();
else
if (line.skipOver(" grab "))
{
currentGrab = false;
line.skipUntil(' ');
if (!line.startsWith("(core), type 'KeyPress' on window "))
continue;
currentGrab = true;
}
else
if (line.skipOver(" device "))
{
if (!line.startsWith("'Virtual core keyboard' ("))
currentGrab = false;
}
else
if (line.skipOver(" detail "))
{
currentKey = line.skipUntil(' ').to!int;
if (!line.skipOver("(mask 0), modifiersDetail "))
continue;
currentMod = line.skipUntil(' ').to!int;
}
else
if (line.skipOver(" owner-events "))
{
if (currentGrab)
{
auto key = xModToString(currentMod)~xKeyToString(currentKey);
results[currentClient][key] = true;
currentGrab = false;
}
}
}
foreach (client; results.keys.sort())
{
writefln("%s:", client);
foreach (key; results[client].keys.sort())
writefln(" %s", key);
}
}
auto skipUntil(T)(ref T[] s, T c)
{
auto i = s.indexOf(c);
if (i < 0)
{
s = null;
return null;
}
auto result = s[0..i];
s = s[i+1..$];
return result;
}
pragma(lib, "X11");
import core.stdc.config;
struct Display;
alias KeyCode = ubyte;
alias KeySym = c_ulong;
extern(C) Display* XOpenDisplay(const(char)*);
extern(C) KeySym XkbKeycodeToKeysym(Display *dpy, KeyCode kc, uint group, uint level);
extern(C) char* XKeysymToString(KeySym);
string xKeyToString(int key)
{
static Display *dpy = null;
if (!dpy)
dpy = enforce(XOpenDisplay(":0"), "Can't open display!");
KeySym ks = XkbKeycodeToKeysym(dpy, cast(ubyte)key, 0, 0);
return XKeysymToString(ks).to!string();
}
string xModToString(int mod)
{
// 1 2 4 8 0x10 0x20 0x40 0x80
//const string[] names = [ "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5"];
//const string[] names = [ "Shift", "Lock", "Control", "Alt" , "Mod2", "Mod3", "Win" , "Mod5"];
const string[] names = [ "Shift", "Lock", "Control", "Mod1(Alt)" , "Mod2", "Mod3", "Mod4(Win)" ,"Mod5"];
string result;
foreach (i, name; names)
if ((1<<i) & mod)
result ~= name ~ " + ";
return result;
}
@dpflug
Copy link

dpflug commented Mar 20, 2025

On Arch / Manjaro, gdc unfortunately does not build anymore

In case anyone else ends up here, that's because the lto plugin was folded into gdc. You just leave that one off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment