From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: David Kastrup Newsgroups: gmane.emacs.devel Subject: Re: local keymap patch for key-binding Date: Sun, 10 Sep 2006 15:25:51 +0200 Message-ID: <85pse3n99c.fsf@lola.goethe.zz> References: <87slj1hybl.fsf@stupidchicken.com> <85pse5cbqw.fsf@lola.goethe.zz> <87zmd7yjq4.fsf@furball.mit.edu> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1157894771 10323 80.91.229.2 (10 Sep 2006 13:26:11 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Sun, 10 Sep 2006 13:26:11 +0000 (UTC) Cc: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Sep 10 15:26:08 2006 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1GMPK2-0007yz-LN for ged-emacs-devel@m.gmane.org; Sun, 10 Sep 2006 15:26:07 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1GMPK2-0004XJ-1A for ged-emacs-devel@m.gmane.org; Sun, 10 Sep 2006 09:26:06 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1GMPJq-0004Wu-Mj for emacs-devel@gnu.org; Sun, 10 Sep 2006 09:25:54 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1GMPJp-0004Wg-VE for emacs-devel@gnu.org; Sun, 10 Sep 2006 09:25:54 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1GMPJp-0004Wd-QP for emacs-devel@gnu.org; Sun, 10 Sep 2006 09:25:53 -0400 Original-Received: from [199.232.76.164] (helo=fencepost.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.52) id 1GMPKs-0002xo-Uy for emacs-devel@gnu.org; Sun, 10 Sep 2006 09:26:59 -0400 Original-Received: from localhost ([127.0.0.1] helo=lola.goethe.zz) by fencepost.gnu.org with esmtp (Exim 4.34) id 1GMPJo-00005M-Hu; Sun, 10 Sep 2006 09:25:53 -0400 Original-Received: by lola.goethe.zz (Postfix, from userid 1002) id BC3381C40B5C; Sun, 10 Sep 2006 15:25:51 +0200 (CEST) Original-To: Chong Yidong In-Reply-To: <87zmd7yjq4.fsf@furball.mit.edu> (Chong Yidong's message of "Sun\, 10 Sep 2006 08\:44\:19 -0400") User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:59627 Archived-At: Chong Yidong writes: > David Kastrup writes: > >> It does too little. Check out what read-key-sequence (defined in >> keyboard.c) does with regard to mouse events (EVENT_HAS_PARAMETERS). >> The problem is that read-key-sequence does such a load of other stuff >> that it is hard to extract the material and transfer it to >> key-binding. >> >> The problem is that keymaps may be provided by text properties and >> overlays, and by keymap properties on strings that display as the >> display or before-string or after-string properties of text properties >> or overlays. > > I just verified that my patch truly works for keymaps on display > strings, text properties, and overlays. For example, with > > (with-output-to-temp-buffer "Testo" > (set-buffer "Testo") > (erase-buffer) > (let* ((map (make-sparse-keymap)) > (str (propertize "foostring" 'keymap map 'mouse-face 'highlight)) > ovr) > (define-key map [mouse-1] 'delete-window) > (insert "1234567890") > (setq ovr (make-overlay 2 3)) > (overlay-put ovr 'keymap map) > (overlay-put ovr 'mouse-face 'highlight) > (put-text-property 5 6 'display str) > (put-text-property 8 9 'keymap map) > (put-text-property 8 9 'mouse-face 'highlight))) > > C-h k followed by mouse-1 on the overlay, display string, or text > propertized region all report the correct action for the given local > keymap. Uh, C-h k has extra code doing this sort of lookup. It does not rely on key-binding. So you should not test this with C-h k unless you have previously dumbed it down with (defun string-key-binding (&rest ignore) nil) after help.el has been loaded. > The reason is that the mouse event passed to `key-binding' contains > all the information you need to reconstruct the binding directly > (including whether or not the object we are looking at is a buffer > position or a string.) > > So it seems like there's no problem. Amazing. Do you have an idea why the stuff in read-key-sequence concerning mouse related maps appears so much more complicated? Or is it just me? Some complication, of course, is due to read-key-sequence having to _assemble_ a key sequence instead of merely looking it up. But still... Concretely, we have the following in keyboard.c concerning mouse events, and I'll add my own comments with // in between. if (EVENT_HAS_PARAMETERS (key)) { Lisp_Object kind; Lisp_Object string; kind = EVENT_HEAD_KIND (EVENT_HEAD (key)); if (EQ (kind, Qmouse_click)) { Lisp_Object window, posn; window = POSN_WINDOW (EVENT_START (key)); posn = POSN_POSN (EVENT_START (key)); // Fake prefixes probably not relevant for keybinding-lookup if (CONSP (posn) || (!NILP (fake_prefixed_keys) && !NILP (Fmemq (key, fake_prefixed_keys)))) { // elided } /* Key sequences beginning with mouse clicks are read using the keymaps in the buffer clicked on, not the current buffer. If we're at the beginning of a key sequence, switch buffers. */ // Do you change the buffer accordingly in your patch? if (last_real_key_start == 0 && WINDOWP (window) && BUFFERP (XWINDOW (window)->buffer) && XBUFFER (XWINDOW (window)->buffer) != current_buffer) { XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key; keybuf[t] = key; mock_input = t + 1; /* Arrange to go back to the original buffer once we're done reading the key sequence. Note that we can't use save_excursion_{save,restore} here, because they save point as well as the current buffer; we don't want to save point, because redisplay may change it, to accommodate a Fset_window_start or something. We don't want to do this at the top of the function, because we may get input from a subprocess which wants to change the selected window and stuff (say, emacsclient). */ record_unwind_protect (Fset_buffer, Fcurrent_buffer ()); if (! FRAME_LIVE_P (XFRAME (selected_frame))) Fkill_emacs (Qnil); set_buffer_internal (XBUFFER (XWINDOW (window)->buffer)); orig_local_map = get_local_map (PT, current_buffer, Qlocal_map); orig_keymap = get_local_map (PT, current_buffer, Qkeymap); goto replay_sequence; // This starts the whole lookup sequence with new values for local-map // and, well, I don't quite understand what Qkeymap is. } /* For a mouse click, get the local text-property keymap of the place clicked on, rather than point. */ if (last_real_key_start == 0 && CONSP (XCDR (key)) && ! localized_local_map) { Lisp_Object map_here, start, pos; localized_local_map = 1; start = EVENT_START (key); if (CONSP (start) && POSN_INBUFFER_P (start)) { pos = POSN_BUFFER_POSN (start); if (INTEGERP (pos) && XINT (pos) >= BEG && XINT (pos) <= Z) { map_here = get_local_map (XINT (pos), current_buffer, Qlocal_map); if (!EQ (map_here, orig_local_map)) { orig_local_map = map_here; keybuf[t] = key; mock_input = t + 1; goto replay_sequence; } map_here = get_local_map (XINT (pos), current_buffer, Qkeymap); if (!EQ (map_here, orig_keymap)) { orig_keymap = map_here; keybuf[t] = key; mock_input = t + 1; goto replay_sequence; } } } } // Another class of events: but they mostly don't require looking in // other maps /* Expand mode-line and scroll-bar events into two events: use posn as a fake prefix key. */ if (SYMBOLP (posn) && (NILP (fake_prefixed_keys) || NILP (Fmemq (key, fake_prefixed_keys)))) { if (t + 1 >= bufsize) error ("Key sequence too long"); keybuf[t] = posn; keybuf[t + 1] = key; mock_input = t + 2; /* Record that a fake prefix key has been generated for KEY. Don't modify the event; this would prevent proper action when the event is pushed back into unread-command-events. */ fake_prefixed_keys = Fcons (key, fake_prefixed_keys); // Except in the following case: /* If on a mode line string with a local keymap, reconsider the key sequence with that keymap. */ if (string = POSN_STRING (EVENT_START (key)), (CONSP (string) && STRINGP (XCAR (string)))) { Lisp_Object pos, map, map2; pos = XCDR (string); string = XCAR (string); if (XINT (pos) >= 0 && XINT (pos) < SCHARS (string)) { map = Fget_text_property (pos, Qlocal_map, string); if (!NILP (map)) orig_local_map = map; map2 = Fget_text_property (pos, Qkeymap, string); if (!NILP (map2)) orig_keymap = map2; if (!NILP (map) || !NILP (map2)) goto replay_sequence; } } goto replay_key; } else if (NILP (from_string) && (string = POSN_STRING (EVENT_START (key)), (CONSP (string) && STRINGP (XCAR (string))))) { /* For a click on a string, i.e. overlay string or a string displayed via the `display' property, consider `local-map' and `keymap' properties of that string. */ Lisp_Object pos, map, map2; pos = XCDR (string); string = XCAR (string); if (XINT (pos) >= 0 && XINT (pos) < SCHARS (string)) { map = Fget_text_property (pos, Qlocal_map, string); if (!NILP (map)) orig_local_map = map; map2 = Fget_text_property (pos, Qkeymap, string); if (!NILP (map2)) orig_keymap = map2; if (!NILP (map) || !NILP (map2)) { from_string = string; goto replay_sequence; } } } } // Menu bar: seemingly does not require other maps. else if (CONSP (XCDR (key)) && CONSP (EVENT_START (key)) && CONSP (XCDR (EVENT_START (key)))) { Lisp_Object posn; posn = POSN_POSN (EVENT_START (key)); /* Handle menu-bar events: insert the dummy prefix event `menu-bar'. */ if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar)) { if (t + 1 >= bufsize) error ("Key sequence too long"); keybuf[t] = posn; keybuf[t+1] = key; /* Zap the position in key, so we know that we've expanded it, and don't try to do so again. */ POSN_SET_POSN (EVENT_START (key), Fcons (posn, Qnil)); mock_input = t + 2; goto replay_sequence; } else if (CONSP (posn)) { /* We're looking at the second event of a sequence which we expanded before. Set last_real_key_start appropriately. */ if (last_real_key_start == t && t > 0) last_real_key_start = t - 1; } } } If it seems to you that your patch gets the same cases (and with the same order of priorities), that would be great! Another thing: I had proposed an additional optional "LOCATION" argument for key-binding. -- David Kastrup, Kriemhildstr. 15, 44793 Bochum