diff options
| author | Jim Blandy | 1993-06-22 02:06:54 +0000 |
|---|---|---|
| committer | Jim Blandy | 1993-06-22 02:06:54 +0000 |
| commit | fbcd35bd72c1778817294cc160a84353fd864a9e (patch) | |
| tree | 09c94a6596f26a5ee13e5dac4b87b6ed402661cc | |
| parent | 69b95560cde2119f7f3c3d5bd241bc7355bcf27d (diff) | |
| download | emacs-fbcd35bd72c1778817294cc160a84353fd864a9e.tar.gz emacs-fbcd35bd72c1778817294cc160a84353fd864a9e.zip | |
* keyboard.c (make_lispy_event): Added detection of double-click
and triple-click events.
(parse_modifiers_uncached, apply_modifiers_uncached): Same.
(read_key_sequence): Coerce double-clicks to clicks, and triple-clicks
to double-clicks or clicks, by analogy with drag events.
(double_click_time): Added variable.
* termhooks.h: Added multi-click event modifier bits.
| -rw-r--r-- | src/keyboard.c | 159 | ||||
| -rw-r--r-- | src/termhooks.h | 11 |
2 files changed, 132 insertions, 38 deletions
diff --git a/src/keyboard.c b/src/keyboard.c index 49d27b0dcdc..6a18aed16f9 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -2143,6 +2143,22 @@ Lisp_Object *scroll_bar_parts[] = { | |||
| 2143 | 2143 | ||
| 2144 | static Lisp_Object button_down_location; | 2144 | static Lisp_Object button_down_location; |
| 2145 | 2145 | ||
| 2146 | /* Information about the most recent up-going button event: Which | ||
| 2147 | button, what location, and what time. */ | ||
| 2148 | |||
| 2149 | static int button_up_button; | ||
| 2150 | static int button_up_x; | ||
| 2151 | static int button_up_y; | ||
| 2152 | static unsigned long button_up_time; | ||
| 2153 | |||
| 2154 | /* The minimum time between clicks to make a double-click. */ | ||
| 2155 | |||
| 2156 | int double_click_time; | ||
| 2157 | |||
| 2158 | /* The number of clicks in this multiple-click. */ | ||
| 2159 | |||
| 2160 | int double_click_count; | ||
| 2161 | |||
| 2146 | /* Given a struct input_event, build the lisp event which represents | 2162 | /* Given a struct input_event, build the lisp event which represents |
| 2147 | it. If EVENT is 0, build a mouse movement event from the mouse | 2163 | it. If EVENT is 0, build a mouse movement event from the mouse |
| 2148 | movement buffer, which should have a movement event in it. | 2164 | movement buffer, which should have a movement event in it. |
| @@ -2176,12 +2192,14 @@ make_lispy_event (event) | |||
| 2176 | c |= (event->modifiers | 2192 | c |= (event->modifiers |
| 2177 | & (meta_modifier | alt_modifier | 2193 | & (meta_modifier | alt_modifier |
| 2178 | | hyper_modifier | super_modifier)); | 2194 | | hyper_modifier | super_modifier)); |
| 2195 | button_up_time = 0; | ||
| 2179 | return c; | 2196 | return c; |
| 2180 | } | 2197 | } |
| 2181 | 2198 | ||
| 2182 | /* A function key. The symbol may need to have modifier prefixes | 2199 | /* A function key. The symbol may need to have modifier prefixes |
| 2183 | tacked onto it. */ | 2200 | tacked onto it. */ |
| 2184 | case non_ascii_keystroke: | 2201 | case non_ascii_keystroke: |
| 2202 | button_up_time = 0; | ||
| 2185 | return modify_event_symbol (XFASTINT (event->code), event->modifiers, | 2203 | return modify_event_symbol (XFASTINT (event->code), event->modifiers, |
| 2186 | Qfunction_key, | 2204 | Qfunction_key, |
| 2187 | lispy_function_keys, &func_key_syms, | 2205 | lispy_function_keys, &func_key_syms, |
| @@ -2316,10 +2334,36 @@ make_lispy_event (event) | |||
| 2316 | pair. */ | 2334 | pair. */ |
| 2317 | Lisp_Object down = Fnth (make_number (2), start_pos); | 2335 | Lisp_Object down = Fnth (make_number (2), start_pos); |
| 2318 | 2336 | ||
| 2319 | event->modifiers |= ((EQ (event->x, XCONS (down)->car) | 2337 | if (EQ (event->x, XCONS (down)->car) |
| 2320 | && EQ (event->y, XCONS (down)->cdr)) | 2338 | && EQ (event->y, XCONS (down)->cdr)) |
| 2321 | ? click_modifier | 2339 | { |
| 2322 | : drag_modifier); | 2340 | if (button == button_up_button |
| 2341 | && XINT (event->x) == button_up_x | ||
| 2342 | && XINT (event->y) == button_up_y | ||
| 2343 | && button_up_time != 0 | ||
| 2344 | && ((int)(event->timestamp - button_up_time) | ||
| 2345 | < double_click_time)) | ||
| 2346 | { | ||
| 2347 | double_click_count++; | ||
| 2348 | event->modifiers |= ((double_click_count > 2) | ||
| 2349 | ? triple_modifier | ||
| 2350 | : double_modifier); | ||
| 2351 | } | ||
| 2352 | else | ||
| 2353 | { | ||
| 2354 | double_click_count = 1; | ||
| 2355 | event->modifiers |= click_modifier; | ||
| 2356 | } | ||
| 2357 | button_up_button = button; | ||
| 2358 | button_up_x = XINT (event->x); | ||
| 2359 | button_up_y = XINT (event->y); | ||
| 2360 | button_up_time = event->timestamp; | ||
| 2361 | } | ||
| 2362 | else | ||
| 2363 | { | ||
| 2364 | button_up_time = 0; | ||
| 2365 | event->modifiers |= drag_modifier; | ||
| 2366 | } | ||
| 2323 | } | 2367 | } |
| 2324 | } | 2368 | } |
| 2325 | else | 2369 | else |
| @@ -2342,6 +2386,11 @@ make_lispy_event (event) | |||
| 2342 | Fcons (start_pos, | 2386 | Fcons (start_pos, |
| 2343 | Fcons (position, | 2387 | Fcons (position, |
| 2344 | Qnil))); | 2388 | Qnil))); |
| 2389 | else if (event->modifiers & (double_modifier | triple_modifier)) | ||
| 2390 | return Fcons (head, | ||
| 2391 | Fcons (position, | ||
| 2392 | Fcons (make_number (double_click_count), | ||
| 2393 | Qnil))); | ||
| 2345 | else | 2394 | else |
| 2346 | return Fcons (head, | 2395 | return Fcons (head, |
| 2347 | Fcons (position, | 2396 | Fcons (position, |
| @@ -2498,6 +2547,24 @@ parse_modifiers_uncached (symbol, modifier_end) | |||
| 2498 | modifiers |= down_modifier; | 2547 | modifiers |= down_modifier; |
| 2499 | i += 5; | 2548 | i += 5; |
| 2500 | } | 2549 | } |
| 2550 | else if (i + 7 <= name->size | ||
| 2551 | && ! strncmp (name->data + i, "double-", 7)) | ||
| 2552 | { | ||
| 2553 | modifiers |= double_modifier; | ||
| 2554 | i += 7; | ||
| 2555 | } | ||
| 2556 | else | ||
| 2557 | goto no_more_modifiers; | ||
| 2558 | break; | ||
| 2559 | |||
| 2560 | case 't': | ||
| 2561 | if (i + 7 > name->size) | ||
| 2562 | goto no_more_modifiers; | ||
| 2563 | if (! strncmp (name->data + i, "triple-", 7)) | ||
| 2564 | { | ||
| 2565 | modifiers |= triple_modifier; | ||
| 2566 | i += 7; | ||
| 2567 | } | ||
| 2501 | else | 2568 | else |
| 2502 | goto no_more_modifiers; | 2569 | goto no_more_modifiers; |
| 2503 | break; | 2570 | break; |
| @@ -2510,7 +2577,8 @@ parse_modifiers_uncached (symbol, modifier_end) | |||
| 2510 | no_more_modifiers: | 2577 | no_more_modifiers: |
| 2511 | 2578 | ||
| 2512 | /* Should we include the `click' modifier? */ | 2579 | /* Should we include the `click' modifier? */ |
| 2513 | if (! (modifiers & (down_modifier | drag_modifier)) | 2580 | if (! (modifiers & (down_modifier | drag_modifier |
| 2581 | | double_modifier | triple_modifier)) | ||
| 2514 | && i + 7 == name->size | 2582 | && i + 7 == name->size |
| 2515 | && strncmp (name->data + i, "mouse-", 6) == 0 | 2583 | && strncmp (name->data + i, "mouse-", 6) == 0 |
| 2516 | && ('0' <= name->data[i + 6] && name->data[i + 6] <= '9')) | 2584 | && ('0' <= name->data[i + 6] && name->data[i + 6] <= '9')) |
| @@ -2536,7 +2604,7 @@ apply_modifiers_uncached (modifiers, base, base_len) | |||
| 2536 | to use Fintern, which expects a genuine Lisp_String, and keeps a | 2604 | to use Fintern, which expects a genuine Lisp_String, and keeps a |
| 2537 | reference to it. */ | 2605 | reference to it. */ |
| 2538 | char *new_mods = | 2606 | char *new_mods = |
| 2539 | (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-")); | 2607 | (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-")); |
| 2540 | int mod_len; | 2608 | int mod_len; |
| 2541 | 2609 | ||
| 2542 | { | 2610 | { |
| @@ -2555,6 +2623,8 @@ apply_modifiers_uncached (modifiers, base, base_len) | |||
| 2555 | if (modifiers & super_modifier) { *p++ = 's'; *p++ = '-'; } | 2623 | if (modifiers & super_modifier) { *p++ = 's'; *p++ = '-'; } |
| 2556 | if (modifiers & down_modifier) { strcpy (p, "down-"); p += 5; } | 2624 | if (modifiers & down_modifier) { strcpy (p, "down-"); p += 5; } |
| 2557 | if (modifiers & drag_modifier) { strcpy (p, "drag-"); p += 5; } | 2625 | if (modifiers & drag_modifier) { strcpy (p, "drag-"); p += 5; } |
| 2626 | if (modifiers & double_modifier) { strcpy (p, "double-"); p += 7; } | ||
| 2627 | if (modifiers & triple_modifier) { strcpy (p, "triple-"); p += 7; } | ||
| 2558 | /* The click modifier is denoted by the absence of other modifiers. */ | 2628 | /* The click modifier is denoted by the absence of other modifiers. */ |
| 2559 | 2629 | ||
| 2560 | *p = '\0'; | 2630 | *p = '\0'; |
| @@ -2575,7 +2645,7 @@ apply_modifiers_uncached (modifiers, base, base_len) | |||
| 2575 | 2645 | ||
| 2576 | static char *modifier_names[] = | 2646 | static char *modifier_names[] = |
| 2577 | { | 2647 | { |
| 2578 | "up", "down", "drag", "click", 0, 0, 0, 0, | 2648 | "up", "down", "drag", "click", "double", "triple", 0, 0, |
| 2579 | 0, 0, 0, 0, 0, 0, 0, 0, | 2649 | 0, 0, 0, 0, 0, 0, 0, 0, |
| 2580 | 0, 0, "alt", "super", "hyper", "shift", "control", "meta" | 2650 | 0, 0, "alt", "super", "hyper", "shift", "control", "meta" |
| 2581 | }; | 2651 | }; |
| @@ -3525,8 +3595,10 @@ follow_key (key, nmaps, current, defs, next) | |||
| 3525 | function key's sequence. If so, we try to read the whole function | 3595 | function key's sequence. If so, we try to read the whole function |
| 3526 | key, and substitute its symbolic name into the key sequence. | 3596 | key, and substitute its symbolic name into the key sequence. |
| 3527 | 3597 | ||
| 3528 | We ignore unbound `down-' mouse clicks. We turn unbound `drag-' | 3598 | We ignore unbound `down-' mouse clicks. We turn unbound `drag-' and |
| 3529 | events into similar click events, if that would make them bound. | 3599 | `double-' events into similar click events, if that would make them |
| 3600 | bound. We try to turn `triple-' events first into `double-' events, | ||
| 3601 | then into clicks. | ||
| 3530 | 3602 | ||
| 3531 | If we get a mouse click in a mode line, vertical divider, or other | 3603 | If we get a mouse click in a mode line, vertical divider, or other |
| 3532 | non-text area, we treat the click as if it were prefixed by the | 3604 | non-text area, we treat the click as if it were prefixed by the |
| @@ -3947,29 +4019,41 @@ read_key_sequence (keybuf, bufsize, prompt) | |||
| 3947 | 4019 | ||
| 3948 | /* We turn unbound `drag-' events into `click-' | 4020 | /* We turn unbound `drag-' events into `click-' |
| 3949 | events, if the click would be bound. */ | 4021 | events, if the click would be bound. */ |
| 3950 | else if (modifiers & drag_modifier) | 4022 | else if (modifiers & (drag_modifier | double_modifier |
| 4023 | | triple_modifier)) | ||
| 3951 | { | 4024 | { |
| 3952 | Lisp_Object new_head = | 4025 | while (modifiers & (drag_modifier | double_modifier |
| 3953 | apply_modifiers (modifiers & ~drag_modifier, | 4026 | | triple_modifier)) |
| 3954 | XCONS (breakdown)->car); | 4027 | { |
| 3955 | Lisp_Object new_click = | 4028 | Lisp_Object new_head, new_click; |
| 3956 | Fcons (new_head, Fcons (EVENT_START (key), Qnil)); | 4029 | if (modifiers & triple_modifier) |
| 3957 | 4030 | modifiers ^= (double_modifier | triple_modifier); | |
| 3958 | /* Look for a binding for this new key. follow_key | 4031 | else |
| 3959 | promises that it didn't munge submaps the | 4032 | modifiers &= ~(drag_modifier | double_modifier); |
| 3960 | last time we called it, since key was unbound. */ | 4033 | new_head = |
| 3961 | first_binding = | 4034 | apply_modifiers (modifiers, XCONS (breakdown)->car); |
| 3962 | (follow_key (new_click, | 4035 | new_click = |
| 3963 | nmaps - local_first_binding, | 4036 | Fcons (new_head, Fcons (EVENT_START (key), Qnil)); |
| 3964 | submaps + local_first_binding, | 4037 | |
| 3965 | defs + local_first_binding, | 4038 | /* Look for a binding for this new key. follow_key |
| 3966 | submaps + local_first_binding) | 4039 | promises that it didn't munge submaps the |
| 3967 | + local_first_binding); | 4040 | last time we called it, since key was unbound. */ |
| 3968 | 4041 | first_binding = | |
| 3969 | /* If that click is bound, go for it. */ | 4042 | (follow_key (new_click, |
| 3970 | if (first_binding < nmaps) | 4043 | nmaps - local_first_binding, |
| 3971 | key = new_click; | 4044 | submaps + local_first_binding, |
| 3972 | /* Otherwise, we'll leave key set to the drag event. */ | 4045 | defs + local_first_binding, |
| 4046 | submaps + local_first_binding) | ||
| 4047 | + local_first_binding); | ||
| 4048 | |||
| 4049 | /* If that click is bound, go for it. */ | ||
| 4050 | if (first_binding < nmaps) | ||
| 4051 | { | ||
| 4052 | key = new_click; | ||
| 4053 | break; | ||
| 4054 | } | ||
| 4055 | /* Otherwise, we'll leave key set to the drag event. */ | ||
| 4056 | } | ||
| 3973 | } | 4057 | } |
| 3974 | } | 4058 | } |
| 3975 | } | 4059 | } |
| @@ -4093,10 +4177,10 @@ of the selected window as normal.\n\ | |||
| 4093 | \n\ | 4177 | \n\ |
| 4094 | `read-key-sequence' drops unbound button-down events, since you normally\n\ | 4178 | `read-key-sequence' drops unbound button-down events, since you normally\n\ |
| 4095 | only care about the click or drag events which follow them. If a drag\n\ | 4179 | only care about the click or drag events which follow them. If a drag\n\ |
| 4096 | event is unbound, but the corresponding click event would be bound,\n\ | 4180 | or multi-click event is unbound, but the corresponding click event would\n\ |
| 4097 | `read-key-sequence' turns the drag event into a click event at the\n\ | 4181 | be bound, `read-key-sequence' turns the event into a click event at the\n\ |
| 4098 | drag's starting position. This means that you don't have to distinguish\n\ | 4182 | drag's starting position. This means that you don't have to distinguish\n\ |
| 4099 | between click and drag events unless you want to.\n\ | 4183 | between click and drag, double, or triple events unless you want to.\n\ |
| 4100 | \n\ | 4184 | \n\ |
| 4101 | `read-key-sequence' prefixes mouse events on mode lines, the vertical\n\ | 4185 | `read-key-sequence' prefixes mouse events on mode lines, the vertical\n\ |
| 4102 | lines separating windows, and scroll bars with imaginary keys\n\ | 4186 | lines separating windows, and scroll bars with imaginary keys\n\ |
| @@ -4979,6 +5063,13 @@ Polling is needed only when using X windows and SIGIO does not work.\n\ | |||
| 4979 | Polling is automatically disabled in all other cases."); | 5063 | Polling is automatically disabled in all other cases."); |
| 4980 | polling_period = 2; | 5064 | polling_period = 2; |
| 4981 | 5065 | ||
| 5066 | DEFVAR_INT ("double-click-time", &double_click_time, | ||
| 5067 | "*Maximum time between mouse clicks to make a double-click.\n\ | ||
| 5068 | Measured in milliseconds. Zero means disable double-click recognition;\n\ | ||
| 5069 | a large number means double-clicks have no time limit and are detected\n\ | ||
| 5070 | by position only."); | ||
| 5071 | double_click_time = 500; | ||
| 5072 | |||
| 4982 | DEFVAR_INT ("num-input-keys", &num_input_keys, | 5073 | DEFVAR_INT ("num-input-keys", &num_input_keys, |
| 4983 | "*Number of complete keys read from the keyboard so far."); | 5074 | "*Number of complete keys read from the keyboard so far."); |
| 4984 | num_input_keys = 0; | 5075 | num_input_keys = 0; |
diff --git a/src/termhooks.h b/src/termhooks.h index a410038f5f6..53d48f254e6 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -286,10 +286,11 @@ struct input_event { | |||
| 286 | is a mouse click lacking the click and drag modifiers. | 286 | is a mouse click lacking the click and drag modifiers. |
| 287 | 287 | ||
| 288 | The window-system independent code turns all up_modifier events | 288 | The window-system independent code turns all up_modifier events |
| 289 | bits into either drag_modifier or click_modifier events. The | 289 | bits into drag_modifier, click_modifier, double_modifier, or |
| 290 | click_modifier has no written representation in the names of the | 290 | triple_modifier events. The click_modifier has no written |
| 291 | symbols used as event heads, but it does appear in the | 291 | representation in the names of the symbols used as event heads, |
| 292 | Qevent_symbol_components property of the event heads. */ | 292 | but it does appear in the Qevent_symbol_components property of the |
| 293 | event heads. */ | ||
| 293 | enum { | 294 | enum { |
| 294 | up_modifier = 1, /* Only used on mouse buttons - always | 295 | up_modifier = 1, /* Only used on mouse buttons - always |
| 295 | turned into a click or a drag modifier | 296 | turned into a click or a drag modifier |
| @@ -299,6 +300,8 @@ enum { | |||
| 299 | queue; it's only used internally by | 300 | queue; it's only used internally by |
| 300 | the window-system-independent code. */ | 301 | the window-system-independent code. */ |
| 301 | click_modifier= 8, /* See drag_modifier. */ | 302 | click_modifier= 8, /* See drag_modifier. */ |
| 303 | double_modifier= 16, /* See drag_modifier. */ | ||
| 304 | triple_modifier= 32, /* See drag_modifier. */ | ||
| 302 | 305 | ||
| 303 | /* The next four modifier bits are used also in keyboard events at | 306 | /* The next four modifier bits are used also in keyboard events at |
| 304 | the Lisp level. | 307 | the Lisp level. |