# HG changeset patch # User Jim Blandy # Date 740714814 0 # Node ID fc8c92b6951312beeac07799762e2baddc820ec3 # Parent 70bdc91ef161dc3f4cde1d114b7e965a06a5c0ad * 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. diff -r 70bdc91ef161 -r fc8c92b69513 src/keyboard.c --- a/src/keyboard.c Tue Jun 22 02:02:00 1993 +0000 +++ b/src/keyboard.c Tue Jun 22 02:06:54 1993 +0000 @@ -2143,6 +2143,22 @@ static Lisp_Object button_down_location; +/* Information about the most recent up-going button event: Which + button, what location, and what time. */ + +static int button_up_button; +static int button_up_x; +static int button_up_y; +static unsigned long button_up_time; + +/* The minimum time between clicks to make a double-click. */ + +int double_click_time; + +/* The number of clicks in this multiple-click. */ + +int double_click_count; + /* Given a struct input_event, build the lisp event which represents it. If EVENT is 0, build a mouse movement event from the mouse movement buffer, which should have a movement event in it. @@ -2176,12 +2192,14 @@ c |= (event->modifiers & (meta_modifier | alt_modifier | hyper_modifier | super_modifier)); + button_up_time = 0; return c; } /* A function key. The symbol may need to have modifier prefixes tacked onto it. */ case non_ascii_keystroke: + button_up_time = 0; return modify_event_symbol (XFASTINT (event->code), event->modifiers, Qfunction_key, lispy_function_keys, &func_key_syms, @@ -2316,10 +2334,36 @@ pair. */ Lisp_Object down = Fnth (make_number (2), start_pos); - event->modifiers |= ((EQ (event->x, XCONS (down)->car) - && EQ (event->y, XCONS (down)->cdr)) - ? click_modifier - : drag_modifier); + if (EQ (event->x, XCONS (down)->car) + && EQ (event->y, XCONS (down)->cdr)) + { + if (button == button_up_button + && XINT (event->x) == button_up_x + && XINT (event->y) == button_up_y + && button_up_time != 0 + && ((int)(event->timestamp - button_up_time) + < double_click_time)) + { + double_click_count++; + event->modifiers |= ((double_click_count > 2) + ? triple_modifier + : double_modifier); + } + else + { + double_click_count = 1; + event->modifiers |= click_modifier; + } + button_up_button = button; + button_up_x = XINT (event->x); + button_up_y = XINT (event->y); + button_up_time = event->timestamp; + } + else + { + button_up_time = 0; + event->modifiers |= drag_modifier; + } } } else @@ -2342,6 +2386,11 @@ Fcons (start_pos, Fcons (position, Qnil))); + else if (event->modifiers & (double_modifier | triple_modifier)) + return Fcons (head, + Fcons (position, + Fcons (make_number (double_click_count), + Qnil))); else return Fcons (head, Fcons (position, @@ -2498,6 +2547,24 @@ modifiers |= down_modifier; i += 5; } + else if (i + 7 <= name->size + && ! strncmp (name->data + i, "double-", 7)) + { + modifiers |= double_modifier; + i += 7; + } + else + goto no_more_modifiers; + break; + + case 't': + if (i + 7 > name->size) + goto no_more_modifiers; + if (! strncmp (name->data + i, "triple-", 7)) + { + modifiers |= triple_modifier; + i += 7; + } else goto no_more_modifiers; break; @@ -2510,7 +2577,8 @@ no_more_modifiers: /* Should we include the `click' modifier? */ - if (! (modifiers & (down_modifier | drag_modifier)) + if (! (modifiers & (down_modifier | drag_modifier + | double_modifier | triple_modifier)) && i + 7 == name->size && strncmp (name->data + i, "mouse-", 6) == 0 && ('0' <= name->data[i + 6] && name->data[i + 6] <= '9')) @@ -2536,7 +2604,7 @@ to use Fintern, which expects a genuine Lisp_String, and keeps a reference to it. */ char *new_mods = - (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-")); + (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-")); int mod_len; { @@ -2555,6 +2623,8 @@ if (modifiers & super_modifier) { *p++ = 's'; *p++ = '-'; } if (modifiers & down_modifier) { strcpy (p, "down-"); p += 5; } if (modifiers & drag_modifier) { strcpy (p, "drag-"); p += 5; } + if (modifiers & double_modifier) { strcpy (p, "double-"); p += 7; } + if (modifiers & triple_modifier) { strcpy (p, "triple-"); p += 7; } /* The click modifier is denoted by the absence of other modifiers. */ *p = '\0'; @@ -2575,7 +2645,7 @@ static char *modifier_names[] = { - "up", "down", "drag", "click", 0, 0, 0, 0, + "up", "down", "drag", "click", "double", "triple", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "alt", "super", "hyper", "shift", "control", "meta" }; @@ -3525,8 +3595,10 @@ function key's sequence. If so, we try to read the whole function key, and substitute its symbolic name into the key sequence. - We ignore unbound `down-' mouse clicks. We turn unbound `drag-' - events into similar click events, if that would make them bound. + We ignore unbound `down-' mouse clicks. We turn unbound `drag-' and + `double-' events into similar click events, if that would make them + bound. We try to turn `triple-' events first into `double-' events, + then into clicks. If we get a mouse click in a mode line, vertical divider, or other non-text area, we treat the click as if it were prefixed by the @@ -3947,29 +4019,41 @@ /* We turn unbound `drag-' events into `click-' events, if the click would be bound. */ - else if (modifiers & drag_modifier) + else if (modifiers & (drag_modifier | double_modifier + | triple_modifier)) { - Lisp_Object new_head = - apply_modifiers (modifiers & ~drag_modifier, - XCONS (breakdown)->car); - Lisp_Object new_click = - Fcons (new_head, Fcons (EVENT_START (key), Qnil)); - - /* Look for a binding for this new key. follow_key - promises that it didn't munge submaps the - last time we called it, since key was unbound. */ - first_binding = - (follow_key (new_click, - nmaps - local_first_binding, - submaps + local_first_binding, - defs + local_first_binding, - submaps + local_first_binding) - + local_first_binding); - - /* If that click is bound, go for it. */ - if (first_binding < nmaps) - key = new_click; - /* Otherwise, we'll leave key set to the drag event. */ + while (modifiers & (drag_modifier | double_modifier + | triple_modifier)) + { + Lisp_Object new_head, new_click; + if (modifiers & triple_modifier) + modifiers ^= (double_modifier | triple_modifier); + else + modifiers &= ~(drag_modifier | double_modifier); + new_head = + apply_modifiers (modifiers, XCONS (breakdown)->car); + new_click = + Fcons (new_head, Fcons (EVENT_START (key), Qnil)); + + /* Look for a binding for this new key. follow_key + promises that it didn't munge submaps the + last time we called it, since key was unbound. */ + first_binding = + (follow_key (new_click, + nmaps - local_first_binding, + submaps + local_first_binding, + defs + local_first_binding, + submaps + local_first_binding) + + local_first_binding); + + /* If that click is bound, go for it. */ + if (first_binding < nmaps) + { + key = new_click; + break; + } + /* Otherwise, we'll leave key set to the drag event. */ + } } } } @@ -4093,10 +4177,10 @@ \n\ `read-key-sequence' drops unbound button-down events, since you normally\n\ only care about the click or drag events which follow them. If a drag\n\ -event is unbound, but the corresponding click event would be bound,\n\ -`read-key-sequence' turns the drag event into a click event at the\n\ +or multi-click event is unbound, but the corresponding click event would\n\ +be bound, `read-key-sequence' turns the event into a click event at the\n\ drag's starting position. This means that you don't have to distinguish\n\ -between click and drag events unless you want to.\n\ +between click and drag, double, or triple events unless you want to.\n\ \n\ `read-key-sequence' prefixes mouse events on mode lines, the vertical\n\ lines separating windows, and scroll bars with imaginary keys\n\ @@ -4979,6 +5063,13 @@ Polling is automatically disabled in all other cases."); polling_period = 2; + DEFVAR_INT ("double-click-time", &double_click_time, + "*Maximum time between mouse clicks to make a double-click.\n\ +Measured in milliseconds. Zero means disable double-click recognition;\n\ +a large number means double-clicks have no time limit and are detected\n\ +by position only."); + double_click_time = 500; + DEFVAR_INT ("num-input-keys", &num_input_keys, "*Number of complete keys read from the keyboard so far."); num_input_keys = 0; diff -r 70bdc91ef161 -r fc8c92b69513 src/termhooks.h --- a/src/termhooks.h Tue Jun 22 02:02:00 1993 +0000 +++ b/src/termhooks.h Tue Jun 22 02:06:54 1993 +0000 @@ -286,10 +286,11 @@ is a mouse click lacking the click and drag modifiers. The window-system independent code turns all up_modifier events - bits into either drag_modifier or click_modifier events. The - click_modifier has no written representation in the names of the - symbols used as event heads, but it does appear in the - Qevent_symbol_components property of the event heads. */ + bits into drag_modifier, click_modifier, double_modifier, or + triple_modifier events. The click_modifier has no written + representation in the names of the symbols used as event heads, + but it does appear in the Qevent_symbol_components property of the + event heads. */ enum { up_modifier = 1, /* Only used on mouse buttons - always turned into a click or a drag modifier @@ -299,6 +300,8 @@ queue; it's only used internally by the window-system-independent code. */ click_modifier= 8, /* See drag_modifier. */ + double_modifier= 16, /* See drag_modifier. */ + triple_modifier= 32, /* See drag_modifier. */ /* The next four modifier bits are used also in keyboard events at the Lisp level.