The discontinuation of support for xneur has caused me some distress over the past six months. (with the introduction of OpenSUSE 15.1 on my desktops: when xneur is enabled, windows lose focus and amusingly flicker in sync with keyboard input).
"Ah, damn, I started typing in the wrong layout again" — this happens to me alarmingly often at work. It doesn't add any positivity.

At the same time, I (as a design engineer) can clearly articulate what I want. And what I wanted (first from Punto Switcher, and then, thanks to Windows Vista, finally switching to Linux, from xneur) was just one thing. Realizing that the screen is filled with nonsense in the wrong layout (this usually occurs at the end of typing a new word), I want to hit 'Pause/Break'. And get what I was typing.
Currently, the product has an optimal (from my perspective) functionality/complexity ratio. It's time to share.
TL;DR
Next will be some technical details, so first — for the impatient.
At the moment, the following behavior is hardcoded:
- "Pause/Break": deletes (Backspace) the last word, switches the layout in the active window (between 0 and 1) and types again.
- "Left Ctrl without anything": switches the layout in the active window (between 0 and 1).
- "Left Shift without anything": enables layout #0 in the active window.
- "Right Shift without anything": enables layout #1 in the active window.
From this moment, I plan to customize the behavior. Without feedback — it's not interesting (I'm already satisfied). I believe there will be a sufficient percentage of the audience on Habr with similar problems.
N.B. Since in the current version the keylogger is attached to "/dev/input/", xswitcher must be run with root privileges:
chown root:root xswitcher
chmod +xs xswitcherPlease note: the file with suid must be owned by root, as whoever is the owner will turn it into suid upon execution.
Paranoids (I am no exception) can clone from and build on site. Something like this:
go get "github.com/micmonay/keybd_event"
go get "github.com/gvalkov/golang-evdev"
### X11 headers for OpenSUSE/deb-based
zypper install libX11-devel libXmu-devel
apt-get install libx11-dev libxmu-dev
cd "x switcher/src/"
go build -o xswitcher -ldflags "-s -w" --tags static_all src/*.go
Add autostart as desired (depending on DE).
Works, "doesn't ask for porridge" (≈30 seconds CPU per day, ≈12 MB in RSS).
Details
Now — details.
The entire repository was initially dedicated to my pet project, and I'm too lazy to start another one for now. So everything is piled up (just in folders) and covered by AGPL (the 'reverse patent').
The xswitcher code is written in golang, with minimal C integrations. This approach is expected to require the least labor (and so far it has). It maintains the ability to connect missing parts through cgo.
The text includes comments explaining where I borrowed various elements from and why. Since the xneur code did not 'inspire me', I used .
Using "/dev/input/" has its pros (everything is visible, including the pressed key with auto-repeat) and cons. The cons are as follows:
- Auto-repeat (events with code '2') does not correlate with repeats from X.
- Input via X11 interfaces is not visible (as VNC operates, for example).
- Root access is required.
On the other hand, you can subscribe to X events through 'XSelectExtensionEvent()'. You can see this in the . I didn't find a similar solution for go, and the draft implementation produced an immediate hundred lines of C code. For now, I've put it aside.
The 'reverse' output has been done by attaching a virtual keyboard. Thanks to the author of keybd_event, but that's a very high-level abstraction, and I'll have to redo it later. For example, my right Win key selects the third row. The left Win key is the only one that translates back.
Known issues
- We don't know anything about 'composite' input (e.g., ½). It isn't needed right now.
- The right Win is incorrectly reproduced. In my case, it breaks the placement of accents.
- There is no clear analysis of input. Instead, there are several functions: Compare(), CtrlSequence(), RepeatSequence(), SpaceSequence(). Thank you for your attention: I fixed it in the code and here. With a certain probability, bugs can be caught during replacement.
At this point, I don't know 'how it's supposed to be' and I would welcome any suggestions. - (Oh horror) concurrent use of channels (keyboardEvents, miceEvents).
Conclusion
The code is the simplest procedural one. And as blunt as I am. So I comfort myself with the hope that any technician can complete the desired features. This product thus won't vanish without support like most just-for-fun projects.
Good luck!
Source: habr.com
