diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2024-09-26 17:59:52 +0200 |
|---|---|---|
| committer | Albrecht Schlosser <fltk@aljus.de> | 2024-10-06 18:53:03 +0200 |
| commit | 4f4a9be15b0c52837dd4d4a04ff021cc3e5d691e (patch) | |
| tree | a7238b08a93b2af73c4df86a66b7abfa47689e76 /src/Fl_x.cxx | |
| parent | 3fbd4f944f0a6e16630974e56e1e896eb7bbf6f7 (diff) | |
Support mouse buttons 4 + 5 (aka "side buttons") (#1076, #1068)
This work is based on PR 1068 (patch by @CendioHalim) and
extended to store button status (4,5) in Fl::event_state() like
it's done for other mouse buttons (1-3).
Changes:
- new symbol: FL_BUTTON4 = side button 1 = "back"
- new symbol: FL_BUTTON5 = side button 2 = "forward"
- modified : FL_BUTTONS now includes bits for two side buttons
Note: the status of these new buttons is not maintained by X11,
therefore we need to maintain them in internal variables for
this platform.
Diffstat (limited to 'src/Fl_x.cxx')
| -rw-r--r-- | src/Fl_x.cxx | 130 |
1 files changed, 95 insertions, 35 deletions
diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index dcae946ab..681014486 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -987,12 +987,25 @@ static ulong ptime; // Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask // 1<<8 .. 1<<12 // }; // -// Note: some more (undefined?) state bits *can* be set if the user uses a keyboard +// Note: some more (undefined?) state bits *may* be set if the user uses a keyboard // other than the primary one (the top-most in keyboard settings). Therefore we must -// take care not to use these undefined bits. These undefined bits will be set in -// Fl::event_state() though: for backwards compatibility and transparency. -// See definition of FL_BUTTONS in FL/Enumerations.H: only three "sticky" mouse -// buttons as of July 2024. +// take care not to use these undefined bits (found by accident). +// These undefined bits are ignored and not set in Fl::event_state(), otherwise we +// might overwrite other valid bits (since FLTK 1.4.0, Sep 2024 or later). +// See definition of FL_BUTTONS in FL/Enumerations.H: +// there are only five "sticky" mouse buttons as of Sep 27, 2024. + +static unsigned int xbutton_state = 0; // extended button state (back, forward) + +// Define the state bits we're interested in for Fl::event_state(). +// Note that we ignore Button4Mask and Button5Mask (vertical scroll wheel). +// X11 doesn't define masks for Button6 and Button7 (horizontal scroll wheel) +// and any higher button numbers. + +static const unsigned int event_state_mask = + ShiftMask | LockMask | ControlMask | + Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | + Button1Mask | Button2Mask | Button3Mask; static void set_event_xy(Fl_Window *win) { # if FLTK_CONSOLIDATE_MOTION @@ -1006,7 +1019,7 @@ static void set_event_xy(Fl_Window *win) { Fl::e_x = fl_xevent->xbutton.x/s; Fl::e_y_root = fl_xevent->xbutton.y_root/s; Fl::e_y = fl_xevent->xbutton.y/s; - Fl::e_state = fl_xevent->xbutton.state << 16; + Fl::e_state = ((fl_xevent->xbutton.state & event_state_mask) << 16) | xbutton_state; fl_event_time = fl_xevent->xbutton.time; # ifdef __sgi // get the meta key off PC keyboards: @@ -2015,26 +2028,56 @@ int fl_handle(const XEvent& thisevent) Fl::e_is_click = 0; } break; - case ButtonPress: - Fl::e_keysym = FL_Button + xevent.xbutton.button; + // Mouse button "press" event: + // --------------------------- + // X11 uses special conventions for mouse "button" numbers: + // 1-3: standard mouse buttons left, middle, right in this order + // 4-5: scroll wheel up, down - not reflected in Fl::event_state() + // 6-7: scroll wheel left, right - not reflected in Fl::event_state() + // 8-9: side buttons back, forward - mapped to 4-5, see below + // Since X11 pseudo button numbers 4-7 are useless for Fl::event_state() we map + // real button numbers 8 and 9 to 4 and 5, respectively in FLTK's button numbers + // and in the event state (Fl::event_state()). + // Variable `xbutton_state` is used internally to store the status of the extra + // mouse buttons 4 (back) and 5 (forward) since X11 doesn't keep their status. + + case ButtonPress: { + int mb = xevent.xbutton.button; // mouse button + if (mb < 1 || mb > 9) return 0; // unknown or unsupported button, ignore + + // FIXME(?): here we set some event related variables although we *might* + // ignore an event sent by X because we don't know or want it. This may lead to + // inconsistencies in Fl::event_key(), Fl::event_state() and more (see set_event_xy). + // For now we ignore this fact though, it's likely that it never happens. + // Albrecht, Sep 27, 2024 + + Fl::e_keysym = 0; // init: not used (zero) for scroll wheel events set_event_xy(window); Fl::e_dx = Fl::e_dy = 0; - if (xevent.xbutton.button == Button4 && !Fl::event_shift()) { - Fl::e_dy = -1; // Up + + if (mb == Button4 && !Fl::event_shift()) { + Fl::e_dy = -1; // up event = FL_MOUSEWHEEL; - } else if (xevent.xbutton.button == Button5 && !Fl::event_shift()) { - Fl::e_dy = +1; // Down + } else if (mb == Button5 && !Fl::event_shift()) { + Fl::e_dy = +1; // down event = FL_MOUSEWHEEL; - } else if (xevent.xbutton.button == 6 || (xevent.xbutton.button == Button4 && Fl::event_shift())) { - Fl::e_dx = -1; // Left + } else if (mb == 6 || (mb == Button4 && Fl::event_shift())) { + Fl::e_dx = -1; // left event = FL_MOUSEWHEEL; - } else if (xevent.xbutton.button == 7 || (xevent.xbutton.button == Button5 && Fl::event_shift())) { - Fl::e_dx = +1; // Right + } else if (mb == 7 || (mb == Button5 && Fl::event_shift())) { + Fl::e_dx = +1; // right event = FL_MOUSEWHEEL; - } else { - Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); - event = FL_PUSH; - checkdouble(); + } else if (mb < 4 || mb > 7) { // real mouse *buttons*, not scroll wheel + if (mb > 7) // 8 = back, 9 = forward + mb -= 4; // map to 4 and 5, resp. + Fl::e_keysym = FL_Button + mb; + Fl::e_state |= (FL_BUTTON1 << (mb-1)); // set button state + if (mb == 4) xbutton_state |= FL_BUTTON4; // save extra button state internally + if (mb == 5) xbutton_state |= FL_BUTTON5; // save extra button state internally + event = FL_PUSH; + checkdouble(); + } else { // unknown button or shift combination + return 0; } #if FLTK_CONSOLIDATE_MOTION @@ -2042,6 +2085,38 @@ int fl_handle(const XEvent& thisevent) #endif // FLTK_CONSOLIDATE_MOTION in_a_window = true; break; + } // ButtonPress + + // Mouse button release event: for details see ButtonPress above + + case ButtonRelease: { + int mb = xevent.xbutton.button; // mouse button + switch (mb) { // figure out which real button this is + case 1: // left + case 2: // middle + case 3: // right + break; // continue + case 8: // side button 1 (back) + case 9: // side button 2 (forward) + mb -= 4; // map to 4 and 5, respectively + break; // continue + default: // unknown button or scroll wheel: + return 0; // don't send FL_RELEASE event + } + Fl::e_keysym = FL_Button + mb; // == FL_BUTTON1 .. FL_BUTTON5 + set_event_xy(window); + + Fl::e_state &= ~(FL_BUTTON1 << (mb-1)); + if (mb == 4) xbutton_state &= ~FL_BUTTON4; // clear internal button state + if (mb == 5) xbutton_state &= ~FL_BUTTON5; // clear internal button state + event = FL_RELEASE; + +#if FLTK_CONSOLIDATE_MOTION + fl_xmousewin = window; +#endif // FLTK_CONSOLIDATE_MOTION + in_a_window = true; + break; + } // ButtonRelease case PropertyNotify: if (xevent.xproperty.atom == fl_NET_WM_STATE) { @@ -2085,21 +2160,6 @@ int fl_handle(const XEvent& thisevent) break; # endif - case ButtonRelease: - Fl::e_keysym = FL_Button + xevent.xbutton.button; - set_event_xy(window); - Fl::e_state &= ~(FL_BUTTON1 << (xevent.xbutton.button-1)); - if (xevent.xbutton.button > Button3) { // "buttons" 4-7 = mousewheel events: don't send FL_RELEASE - return 0; - } - event = FL_RELEASE; - -#if FLTK_CONSOLIDATE_MOTION - fl_xmousewin = window; -#endif // FLTK_CONSOLIDATE_MOTION - in_a_window = true; - break; - case EnterNotify: if (xevent.xcrossing.detail == NotifyInferior) break; // XInstallColormap(fl_display, Fl_X::flx(window)->colormap); |
