[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Bug with S-Tab in keymaps

From: Alan Mackenzie
Subject: Re: Bug with S-Tab in keymaps
Date: Tue, 6 May 2008 21:26:29 +0000
User-agent: Mutt/1.5.9i

Hi, Stefan and Drew!

On Mon, May 05, 2008 at 08:54:11PM +0000, Alan Mackenzie wrote:
> Hi, Stefan!

> On Mon, May 05, 2008 at 02:07:53PM -0400, Stefan Monnier wrote:
> > > Should S-Tab be stored in a keymap as a symbol or a number?  Or are
> > > both valid?  Which is the canonical form?  Where should the
> > > conversion from the uncanonical form to the canonical be done?

[ .... ]

> My own opinion, for what it's worth, is that read_key_sequence (in
> keyboard.c) and lookup-key (in keymap.c) should both massage the
> differences between #x2000009 and 'S-tab and 'S-TAB, somehow.  I suppose
> even #x4000049 (&I + the control bucky bit) for the same thing is
> conceivable.  Maybe `define-key' should canonicalise the key-sequences
> it's given before writing them into a keymap.

> in fact, `canonicalise-key-sequence' would be easy to write in lisp, and
> could be called from all of read_key_sequence, lookup-key and
> define-key.  what do you think?

here's an embryonic `canonicalize-event' (note the American spelling ;-).
It works, e.g. for

(canonicalize-event 'TaB)
(canonicalize-event 'C-Tab)
(canonicalize-event 'C-PgUp)
(canonicalize-event #x4000049)
(canonicalize-event 'M-C-prior)


(defconst non-canon-key-symbs
  '((tab . 9)
    (bs . 127)
    (pgup . "prior"))
  "An alist mapping non-standard keynames to canonical ones")

(defun canonicalize-event (evt)
  "Turn the event EVT into its canonical equivalent.

EVT is typically a single key press after being massaged by the
function-key-map, or a mouse action.

In the following, the \"base-key\" means the key event without
its modifiers.  If EVT is an integer, the base-key is its bottom
8 bits; if EVT's a symbol, the base-key is the symbol name
without the modifiers, a string.

The rules for a key event's canonicity are, in order of
decreasing priority:

\(i) it is a number (character, perhaps including bucky bits) if possible.
\(ii) if it contains control and a low ASCII character (?@, ?a, ...., ?z, ?{,
  ..., ~, del), the base key is the corresponding control character.
\(iii) Upper and lower case letters will be represented as such in the base
  key, rather than by use of the shift bucky bit.

\(iv) if it can't be represented by a number, it is a symbol containing the
  modifiers, e.g. 'C-M-up.
\(v) Any attached modifiers are case significant, and appear in the canonical
  order, A-C-H-M-S-s-.
\(vi) The base key part of the symbol name is in lower case, and is the
  canonical name."
  (let ((M-bit #x8000000)
        (C-bit #x4000000)
        (S-bit #x2000000)               ; shift
        (H-bit #x1000000)
        (s-bit #x800000)                ; super
        (A-bit #x400000)
        (base-mask #x3fffff)
        base-key                        ; key without modifiers; number or 
        got-M got-C got-S got-H got-s got-A ; are explicit modifiers present?
        is-C is-upper-case                  ; is it a control/upper-case key?
        is-CC                         ; is it a "double" ctrl key, e.g. C-TAB?
         '((?M . got-M) (?C . got-C) (?S . got-S)
           (?H . got-H) (?s . got-s) (?A . got-A)))
        key-string canon-symb ch pos
;;;; Analyse the argument
     ((numberp evt)
      (setq base-key (logand evt base-mask) ; Unchanged until the "Synthesize" 
            got-M (/= 0 (logand evt M-bit))
            got-C (/= 0 (logand evt C-bit))
            got-S (/= 0 (logand evt S-bit))
            got-H (/= 0 (logand evt H-bit))
            got-s (/= 0 (logand evt s-bit))
            got-A (/= 0 (logand evt A-bit)))

      ;; Have we got a "double <ctrl>", e.g. C-TAB?
      (setq is-CC (and got-C (< base-key 32))))

     ((symbolp evt)
      (setq key-string (symbol-name evt))
      ;; get the modifiers.
      (setq pos 0)
      (while (eq (string-match "[MCSHsA]-." key-string pos) pos)
        (setq ch (aref key-string pos))
        (set (cdr (assq ch char-mod-alist)) t)
        (setq pos (+ 2 pos)))
      ;; get the base "key" (might be a mouse event).
      (or (string-match "[^-]+$" key-string pos)
          (error "canonicalize-event: invalid symbol: %s" evt))
      (setq base-key (substring key-string pos)))

     (t (error "canonicalize-event: argument not number or symbol: %s" evt)))

;;;; Synthesize the result
    (when (stringp base-key)
      (if (eq (length base-key) 1)              ; must be a letter or digit.
          (setq base-key (aref base-key 0))
        (setq base-key (downcase base-key))
        (if (setq canon-symb (assoc (intern base-key) non-canon-key-symbs))
            (setq base-key (cdr canon-symb))))) ; symbol or number
    ;; Can we transform base-key into an ASCII control sequnce (0 - 31)?
    (when (and got-C (numberp base-key))
       ;; Convert got-C with (e.g.) ?A -> shift + ?\C-a
       ((and (>= base-key ?A) (<= base-key ?Z))
        (setq base-key (- base-key ?A -1)
              got-C nil
              got-S t))
       ;; got-C with (e.g.) ?@ -> ?\C-@
       ((or (eq base-key ?@)
            (and (>= base-key ?\[) (<= base-key ?_)))
        (setq base-key (- base-key ?@)
              got-C nil))
       ;; got-C with (e.g.) ?a -> ?\C-a
       ((and (>= base-key ?a) (<= base-key ?z))
        (setq base-key (- base-key ?a -1)
              got-C nil))))

    (if (numberp base-key)
         (if got-M M-bit 0)
         (if (or got-C is-CC) C-bit 0)
         (if got-S S-bit 0)
         (if got-H H-bit 0)
         (if got-M M-bit 0)
         (if got-M M-bit 0))
       (if got-A "A-" "")
       (if got-C "C-" "")
       (if got-H "H-" "")
       (if got-M "M-" "")
       (if got-S "S-" "")
       (if got-s "s-" "")

Alan Mackenzie (Nuremberg, Germany).

reply via email to

[Prev in Thread] Current Thread [Next in Thread]