all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Alan Mackenzie <acm@muc.de>
To: Stefan Monnier <monnier@iro.umontreal.ca>,
	Drew Adams <drew.adams@oracle.com>
Cc: emacs-devel@gnu.org
Subject: Re: Bug with S-Tab in keymaps
Date: Tue, 6 May 2008 21:26:29 +0000	[thread overview]
Message-ID: <20080506212629.GA4534@muc.de> (raw)
In-Reply-To: <20080505205411.GB1365@muc.de>

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 string.
	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?
	(char-mod-alist
	 '((?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
    (cond
     ((numberp evt)
      (setq base-key (logand evt base-mask) ; Unchanged until the "Synthesize" bit.
	    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))
      (cond
       ;; 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)
	(logior
	 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))
      (intern
       (concat
       (if got-A "A-" "")
       (if got-C "C-" "")
       (if got-H "H-" "")
       (if got-M "M-" "")
       (if got-S "S-" "")
       (if got-s "s-" "")
       base-key)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

-- 
Alan Mackenzie (Nuremberg, Germany).





  parent reply	other threads:[~2008-05-06 21:26 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-05-05 14:11 Bug with S-Tab in keymaps Alan Mackenzie
2008-05-05 18:07 ` Stefan Monnier
2008-05-05 20:40   ` Drew Adams
2008-05-06  0:46     ` Stefan Monnier
2008-05-05 20:54   ` Alan Mackenzie
2008-05-05 20:46     ` Lennart Borgman (gmail)
2008-05-05 21:00       ` Drew Adams
2008-05-06 21:26     ` Alan Mackenzie [this message]
2008-05-06 23:13       ` Miles Bader
2008-05-07  8:24         ` Alan Mackenzie
2008-05-07 15:17           ` Stefan Monnier
2008-05-06 17:08 ` Drew Adams

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080506212629.GA4534@muc.de \
    --to=acm@muc.de \
    --cc=drew.adams@oracle.com \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.