emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Subject: w32 mouse wheel handling


From: David Ponce
Subject: Re: Subject: w32 mouse wheel handling
Date: Thu, 29 May 2003 00:18:54 +0200
User-agent: Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4b) Gecko/20030526

[...]
`wheel-up' and `wheel-down' are better because they are similar to the
names of the vertical arrow keys, which are `up' and `down'.  I don't
think people will confuse this with the `down-' prefix for mouse keys.
(There is no `up-' prefix.)

Hi,

Following above suggestion to produce wheel-up/down Lisp events from
mouse wheel, I propose you an implementation :-)

Here is an overview:

I introduced the new event type WHEEL_EVENT which results in
wheel-up/down Lisp events (kind of mouse click events), depending on
the setting of the up_modifier or down_modifier.

Like with mouse buttons, it will be possible to handle several wheels:
wheel-up-1 and wheel-down-1 events are associated to the first wheel,
wheel-up-2 and wheel-down-2 to the second wheel, etc..

Depending on the speed the wheel is moved, wheel-up/down events can
get a double- or triple- modifier with `event-click-count' set.  For
example, `mwheel-scroll' uses that information to implement
`mouse-wheel-progessive-speed'.

For now I updated w32term.c to generate WHEEL_EVENTs from
w32 WM_MOUSEWHEEL events.  This result in wheel-up-1/wheel-down-1
Lisp events (as there is only one mouse wheel button).

My X and MAC skills are too limited, so I didn't updated xterm.c and
macterm.c.  Sorry.

To try the new code with mwheel.el, you need to customize
`mouse-wheel-down-event' and `mouse-wheel-up-event' to be respectively
wheel-down-1 and wheel-up-1.

Following is the change log and the patch.

Hope it will help.

Sincerely,
David

2003-05-28  David Ponce  <address@hidden>

        * termhooks.h (enum event_kind): Added new WHEEL_EVENT event.

        * keyboard.c (Qmouse_wheel): Declare only if MAC_OSX defined.
        (mouse_wheel_syms, lispy_mouse_wheel_names): Likewise.
        (discard_mouse_events): Discard WHEEL_EVENT events too.
        (Vlispy_wheel_up_stem, Vlispy_wheel_down_stem)
        (wheel_up_syms, wheel_down_syms): New.
        (syms_of_keyboard): Init and staticpro them.  Init and staticpro
        Qmouse_wheel and mouse_wheel_syms only if MAC_OSX defined.
        (make_lispy_event): Added WHEEL_EVENT handler.

        * w32term.c (construct_mouse_wheel): Construct WHEEL_EVENT.
        (w32_read_socket): Map w32 WM_MOUSEWHEEL events to Emacs
        WHEEL_EVENT events.

Index: src/keyboard.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/keyboard.c,v
retrieving revision 1.747
diff -c -r1.747 keyboard.c
*** src/keyboard.c      26 May 2003 22:55:45 -0000      1.747
--- src/keyboard.c      28 May 2003 22:04:11 -0000
***************
*** 547,553 ****
  /* Symbols to denote kinds of events.  */
  Lisp_Object Qfunction_key;
  Lisp_Object Qmouse_click;
! #if defined(WINDOWSNT) || defined(MAC_OSX)
  Lisp_Object Qmouse_wheel;
  #endif
  #ifdef WINDOWSNT
--- 547,553 ----
  /* Symbols to denote kinds of events.  */
  Lisp_Object Qfunction_key;
  Lisp_Object Qmouse_click;
! #if defined(MAC_OSX)
  Lisp_Object Qmouse_wheel;
  #endif
  #ifdef WINDOWSNT
***************
*** 3737,3742 ****
--- 3737,3743 ----
        sp = kbd_buffer;

        if (sp->kind == MOUSE_CLICK_EVENT
+           || sp->kind == WHEEL_EVENT
  #ifdef WINDOWSNT
          || sp->kind == W32_SCROLL_BAR_CLICK_EVENT
  #endif
***************
*** 4436,4442 ****
  static Lisp_Object accent_key_syms;
  static Lisp_Object func_key_syms;
  static Lisp_Object mouse_syms;
! #if defined(WINDOWSNT) || defined(MAC_OSX)
  static Lisp_Object mouse_wheel_syms;
  #endif
  static Lisp_Object drag_n_drop_syms;
--- 4437,4445 ----
  static Lisp_Object accent_key_syms;
  static Lisp_Object func_key_syms;
  static Lisp_Object mouse_syms;
! static Lisp_Object wheel_up_syms;
! static Lisp_Object wheel_down_syms;
! #if defined(MAC_OSX)
  static Lisp_Object mouse_wheel_syms;
  #endif
  static Lisp_Object drag_n_drop_syms;
***************
*** 4891,4898 ****
  #endif /* not HAVE_NTGUI */

  Lisp_Object Vlispy_mouse_stem;

! #if defined(WINDOWSNT) || defined(MAC_OSX)
  /* mouse-wheel events are generated by the wheel on devices such as
     the MS Intellimouse.  The wheel sits in between the left and right
     mouse buttons, and is typically used to scroll or zoom the window
--- 4894,4903 ----
  #endif /* not HAVE_NTGUI */

  Lisp_Object Vlispy_mouse_stem;
+ Lisp_Object Vlispy_wheel_up_stem;
+ Lisp_Object Vlispy_wheel_down_stem;

! #if defined(MAC_OSX)
  /* mouse-wheel events are generated by the wheel on devices such as
     the MS Intellimouse.  The wheel sits in between the left and right
     mouse buttons, and is typically used to scroll or zoom the window
***************
*** 5416,5421 ****
--- 5421,5623 ----
        }
        }

+     case WHEEL_EVENT:
+       {
+       int button = event->code;
+       int is_double;
+       Lisp_Object position;
+       Lisp_Object window;
+         Lisp_Object head;
+
+       position = Qnil;
+
+       /* Build the position as appropriate for this mouse click.  */
+         enum window_part part;
+         struct frame *f = XFRAME (event->frame_or_window);
+         Lisp_Object posn;
+         Lisp_Object string_info = Qnil;
+         int row, column;
+         int wx, wy;
+
+         /* Ignore mouse events that were made on frame that
+            have been deleted.  */
+         if (! FRAME_LIVE_P (f))
+           return Qnil;
+
+         /* EVENT->x and EVENT->y are frame-relative pixel
+            coordinates at this place.  Under old redisplay, COLUMN
+            and ROW are set to frame relative glyph coordinates
+            which are then used to determine whether this click is
+            in a menu (non-toolkit version).  */
+         pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                                &column, &row, NULL, 1);
+
+         /* Set `window' to the window under frame pixel coordinates
+            event->x/event->y.  */
+         window = window_from_coordinates (f, XINT (event->x),
+                                           XINT (event->y),
+                                           &part, &wx, &wy, 0);
+
+         if (!WINDOWP (window))
+           {
+             window = event->frame_or_window;
+             posn = Qnil;
+           }
+         else
+           {
+             /* It's a click in window window at frame coordinates
+                event->x/ event->y.  */
+             struct window *w = XWINDOW (window);
+
+             /* Set event coordinates to window-relative coordinates
+                for constructing the Lisp event below.  */
+             XSETINT (event->x, wx);
+             XSETINT (event->y, wy);
+
+             if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
+               {
+                 /* Mode line or header line.  Look for a string under
+                    the mouse that may have a `local-map' property.  */
+                 Lisp_Object string;
+                 int charpos;
+
+                 posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
+                 string = mode_line_string (w, wx, wy, part, &charpos);
+                 if (STRINGP (string))
+                   string_info = Fcons (string, make_number (charpos));
+               }
+             else if (part == ON_VERTICAL_BORDER)
+               posn = Qvertical_line;
+             else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
+               {
+                 int charpos;
+                 Lisp_Object object = marginal_area_string (w, wx, wy, part,
+                                                            &charpos);
+                 posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : 
Qright_margin;
+                 if (STRINGP (object))
+                   string_info = Fcons (object, make_number (charpos));
+               }
+             else
+               {
+                 Lisp_Object object;
+                 struct display_pos p;
+                 buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+                 posn = make_number (CHARPOS (p.pos));
+                 if (STRINGP (object))
+                   string_info
+                     = Fcons (object,
+                              make_number (CHARPOS (p.string_pos)));
+               }
+           }
+
+         position
+           = Fcons (window,
+                    Fcons (posn,
+                           Fcons (Fcons (event->x, event->y),
+                                  Fcons (make_number (event->timestamp),
+                                         (NILP (string_info)
+                                          ? Qnil
+                                          : Fcons (string_info, Qnil))))));
+
+         /* Set double or triple modifiers to indicate the wheel speed.  */
+       {
+         /* On window-system frames, use the value of
+            double-click-fuzz as is.  On other frames, interpret it
+            as a multiple of 1/8 characters.  */
+         struct frame *f;
+         int fuzz;
+
+         if (WINDOWP (event->frame_or_window))
+           f = XFRAME (XWINDOW (event->frame_or_window)->frame);
+         else if (FRAMEP (event->frame_or_window))
+           f = XFRAME (event->frame_or_window);
+         else
+           abort ();
+
+         if (FRAME_WINDOW_P (f))
+           fuzz = double_click_fuzz;
+         else
+           fuzz = double_click_fuzz / 8;
+
+         is_double = ((-button - 1) == last_mouse_button
+                      && (abs (XINT (event->x) - last_mouse_x) <= fuzz)
+                      && (abs (XINT (event->y) - last_mouse_y) <= fuzz)
+                      && button_down_time != 0
+                      && (EQ (Vdouble_click_time, Qt)
+                          || (INTEGERP (Vdouble_click_time)
+                              && ((int)(event->timestamp - button_down_time)
+                                  < XINT (Vdouble_click_time)))));
+       }
+
+         if (is_double)
+           {
+             double_click_count++;
+             event->modifiers |= ((double_click_count > 2)
+                                  ? triple_modifier
+                                  : double_modifier);
+           }
+         else
+           {
+             double_click_count = 1;
+             event->modifiers |= click_modifier;
+           }
+         button_down_time = event->timestamp;
+         /* Use a negative value to distinguish wheel from mouse button.  */
+       last_mouse_button = -button - 1;
+       last_mouse_x = XINT (event->x);
+       last_mouse_y = XINT (event->y);
+
+       /* This is a wheel-down event.  */
+       if (event->modifiers & down_modifier)
+         {
+           event->modifiers &= ~down_modifier;
+
+             if (button >= ASIZE (wheel_down_syms))
+               wheel_down_syms = larger_vector (wheel_down_syms, button + 1, 
Qnil);
+
+             /* Get the symbol we should use for the wheel event.  */
+             head = modify_event_symbol (button,
+                                         event->modifiers,
+                                         Qmouse_click,
+                                         Vlispy_wheel_down_stem,
+                                         NULL,
+                                         &wheel_down_syms,
+                                         ASIZE (wheel_down_syms));
+         }
+
+       /* This is a wheel-up event.  */
+       else if (event->modifiers & up_modifier)
+         {
+           event->modifiers &= ~up_modifier;
+
+             if (button >= ASIZE (wheel_up_syms))
+               wheel_up_syms = larger_vector (wheel_up_syms, button + 1, Qnil);
+
+             /* Get the symbol we should use for the wheel event.  */
+             head = modify_event_symbol (button,
+                                         event->modifiers,
+                                         Qmouse_click,
+                                         Vlispy_wheel_up_stem,
+                                         NULL,
+                                         &wheel_up_syms,
+                                         ASIZE (wheel_up_syms));
+           }
+       else
+         /* Every wheel event should either have the down_modifier or
+              the up_modifier set.  */
+         abort ();
+
+         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,
+                                Qnil));
+       }
+
  #ifdef USE_TOOLKIT_SCROLL_BARS

        /* We don't have down and up events if using toolkit scroll bars,
***************
*** 10616,10621 ****
--- 10818,10827 ----

    Vlispy_mouse_stem = build_string ("mouse");
    staticpro (&Vlispy_mouse_stem);
+   Vlispy_wheel_up_stem = build_string ("wheel-up");
+   staticpro (&Vlispy_wheel_up_stem);
+   Vlispy_wheel_down_stem = build_string ("wheel-down");
+   staticpro (&Vlispy_wheel_down_stem);

    /* Tool-bars.  */
    QCimage = intern (":image");
***************
*** 10675,10681 ****
    staticpro (&Qfunction_key);
    Qmouse_click = intern ("mouse-click");
    staticpro (&Qmouse_click);
! #if defined(WINDOWSNT) || defined(MAC_OSX)
    Qmouse_wheel = intern ("mouse-wheel");
    staticpro (&Qmouse_wheel);
  #endif
--- 10881,10887 ----
    staticpro (&Qfunction_key);
    Qmouse_click = intern ("mouse-click");
    staticpro (&Qmouse_click);
! #if defined(MAC_OSX)
    Qmouse_wheel = intern ("mouse-wheel");
    staticpro (&Qmouse_wheel);
  #endif
***************
*** 10793,10798 ****
--- 10999,11008 ----
    staticpro (&button_down_location);
    mouse_syms = Fmake_vector (make_number (1), Qnil);
    staticpro (&mouse_syms);
+   wheel_down_syms = Fmake_vector (make_number (1), Qnil);
+   staticpro (&wheel_down_syms);
+   wheel_up_syms = Fmake_vector (make_number (1), Qnil);
+   staticpro (&wheel_up_syms);

    {
      int i;
***************
*** 10827,10838 ****
    func_key_syms = Qnil;
    staticpro (&func_key_syms);

! #if defined(WINDOWSNT) || defined(MAC_OSX)
    mouse_wheel_syms = Qnil;
    staticpro (&mouse_wheel_syms);
    drag_n_drop_syms = Qnil;
    staticpro (&drag_n_drop_syms);
- #endif

    unread_switch_frame = Qnil;
    staticpro (&unread_switch_frame);
--- 11037,11048 ----
    func_key_syms = Qnil;
    staticpro (&func_key_syms);

! #if defined(MAC_OSX)
    mouse_wheel_syms = Qnil;
    staticpro (&mouse_wheel_syms);
+ #endif
    drag_n_drop_syms = Qnil;
    staticpro (&drag_n_drop_syms);

    unread_switch_frame = Qnil;
    staticpro (&unread_switch_frame);
Index: src/termhooks.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/termhooks.h,v
retrieving revision 1.62
diff -c -r1.62 termhooks.h
*** src/termhooks.h     4 Feb 2003 14:03:13 -0000       1.62
--- src/termhooks.h     28 May 2003 22:04:13 -0000
***************
*** 240,245 ****
--- 240,255 ----
                                   the mouse click occurred in.
                                   .timestamp gives a timestamp (in
                                   milliseconds) for the click.  */
+   WHEEL_EVENT,                        /* The wheel number is in .code; it must
+                                  be >= 0.
+                                  .modifiers holds the state of the
+                                  modifier keys.
+                                  .x and .y give the mouse position,
+                                  in characters, within the window.
+                                  .frame_or_window gives the frame
+                                  the wheel event occurred in.
+                                  .timestamp gives a timestamp (in
+                                  milliseconds) for the event.  */
  #if defined(WINDOWSNT) || defined(MAC_OSX)
    MOUSE_WHEEL_EVENT,          /* A mouse-wheel event is generated
                                   on WINDOWSNT or MAC_OSX by a
Index: src/w32term.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/w32term.c,v
retrieving revision 1.192
diff -c -r1.192 w32term.c
*** src/w32term.c       27 May 2003 22:34:58 -0000      1.192
--- src/w32term.c       28 May 2003 22:04:50 -0000
***************
*** 2910,2925 ****
  }

  static Lisp_Object
! construct_mouse_wheel (result, msg, f)
       struct input_event *result;
       W32Msg *msg;
       struct frame *f;
  {
    POINT p;
!   result->kind = MOUSE_CLICK_EVENT;
!   result->code = (GET_WHEEL_DELTA_WPARAM (msg->msg.wParam) < 0) ? 4 : 3;
    result->timestamp = msg->msg.time;
!   result->modifiers = msg->dwModifiers;
    p.x = LOWORD (msg->msg.lParam);
    p.y = HIWORD (msg->msg.lParam);
    ScreenToClient (msg->msg.hwnd, &p);
--- 2910,2933 ----
  }

  static Lisp_Object
! construct_mouse_wheel (result, msg, f, button)
       struct input_event *result;
       W32Msg *msg;
       struct frame *f;
+      int button;
  {
    POINT p;
!   int scroll_dir;
!
!   result->kind = WHEEL_EVENT;
!   result->code = button;
    result->timestamp = msg->msg.time;
!   /* Use the up and down modifiers to indicate if the wheel was
!      scrolled up or down.  */
!   scroll_dir = (GET_WHEEL_DELTA_WPARAM (msg->msg.wParam) < 0) ?
!     up_modifier : down_modifier;
!
!   result->modifiers = (msg->dwModifiers | scroll_dir);
    p.x = LOWORD (msg->msg.lParam);
    p.y = HIWORD (msg->msg.lParam);
    ScreenToClient (msg->msg.hwnd, &p);
***************
*** 4389,4402 ****

        case WM_MOUSEWHEEL:
          {
!           /* Convert each Windows mouse wheel event in a couple of
!              Emacs mouse click down/up events.  Scrolling the wheel up
!              is associated to mouse button 4 and scrolling the wheel
!              down to the mouse button 5.  */
!           int button;
!           int up;
!
!           up = msg.dwModifiers & up_modifier;

            if (dpyinfo->grabbed && last_mouse_frame
                && FRAME_LIVE_P (last_mouse_frame))
--- 4397,4409 ----

        case WM_MOUSEWHEEL:
          {
!           /* Map each Windows mouse wheel event to an Emacs
!              wheel-up-1/down-1 event.
!              Assume there is only one mouse wheel button for now.  */
!
!             int button;
!
!           button = 0;

            if (dpyinfo->grabbed && last_mouse_frame
                && FRAME_LIVE_P (last_mouse_frame))
***************
*** 4426,4475 ****
                     || f == dpyinfo->w32_focus_frame)
                    && (numchars >= 1))
                  {
!                   if ( !up )
!                     {
!                       /* Emit an Emacs mouse down message.  */
!                       msg.dwModifiers |= down_modifier;
!                       construct_mouse_wheel (bufp, &msg, f);
!                       bufp++;
!                       count++;
!                       numchars--;
!
!                       /* Push a simulated WM_MOUSEWHEEL up message.  */
!                       msg.dwModifiers &= ~down_modifier;
!                       msg.dwModifiers |= up_modifier;
!                       prepend_msg (&msg);
!                     }
!                   else
!                     {
!                       /* Emit an Emacs mouse up message.  */
!                       construct_mouse_wheel (bufp, &msg, f);
!                       bufp++;
!                       count++;
!                       numchars--;
!                     }
!                 }
!             }
!
!           button = (GET_WHEEL_DELTA_WPARAM (msg.msg.wParam) < 0)? 4 : 3;
!
!           if (up)
!             {
!               dpyinfo->grabbed &= ~ (1 << button);
!             }
!           else
!             {
!               dpyinfo->grabbed |= (1 << button);
!               last_mouse_frame = f;
!               /* Ignore any mouse motion that happened
!                  before this event; any subsequent mouse-movement
!                  Emacs events should reflect only motion after
!                  the ButtonPress.  */
!               if (f != 0)
!                 f->mouse_moved = 0;
!
!               last_tool_bar_item = -1;
!             }
          }
          break;

--- 4433,4455 ----
                     || f == dpyinfo->w32_focus_frame)
                    && (numchars >= 1))
                  {
!                     construct_mouse_wheel (bufp, &msg, f, button);
!                     bufp++;
!                     count++;
!                     numchars--;
!                   }
!               }
!
!             dpyinfo->grabbed |= (1 << button);
!             last_mouse_frame = f;
!             /* Ignore any mouse motion that happened
!                before this event; any subsequent mouse-movement
!                Emacs events should reflect only motion after
!                the ButtonPress.  */
!             if (f != 0)
!               f->mouse_moved = 0;
!
!             last_tool_bar_item = -1;
          }
          break;







reply via email to

[Prev in Thread] Current Thread [Next in Thread]