Using Emacs with Windows 8 touch keyboard

At the end of this post is some code I use to enter Ctrl, Meta, Shift keys or combinations when I am using Emacs with Windows 8 touch keyboard.

As for why anyone would want to do that, I have a Windows tablet (hybrid laptop) and I thought I wanted to edit org-mode files on my tablet even when I left its physical keyboard at home. By touch keyboard, I mean this: Windows 8 touch keyboard. Windows 8 provides at least three kinds of touch keyboards: default one, thumb keyboard, and lastly a full keyboard which has Alt, Esc, Fn, and so on. The latter is disabled by default, and you can enable it and then you can use it, but it is not optimized for typing sentences like the default one is, so I wanted to have some way to enter modifier keys while using the default keyboard without switching to the full keyboard.

1. some preliminary

With English US touch keyboard (default keyboard), you can type letters like ö or œ easily and quickly (so these are the letters I will map to Meta, Ctrl, etc). For example, to type ö quickly, do the following steps quickly:

  • press o (with your finger)
  • (while your finger is still touching the screen) move the finger toward the up-right direction.
  • release

To see what other letters can be typed with this kind of action, do above steps slowly.

2. some observations

Windows 8 touch keyboard provides word correction feature but it does not seem to work on current version of Emacs. Probably related is that also you cannot use Windows Speech Recognition to enter text into Emacs via voice input (but then Tavid Rudd figured out a way to use Emacs by voice some other way).

3. the code

With the following code, œ corresponds to Meta, which means that when you type œx, Emacs recognizes it as M-x. ō corresponds to Control Meta, õ corresponds to Control, ó corresponds to Control Shift, ö corresponds to Shift, ò corresponds to Meta Shift. Also, ĝ and ĥ correspond to up and down. Additionally for convenience, ê, ē, é correspond to M-x, C-x, C-c, respectively.

Some downside: For obvious reasons, European users should not use this code.

This code builds upon some code written by Al Petrofsky which he wrote to do some other thing.

(defun my-read-function-mapped-event ()
  "Read an event or function key.
Like `read-event', but input is first translated according to
`function-key-map' and `key-translation-map', so that a function key
event may be composed."
  (let ((event (read-event)))
    (if (consp event)
        ;; Don't touch mouse events.
        event
      ;; Otherwise, block out the maps that are used after
      ;; key-translation-map, and call read-key-sequence.
      (push event unread-command-events)
      (let ((overriding-local-map (make-sparse-keymap))
            (global (current-global-map)))
        (unwind-protect
            (progn (use-global-map (make-sparse-keymap))
                   (let ((vec (read-key-sequence-vector nil)))
                     (if (> (length vec) 1)
                         (setq unread-command-events
                               (cdr (append vec unread-command-events))))
                     (aref vec 0)))
          (use-global-map global))))))

;; These functions -- which are not commands -- each add one modifier
;; to the following event.

(defun my-event-apply-alt-modifier (_ignore-prompt)
  "Add the Alt modifier to the following event.
For example, type \\[my-event-apply-alt-modifier] & to enter Alt-&."
  `[,(my-event-apply-modifier (my-read-function-mapped-event) 'alt)])
(defun my-event-apply-super-modifier (_ignore-prompt)
  "Add the Super modifier to the following event.
For example, type \\[my-event-apply-super-modifier] & to enter Super-&."
  `[,(my-event-apply-modifier (my-read-function-mapped-event) 'super)])
(defun my-event-apply-hyper-modifier (_ignore-prompt)
  "Add the Hyper modifier to the following event.
For example, type \\[my-event-apply-hyper-modifier] & to enter Hyper-&."
  `[,(my-event-apply-modifier (my-read-function-mapped-event) 'hyper)])
(defun my-event-apply-shift-modifier (_ignore-prompt)
  "Add the Shift modifier to the following event.
For example, type \\[my-event-apply-shift-modifier] & to enter Shift-&."
  `[,(my-event-apply-modifier (my-read-function-mapped-event) 'shift)])
(defun my-event-apply-control-modifier (_ignore-prompt)
  "Add the Control modifier to the following event.
For example, type \\[my-event-apply-control-modifier] & to enter Control-&."
  `[,(my-event-apply-modifier (my-read-function-mapped-event) 'control)])
(defun my-event-apply-meta-modifier (_ignore-prompt)
  "Add the Meta modifier to the following event.
For example, type \\[my-event-apply-meta-modifier] & to enter Meta-&."
  `[,(my-event-apply-modifier (my-read-function-mapped-event) 'meta)])

(defun my-event-apply-control-meta-modifier (_ignore-prompt)
  `[,(my-event-apply-modifier (my-event-apply-modifier (my-read-function-mapped-event) 'control) 'meta)])
(defun my-event-apply-control-shift-modifier (_ignore-prompt)
  `[,(my-event-apply-modifier (my-event-apply-modifier (my-read-function-mapped-event) 'control) 'shift)])
(defun my-event-apply-meta-shift-modifier (_ignore-prompt)
  `[,(my-event-apply-modifier (my-event-apply-modifier (my-read-function-mapped-event) 'meta) 'shift)])

(defun my-event-apply-modifier (event modifier)
  "Apply a modifier flag to event EVENT.
MODIFIER is the name of the modifier, as a symbol."
  (let ((modified (event-convert-list `(,modifier
                                        ,@(delq 'click (event-modifiers event))
                                        ,(event-basic-type event)))))
    (if (consp event)
        (cons modified (cdr event))
      modified)))

(require 'cl-lib)
(cl-loop for (ks def ok) in (list
                             (list "œ" 'my-event-apply-meta-modifier t)
                             (list "ō" 'my-event-apply-control-meta-modifier t)
                             (list "õ" 'my-event-apply-control-modifier t)
                             (list "ó" 'my-event-apply-control-shift-modifier t)
                             (list "ö" 'my-event-apply-shift-modifier t)
                             (list "ò" 'my-event-apply-meta-shift-modifier t)

                             ;; for up and down
                             (list "ĝ" (kbd "<up>") t)
                             (list "ĥ" (kbd "<down>") t)

                             ;; for quicker access to M-x, C-x, C-c
                             (list "ê" (kbd "M-x") t)
                             (list "ē" (kbd "C-x") t)
                             (list "é" (kbd "C-c") t))
         for key = (kbd ks)
         for bound = (key-binding key)
         do (progn (and bound
                        (not ok)
                        (warn "key %s is already bound to %s" ks bound))
                   (define-key key-translation-map key def)))
This entry was posted in Emacs and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s