Using Emacs and Org-Roam/Org-Node on Android (with Termux Extra Keys)
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
isdelete-other-windows
because you’re ‘escaping’ from them - ☝️
CTRL
isC-c
becauseC-c
starts with CTRL - ☝️
ALT
isM-x
becauseM-x
starts with ALT - ☝️
~
isorg-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) - ☝️
-
isC-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!” - ☝️
↑
isorg-roam-dailies-capture-today
because this is the function to capture a new Org-roam daily note and ↑ is like “opening up something” - ☝️
↓
isC-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’ - ☝️
→
isorg-node-goto-daily
because we’re looking ‘forward’ towards a specific date and going to it - ☝️
PGUP
isorg-node-goto-prev-day
because we’re going ‘up’/‘backwards’ in the calendar (of daily Org-roam journal entries) - ☝️
PGDN
isorg-node-goto-prev-day
because we’re going ‘down’/‘forwards’ in the calendar (of daily Org-roam journal entries) - ☝️
TAB
isconsult-buffer
/switch-to-buffer
because this function is sort of likeAlt-TAB
in many window environments - ☝️
/
isorg-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] - ☝️
\
isorg-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]
-
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. ↩︎
-
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. ↩︎
-
With a package like https://github.com/seagle0128/all-the-icons-ibuffer. On IBuffer itself, see https://www.emacswiki.org/emacs/IbufferMode. ↩︎
-
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): ↩︎
-
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.
-
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. ↩︎