diff options
| author | Jim Blandy | 1992-10-03 15:37:35 +0000 |
|---|---|---|
| committer | Jim Blandy | 1992-10-03 15:37:35 +0000 |
| commit | 0a7f1fc0b510f3f7a220e8702b71563d909d7a7d (patch) | |
| tree | b3da50e4fa96e7a10df393865025f68b51ee7fdd /src | |
| parent | 20d2471455526acfd5fe96681ea31f0eac88fae4 (diff) | |
| download | emacs-0a7f1fc0b510f3f7a220e8702b71563d909d7a7d.tar.gz emacs-0a7f1fc0b510f3f7a220e8702b71563d909d7a7d.zip | |
* keyboard.c (read_key_sequence): Treat mouse clicks on non-text
areas as if they were prefixed with the symbol denoting the
area clicked on - `mode-line', etcetera.
When we throw away an unbound `down-' event, reset mock_input as
well.
* keyboard.c (Qevent_symbol_element_mask, Qmodifier_cache): Two
new symbols, used to implement caches on event heads. These take
the place of some of the caching that modify_event_symbol used to do.
(parse_modifiers_uncached, apply_modifiers_uncached,
lispy_modifier_list, parse_modifiers, apply_modifiers): New
functions, which replace format_modifiers and reorder_modifiers;
they can be useful elsewhere too.
(reorder_modifiers, modify_event_symbol): Re-implement these in
terms of parse_modifiers and apply_modifiers. modify_event_symbol
now uses a much simpler cache, and takes advantage of the caches
maintained by parse_ and apply_modifiers.
(follow_key): Don't modify NEXT if KEY has no bindings.
(read_key_sequence): Drop unbound `down-' events, and turn unbound
`drag-' events into clicks if that would make them bound. This
benefits from the rewriting of the modifier key handling code.
(syms_of_keyboard): Initialize and intern
Qevent_symbol_element_mask and Qmodifier_cache.
* keyboard.c (echo_prompt): Terminate the echo buffer properly
even when the string is too long to display in the minibuffer.
(echo_truncate): Just return echoptr - echobuf, rather than
calling strlen on echobuf.
* keyboard.c (modifier_names): The modifier is named "control",
not "ctrl".
Diffstat (limited to 'src')
| -rw-r--r-- | src/keyboard.c | 529 |
1 files changed, 359 insertions, 170 deletions
diff --git a/src/keyboard.c b/src/keyboard.c index 06fe85d6bb4..9afcb951a1b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -295,6 +295,19 @@ Lisp_Object Qscrollbar_click; | |||
| 295 | Lisp_Object Qevent_kind; | 295 | Lisp_Object Qevent_kind; |
| 296 | Lisp_Object Qevent_symbol_elements; | 296 | Lisp_Object Qevent_symbol_elements; |
| 297 | 297 | ||
| 298 | /* An event header symbol HEAD may have a property named | ||
| 299 | Qevent_symbol_element_mask, which is of the form (BASE MODIFIERS); | ||
| 300 | BASE is the base, unmodified version of HEAD, and MODIFIERS is the | ||
| 301 | mask of modifiers applied to it. If present, this is used to help | ||
| 302 | speed up parse_modifiers. */ | ||
| 303 | Lisp_Object Qevent_symbol_element_mask; | ||
| 304 | |||
| 305 | /* An unmodified event header BASE may have a property named | ||
| 306 | Qmodifier_cache, which is an alist mapping modifier masks onto | ||
| 307 | modified versions of BASE. If present, this helps speed up | ||
| 308 | apply_modifiers. */ | ||
| 309 | Lisp_Object Qmodifier_cache; | ||
| 310 | |||
| 298 | /* Symbols to use for non-text mouse positions. */ | 311 | /* Symbols to use for non-text mouse positions. */ |
| 299 | Lisp_Object Qmode_line; | 312 | Lisp_Object Qmode_line; |
| 300 | Lisp_Object Qvertical_line; | 313 | Lisp_Object Qvertical_line; |
| @@ -369,8 +382,9 @@ echo_prompt (str) | |||
| 369 | int len = strlen (str); | 382 | int len = strlen (str); |
| 370 | if (len > sizeof echobuf - 4) | 383 | if (len > sizeof echobuf - 4) |
| 371 | len = sizeof echobuf - 4; | 384 | len = sizeof echobuf - 4; |
| 372 | bcopy (str, echobuf, len + 1); | 385 | bcopy (str, echobuf, len); |
| 373 | echoptr = echobuf + len; | 386 | echoptr = echobuf + len; |
| 387 | *echoptr = '\0'; | ||
| 374 | 388 | ||
| 375 | echo (); | 389 | echo (); |
| 376 | } | 390 | } |
| @@ -487,7 +501,7 @@ echo_truncate (len) | |||
| 487 | int len; | 501 | int len; |
| 488 | { | 502 | { |
| 489 | echobuf[len] = '\0'; | 503 | echobuf[len] = '\0'; |
| 490 | echoptr = echobuf + strlen (echobuf); | 504 | echoptr = echobuf + len; |
| 491 | } | 505 | } |
| 492 | 506 | ||
| 493 | 507 | ||
| @@ -1703,7 +1717,7 @@ make_lispy_event (event) | |||
| 1703 | { | 1717 | { |
| 1704 | /* A simple keystroke. */ | 1718 | /* A simple keystroke. */ |
| 1705 | case ascii_keystroke: | 1719 | case ascii_keystroke: |
| 1706 | return event->code; | 1720 | return XFASTINT (event->code); |
| 1707 | break; | 1721 | break; |
| 1708 | 1722 | ||
| 1709 | /* A function key. The symbol may need to have modifier prefixes | 1723 | /* A function key. The symbol may need to have modifier prefixes |
| @@ -1720,12 +1734,13 @@ make_lispy_event (event) | |||
| 1720 | a press, click or drag, and build the appropriate structure. */ | 1734 | a press, click or drag, and build the appropriate structure. */ |
| 1721 | case mouse_click: | 1735 | case mouse_click: |
| 1722 | { | 1736 | { |
| 1737 | int button = XFASTINT (event->code); | ||
| 1723 | int part; | 1738 | int part; |
| 1724 | Lisp_Object window; | 1739 | Lisp_Object window; |
| 1725 | Lisp_Object posn; | 1740 | Lisp_Object posn; |
| 1726 | struct mouse_position *loc; | 1741 | struct mouse_position *loc; |
| 1727 | 1742 | ||
| 1728 | if (event->code < 0 || event->code >= NUM_MOUSE_BUTTONS) | 1743 | if (button < 0 || button >= NUM_MOUSE_BUTTONS) |
| 1729 | abort (); | 1744 | abort (); |
| 1730 | 1745 | ||
| 1731 | /* Where did this mouse click occur? */ | 1746 | /* Where did this mouse click occur? */ |
| @@ -1753,7 +1768,7 @@ make_lispy_event (event) | |||
| 1753 | 1768 | ||
| 1754 | /* If this is a button press, squirrel away the location, so we | 1769 | /* If this is a button press, squirrel away the location, so we |
| 1755 | can decide later whether it was a click or a drag. */ | 1770 | can decide later whether it was a click or a drag. */ |
| 1756 | loc = button_down_location + event->code; | 1771 | loc = button_down_location + button; |
| 1757 | if (event->modifiers & down_modifier) | 1772 | if (event->modifiers & down_modifier) |
| 1758 | { | 1773 | { |
| 1759 | loc->window = window; | 1774 | loc->window = window; |
| @@ -1783,7 +1798,7 @@ make_lispy_event (event) | |||
| 1783 | Lisp_Object head, start, end; | 1798 | Lisp_Object head, start, end; |
| 1784 | 1799 | ||
| 1785 | /* Build the components of the event. */ | 1800 | /* Build the components of the event. */ |
| 1786 | head = modify_event_symbol (XFASTINT (event->code) - 1, | 1801 | head = modify_event_symbol (button - 1, |
| 1787 | event->modifiers, | 1802 | event->modifiers, |
| 1788 | Qmouse_click, | 1803 | Qmouse_click, |
| 1789 | lispy_mouse_names, &mouse_syms, | 1804 | lispy_mouse_names, &mouse_syms, |
| @@ -1883,107 +1898,64 @@ make_lispy_movement (frame, x, y, time) | |||
| 1883 | } | 1898 | } |
| 1884 | 1899 | ||
| 1885 | 1900 | ||
| 1901 | |||
| 1902 | /* Manipulating modifiers. */ | ||
| 1886 | 1903 | ||
| 1887 | /* Place the written representation of MODIFIERS in BUF, '\0'-terminated, | 1904 | /* Parse the name of SYMBOL, and return the set of modifiers it contains. |
| 1888 | and return its length. */ | ||
| 1889 | |||
| 1890 | static int | ||
| 1891 | format_modifiers (modifiers, buf) | ||
| 1892 | int modifiers; | ||
| 1893 | char *buf; | ||
| 1894 | { | ||
| 1895 | char *p = buf; | ||
| 1896 | |||
| 1897 | /* Only the event queue may use the `up' modifier; it should always | ||
| 1898 | be turned into a click or drag event before presented to lisp code. */ | ||
| 1899 | if (modifiers & up_modifier) | ||
| 1900 | abort (); | ||
| 1901 | |||
| 1902 | if (modifiers & alt_modifier) { *p++ = 'A'; *p++ = '-'; } | ||
| 1903 | if (modifiers & ctrl_modifier) { *p++ = 'C'; *p++ = '-'; } | ||
| 1904 | if (modifiers & hyper_modifier) { *p++ = 'H'; *p++ = '-'; } | ||
| 1905 | if (modifiers & meta_modifier) { *p++ = 'M'; *p++ = '-'; } | ||
| 1906 | if (modifiers & shift_modifier) { *p++ = 'S'; *p++ = '-'; } | ||
| 1907 | if (modifiers & super_modifier) { strcpy (p, "super-"); p += 6; } | ||
| 1908 | if (modifiers & down_modifier) { strcpy (p, "down-"); p += 5; } | ||
| 1909 | if (modifiers & drag_modifier) { strcpy (p, "drag-"); p += 5; } | ||
| 1910 | /* The click modifier is denoted by the absence of other modifiers. */ | ||
| 1911 | *p = '\0'; | ||
| 1912 | |||
| 1913 | return p - buf; | ||
| 1914 | } | ||
| 1915 | 1905 | ||
| 1906 | If MODIFIER_END is non-zero, set *MODIFIER_END to the position in | ||
| 1907 | SYMBOL's name of the end of the modifiers; the string from this | ||
| 1908 | position is the unmodified symbol name. | ||
| 1916 | 1909 | ||
| 1917 | /* Given a symbol whose name begins with modifiers ("C-", "M-", etc), | 1910 | This doesn't use any caches. */ |
| 1918 | return a symbol with the modifiers placed in the canonical order. | 1911 | static int |
| 1919 | Canonical order is alphabetical, except for down and drag, which | 1912 | parse_modifiers_uncached (symbol, modifier_end) |
| 1920 | always come last. The 'click' modifier is never written out. | ||
| 1921 | |||
| 1922 | Fdefine_key calls this to make sure that (for example) C-M-foo | ||
| 1923 | and M-C-foo end up being equivalent in the keymap. */ | ||
| 1924 | |||
| 1925 | Lisp_Object | ||
| 1926 | reorder_modifiers (symbol) | ||
| 1927 | Lisp_Object symbol; | 1913 | Lisp_Object symbol; |
| 1914 | int *modifier_end; | ||
| 1928 | { | 1915 | { |
| 1929 | struct Lisp_String *name; | 1916 | struct Lisp_String *name; |
| 1930 | int i; | 1917 | int i; |
| 1931 | int modifiers; | 1918 | int modifiers; |
| 1932 | int not_canonical; | ||
| 1933 | 1919 | ||
| 1934 | CHECK_SYMBOL (symbol, 1); | 1920 | CHECK_SYMBOL (symbol, 1); |
| 1935 | 1921 | ||
| 1936 | modifiers = 0; | 1922 | modifiers = 0; |
| 1937 | name = XSYMBOL (symbol)->name; | 1923 | name = XSYMBOL (symbol)->name; |
| 1938 | 1924 | ||
| 1939 | /* Special case for things with only one modifier, which is | ||
| 1940 | (hopefully) the vast majority of cases. */ | ||
| 1941 | if (! (name->size >= 4 && name->data[1] == '-' && name->data[3] == '-')) | ||
| 1942 | return symbol; | ||
| 1943 | 1925 | ||
| 1944 | for (i = 0; i+1 < name->data[i]; ) | 1926 | for (i = 0; i+2 <= name->size; ) |
| 1945 | switch (name->data[i]) | 1927 | switch (name->data[i]) |
| 1946 | { | 1928 | { |
| 1947 | case 'A': | 1929 | #define SINGLE_LETTER_MOD(bit) \ |
| 1948 | if (name->data[i] != '-') goto no_more_modifiers; | 1930 | if (name->data[i+1] != '-') \ |
| 1949 | not_canonical |= (modifiers & ~(alt_modifier - 1)); | 1931 | goto no_more_modifiers; \ |
| 1950 | modifiers |= alt_modifier; | 1932 | modifiers |= bit; \ |
| 1951 | i += 2; | 1933 | i += 2; |
| 1934 | |||
| 1935 | case 'A': | ||
| 1936 | SINGLE_LETTER_MOD (alt_modifier); | ||
| 1952 | break; | 1937 | break; |
| 1953 | 1938 | ||
| 1954 | case 'C': | 1939 | case 'C': |
| 1955 | if (name->data[i] != '-') goto no_more_modifiers; | 1940 | SINGLE_LETTER_MOD (ctrl_modifier); |
| 1956 | not_canonical |= (modifiers & ~(ctrl_modifier - 1)); | ||
| 1957 | modifiers |= ctrl_modifier; | ||
| 1958 | i += 2; | ||
| 1959 | break; | 1941 | break; |
| 1960 | 1942 | ||
| 1961 | case 'H': | 1943 | case 'H': |
| 1962 | if (name->data[i] != '-') goto no_more_modifiers; | 1944 | SINGLE_LETTER_MOD (hyper_modifier); |
| 1963 | not_canonical |= (modifiers & ~(hyper_modifier - 1)); | ||
| 1964 | modifiers |= hyper_modifier; | ||
| 1965 | i += 2; | ||
| 1966 | break; | 1945 | break; |
| 1967 | 1946 | ||
| 1968 | case 'M': | 1947 | case 'M': |
| 1969 | if (name->data[i] != '-') goto no_more_modifiers; | 1948 | SINGLE_LETTER_MOD (meta_modifier); |
| 1970 | not_canonical |= (modifiers & ~(meta_modifier - 1)); | ||
| 1971 | modifiers |= meta_modifier; | ||
| 1972 | i += 2; | ||
| 1973 | break; | 1949 | break; |
| 1974 | 1950 | ||
| 1975 | case 'S': | 1951 | case 'S': |
| 1976 | if (name->data[i] != '-') goto no_more_modifiers; | 1952 | SINGLE_LETTER_MOD (shift_modifier); |
| 1977 | not_canonical |= (modifiers & ~(shift_modifier - 1)); | ||
| 1978 | modifiers |= shift_modifier; | ||
| 1979 | i += 2; | ||
| 1980 | break; | 1953 | break; |
| 1981 | 1954 | ||
| 1982 | case 's': | 1955 | case 's': |
| 1983 | if (i + 6 > name->size | 1956 | if (i + 6 > name->size |
| 1984 | || strncmp (name->data + i, "super-", 6)) | 1957 | || strncmp (name->data + i, "super-", 6)) |
| 1985 | goto no_more_modifiers; | 1958 | goto no_more_modifiers; |
| 1986 | not_canonical |= (modifiers & ~(super_modifier - 1)); | ||
| 1987 | modifiers |= super_modifier; | 1959 | modifiers |= super_modifier; |
| 1988 | i += 6; | 1960 | i += 6; |
| 1989 | break; | 1961 | break; |
| @@ -1993,13 +1965,11 @@ reorder_modifiers (symbol) | |||
| 1993 | goto no_more_modifiers; | 1965 | goto no_more_modifiers; |
| 1994 | if (! strncmp (name->data + i, "drag-", 5)) | 1966 | if (! strncmp (name->data + i, "drag-", 5)) |
| 1995 | { | 1967 | { |
| 1996 | not_canonical |= (modifiers & ~(drag_modifier - 1)); | ||
| 1997 | modifiers |= drag_modifier; | 1968 | modifiers |= drag_modifier; |
| 1998 | i += 5; | 1969 | i += 5; |
| 1999 | } | 1970 | } |
| 2000 | else if (! strncmp (name->data + i, "down-", 5)) | 1971 | else if (! strncmp (name->data + i, "down-", 5)) |
| 2001 | { | 1972 | { |
| 2002 | not_canonical |= (modifiers & ~(down_modifier - 1)); | ||
| 2003 | modifiers |= down_modifier; | 1973 | modifiers |= down_modifier; |
| 2004 | i += 5; | 1974 | i += 5; |
| 2005 | } | 1975 | } |
| @@ -2009,29 +1979,209 @@ reorder_modifiers (symbol) | |||
| 2009 | 1979 | ||
| 2010 | default: | 1980 | default: |
| 2011 | goto no_more_modifiers; | 1981 | goto no_more_modifiers; |
| 1982 | |||
| 1983 | #undef SINGLE_LETTER_MOD | ||
| 2012 | } | 1984 | } |
| 2013 | no_more_modifiers: | 1985 | no_more_modifiers: |
| 2014 | 1986 | ||
| 2015 | if (!not_canonical) | 1987 | /* Should we include the `click' modifier? */ |
| 2016 | return symbol; | 1988 | if (! (modifiers & (down_modifier | drag_modifier)) |
| 1989 | && i + 7 == name->size | ||
| 1990 | && strncmp (name->data + i, "mouse-", 6) | ||
| 1991 | && '0' <= name->data[i + 6] | ||
| 1992 | && name->data[i + 6] <= '9') | ||
| 1993 | modifiers |= click_modifier; | ||
| 1994 | |||
| 1995 | if (modifier_end) | ||
| 1996 | *modifier_end = i; | ||
| 1997 | |||
| 1998 | return modifiers; | ||
| 1999 | } | ||
| 2000 | |||
| 2001 | |||
| 2002 | /* Return a symbol whose name is the modifier prefixes for MODIFIERS | ||
| 2003 | prepended to the string BASE[0..BASE_LEN-1]. | ||
| 2004 | This doesn't use any caches. */ | ||
| 2005 | static Lisp_Object | ||
| 2006 | apply_modifiers_uncached (modifiers, base, base_len) | ||
| 2007 | int modifiers; | ||
| 2008 | char *base; | ||
| 2009 | int base_len; | ||
| 2010 | { | ||
| 2011 | /* Since BASE could contain nulls, we can't use intern here; we have | ||
| 2012 | to use Fintern, which expects a genuine Lisp_String, and keeps a | ||
| 2013 | reference to it. */ | ||
| 2014 | char *new_mods = | ||
| 2015 | (char *) alloca (sizeof ("A-C-H-M-S-super-down-drag-")); | ||
| 2016 | int mod_len; | ||
| 2017 | 2017 | ||
| 2018 | /* The modifiers were out of order, so find a new symbol with the | ||
| 2019 | mods in order. Since the symbol name could contain nulls, we can't | ||
| 2020 | use intern here; we have to use Fintern, which expects a genuine | ||
| 2021 | Lisp_String, and keeps a reference to it. */ | ||
| 2022 | { | 2018 | { |
| 2023 | char *new_mods = (char *) alloca (sizeof ("A-C-H-M-S-super-U-down-drag-")); | 2019 | char *p = new_mods; |
| 2024 | int len = format_modifiers (modifiers, new_mods); | 2020 | |
| 2025 | Lisp_Object new_name = make_uninit_string (len + name->size - i); | 2021 | /* Only the event queue may use the `up' modifier; it should always |
| 2022 | be turned into a click or drag event before presented to lisp code. */ | ||
| 2023 | if (modifiers & up_modifier) | ||
| 2024 | abort (); | ||
| 2025 | |||
| 2026 | if (modifiers & alt_modifier) { *p++ = 'A'; *p++ = '-'; } | ||
| 2027 | if (modifiers & ctrl_modifier) { *p++ = 'C'; *p++ = '-'; } | ||
| 2028 | if (modifiers & hyper_modifier) { *p++ = 'H'; *p++ = '-'; } | ||
| 2029 | if (modifiers & meta_modifier) { *p++ = 'M'; *p++ = '-'; } | ||
| 2030 | if (modifiers & shift_modifier) { *p++ = 'S'; *p++ = '-'; } | ||
| 2031 | if (modifiers & super_modifier) { strcpy (p, "super-"); p += 6; } | ||
| 2032 | if (modifiers & down_modifier) { strcpy (p, "down-"); p += 5; } | ||
| 2033 | if (modifiers & drag_modifier) { strcpy (p, "drag-"); p += 5; } | ||
| 2034 | /* The click modifier is denoted by the absence of other modifiers. */ | ||
| 2035 | |||
| 2036 | *p = '\0'; | ||
| 2037 | |||
| 2038 | mod_len = p - new_mods; | ||
| 2039 | } | ||
| 2026 | 2040 | ||
| 2027 | bcopy (new_mods, XSTRING (new_name)->data, len); | 2041 | { |
| 2028 | bcopy (name->data + i, XSTRING (new_name)->data + len, name->size - i); | 2042 | Lisp_Object new_name = make_uninit_string (mod_len + base_len); |
| 2043 | |||
| 2044 | bcopy (new_mods, XSTRING (new_name)->data, mod_len); | ||
| 2045 | bcopy (base, XSTRING (new_name)->data + mod_len, base_len); | ||
| 2029 | 2046 | ||
| 2030 | return Fintern (new_name, Qnil); | 2047 | return Fintern (new_name, Qnil); |
| 2031 | } | 2048 | } |
| 2032 | } | 2049 | } |
| 2033 | 2050 | ||
| 2034 | 2051 | ||
| 2052 | static char *modifier_names[] = | ||
| 2053 | { | ||
| 2054 | "up", "alt", "control", "hyper", "meta", "shift", "super", "down", "drag", | ||
| 2055 | "click" | ||
| 2056 | }; | ||
| 2057 | |||
| 2058 | static Lisp_Object modifier_symbols; | ||
| 2059 | |||
| 2060 | /* Return the list of modifier symbols corresponding to the mask MODIFIERS. */ | ||
| 2061 | static Lisp_Object | ||
| 2062 | lispy_modifier_list (modifiers) | ||
| 2063 | int modifiers; | ||
| 2064 | { | ||
| 2065 | Lisp_Object modifier_list; | ||
| 2066 | int i; | ||
| 2067 | |||
| 2068 | modifier_list = Qnil; | ||
| 2069 | for (i = 0; (1<<i) <= modifiers; i++) | ||
| 2070 | if (modifiers & (1<<i)) | ||
| 2071 | modifier_list = Fcons (XVECTOR (modifier_symbols)->contents[i], | ||
| 2072 | modifier_list); | ||
| 2073 | |||
| 2074 | return modifier_list; | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | |||
| 2078 | /* Parse the modifiers on SYMBOL, and return a list like (UNMODIFIED MASK), | ||
| 2079 | where UNMODIFIED is the unmodified form of SYMBOL, | ||
| 2080 | MASK is the set of modifiers present in SYMBOL's name. | ||
| 2081 | This is similar to parse_modifiers_uncached, but uses the cache in | ||
| 2082 | SYMBOL's Qevent_symbol_element_mask property, and maintains the | ||
| 2083 | Qevent_symbol_elements property. */ | ||
| 2084 | static Lisp_Object | ||
| 2085 | parse_modifiers (symbol) | ||
| 2086 | Lisp_Object symbol; | ||
| 2087 | { | ||
| 2088 | Lisp_Object elements = Fget (symbol, Qevent_symbol_element_mask); | ||
| 2089 | |||
| 2090 | if (CONSP (elements)) | ||
| 2091 | return elements; | ||
| 2092 | else | ||
| 2093 | { | ||
| 2094 | int end; | ||
| 2095 | int modifiers = parse_modifiers_uncached (symbol, &end); | ||
| 2096 | Lisp_Object unmodified | ||
| 2097 | = Fintern (make_string (XSYMBOL (symbol)->name->data + end, | ||
| 2098 | XSYMBOL (symbol)->name->size - end), | ||
| 2099 | Qnil); | ||
| 2100 | Lisp_Object mask; | ||
| 2101 | |||
| 2102 | XFASTINT (mask) = modifiers; | ||
| 2103 | elements = Fcons (unmodified, Fcons (mask, Qnil)); | ||
| 2104 | |||
| 2105 | /* Cache the parsing results on SYMBOL. */ | ||
| 2106 | Fput (symbol, Qevent_symbol_element_mask, | ||
| 2107 | elements); | ||
| 2108 | Fput (symbol, Qevent_symbol_elements, | ||
| 2109 | Fcons (unmodified, lispy_modifier_list (modifiers))); | ||
| 2110 | |||
| 2111 | /* Since we know that SYMBOL is modifiers applied to unmodified, | ||
| 2112 | it would be nice to put that in unmodified's cache. | ||
| 2113 | But we can't, since we're not sure that parse_modifiers is | ||
| 2114 | canonical. */ | ||
| 2115 | |||
| 2116 | return elements; | ||
| 2117 | } | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | /* Apply the modifiers MODIFIERS to the symbol BASE. | ||
| 2121 | BASE must be unmodified. | ||
| 2122 | |||
| 2123 | This is like apply_modifiers_uncached, but uses BASE's | ||
| 2124 | Qmodifier_cache property, if present. It also builds | ||
| 2125 | Qevent_symbol_elements properties, since it has that info anyway. */ | ||
| 2126 | static Lisp_Object | ||
| 2127 | apply_modifiers (modifiers, base) | ||
| 2128 | int modifiers; | ||
| 2129 | Lisp_Object base; | ||
| 2130 | { | ||
| 2131 | Lisp_Object cache, index, entry; | ||
| 2132 | |||
| 2133 | /* The click modifier never figures into cache indices. */ | ||
| 2134 | XFASTINT (index) = (modifiers & ~click_modifier); | ||
| 2135 | cache = Fget (base, Qmodifier_cache); | ||
| 2136 | entry = Fassq (index, cache); | ||
| 2137 | |||
| 2138 | if (CONSP (entry)) | ||
| 2139 | return XCONS (entry)->cdr; | ||
| 2140 | |||
| 2141 | /* We have to create the symbol ourselves. */ | ||
| 2142 | { | ||
| 2143 | Lisp_Object new_symbol | ||
| 2144 | = apply_modifiers_uncached (modifiers, | ||
| 2145 | XSYMBOL (base)->name->data, | ||
| 2146 | XSYMBOL (base)->name->size); | ||
| 2147 | |||
| 2148 | /* Add the new symbol to the base's cache. */ | ||
| 2149 | Fput (base, Qmodifier_cache, | ||
| 2150 | Fcons (Fcons (index, new_symbol), cache)); | ||
| 2151 | |||
| 2152 | /* We have the parsing info now for free, so add it to the caches. */ | ||
| 2153 | XFASTINT (index) = modifiers; | ||
| 2154 | Fput (new_symbol, Qevent_symbol_element_mask, | ||
| 2155 | Fcons (base, Fcons (index, Qnil))); | ||
| 2156 | Fput (new_symbol, Qevent_symbol_elements, | ||
| 2157 | Fcons (base, lispy_modifier_list (modifiers))); | ||
| 2158 | |||
| 2159 | return new_symbol; | ||
| 2160 | } | ||
| 2161 | } | ||
| 2162 | |||
| 2163 | |||
| 2164 | /* Given a symbol whose name begins with modifiers ("C-", "M-", etc), | ||
| 2165 | return a symbol with the modifiers placed in the canonical order. | ||
| 2166 | Canonical order is alphabetical, except for down and drag, which | ||
| 2167 | always come last. The 'click' modifier is never written out. | ||
| 2168 | |||
| 2169 | Fdefine_key calls this to make sure that (for example) C-M-foo | ||
| 2170 | and M-C-foo end up being equivalent in the keymap. */ | ||
| 2171 | |||
| 2172 | Lisp_Object | ||
| 2173 | reorder_modifiers (symbol) | ||
| 2174 | Lisp_Object symbol; | ||
| 2175 | { | ||
| 2176 | /* It's hopefully okay to write the code this way, since everything | ||
| 2177 | will soon be in caches, and no consing will be done at all. */ | ||
| 2178 | Lisp_Object parsed = parse_modifiers (symbol); | ||
| 2179 | |||
| 2180 | return apply_modifiers (XCONS (XCONS (parsed)->cdr)->car, | ||
| 2181 | XCONS (parsed)->car); | ||
| 2182 | } | ||
| 2183 | |||
| 2184 | |||
| 2035 | /* For handling events, we often want to produce a symbol whose name | 2185 | /* For handling events, we often want to produce a symbol whose name |
| 2036 | is a series of modifier key prefixes ("M-", "C-", etcetera) attached | 2186 | is a series of modifier key prefixes ("M-", "C-", etcetera) attached |
| 2037 | to some base, like the name of a function key or mouse button. | 2187 | to some base, like the name of a function key or mouse button. |
| @@ -2058,14 +2208,6 @@ reorder_modifiers (symbol) | |||
| 2058 | `event-symbol-elements' propery, which lists the modifiers present | 2208 | `event-symbol-elements' propery, which lists the modifiers present |
| 2059 | in the symbol's name. */ | 2209 | in the symbol's name. */ |
| 2060 | 2210 | ||
| 2061 | static char *modifier_names[] = | ||
| 2062 | { | ||
| 2063 | "up", "alt", "ctrl", "hyper", "meta", "shift", "super", "down", "drag", | ||
| 2064 | "click" | ||
| 2065 | }; | ||
| 2066 | |||
| 2067 | static Lisp_Object modifier_symbols; | ||
| 2068 | |||
| 2069 | static Lisp_Object | 2211 | static Lisp_Object |
| 2070 | modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table, | 2212 | modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table, |
| 2071 | symbol_table, table_size) | 2213 | symbol_table, table_size) |
| @@ -2077,89 +2219,42 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table, | |||
| 2077 | int table_size; | 2219 | int table_size; |
| 2078 | { | 2220 | { |
| 2079 | Lisp_Object *slot; | 2221 | Lisp_Object *slot; |
| 2080 | Lisp_Object unmodified; | ||
| 2081 | Lisp_Object temp; | ||
| 2082 | 2222 | ||
| 2083 | /* Is this a request for a valid symbol? */ | 2223 | /* Is this a request for a valid symbol? */ |
| 2084 | if (symbol_num < 0 || symbol_num >= table_size) | 2224 | if (symbol_num < 0 || symbol_num >= table_size) |
| 2085 | abort (); | 2225 | abort (); |
| 2086 | 2226 | ||
| 2087 | /* If *symbol_table doesn't seem to be initialized property, fix that. | 2227 | /* If *symbol_table doesn't seem to be initialized properly, fix that. |
| 2088 | |||
| 2089 | *symbol_table should be a lisp vector TABLE_SIZE elements long, | 2228 | *symbol_table should be a lisp vector TABLE_SIZE elements long, |
| 2090 | where the Nth element is an alist for modified versions of | 2229 | where the Nth element is the symbol for NAME_TABLE[N]. */ |
| 2091 | name_table[N]; the alist maps modifier masks onto the modified | ||
| 2092 | symbols. The click modifier is always omitted from the mask; it | ||
| 2093 | is indicated implicitly on a mouse event by the absence of the | ||
| 2094 | down_ and drag_ modifiers. */ | ||
| 2095 | if (XTYPE (*symbol_table) != Lisp_Vector | 2230 | if (XTYPE (*symbol_table) != Lisp_Vector |
| 2096 | || XVECTOR (*symbol_table)->size != table_size) | 2231 | || XVECTOR (*symbol_table)->size != table_size) |
| 2097 | { | 2232 | { |
| 2098 | XFASTINT (temp) = table_size; | 2233 | Lisp_Object size; |
| 2099 | *symbol_table = Fmake_vector (temp, Qnil); | 2234 | |
| 2235 | XFASTINT (size) = table_size; | ||
| 2236 | *symbol_table = Fmake_vector (size, Qnil); | ||
| 2100 | } | 2237 | } |
| 2101 | 2238 | ||
| 2102 | slot = & XVECTOR (*symbol_table)->contents[symbol_num]; | 2239 | slot = & XVECTOR (*symbol_table)->contents[symbol_num]; |
| 2103 | 2240 | ||
| 2104 | /* Have we already modified this symbol? */ | 2241 | /* Have we already used this symbol before? */ |
| 2105 | XFASTINT (temp) = modifiers & ~(click_modifier); | 2242 | if (NILP (*slot)) |
| 2106 | temp = Fassq (temp, *slot); | ||
| 2107 | if (CONSP (temp)) | ||
| 2108 | return (XCONS (temp)->cdr); | ||
| 2109 | |||
| 2110 | /* We don't have an entry for the symbol; we have to build it. */ | ||
| 2111 | |||
| 2112 | /* Create a modified version of the symbol, and add it to the alist. */ | ||
| 2113 | { | ||
| 2114 | Lisp_Object modified; | ||
| 2115 | char *modified_name | ||
| 2116 | = (char *) alloca (sizeof ("A-C-H-M-S-super-U-down-drag") | ||
| 2117 | + strlen (name_table [symbol_num])); | ||
| 2118 | |||
| 2119 | strcpy (modified_name + format_modifiers (modifiers, modified_name), | ||
| 2120 | name_table [symbol_num]); | ||
| 2121 | |||
| 2122 | modified = intern (modified_name); | ||
| 2123 | XFASTINT (temp) = modifiers & ~click_modifier; | ||
| 2124 | *slot = Fcons (Fcons (temp, modified), *slot); | ||
| 2125 | Fput (modified, Qevent_kind, symbol_kind); | ||
| 2126 | |||
| 2127 | { | 2243 | { |
| 2128 | Lisp_Object modifier_list; | 2244 | /* No; let's create it. */ |
| 2129 | int i; | 2245 | *slot = intern (name_table[symbol_num]); |
| 2130 | 2246 | ||
| 2131 | modifier_list = Qnil; | 2247 | /* Fill in the cache entries for this symbol; this also |
| 2132 | for (i = 0; (1<<i) <= modifiers; i++) | 2248 | builds the Qevent_symbol_elements property, which the user |
| 2133 | if (modifiers & (1<<i)) | 2249 | cares about. */ |
| 2134 | modifier_list = Fcons (XVECTOR (modifier_symbols)->contents[i], | 2250 | apply_modifiers (0, *slot); |
| 2135 | modifier_list); | 2251 | Fput (*slot, Qevent_kind, symbol_kind); |
| 2136 | |||
| 2137 | /* Put an unmodified version of the symbol at the head of the | ||
| 2138 | list of symbol elements. */ | ||
| 2139 | { | ||
| 2140 | /* We recurse to get the unmodified symbol; this allows us to | ||
| 2141 | write out the code to build event headers only once. | ||
| 2142 | |||
| 2143 | Note that we put ourselves in the symbol_table before we | ||
| 2144 | recurse, so when an unmodified symbol calls this code | ||
| 2145 | to put itself on its Qevent_symbol_elements property, we do | ||
| 2146 | terminate. */ | ||
| 2147 | Lisp_Object unmodified = | ||
| 2148 | modify_event_symbol (symbol_num, | ||
| 2149 | ((modifiers & (down_modifier | drag_modifier)) | ||
| 2150 | ? click_modifier | ||
| 2151 | : 0), | ||
| 2152 | symbol_kind, | ||
| 2153 | name_table, symbol_table, table_size); | ||
| 2154 | |||
| 2155 | Fput (modified, Qevent_symbol_elements, | ||
| 2156 | Fcons (unmodified, modifier_list)); | ||
| 2157 | } | ||
| 2158 | } | 2252 | } |
| 2159 | 2253 | ||
| 2160 | return modified; | 2254 | /* Apply modifiers to that symbol. */ |
| 2161 | } | 2255 | return apply_modifiers (modifiers, *slot); |
| 2162 | } | 2256 | } |
| 2257 | |||
| 2163 | 2258 | ||
| 2164 | DEFUN ("mouse-click-p", Fmouse_click_p, Smouse_click_p, 1, 1, 0, | 2259 | DEFUN ("mouse-click-p", Fmouse_click_p, Smouse_click_p, 1, 1, 0, |
| 2165 | "Return non-nil iff OBJECT is a representation of a mouse event.\n\ | 2260 | "Return non-nil iff OBJECT is a representation of a mouse event.\n\ |
| @@ -2667,8 +2762,9 @@ follow_key (key, nmaps, current, defs, next) | |||
| 2667 | } | 2762 | } |
| 2668 | 2763 | ||
| 2669 | /* Given the set of bindings we've found, produce the next set of maps. */ | 2764 | /* Given the set of bindings we've found, produce the next set of maps. */ |
| 2670 | for (i = 0; i < nmaps; i++) | 2765 | if (first_binding < nmaps) |
| 2671 | next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0); | 2766 | for (i = 0; i < nmaps; i++) |
| 2767 | next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0); | ||
| 2672 | 2768 | ||
| 2673 | return first_binding; | 2769 | return first_binding; |
| 2674 | } | 2770 | } |
| @@ -2768,6 +2864,11 @@ read_key_sequence (keybuf, bufsize, prompt) | |||
| 2768 | t = 0; | 2864 | t = 0; |
| 2769 | this_command_key_count = keys_start; | 2865 | this_command_key_count = keys_start; |
| 2770 | 2866 | ||
| 2867 | /* This is a no-op the first time through, but if we restart, it | ||
| 2868 | reverts the echo area to its original state. */ | ||
| 2869 | if (INTERACTIVE) | ||
| 2870 | echo_truncate (echo_start); | ||
| 2871 | |||
| 2771 | { | 2872 | { |
| 2772 | Lisp_Object *maps; | 2873 | Lisp_Object *maps; |
| 2773 | 2874 | ||
| @@ -2794,9 +2895,26 @@ read_key_sequence (keybuf, bufsize, prompt) | |||
| 2794 | Lisp_Object key; | 2895 | Lisp_Object key; |
| 2795 | int used_mouse_menu = 0; | 2896 | int used_mouse_menu = 0; |
| 2796 | 2897 | ||
| 2898 | /* These variables are analogous to echo_start and keys_start; | ||
| 2899 | while those allow us to restart the entire key sequence, | ||
| 2900 | echo_local_start and keys_local_start allow us to throw away | ||
| 2901 | just one key. */ | ||
| 2902 | int echo_local_start = echo_length (); | ||
| 2903 | int keys_local_start = this_command_key_count; | ||
| 2904 | int local_first_binding = first_binding; | ||
| 2905 | |||
| 2797 | if (t >= bufsize) | 2906 | if (t >= bufsize) |
| 2798 | error ("key sequence too long"); | 2907 | error ("key sequence too long"); |
| 2799 | 2908 | ||
| 2909 | retry_key: | ||
| 2910 | /* These are no-ops, unless we throw away a keystroke below and | ||
| 2911 | jumped back up to retry_key; in that case, these restore these | ||
| 2912 | variables to their original state, allowing us to restart the | ||
| 2913 | loop. */ | ||
| 2914 | echo_truncate (echo_local_start); | ||
| 2915 | this_command_key_count = keys_local_start; | ||
| 2916 | first_binding = local_first_binding; | ||
| 2917 | |||
| 2800 | /* Are we re-reading a key sequence, as indicated by mock_input? */ | 2918 | /* Are we re-reading a key sequence, as indicated by mock_input? */ |
| 2801 | if (t < mock_input) | 2919 | if (t < mock_input) |
| 2802 | { | 2920 | { |
| @@ -2821,6 +2939,26 @@ read_key_sequence (keybuf, bufsize, prompt) | |||
| 2821 | 2939 | ||
| 2822 | Vquit_flag = Qnil; | 2940 | Vquit_flag = Qnil; |
| 2823 | 2941 | ||
| 2942 | /* Clicks in non-text areas get prefixed by the symbol | ||
| 2943 | in their CHAR-ADDRESS field. For example, a click on | ||
| 2944 | the mode line is prefixed by the symbol `mode-line'. */ | ||
| 2945 | if (EVENT_HAS_PARAMETERS (key) | ||
| 2946 | && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qmouse_click)) | ||
| 2947 | { | ||
| 2948 | Lisp_Object posn = POSN_BUFFER_POSN (EVENT_START (key)); | ||
| 2949 | |||
| 2950 | if (XTYPE (posn) == Lisp_Symbol) | ||
| 2951 | { | ||
| 2952 | if (t + 1 >= bufsize) | ||
| 2953 | error ("key sequence too long"); | ||
| 2954 | keybuf[t] = posn; | ||
| 2955 | keybuf[t+1] = key; | ||
| 2956 | mock_input = t + 2; | ||
| 2957 | |||
| 2958 | goto retry_key; | ||
| 2959 | } | ||
| 2960 | } | ||
| 2961 | |||
| 2824 | #ifdef MULTI_FRAME | 2962 | #ifdef MULTI_FRAME |
| 2825 | /* What buffer was this event typed/moused at? */ | 2963 | /* What buffer was this event typed/moused at? */ |
| 2826 | if (used_mouse_menu) | 2964 | if (used_mouse_menu) |
| @@ -2859,21 +2997,72 @@ read_key_sequence (keybuf, bufsize, prompt) | |||
| 2859 | keybuf[0] = key; | 2997 | keybuf[0] = key; |
| 2860 | mock_input = 1; | 2998 | mock_input = 1; |
| 2861 | 2999 | ||
| 2862 | /* Truncate the key sequence in the echo area. */ | ||
| 2863 | if (INTERACTIVE) | ||
| 2864 | echo_truncate (echo_start); | ||
| 2865 | |||
| 2866 | goto restart; | 3000 | goto restart; |
| 2867 | } | 3001 | } |
| 2868 | #endif | 3002 | #endif |
| 2869 | } | 3003 | } |
| 2870 | 3004 | ||
| 2871 | first_binding = (follow_key (key, | 3005 | first_binding = (follow_key (key, |
| 2872 | nmaps - first_binding, | 3006 | nmaps - first_binding, |
| 2873 | submaps + first_binding, | 3007 | submaps + first_binding, |
| 2874 | defs + first_binding, | 3008 | defs + first_binding, |
| 2875 | submaps + first_binding) | 3009 | submaps + first_binding) |
| 2876 | + first_binding); | 3010 | + first_binding); |
| 3011 | |||
| 3012 | /* If this key wasn't bound, we'll try some fallbacks. */ | ||
| 3013 | if (first_binding >= nmaps) | ||
| 3014 | { | ||
| 3015 | Lisp_Object head = EVENT_HEAD (key); | ||
| 3016 | |||
| 3017 | if (XTYPE (head) == Lisp_Symbol) | ||
| 3018 | { | ||
| 3019 | Lisp_Object breakdown = parse_modifiers (head); | ||
| 3020 | Lisp_Object modifiers = | ||
| 3021 | XINT (XCONS (XCONS (breakdown)->cdr)->car); | ||
| 3022 | |||
| 3023 | /* We drop unbound `down-' events altogether. */ | ||
| 3024 | if (modifiers & down_modifier) | ||
| 3025 | { | ||
| 3026 | /* Adding prefixes for non-textual mouse clicks creates | ||
| 3027 | two characters of mock input, and this can't be the | ||
| 3028 | first, so it's okay to clear mock_input in that case. | ||
| 3029 | Only function key expansion could create more than | ||
| 3030 | two keys, but that should never generate mouse events, | ||
| 3031 | so it's okay to nuke mock_input in that case too. | ||
| 3032 | Isn't this just the most wonderful code ever? */ | ||
| 3033 | mock_input = 0; | ||
| 3034 | goto retry_key; | ||
| 3035 | } | ||
| 3036 | |||
| 3037 | /* We turn unbound `drag-' events into `click-' | ||
| 3038 | events, if the click would be bound. */ | ||
| 3039 | else if (modifiers & drag_modifier) | ||
| 3040 | { | ||
| 3041 | Lisp_Object new_head = | ||
| 3042 | apply_modifiers (modifiers & ~drag_modifier, | ||
| 3043 | XCONS (breakdown)->car); | ||
| 3044 | Lisp_Object new_click = | ||
| 3045 | Fcons (new_head, Fcons (EVENT_START (key), Qnil)); | ||
| 3046 | |||
| 3047 | /* Look for a binding for this new key. follow_key | ||
| 3048 | promises that it didn't munge submaps the | ||
| 3049 | last time we called it, since key was unbound. */ | ||
| 3050 | first_binding = | ||
| 3051 | (follow_key (new_click, | ||
| 3052 | nmaps - local_first_binding, | ||
| 3053 | submaps + local_first_binding, | ||
| 3054 | defs + local_first_binding, | ||
| 3055 | submaps + local_first_binding) | ||
| 3056 | + local_first_binding); | ||
| 3057 | |||
| 3058 | /* If that click is bound, go for it. */ | ||
| 3059 | if (first_binding < nmaps) | ||
| 3060 | key = new_click; | ||
| 3061 | /* Otherwise, we'll leave key set to the drag event. */ | ||
| 3062 | } | ||
| 3063 | } | ||
| 3064 | } | ||
| 3065 | |||
| 2877 | keybuf[t++] = key; | 3066 | keybuf[t++] = key; |
| 2878 | /* Normally, last_nonmenu_event gets the previous key we read. | 3067 | /* Normally, last_nonmenu_event gets the previous key we read. |
| 2879 | But when a mouse popup menu is being used, | 3068 | But when a mouse popup menu is being used, |
| @@ -2926,10 +3115,6 @@ read_key_sequence (keybuf, bufsize, prompt) | |||
| 2926 | mock_input = t; | 3115 | mock_input = t; |
| 2927 | fkey_start = fkey_end = t; | 3116 | fkey_start = fkey_end = t; |
| 2928 | 3117 | ||
| 2929 | /* Truncate the key sequence in the echo area. */ | ||
| 2930 | if (INTERACTIVE) | ||
| 2931 | echo_truncate (echo_start); | ||
| 2932 | |||
| 2933 | goto restart; | 3118 | goto restart; |
| 2934 | } | 3119 | } |
| 2935 | 3120 | ||
| @@ -3125,7 +3310,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ | |||
| 3125 | 3310 | ||
| 3126 | UNGCPRO; | 3311 | UNGCPRO; |
| 3127 | 3312 | ||
| 3128 | function = Fintern (function, Vobarray); | 3313 | function = Fintern (function, Qnil); |
| 3129 | Vprefix_arg = prefixarg; | 3314 | Vprefix_arg = prefixarg; |
| 3130 | this_command = function; | 3315 | this_command = function; |
| 3131 | 3316 | ||
| @@ -3621,6 +3806,10 @@ syms_of_keyboard () | |||
| 3621 | staticpro (&Qevent_kind); | 3806 | staticpro (&Qevent_kind); |
| 3622 | Qevent_symbol_elements = intern ("event-symbol-elements"); | 3807 | Qevent_symbol_elements = intern ("event-symbol-elements"); |
| 3623 | staticpro (&Qevent_symbol_elements); | 3808 | staticpro (&Qevent_symbol_elements); |
| 3809 | Qevent_symbol_element_mask = intern ("event-symbol-element-mask"); | ||
| 3810 | staticpro (&Qevent_symbol_element_mask); | ||
| 3811 | Qmodifier_cache = intern ("modifier-cache"); | ||
| 3812 | staticpro (&Qmodifier_cache); | ||
| 3624 | 3813 | ||
| 3625 | { | 3814 | { |
| 3626 | struct event_head *p; | 3815 | struct event_head *p; |