‘The half minute which we daily devote to the winding-up of our watches is an exertion of labour almost insensible; yet, by the aid of a few wheels, its effect is spread over the whole twenty-four hours.’

Using Emacs and Org-Roam/Org-Node on Android (with Termux Extra Keys)

Benjamin Slade

My main use of Emacs on Android (via Termux) is to be able to access and add to my Org-roam library of notes: to have access to a second brain while not at a proper computer. And this post is primarily about some Termux features which improve the experience for this use case.

Trying to Cope with Emacs on mobile #

I’ve tried a number of different solutions for managing sync’ed Org files on mobile1, and some of these are useful for some purposes, but to being able to access and add to my Org-Roam notes, I’ve found I really need a full-blooded Emacs instance.2

And dealing with interacting with Emacs on a touchscreen interface/touchscreen keyboard is a bit of a nightmare.

Here, we’ll try to improve it a little. Into the rabbit-hole….

Note about using Termux for Emacs on Android #

You’re probably better off installing Termux from F-Droid rather than from the Google Play Store [see the note from the official Termux maintainers at: https://github.com/termux/termux-app/discussions/4000]. This is especially true is you want to use Emacs in Termux for managing Org-roam files which are shared/kept in sync with your Emacs on desktop machines, which you can do with Syncthing (use Catfriend1’s Syncthing-fork [Github]/[F-Droid] on Android), in order to be able to grant Termux (and thus Emacs) access to your shared Org files.

Termux Extra Keys #

Termux has a very useful feature adding extra keys above the system keyboard. These are quite useful, including ‘sticky’ CTRL and ALT keys. (In addition, one can hold volume-down and press a key for CTRL + [that-key] or volume-up and press a key for ALT + [that-key]; with volume-up + t inputting TAB. At least on my phone, using the volume keys as modifiers is fairly awkward/uncomfortable, so I prefer these extra keys.)

[Nb.: These keys are toggled on and off by pressing volume-up + k or volume-up + q. This is important to note, for I once toggled them off by accident and couldn’t understand what had happened to them for several months.]

Also worth mentioning is the fact that:

  • swipe left on extra keys brings up swipe-compatible/regular keyboard typing
  • swipe right on regular keyboard typing area (where extra keys was) will get you back to extra keys

The first of these lets you use any of your keyboard’s regular features and so can be quite useful.

See the Termux manual on Extra Keys for a description and basic configuration and usage instructions.

Extra Keys for better Emacs navigation #

Here, I explore the possibilities offered by the advanced configuration options for Extra Keys for navigating Emacs in Termux, especially Org-Roam or Org-node 3, to create faster/easier ways of calling commonly used commands since the user-interface to Emacs with an on-screen keyboard is often somewhat frustrating compared to the using Emacs with a physical keyboard. In addition to extra tappable keys, Extra Keys also allows for different outcomes when the user does swipe-up on a key, including the outputting of key sequences, which can include modifier keys like CTRL. This allows the possibility of loading them with Emacs key sequences which would otherwise be much slower to access with an onscreen keyboard.

What I wanted was:

  • An easy, single-key (no modifier) way of doing forward and backward searches. It is painful to either hold volume-down or have to keep on toggling the Extra Keys’ CTRL for each next/previous result. So I recruited and for forward and back searches, respectively (because ♡ is sort of pointed down and ♤ is sort of pointing up), and bound these appropriately in my Emacs configuration (see below).
  • other convenient single-key buffer navigation interface features, e.g., arrow keys and page-up and page-down
  • some convenience things like closing all but the current window (delete-other-windows = C-x 1), opening up iBuffer, switch-buffer
  • slashes and - and ~ available immediately to tap insert (not under my keyboard’s symbol toggle or long-hold)
  • ability to call some Org-mode/Org-node commands quickly: including finding nodes, inserting links to nodes, capturing new dailies, committing captures, going to today’s daily entry, moving forward and backwards through the dailies, toggling the org-roam backlinks buffer

Example configuration #

The configuration outlined below is partially specific for my Emacs configuration, especially for the C-c (CTRL c) keys, but some things involve default Emacs keybindings and it can at least serve as a model for what one can do. To configure Extra Keys, you need to modify the extra-keys part of ~/.termux/termux.properties in this fashion:

extra-keys = [[ \
  {key: 'ESC', popup: {macro: "CTRL x 1", display: "C-x 1"}}, \
  {key: 'CTRL', popup: {macro: "CTRL c", display: "C-c"}}, \
  {key: 'ALT', popup: {macro: "ALT x", display: "M-x"}}, \
  {key: '♡', popup: {macro: "CTRL x r b", display: "bookmarks"}}, \
  {key: '~', popup: {macro: "CTRL c n d", display: "today"}}, \
  {key: 'UP', popup: {macro: "CTRL c n n", display: "new note"}}, \
  {key: '-', popup: {macro: "CTRL c CTRL k", display: "cancel note"}}, \
  {key: 'PGUP', popup: {macro: "CTRL c n y", display: "prev note"}}], \
  [ \
  {key: 'TAB', popup: {macro: "CTRL x b", display: "alttab"}}, \
  {key: '/', popup: {macro: "CTRL c n f", display: "find node"}}, \
  {key: '\\\\', popup: {macro: "CTRL c n i", display: "insert link"}}, \
  {key: '♤', popup: {macro: "CTRL x CTRL b", display: "ibuffer"}}, \
  {key: 'LEFT', popup: {macro: "CTRL c n l", display: "backlinks"}}, \
  {key: 'DOWN', popup: {macro: "CTRL c CTRL c", display: "commit"}}, \
  {key: 'RIGHT', popup: {macro: "CTRL c n v", display: "goto-date"}}, \
  {key: 'PGDN', popup: {macro: "CTRL c n t", display: "next note"}}]]

Here is a rough summary of what this does:

key do on key tap do on key swipe up display on swipe up what key swipe up does
ESC ‘esc’ C-x 1 “C-x 1” delete-other-windows
CTRL ‘ctrl’ (C-) toggle C-c “C-c” start C-c prefix command
ALT ‘alt’ (M-) toggle M-x “M-x” M-x
isearch-forward C-x r b “bookmarks” bookmark-jump
~ ‘~’ C-c n d “today” org-node-goto-today
‘up’ C-c n n “new note” org-roam-dailies-capture-today
- ‘-’ C-c C-k “cancel note” C-c C-k to cancel capture
PGUP ‘pageup’ C-c n y “prev note” org-node-goto-next-day
TAB ‘tab key’ C-x b “alttab” consult-buffer (switch-to-buffer)
/ ‘/’ C-c n f “find node” org-node-find
\ ‘\’ C-c n i “insert link” org-node-insert-link*
isearch-backward C-x C-b “ibuffer” ibuffer
‘left’ C-c n l “backlinks” org-roam-buffer-toggle
‘down’ C-c C-c “commit” C-c C-c to ‘commit’
‘right’ C-c n v “goto-date” org-node-goto-daily
PGDN ‘pagedown’ C-c n t “next note” org-node-goto-prev-day

In case you do use Org-node (and, if you’re trying to do Org-roam things on Android, I would again recommend considering Org-node, if only for making interactions fast enough to not be completely frustrating), you could implement the following interactive functions:

(defun org-node-goto-daily ()
  (interactive)
  (org-node-seq--jump "d"))

(defun org-node-goto-today ()
  (interactive)
  (org-node-seq-goto "d" (format-time-string "%F")))

(defun org-node-goto-next-day ()
  (interactive nil org-mode)
  (org-node-seq--goto-next "d"))

(defun org-node-goto-prev-day ()
  (interactive nil org-mode)
  (org-node-seq--goto-previous "d"))

(defun org-roam-dailies-capture-today ()
  (interactive)
  (org-roam-dailies-capture-today nil "d"))

And then bind:

  • org-node-insert-link* to “C-c n i”
  • org-node-find to “C-c n f”
  • org-node-goto-daily to “C-c n v”
  • org-node-goto-today to “C-c n d”
  • org-node-goto-next-day to “C-c n t” ('[t]omorrow’)
  • org-node-goto-prev-day to “C-c n y” ('[y]esterday’)
  • org-roam-dailies-capture-today to “C-c n n”
  • org-roam-buffer-toggle to “C-c n l”

Most of the other keybindings implemented above are default Emacs bindings.

In terms of how this improves the Termux Emacs experience, consider that you could open up Emacs in Termux and then proceed by:

  • swiping up on to open up a new Org-[roam/node] note in today’s daily journal
  • then swiping left on the extra keys pane to get into normal keyboard entry mode
  • swipe/glide-typing the text of your note quickly, and pressing enter
  • swiping right on the now clear virtual keyboard pane to bring back the extra keys
  • swiping up on \ to insert (‘splice in’) a org-id link to another Org-roam node or two
  • swiping up on to commit/complete your daily note
  • swiping up on PGUP to see yesterday’s Org-roam daily journal
  • swiping up on / to search for your “Termux” Org-roam node to add notes about Extra Keys to your Termux Org-roam node/file
  • tapping to search through the entry to see all the places you made reference to “extra keys”
  • swiping up on to see what backlinks you have for “Termux”
  • swiping up on ESC to get back to single window view
  • swiping up on to get to IBuffer to be able to manage your buffers
  • swiping up on to open another new daily note in today’s journal
  • changing your mind and swiping up on - to cancel the note capture
  • …..

This is all a lot faster than having to tap CTRL and then type c n n to start a new entry in today’s Org-roam daily journal, typing it out (tapping CTRL and then c n i each time you want to link text to another node), and then tapping CTRL and then c and then CTRL and then c to commit it, and so on.

For a bonus reduction in modifier and key tapping, consider using a modal mode in Emacs: I particularly like meow.

Appendix: Key Mnemonics #

A potentially useful/emblematic list of mnemonics for the keys. [I use ☝️ to indicate swiping up on a key below.] Some of these mnemonics are stretches, but there are only so many keys and a particular set of things one wants, so stretches are sometimes required.

  • is a forwards/downwards search because the heart points down
  • is a backwards/upwards search because the spade points up [and we use these pointy characters indicating card suits in preference to others because I’m not going to be typing them on Android ever]
  • (all other single tap keys just do what it says on the tin, inserting characters, toggling modifiers, &c.)
  • ☝️ is bookmarks because these are ‘favourites’ because you ‘♡’ them
  • ☝️ is IBuffer because if you have icons enabled in your IBuffer4 then you’ll see icons and ♤ is like an icon (I know this one is a stretch, but….5)
  • ☝️ ESC is delete-other-windows because you’re ‘escaping’ from them
  • ☝️ CTRL is C-c because C-c starts with CTRL
  • ☝️ ALT is M-x because M-x starts with ALT
  • ☝️ ~ is org-node-goto-today because in Unix ~ is “user’s home directory” and today’s daily Org-roam entry is a sort of a ‘home’ (it makes sense to me anyway)
  • ☝️ - is C-c C-k is which ‘cancel’ in lots of places (like capture templates) and - is a negative sign and so can be understood like “don’t do it!”
  • ☝️ is org-roam-dailies-capture-today because this is the function to capture a new Org-roam daily note and ↑ is like “opening up something”
  • ☝️ is C-c C-c which is in many places in Emacs something like ‘commit’, and for capture templates it is the ‘finish capture’ binding and if ↑ is opening a new note, then ↓ is finishing it, putting it ‘down’
  • ☝️ is open up Org-roam backlinks buffer because ← is pointing ‘backwards’
  • ☝️ is org-node-goto-daily because we’re looking ‘forward’ towards a specific date and going to it
  • ☝️ PGUP is org-node-goto-prev-day because we’re going ‘up’/‘backwards’ in the calendar (of daily Org-roam journal entries)
  • ☝️ PGDN is org-node-goto-prev-day because we’re going ‘down’/‘forwards’ in the calendar (of daily Org-roam journal entries)
  • ☝️ TAB is consult-buffer / switch-to-buffer because this function is sort of like Alt-TAB in many window environments
  • ☝️ / is org-node-find because / is the search key in Vim, and also associated with searches elsewhere in Unixland (the marker of beginning/end of regexs, often used for searches) [and because / is the opposite slash from \, which we’re going to use for the complementary operation to insert links]
  • ☝️ \ is org-node-insert-link* because in many environments \ is some sort of ‘splice’ indicator6, and inserting a link to a node is also sort of a splice [and because \ is the opposite slash from / which performs a complementary operation]

  1. E.g., orgzly, organice. ↩︎

  2. There is a full GUI Emacs now on Android, but I don’t know how to get it to be able to access files shared via Syncthing, and, anyway, you wouldn’t be able to do the sort of convenient keyboard hacks there I’m going to discuss in this post. ↩︎

  3. I highly recommend looking at Martin Edström’s Org-node package if you’re trying to manage Org-roam notes on Android; the performance differences between the two packages are especially noticeable on Android (orders of magnitude7). And the two packages can live alongside each other, so you can keep your existing Org-roam set-up going while you set-up/experiment with Org-node. ↩︎

  4. With a package like https://github.com/seagle0128/all-the-icons-ibuffer. On IBuffer itself, see https://www.emacswiki.org/emacs/IbufferMode. ↩︎

  5. Well, okay, so here’s another one: think of IBuffer as trying to right your buffer organisation like Two, Five, and Seven (of Spades) in Alice in Wonderland trying sort out the Queen of Hearts’ rose-bushes (by painting the roses red): ↩︎

  6. From https://port70.net/~nsz/c/c11/n1570.html#5.1.1.2:

    Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. Only the last backslash on any physical source line shall be eligible for being part of such a splice. A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character before any such splicing takes place.

    ↩︎
  7. Android 10/11 seems to have introduced which restricts how regular applications/users can interact with the filesystem, for ‘security’ reasons, implemented via Filesystem in Userspace (FUSE), which makes operations which interact with the file system sometimes very sluggish. Accessing directories with lots of files, as one might have in an Org-roam directory, can be amazingly slow. The increases exponentially with the number of Org-roam files.

    Org-node is implemented in such a way [cf. https://github.com/meedstrom/org-node/issues/26] that it caches/stores and accesses many things in ways that avoid directly accessing the file-system (especially in org-node-fakeroam), where Org-roam does not. ↩︎