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.
This commit is contained in:
Albrecht Schlosser 2024-09-26 17:59:52 +02:00 committed by Albrecht Schlosser
parent 3fbd4f944f
commit 4f4a9be15b
6 changed files with 202 additions and 83 deletions

View File

@ -551,6 +551,8 @@ enum Fl_Callback_Reason {
#define FL_LEFT_MOUSE 1 ///< The left mouse button #define FL_LEFT_MOUSE 1 ///< The left mouse button
#define FL_MIDDLE_MOUSE 2 ///< The middle mouse button #define FL_MIDDLE_MOUSE 2 ///< The middle mouse button
#define FL_RIGHT_MOUSE 3 ///< The right mouse button #define FL_RIGHT_MOUSE 3 ///< The right mouse button
#define FL_BACK_MOUSE 4 ///< The back mouse button (side button 1)
#define FL_FORWARD_MOUSE 5 ///< The forward mouse button (side button 2)
/**@}*/ // group: Mouse Buttons /**@}*/ // group: Mouse Buttons
@ -575,11 +577,17 @@ enum Fl_Callback_Reason {
// correct for XFree86 // correct for XFree86
#define FL_SCROLL_LOCK 0x00800000 ///< The scroll lock is on #define FL_SCROLL_LOCK 0x00800000 ///< The scroll lock is on
// correct for XFree86 // correct for XFree86
// Mouse buttons
#define FL_BUTTON1 0x01000000 ///< Mouse button 1 is pushed (L) #define FL_BUTTON1 0x01000000 ///< Mouse button 1 is pushed (L)
#define FL_BUTTON2 0x02000000 ///< Mouse button 2 is pushed (M) #define FL_BUTTON2 0x02000000 ///< Mouse button 2 is pushed (M)
#define FL_BUTTON3 0x04000000 ///< Mouse button 3 is pushed (R) #define FL_BUTTON3 0x04000000 ///< Mouse button 3 is pushed (R)
#define FL_BUTTONS 0x07000000 ///< Any mouse button (1-3) is pushed #define FL_BUTTON4 0x08000000 ///< Mouse button 4 is pushed (BACK)
#define FL_BUTTON(n) (0x00800000<<(n)) ///< Mouse button n (n > 0) is pushed #define FL_BUTTON5 0x10000000 ///< Mouse button 5 is pushed (FORWARD)
#define FL_BUTTONS 0x1f000000 ///< Bitmask: any mouse button (1-5) is pushed
#define FL_BUTTON(n) (0x00800000<<(n)) ///< Mouse button n (n = 1..5) is pushed,
///< *undefined* if n outside 1..5
#define FL_KEY_MASK 0x0000ffff ///< All keys are 16 bit for now #define FL_KEY_MASK 0x0000ffff ///< All keys are 16 bit for now
// FIXME: Unicode needs 21 bits! // FIXME: Unicode needs 21 bits!

77
FL/Fl.H
View File

@ -705,40 +705,51 @@ public:
This returns garbage if the most recent event was not a FL_PUSH or FL_RELEASE event. This returns garbage if the most recent event was not a FL_PUSH or FL_RELEASE event.
\retval FL_LEFT_MOUSE \retval FL_LEFT_MOUSE
\retval FL_MIDDLE_MOUSE \retval FL_MIDDLE_MOUSE
\retval FL_RIGHT_MOUSE. \retval FL_RIGHT_MOUSE
\see Fl::event_buttons() \retval FL_BACK_MOUSE
\retval FL_FORWARD_MOUSE.
\see Fl::event_buttons(), Fl::event_state()
*/ */
static int event_button() {return e_keysym-FL_Button;} static int event_button() { return e_keysym - FL_Button; }
/** /**
Returns the keyboard and mouse button states of the last event. Returns the keyboard and mouse button states of the last event.
This is a bitfield of what shift states were on and what mouse buttons This is a bitfield of what shift states were on and what mouse buttons
were held down during the most recent event. were held down during the most recent event.
\note FLTK platforms differ in what Fl::event_state() returns when it is called
while a modifier key or mouse button is being pressed or released.
- Under X11 and Wayland, Fl::event_state() indicates the state of the modifier keys and
mouse buttons just \b prior to the event. Thus, during the \c FL_KEYDOWN event generated
when pressing the shift key, for example, the \c FL_SHIFT bit of event_state() is 0 and
becomes 1 only at the next event which can be any other event, including e.g. \c FL_MOVE.
- Under other platforms the reported state of modifier keys or mouse buttons includes that
of the key or button being pressed or released.
- Fl::event_state() returns the same value under all platforms when it's called while a
non-modifier key (e.g. a letter or function key) is being pressed or released.
- X servers do not agree on shift states, and \c FL_NUM_LOCK, \c FL_META, and \c FL_SCROLL_LOCK
may not work.
- The values were selected to match the XFree86 server on Linux.
\note This inconsistency \b may be fixed (on X11 and Wayland) in a later release.
The legal event state bits are: The legal event state bits are:
- FL_SHIFT | Device | State Bit | Key or Button | Since |
- FL_CAPS_LOCK |----------|----------------|-------------------------|-------|
- FL_CTRL | Keyboard | FL_SHIFT | Shift | |
- FL_ALT | Keyboard | FL_CAPS_LOCK | Caps Lock | |
- FL_NUM_LOCK | Keyboard | FL_CTRL | Ctrl | |
- FL_META | Keyboard | FL_ALT | Alt | |
- FL_SCROLL_LOCK | Keyboard | FL_NUM_LOCK | Num Lock | |
- FL_BUTTON1 | Keyboard | FL_META | Meta, e.g. "Windows" | |
- FL_BUTTON2 | Keyboard | FL_SCROLL_LOCK | Scroll Lock | |
- FL_BUTTON3 | Mouse | FL_BUTTON1 | left button | |
| Mouse | FL_BUTTON2 | middle button | |
\note FLTK platforms differ in what Fl::event_state() returns when it is called while a modifier key | Mouse | FL_BUTTON3 | right button | |
is being pressed or released. | Mouse | FL_BUTTON4 | side button 1 (back) | 1.4.0 |
Under X11 and Wayland, Fl::event_state() indicates the state of the modifier keys just \b prior to the event. | Mouse | FL_BUTTON5 | side button 2 (forward) | 1.4.0 |
Thus, during the FL_KEYDOWN event generated when pressing the shift key, for example, the FL_SHIFT bit of event_state()
is 0 and becomes 1 only at the next event (which can be another FL_KEYDOWN, FL_DRAG or FL_KEYUP).
Under other platforms, the reported state of modifier keys includes that of the key being pressed or released.
Notice that Fl::event_state() returns the same value under all platforms when it's called while a non-modifier key
(e.g., a letter, a function key) is being pressed or released.
X servers do not agree on shift states, and FL_NUM_LOCK, FL_META, and
FL_SCROLL_LOCK may not work. The values were selected to match the
XFree86 server on Linux.
*/ */
static int event_state() {return e_state;} static int event_state() {return e_state;}
@ -1267,7 +1278,7 @@ public:
time of the event. During an FL_RELEASE event, the state time of the event. During an FL_RELEASE event, the state
of the released button will be 0. To find out, which button of the released button will be 0. To find out, which button
caused an FL_RELEASE event, you can use Fl::event_button() instead. caused an FL_RELEASE event, you can use Fl::event_button() instead.
\return a bit mask value like { [FL_BUTTON1] | [FL_BUTTON2] | [FL_BUTTON3] } \return a bit mask value like { [FL_BUTTON1] | [FL_BUTTON2] | ... | [FL_BUTTON5] }
*/ */
static int event_buttons() {return e_state & FL_BUTTONS;} static int event_buttons() {return e_state & FL_BUTTONS;}
/** /**
@ -1276,15 +1287,25 @@ public:
*/ */
static int event_button1() {return e_state & FL_BUTTON1;} static int event_button1() {return e_state & FL_BUTTON1;}
/** /**
Returns non-zero if button 2 is currently held down. Returns non-zero if mouse button 2 is currently held down.
For more details, see Fl::event_buttons(). For more details, see Fl::event_buttons().
*/ */
static int event_button2() {return e_state & FL_BUTTON2;} static int event_button2() {return e_state & FL_BUTTON2;}
/** /**
Returns non-zero if button 3 is currently held down. Returns non-zero if mouse button 3 is currently held down.
For more details, see Fl::event_buttons(). For more details, see Fl::event_buttons().
*/ */
static int event_button3() {return e_state & FL_BUTTON3;} static int event_button3() {return e_state & FL_BUTTON3;}
/**
Returns non-zero if mouse button 4 is currently held down.
For more details, see Fl::event_buttons().
*/
static int event_button4() {return e_state & FL_BUTTON4;}
/**
Returns non-zero if mouse button 5 is currently held down.
For more details, see Fl::event_buttons().
*/
static int event_button5() {return e_state & FL_BUTTON5;}
/** @} */ /** @} */
/** /**

View File

@ -1046,7 +1046,7 @@ static void cocoaMagnifyHandler(NSEvent *theEvent)
*/ */
static void cocoaMouseHandler(NSEvent *theEvent) static void cocoaMouseHandler(NSEvent *theEvent)
{ {
static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2 }; static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2, FL_Button+4, FL_Button+5 };
static int px, py; static int px, py;
fl_lock_function(); fl_lock_function();
@ -1070,12 +1070,16 @@ static void cocoaMouseHandler(NSEvent *theEvent)
if (btn == 1) Fl::e_state |= FL_BUTTON1; if (btn == 1) Fl::e_state |= FL_BUTTON1;
else if (btn == 3) Fl::e_state |= FL_BUTTON2; else if (btn == 3) Fl::e_state |= FL_BUTTON2;
else if (btn == 2) Fl::e_state |= FL_BUTTON3; else if (btn == 2) Fl::e_state |= FL_BUTTON3;
else if (btn == 4) Fl::e_state |= FL_BUTTON4;
else if (btn == 5) Fl::e_state |= FL_BUTTON5;
} }
else if (etype == NSEventTypeLeftMouseUp || etype == NSEventTypeRightMouseUp || else if (etype == NSEventTypeLeftMouseUp || etype == NSEventTypeRightMouseUp ||
etype == NSEventTypeOtherMouseUp) { etype == NSEventTypeOtherMouseUp) {
if (btn == 1) Fl::e_state &= ~FL_BUTTON1; if (btn == 1) Fl::e_state &= ~FL_BUTTON1;
else if (btn == 3) Fl::e_state &= ~FL_BUTTON2; else if (btn == 3) Fl::e_state &= ~FL_BUTTON2;
else if (btn == 2) Fl::e_state &= ~FL_BUTTON3; else if (btn == 2) Fl::e_state &= ~FL_BUTTON3;
else if (btn == 4) Fl::e_state &= ~FL_BUTTON4;
else if (btn == 5) Fl::e_state &= ~FL_BUTTON5;
} }
switch ( etype ) { switch ( etype ) {

View File

@ -1044,9 +1044,12 @@ static int mouse_event(Fl_Window *window, int what, int button,
if (wParam & MK_SHIFT) state |= FL_SHIFT; if (wParam & MK_SHIFT) state |= FL_SHIFT;
if (wParam & MK_CONTROL) state |= FL_CTRL; if (wParam & MK_CONTROL) state |= FL_CTRL;
#endif #endif
if (wParam & MK_LBUTTON) state |= FL_BUTTON1; if (wParam & MK_LBUTTON) state |= FL_BUTTON1; // left
if (wParam & MK_MBUTTON) state |= FL_BUTTON2; if (wParam & MK_MBUTTON) state |= FL_BUTTON2; // right
if (wParam & MK_RBUTTON) state |= FL_BUTTON3; if (wParam & MK_RBUTTON) state |= FL_BUTTON3; // middle
if (wParam & MK_XBUTTON1) state |= FL_BUTTON4; // side button 1 (back)
if (wParam & MK_XBUTTON2) state |= FL_BUTTON5; // side button 2 (forward)
Fl::e_state = state; Fl::e_state = state;
switch (what) { switch (what) {
@ -1348,6 +1351,21 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
case WM_RBUTTONUP: case WM_RBUTTONUP:
mouse_event(window, 2, 3, wParam, lParam); mouse_event(window, 2, 3, wParam, lParam);
return 0; return 0;
case WM_XBUTTONDOWN: {
int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5;
mouse_event(window, 0, xbutton, wParam, lParam);
return 0;
}
case WM_XBUTTONDBLCLK: {
int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5;
mouse_event(window, 1, xbutton, wParam, lParam);
return 0;
}
case WM_XBUTTONUP: {
int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5;
mouse_event(window, 2, xbutton, wParam, lParam);
return 0;
}
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
#ifdef USE_TRACK_MOUSE #ifdef USE_TRACK_MOUSE

View File

@ -987,12 +987,25 @@ static ulong ptime;
// Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask // 1<<8 .. 1<<12 // 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 // 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 // take care not to use these undefined bits (found by accident).
// Fl::event_state() though: for backwards compatibility and transparency. // These undefined bits are ignored and not set in Fl::event_state(), otherwise we
// See definition of FL_BUTTONS in FL/Enumerations.H: only three "sticky" mouse // might overwrite other valid bits (since FLTK 1.4.0, Sep 2024 or later).
// buttons as of July 2024. // 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) { static void set_event_xy(Fl_Window *win) {
# if FLTK_CONSOLIDATE_MOTION # 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_x = fl_xevent->xbutton.x/s;
Fl::e_y_root = fl_xevent->xbutton.y_root/s; Fl::e_y_root = fl_xevent->xbutton.y_root/s;
Fl::e_y = fl_xevent->xbutton.y/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; fl_event_time = fl_xevent->xbutton.time;
# ifdef __sgi # ifdef __sgi
// get the meta key off PC keyboards: // get the meta key off PC keyboards:
@ -2015,26 +2028,56 @@ int fl_handle(const XEvent& thisevent)
Fl::e_is_click = 0; } Fl::e_is_click = 0; }
break; break;
case ButtonPress: // Mouse button "press" event:
Fl::e_keysym = FL_Button + xevent.xbutton.button; // ---------------------------
// 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); set_event_xy(window);
Fl::e_dx = Fl::e_dy = 0; 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; event = FL_MOUSEWHEEL;
} else if (xevent.xbutton.button == Button5 && !Fl::event_shift()) { } else if (mb == Button5 && !Fl::event_shift()) {
Fl::e_dy = +1; // Down Fl::e_dy = +1; // down
event = FL_MOUSEWHEEL; event = FL_MOUSEWHEEL;
} else if (xevent.xbutton.button == 6 || (xevent.xbutton.button == Button4 && Fl::event_shift())) { } else if (mb == 6 || (mb == Button4 && Fl::event_shift())) {
Fl::e_dx = -1; // Left Fl::e_dx = -1; // left
event = FL_MOUSEWHEEL; event = FL_MOUSEWHEEL;
} else if (xevent.xbutton.button == 7 || (xevent.xbutton.button == Button5 && Fl::event_shift())) { } else if (mb == 7 || (mb == Button5 && Fl::event_shift())) {
Fl::e_dx = +1; // Right Fl::e_dx = +1; // right
event = FL_MOUSEWHEEL; event = FL_MOUSEWHEEL;
} else { } else if (mb < 4 || mb > 7) { // real mouse *buttons*, not scroll wheel
Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); 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; event = FL_PUSH;
checkdouble(); checkdouble();
} else { // unknown button or shift combination
return 0;
} }
#if FLTK_CONSOLIDATE_MOTION #if FLTK_CONSOLIDATE_MOTION
@ -2042,6 +2085,38 @@ int fl_handle(const XEvent& thisevent)
#endif // FLTK_CONSOLIDATE_MOTION #endif // FLTK_CONSOLIDATE_MOTION
in_a_window = true; in_a_window = true;
break; 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: case PropertyNotify:
if (xevent.xproperty.atom == fl_NET_WM_STATE) { if (xevent.xproperty.atom == fl_NET_WM_STATE) {
@ -2085,21 +2160,6 @@ int fl_handle(const XEvent& thisevent)
break; break;
# endif # 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: case EnterNotify:
if (xevent.xcrossing.detail == NotifyInferior) break; if (xevent.xcrossing.detail == NotifyInferior) break;
// XInstallColormap(fl_display, Fl_X::flx(window)->colormap); // XInstallColormap(fl_display, Fl_X::flx(window)->colormap);

View File

@ -303,10 +303,18 @@ static void pointer_button(void *data,
if (button == BTN_LEFT) { Fl::e_state |= FL_BUTTON1; b = 1; } if (button == BTN_LEFT) { Fl::e_state |= FL_BUTTON1; b = 1; }
else if (button == BTN_RIGHT) { Fl::e_state |= FL_BUTTON3; b = 3; } else if (button == BTN_RIGHT) { Fl::e_state |= FL_BUTTON3; b = 3; }
else if (button == BTN_MIDDLE) { Fl::e_state |= FL_BUTTON2; b = 2; } else if (button == BTN_MIDDLE) { Fl::e_state |= FL_BUTTON2; b = 2; }
else if (button == BTN_BACK) { Fl::e_state |= FL_BUTTON4; b = 4; } // ?
else if (button == BTN_SIDE) { Fl::e_state |= FL_BUTTON4; b = 4; } // OK: Debian 12
else if (button == BTN_FORWARD) { Fl::e_state |= FL_BUTTON5; b = 5; } // ?
else if (button == BTN_EXTRA) { Fl::e_state |= FL_BUTTON5; b = 5; } // OK: Debian 12
} else { // must be WL_POINTER_BUTTON_STATE_RELEASED } else { // must be WL_POINTER_BUTTON_STATE_RELEASED
if (button == BTN_LEFT) { Fl::e_state &= ~FL_BUTTON1; b = 1; } if (button == BTN_LEFT) { Fl::e_state &= ~FL_BUTTON1; b = 1; }
else if (button == BTN_RIGHT) { Fl::e_state &= ~FL_BUTTON3; b = 3; } else if (button == BTN_RIGHT) { Fl::e_state &= ~FL_BUTTON3; b = 3; }
else if (button == BTN_MIDDLE) { Fl::e_state &= ~FL_BUTTON2; b = 2; } else if (button == BTN_MIDDLE) { Fl::e_state &= ~FL_BUTTON2; b = 2; }
else if (button == BTN_BACK) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // ?
else if (button == BTN_SIDE) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // OK: Debian 12
else if (button == BTN_FORWARD) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // ?
else if (button == BTN_EXTRA) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // OK: Debian 12
} }
Fl::e_keysym = FL_Button + b; Fl::e_keysym = FL_Button + b;
Fl::e_dx = Fl::e_dy = 0; Fl::e_dx = Fl::e_dy = 0;