Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Incosnsistency in al_get_mouse_state_axis and al_mouse_button_down

This thread is locked; no one can reply to it. rss feed Print
Incosnsistency in al_get_mouse_state_axis and al_mouse_button_down
Dennis
Member #1,090
July 2003
avatar

I think there is a minor inconsistency in how the data sources on the mouse device are handled.

The available axes start counting at 0.
The available buttons start counting at 1.

The code below is a snippet from "mousenu.c"

#SelectExpand
1/* Function: al_get_mouse_state_axis 2 */ 3int al_get_mouse_state_axis(ALLEGRO_MOUSE_STATE *ret_state, int axis) 4{ 5 ASSERT(ret_state); 6 ASSERT(axis >= 0); 7 ASSERT(axis < (4 + ALLEGRO_MOUSE_MAX_EXTRA_AXES)); 8 9 switch (axis) { 10 case 0: 11 return ret_state->x; 12 case 1: 13 return ret_state->y; 14 case 2: 15 return ret_state->z; 16 case 3: 17 return ret_state->w; 18 default: 19 return ret_state->more_axes[axis - 4]; 20 } 21} 22 23/* Function: al_mouse_button_down 24 */ 25bool al_mouse_button_down(ALLEGRO_MOUSE_STATE *state, int button) 26{ 27 ASSERT(state); 28 ASSERT(button > 0); 29 30 return (state->buttons & (1 << (button-1))); 31}

and the documentation said:
{"name":"602354","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/b\/db78e00ddbf7cc1b33594eec282a7799.png","w":821,"h":391,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/b\/db78e00ddbf7cc1b33594eec282a7799"}602354

Now, as I see that, there are two options now.
option 1) fix the code (and the existing examples) to make the first button 0

option 2) add a remark to the documentation to those two functions, which says something like "first axis is 0" / "first (left) button is 1"

Option 2 has the benefit of not destroying any existing code which uses Allegro5 (less intrusive).

I would personally prefer option 1, so that "the first" of whatever collection of thing is always 0.

Mark Oates
Member #1,146
March 2001
avatar

Dennis said:

Option 2 has the benefit of not destroying any existing code which uses Allegro5 (less intrusive).

Though I'm not one to know about the purpose of the standard, I vote that we "do it right", regardless of what that does to the existing API.

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

Elias
Member #358
May 2000

I'd agree, "mouse_state.buttons & (button - 1)" or "event.button - 1" make no sense. The only thing the currently required -1 is likely to do is cause someone to get their mouse button code wrong at first. On the other hand it's a fairly minor issue and breaks existing mouse button code in a somewhat bad manner (e.g. the A5 examples themselves would crash if 0 can now be returned in "buttons[event.mouse.button-1]").

In any case, we need to add information about what the button field does to the ALLEGRO_EVENT and ALLEGRO_MOUSE_STATE documentation. Like for example say that 1 or 0 (depending on if we change it) is the left button.

--
"Either help out or stop whining" - Evert

Evert
Member #794
November 2000
avatar

I vote that we "do it right", regardless of what that does to the existing API.

Yes.
Now is the time to catch inconsistencies and fix them, before we release 5.0.
That said, I'm not sure whether this actually is an inconsistency.

Elias said:

On the other hand it's a fairly minor issue and breaks existing mouse button code in a somewhat bad manner

This is a valid point. It also doesn't break it in a way that is immediately obvious. You hope things will crash immediately when you do a bad memory access, but we all know that sometimes that doesn't happen - and that's the optimal case where it would be something obvious like that.

Anyway, before deciding on whether to change it or not, maybe it's a good idea to think about whether there is a reason for the difference? I can't imagine that someone arbitrarily decided to use 0 or 1 in one case or the other.
One obvious reason for using "1" rather than "0" to refer to the first mouse button is that "0" can mean "no button held down". All mouse events return a button status (I would actually expect them to return a bitfield for the different buttons, so 0 for none, 1 for primary [let], 2 for secondary [right] etc.) and so you must have a way of returning "no buttons pressed" when that makes sense.
I think that is probably enough justification to leave things the way they are, possibly with the exception of returning a bitfield rather than a button number (if that is indeed what it does now), but that's not really a major thing and I don't really care either way.

Quote:

In any case, we need to add information about what the button field does to the ALLEGRO_EVENT and ALLEGRO_MOUSE_STATE documentation.

Agreed.

Matthew Leverton
Supreme Loser
January 1999
avatar

I think all index related functions should start at 0, so I would vote to change it. It doesn't return a bitfield, not in that instance. It shouldn't matter that the underlying structure is a bitfield.

ALLEGRO_MOUSE_STATE.buttons is a bitfield, so the buttons are 1, 2, 4, ... So either way there will be differences:

state | func (curr) | func (new)
---------------------------------
  1         1            0
  2         2            1
  4         3            2

Slartibartfast
Member #8,789
June 2007
avatar

Dennis
Member #1,090
July 2003
avatar

Evert said:

It also doesn't break it in a way that is immediately obvious. You hope things will crash immediately when you do a bad memory access, but we all know that sometimes that doesn't happen - and that's the optimal case where it would be something obvious like that.

Concerning the necessary refactoring of the library itself (and any other code included with Allegro5 inside the SVN), a safe way to catch all the code using the "al_mouse_button_down" function is to rename it temporarily. The compiler will then complain about being unable to find the function wherever it is used. The function can then be changed (to start with 0 for the left button). Each code file/line (identified by compiler) which uses the function can then be adjusted for the changed way of numbering the buttons (without renaming the call to the function though). Then after all the calls to it have been changed, the function can be renamed to its current name.

This does not fix any usercode (not included with Allegro5) of course, but if the release notes for the next version include a well visible hint that that has been changed, users can adjust their code accordingly.

Quote:

Anyway, before deciding on whether to change it or not, maybe it's a good idea to think about whether there is a reason for the difference? I can't imagine that someone arbitrarily decided to use 0 or 1 in one case or the other.
One obvious reason for using "1" rather than "0" to refer to the first mouse button is that "0" can mean "no button held down".

I think the current behavior might be a relic from the old Allegro (pre 5) api, where "mouse_b" was a bitfield (same that is now button in the state structure). In the old Allegro, there was no function to test for any specific mouse button (it had to be done by manually comparing the bits).

In the current code, there are two different ways to test for a button state (which I like, because the user isn't forced to use either the event code or the manual state get/check).

In the event handling code, the user would still have to compare the "button" bitfield to 1, 2, 4 to get which button was pressed, whereas with "al_mouse_button_down", currently 1,2,3 must be passed for the button parameter.

"0" for "no button held down" does not make sense with the event handling code, because there are only the events "ALLEGRO_EVENT_MOUSE_AXES", "ALLEGRO_EVENT_MOUSE_BUTTON_DOWN" and "ALLEGRO_EVENT_MOUSE_BUTTON_UP".
(or in other words, if no button was held down, there is no event, so no button field to inspect)

Matthew Leverton
Supreme Loser
January 1999
avatar

Why not dump the numbers and go with something like ALLEGRO_MOUSE_BUTTON_LEFT; You know, magic numbers and whatnot.

The first button is not necessarily the left button. So you'd have _FIRST, _SECOND, ... or _PRIMARY, _SECONDARY, ..., which to me is more verbose than it needs to be.

Evert
Member #794
November 2000
avatar

I think all index related functions should start at 0, so I would vote to change it. It doesn't return a bitfield, not in that instance.

Obviously, since C arrays start at 0, any index returned should be 0-based.
In this case, I would opt to make the return field a bitfield, also because more than one mouse button could (in principle) be held down. Somewhat unusual, I know.

Dennis said:

Concerning the necessary refactoring of the library itself (and any other code included with Allegro5 inside the SVN), a safe way to catch all the code using the "al_mouse_button_down" function is to rename it temporarily.

I'm not actually too worried about introducing bugs due to that in Allegro itself, which mostly records the information and passes it on to the user. I don't think any part of Allegro's internals poll the state-query functions.

Quote:

"0" for "no button held down" does not make sense with the event handling code, because there are only the events "ALLEGRO_EVENT_MOUSE_AXES", "ALLEGRO_EVENT_MOUSE_BUTTON_DOWN" and "ALLEGRO_EVENT_MOUSE_BUTTON_UP".
(or in other words, if no button was held down, there is no event, so no button field to inspect)

You can get an ALLEGRO_EVENT_MOUSE_AXES with the buttons in either state, depending on whether the mouse was moved or dragged. I know, you can keep track of this yourself easily as a user. I would personally prefer a bitfield to tell me which buttons are held down, but again, not a big deal.

Peter Wang
Member #23
April 2000

Evert said:

Anyway, before deciding on whether to change it or not, maybe it's a good idea to think about whether there is a reason for the difference? I can't imagine that someone arbitrarily decided to use 0 or 1 in one case or the other.

For some reason, I always number mouse buttons from 1 in my mind. Probably 1==primary, or as Dennis said, influence from mouse_b: in A4 you write, (mouse_b & 1) or (mouse_b & 2), which happens to work for the first two mouse buttons.

I'm not opposed to changing it, which seems to be the consensus. The only worry is breaking user code at this stage.

So you'd have _FIRST, _SECOND, ... or _PRIMARY, _SECONDARY, ..., which to me is more verbose than it needs to be.

We can provide them as synonyms.

Evert said:

I would personally prefer a bitfield to tell me which buttons are held down, but again, not a big deal.

-It already is a bitfield, so your wish is granted-

Matthew Leverton
Supreme Loser
January 1999
avatar

Evert said:

In this case, I would opt to make the return field a bitfield

But you already have that:

ALLEGRO_MOUSE_STATE m;
al_get_mouse_state(&m);
if (m.buttons & 1) {
  // first button is pressed
}
if (m.buttons & 4) {
  // third button is pressed
}

The function works like:

ALLEGRO_MOUSE_STATE m;
al_get_mouse_state(&m);
if (al_mouse_button_down(&m, 1)) {
  // first button is pressed
}
if (al_mouse_button_down(&m, 3)) {
  // third button is pressed
}

The joystick buttons go from 0 to n-1, don't they?

PS: Should the function be named al_is_mouse_button_down? I don't know how we are handling similar function names elsewhere.

Evert
Member #794
November 2000
avatar

But you already have that:

In the event structure, I mean.
I've never used the state-based API (too cumbersome compared to the event based API and the A4 state-based API :P).

But if that's already a bitfield too, then that's fine.

Matthew Leverton
Supreme Loser
January 1999
avatar

ALLEGRO_EVENT_MOUSE_BUTTON_DOWN - a mouse button was pressed.

Fields:
mouse.x,
mouse.y,
mouse.z,
mouse.button,
mouse.display

I don't remember what it is without looking at it, but I'd assume it was only the individual mouse button pressed. For example, if I did this:

  • Press & hold left button

  • Press & hold right button

  • Release both at same time

I'd assume there would be four events triggered, each with an indexed button (given that the field name is singular.)

If only three events are triggered, then they'd obviously need to be a bitfield.

Personally, I don't care which way the event system works, as long as it is documented correctly...

Evert
Member #794
November 2000
avatar

I don't remember what it is without looking at it, but I'd assume it was only the individual mouse button pressed.

So did I, but Peter's comment seemed to indicate that it's actually a bitfield. He seems to have corrected that.

Quote:

Personally, I don't care which way the event system works, as long as it is documented correctly...

Quite.
Clearly, if the state of the API is such that this is one of the major issues, there's nothing to stop us from calling it a release. ;)

Dennis
Member #1,090
July 2003
avatar

Evert said:

You can get an ALLEGRO_EVENT_MOUSE_AXES with the buttons in either state

The button is not a part of the ALLEGRO_EVENT_MOUSE_AXES event fields.
{"name":"602360","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/5\/15b653af3290c3148a4e442c45d779a8.png","w":578,"h":564,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/5\/15b653af3290c3148a4e442c45d779a8"}602360

Evert said:

So did I, but Peter's comment seemed to indicate that it's actually a bitfield. He seems to have corrected that.

So in the event field "button" is not a bitfield? (see strikethrough in his last post)

If that's so, that's good, as long as it starts counting at 0. Then all that has to be done is have al_mouse_button_down start at 0 as well. (The buttons in the state can still stay a bitfield internally.)

Personally, I don't care which way the event system works, as long as it is documented correctly

Same here but it would be nice if things were consistent across different functions with similar names and purposes.

edit,append:
Looking through the code, it seems that in the event.button field, 1 is the first mouse button. So that's consistent with 1 being the first button in al_mouse_button_down.

Changing that to 0 in both would result in a lot more changes necessary than I first thought, because each platform code would have to change the function that fills the event structure as well.

The more I think about it, the more I lean towards voting to just adjust the documentation for event.button and al_mouse_button_down.
Make it clearly state that the mouse buttons are 1,2,3.. and everything should be ok.

But then that's inconsistent with the joystick button numbers and the axis numbers.. :-X

Evert
Member #794
November 2000
avatar

Dennis said:

The button is not a part of the ALLEGRO_EVENT_MOUSE_AXES event fields.

'course it is.
But it seems that its value is undefined for a MOUSE_AXIS event.

Quote:

So in the event field "button" is not a bitfield? (see strikethrough in his last post)

Seems so.

Quote:

Changing that to 0 in both would result in a lot more changes necessary than I first thought, because each platform code would have to change the function that fills the event structure as well.

Shouldn't be too bad. At least on OS X, the function that records the current state is the same function that fires off the events. I assume it's similar on the other platforms.

Quote:

The more I think about it, the more I lean towards voting to just adjust the documentation for event.button and al_mouse_button_down.
Make it clearly state that the mouse buttons are 1,2,3.. and everything should be ok.

That is certainly the easiest thing to do. :)

Peter Wang
Member #23
April 2000

Dennis said:

So in the event field "button" is not a bitfield? (see strikethrough in his last post)

Yes, I made the mistake of posting too early in the morning.
It would certainly be useful if there was a "buttons" bitfield, in addition to the "button" field (which would still only be defined for button events).

Ah, that gives me a half-decent reason to number mouse buttons from 1: as the "button" field is undefined in axis events, we should fill it with a nonce value that the user can't accidentally use, such as zero. That doesn't explain why joystick buttons are numbered from 0, but anyway...

Matthew Leverton
Supreme Loser
January 1999
avatar

we should fill it with a nonce value that the user can't accidentally use, such as zero

Or -1.

Elias
Member #358
May 2000

Maybe we can rename the button field and also add the additional bit-field. That way we fix the issue with existing code (instead of .button there's two new fields). And it would allow to do things in a consistent way now.

--
"Either help out or stop whining" - Evert

Dennis
Member #1,090
July 2003
avatar

Sounds good to me.

What should the new field names (in the ALLEGRO_MOUSE_STATE) be?
button(current) -> button_index (0,1,2,3..)
buttons_bitfield(new) (0x00000000 (lsb = first button))

And in al_mouse_button_down, rename the "button" parameter to "button_index"? (let that start from 0 too)

The fields in the ALLEGRO_MOUSE_EVENT structure should probably have the same names as the fields in tha ALLEGRO_MOUSE_STATE?
button_index would hold the button which caused the event to fire
buttons_bitfield could still hold all the current mouse buttons states (regardless of which specific button fired the event)

Go to: