Note: Check out my original article from 2013 about the rationale behind this remapping.
Recently I’ve switched back from macOS to GNU/Linux, as my primary development environment, and I found out that my old article on remapping
Controlwas no longer the optimal way to achieve this (e.g. -
xcapeoperates at the X level, which means it doesn’t work with Wayland or without a GUI). It took me a bit of digging, but eventually I found dual-function-keys (a plugin for the interception framework), which does exactly what I needed and it does it splendidly.
Unfortunately, the tool is not packaged for most GNU/Linux distros1, but setting it up from source is not that complex. In this article I’ll share instructions that are specific to Ubuntu, but they should be easy to modify for other Linux distros.
Let’s kick it off by downloading and installing the
# install build deps $ sudo apt install libudev-dev libyaml-cpp-dev libevdev-dev cmake # create a folder where to clone the source code $ mkdir src && cd src # clone the necessary code $ git clone https://gitlab.com/interception/linux/tools $ git clone https://gitlab.com/interception/linux/plugins/dual-function-keys # build and install the interception framework $ cd tools $ mkdir build $ cd build $ cmake .. $ make $ sudo make install $ cd ../.. # build the dual-function-keys plugin $ cd dual-functions-keys $ make && sudo make install
That wasn’t so hard, right? Now we have to create a couple of configuration files and we’re ready for action. The first one is
.dual-function-keys.yaml(normally placed in your home folder):
# /home/username/.dual-function-keys.yaml TIMING: TAP_MILLISEC: 200 DOUBLE_TAP_MILLISEC: 150 MAPPINGS: - KEY: KEY_ENTER TAP: KEY_ENTER HOLD: KEY_RIGHTCTRL
That’s the main config for
dual-function-keys, where we’re specifying the duration of a tap and double tap and our remapping rules. In our case there’s a single rule -
Enteron tap (when pressed briefly) and as (right)
Controlwhen held down longer.
Then we need to create
# /etc/udevmon.yaml - JOB: "intercept -g $DEVNODE | dual-function-keys -c /home/bozhidar/.dual-function-keys.yaml | uinput -d $DEVNODE" DEVICE: EVENTS: EV_KEY: [KEY_ENTER]
Note: Update the path the
Finally we need to create a
systemdservice definition file for
udevmonand start the new service:
# /etc/systemd/system/udevmon.service [Unit] Description=udevmon Wants=systemd-udev-settle.service After=systemd-udev-settle.service [Service] ExecStart=/usr/bin/nice -n -20 /usr/local/bin/udevmon -c /etc/udevmon.yaml [Install] WantedBy=multi-user.target
Now we simply have to enable the
udevmonservice our remapping will kick in:
$ sudo systemctl enable --now udevmon
That’s all! Now you can start enjoying your beloved productivity boost!
You can achieve a lot more with
dual-function-keys, so I’d advice you to explore the tool further. Keep hacking!
If someone’s using another approach to achieve the same result I’d love to hear about it!
Seems currently it’s only packaged for Arch Linux and family (e.g. Manjaro). ↩
I guess everyone who has spent any time with Emacs Lisp, knows that the language is full of oddities and quirks. That’s often a source of frustration for people coming from other languages, but it’s part of Emacs’s charm. Even after 15 years with Emacs and working on numerous Emacs packages, I still find things that manage to surprise me in Emacs Lisp. Consider the following:
(functionp (lambda (x) "I don't do much")) ;; => t (functionp '(1 2 3)) ;; => nil (listp (lambda (x) "I don't do much")) ;; => t (listp '(1 2 3)) ;; => t
Turns out lambdas are both functions and lists! Weird, right?
I learned this yesterday, when someone reported a bug in Projectile triggered by the following code:
(if (listp marker) (and (projectile-verify-files marker) project-type) (and (funcall marker) project-type))
markercould be both a function or a list and this
ifcovers both cases. It works fine if
markeris something defined with
defun, but blows up for lambdas, as
tfor them. The solution to the bug was pretty simple:
(if (functionp marker) (and (funcall marker) project-type) (and (projectile-verify-files marker) project-type))
I guess that’s the lesson from today’s post - if something can be both a lambda and list, you definitely want to have the
That’s all I have for you today. Keep hacking!
P.S. Feel free to share your favourite weird things about Emacs Lisp in the comments!
Often when working on some Emacs package you’d want to create some logic that’s conditional on the major mode of a particular Emacs buffer. There are several ways check the major mode, but some are definitely better than others.
Every buffer has a buffer-local variable named
major-modethat you can check directly. If you evaluate the symbol
major-modein a scratch buffer or an Emacs Lisp REPL (
M-x ielm), you’ll get
inferior-emacs-lisp-mode. You can easily do this for any buffer by pressing
M-x eval-expression) and typing
major-modein the minibuffer when prompted to do so. Making this a bit more generic can easily obtain the major mode of any buffer like this:
;; option 1 (with-current-buffer buffer major-mode) ;; option 2 (buffer-local-value 'major-mode buffer)
So, how would you compare
major-bufferto something? As it’s a symbol, the first thing that comes to mind is using
(if (eq major-mode 'clojure-mode) (do-something))
While this generally works, there’s one subtle problem with it - you’re doing an exact match for a particular mode, but major modes can be inherited by other modes. Consider
clojure-mode- it’s the parent of modes like
clojurec-mode, and it inherits from
prog-mode(which is the parent mode of most programming major modes). Enter
;; assuming we're in a ClojureScript buffer and the current major mode is clojurescript-mode (derived-mode-p 'clojurescript-mode) ;; => t (derived-mode-p 'clojure-mode) ;; => t (derived-mode-p 'prog-mode) ;; => t
As you can see from the examples above,
derived-mode-punderstands the major mode inheritance hierarchy, which makes it the best solution for most cases when you’d want to do something depending on the major mode. Unfortunately I’ve seen too many times
derived-mode-pwould be a better option, which is why I decided to write this short article.
That’s all I’ve had for you today! Keep hacking!
Comments are an important aspect of every programming language and dealing with them effectively is an useful skill.
Emacs offers a bunch of comment-related commands and in this post we’re going to examine them.Read More
Projectile had a pretty quiet year since the massive amount of work that lead to the release of Projectile 2.0 early last year. These days Projectile is both quite mature and feature-full, so there wasn’t really any burning need to add anything new. Still, there’s always some room for improvement. Enter the recently released Projectile 2.1.
The focus in Projectile 2.1 was bug-fixes and small improvements here and there. There’s no few functionality worth highlighting, other than the addition of basic integration with
projectile-run-vterm). You can read all about the changes in the release notes.
Most likely in the future the focus is going to remain on polishing the existing functionality (e.g. bug-fixes, performance improvements) as opposed to adding more features. There are plenty of open issues and help from anyone would be most welcome!
There’s also a lot of work to be done on the documentation side. After launching https://docs.projectile.mx the content there has stayed mostly the same and there’s certainly a lot of ground to cover. At the very least I want to add some animated gifs to the manual this year, so it’s easier for people to understand how to use certain commands.
That’s all I have for you today. I hope you’ll enjoy the latest Projectile. Until next time!
P.S. You can now support my work on Projectile via GitHub Sponsors.