DevHeads.net

mouse buttons - my view from X11 upwards into Qt

Hi. I'm the X11-oriented "mouse guy" whom Todd mentioned in his "last
call for GSOC, what about shortcuts?" post (Topic #1 in Vol 95, Issue 69).

His focus is within KDE itself, while I'm focusing from the lower
layers, moving "up" into KDE Development tools, API, and UI from those
lower layers. (X11, the qt-X11 interface, and upwards into signal
handling.) I have some ideas about Co-Requisite enhancements to the KDE
System Settings Mouse/Pointer Module, and uses within Kwin, Shortcuts,
and some other places. This email will NOT address those higher-level
KDE modules. There's a lot of fundamental stuff, for which which I will
need design advice, and I've been unable to get it so far. I'll be
discussing those other areas in follow-up emails, if that's OK.

I'm going to need some direction from KDE visionaries, because there are
four alternative "levels" at which we could do this. But first let me
show the naming convention which I will be using.
"ButtonX" means the button number which gets emitted from X11. Here's
the translation layout which I want to use. Please use it, because we'll
get the numbers confused if some replies and new comments INCLUDE "wheel
events" as numbered buttons, while others EXCLUDE the two pairs. And
also, lots of existing hardware is built with "wrong" numbers.

Button1 = "left button"
Button2 = "right button", AKA "context menu button"
Button3 = "middle button"
Button4 = "scroll wheel up"
Button5 = "scroll wheel down"
Button6 = "tilt wheel left", AKA "scroll wheel left"
Button7 = "tilt wheel right", AKA "scroll wheel right"
Button8 = "back button", AKA "XButton1"
Button9 = "forward button" AKA "XButton2"
Button10 = first additional "gamer" button
Button11 = 2nd additional "gamer" button
Button12 = 3rd additional "gamer" button ... and so on.

Within Qt, the Devs have recognized that Button8 and Button9 are
frequently implemented "backwards". Thus they assigned the more cryptic
names "XButton1" and "XButton2". But Qt has not considered the
possibility of horizontal tilt wheels (or genuine horizontal wheels)
implemented on a different pair. And unfortunately, many mice are built
with "nonstandard" numbers. (Even products from a single manufacturer
can vary. For example, Logitech emits 6/7 from some models, and 13/14
from different ones- usually older models, but still in widespread use.)

Here are the 3 alternatives (within Qt4.x, using XI 1.5) which I've
identified for KDE to build upon:

(A) Do absolutely nothing in Qt, simply enhance KWin, KDevelop, and etc.
to "support" the buttons which Qt now provides.
(B) Add 3 more buttons (Button10 thru Button12), extending the defined
enum and mask bits (Qt::MouseButton and QAt::MouseButtons) until they
hit a byte boundary.
(C) Use 31, bytes.

- - - - -
ALTERNATIVE (A): DO NOTHING ALL IN QT.

I hate this approach, because it's manifestly easy and risk-free for
even a child to "extend" Qt's bit definitions to at least a byte
boundary. (With X11; I don't know about other platforms, such as Win32
or OSX, or Symbian. And anyway, OSX support is broken with just 3
buttons, and the authors of the Button8/Button9 updates didn't actually
bother with doing the whole job: The automated testing code tools, among
other "non-production" parts of Qt, still don't have them.

ALTERNATIVE (B): EXTEND SUPPORT FOR MORE BUTTONS, BUT ONLY TO THE 1ST
BYTE BOUNDARY IN THE BUTTON MASK.

Add Button10 through Button12. That's a LOT of buttons (although my
"test mouse", like most "gamer" mice, has even more). Very safe, with no
possibility of compilers "doing the wrong thing".

ALTERNATIVE (C): DEFINE AND SUPPORT AT LEAST 31 POSSIBLE BUTTONS.

This is my recommendation, but it depends on something I don't know: The
current enum for Qt::MouseButton defines all values as 32-bit hex values
(with leading zeroes):

Qt::NoButton 0x00000000 The button state does not refer to any button
(see QMouseEvent::button
<http://doc.qt.nokia.com/4.7-snapshot/qmouseevent.html#button>()).
Qt::LeftButton 0x00000001 The left button is pressed, or an event
refers to the left button. (The left button may be the right button on
left-handed mice.)
Qt::RightButton 0x00000002 The right button.
Qt::MidButton 0x00000004 The middle button.
Qt::MiddleButton MidButton The middle button.
Qt::XButton1 0x00000008 The first X button.
Qt::XButton2 0x00000010 The second X button.

I think that an enumerated item with an explicit value will NEVER be
compressed, even though a Compiler which wanted to squeeze an enum of 7
items (defined without specific values) into a SINGLE BYTE would be free
to do so. If my understanding is correct on all platforms, then we can
safely use the entire Uint32. If it isn't, then we'd better stay with
ALTERNATIVE-B. BTW, I don't want to define or support Button32 in Qt --
no existing mouse needs it, and it might be useful as some kind of flag
bit within a migration of XI --> XI2.

Finally, let me describe the special "trick" which I'll be using within
qapplication_x11.cpp, in order to offer an "ALMOST-reliable" Button
State Mask. (As you know, Xinput 1.5 events provide a Button Sate Mask
which is only one byte in length.) Credit for this suggestion goes to
Daniel Stone: After receiving the event (and deciding not to ignore it),
query the state of the core pointer buttons, and use the response to set
the mask bits for higher-order buttons which are in "pressed" State. The
information isn't absolutely reliable, because Event State precedes
Query State in priority (within X11). We wouldn't want to do anything
like this for pointer motion, or for keyboard ;) But mouse button
states, especially after Qt has "compressed" the X11 wheel events before
pushing them up into the state machine, remain constant for relatively
long time. This makes a query-based mask pretty reliable -- at least in
the *local* case, on a machine which isn't suffering CPU or memory problems.

In the remote case, maybe not so good... but I can't do better without
moving to XI2. If the network and machines are really slow, then users
will have to learn to hold down any high-order "modifier" mouse buttons
until they see the App respond on their screen. And the I think that the
situation of an App treating TWO concurrent high-order buttons as a
unique event is going to be uncommon- and our doco should advise against it.

Because of the delay, and the lack of reliability, a User who really,
really wants to get the FULL Button Mask should do so via a separate
function call (new API). With Event and Standard Signals, I think that
Qt should present Mask as now stands... with the reliable, low-order
mask included (from X11, in Event State), but the higher order bits of
other buttons zeroed out. This keeps it fast and efficient for
programmers who aren't doing anything crazy.

- - - - -
This portion of "more mouse buttons", the part within Qt, isn't big
enough for GSOC. Perhaps the KDE follow-ups are, and I will touch on a
few in separate messages. I intend to write and fully document the Qt
Updates myself, after I receive your comments and recommendation -- and,
I hope, a similar input from a Qt person working in the "input devices"
area. (I know that they have other, big things to think about, but I'd
hate to do a bunch of work and be told "this isn't the right design"
AFTERWARDS.) So, if you can link me up with such a Qt person, please do
so. This is a REAL email address and a good contact point for me.

Thanks for reading, and all upcoming replies.

Comments

Re: mouse buttons - my view from X11 upwards into Qt

By todd rme at 02/21/2011 - 17:11

On Sun, Feb 20, 2011 at 4:57 PM, Rick Stockton <

Are you sure about this? I thought xbutton1 and xbutton2 where the
"buttons" for the x-axis, that is the scroll wheel. In other words,
xbutton1 is scroll up and xbutton 2 is scroll down (or vice versus).

-Todd

Re: mouse buttons - XButton1 and XButton2

By Rick Stockton at 02/22/2011 - 12:36

On 01/-10/-28163 11:59 AM, todd rme wrote:
BTW, the switch statement is being done on an unsigned int
(event->xbutton.button). Code for the higher-numbered buttons doesn't
bother to create names like "Button3", the lines simply specify the uint
values directly.

Re: mouse buttons - my view from X11 upwards into Qt

By David Faure at 02/21/2011 - 16:03

On Sunday 20 February 2011, Rick Stockton wrote:
Let's look at the header file rather than the API docs:

enum MouseButton {
NoButton = 0x00000000,
LeftButton = 0x00000001,
RightButton = 0x00000002,
MidButton = 0x00000004, // ### Qt 5: remove me
MiddleButton = MidButton,
XButton1 = 0x00000008,
XButton2 = 0x00000010,
MouseButtonMask = 0x000000ff
};

"Qt::MouseButton defines all values as 32-bit hex values
(with leading zeroes)" is true, but does this really matter to the compiler?
0x00000001 is really just 1.

The standard (6.7.2.2 Enumeration specifiers) (not that I know this by heart,
google helped) says:

Each enumerated type shall be compatible with char, a signed integer type, or
an unsigned integer type. The choice of type is implementation-defined, but
shall be capable of representing the values of all the members of the
enumeration.

So this enum might very well be a single byte on some compilers, since 0xff
fits. AFAIK gcc and msvc don't do this, though. I'll let Thiago answer about
the more unusual compilers out there :-)

You might want to try IRC, irc.freenode.net, channel #qt-labs.