Posts

  • Remap Enter to Control in GNU/Linux (2020 Edition)

    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 Enter to Control was no longer the optimal way to achieve this (e.g. - xcape operates 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 interception framework and dual-function-keys:

    # 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 - Enter acts as Enter on tap (when pressed briefly) and as (right) Control when held down longer.

    Then we need to create /etc/udevmon.yaml (you’ll need sudo for this):

    # /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 .dual-function-keys.yaml accordingly.

    Finally we need to create a systemd service definition file for udevmon and 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 udevmon service 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!

    Alternatives

    Another option I considered was xkeysnail, which seemed a bit simpler to setup, as it’s written in Python, and even has an example config geared towards Emacs users. You might want to check it out.

    If someone’s using another approach to achieve the same result I’d love to hear about it!

    1. Seems currently it’s only packaged for Arch Linux and family (e.g. Manjaro). 

  • Weird Emacs: Listy Lambdas

    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))
    

    marker could be both a function or a list and this if covers both cases. It works fine if marker is something defined with defun, but blows up for lambdas, as listp returns t for 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 functionp check first.

    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!

  • Checking the Major Mode in Emacs Lisp

    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-mode that you can check directly. If you evaluate the symbol major-mode in a scratch buffer or an Emacs Lisp REPL (M-x ielm), you’ll get list-interaction-mode and inferior-emacs-lisp-mode. You can easily do this for any buffer by pressing M-: (M-x eval-expression) and typing major-mode in 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-buffer to something? As it’s a symbol, the first thing that comes to mind is using eq:

    (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 clojurescript-mode and clojurec-mode, and it inherits from prog-mode (which is the parent mode of most programming major modes). Enter derived-mode-p:

    ;; 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-p understands 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 eq used when derived-mode-p would 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!

  • Comment Commands Redux

    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 2.1

    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 vterm (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.

Subscribe via RSS | View Older Posts