The mouse functionality is something of a mess, especially if you're trying to handle it procedurally. I might suggest using my Mouse class. You'd have to modify it to accumulate the data you want but it does have the functionality to detect transitional events.
Mouse.h
/////////////////////////////////////////////////////
// a Mouse class for handling Mouse functions in //
// GDK //
/////////////////////////////////////////////////////
#pragma once
#ifndef _SMOUSE_H_LAC
#define _SMOUSE_H_LAC
#include "DarkGDK.h"
#include "Bitmap.h"
class Mouse
{
private:
int xPos; // x position
int yPos; // y position
int spriteDrag; // -1 if not being dragged
int mouseStat; // holds click status of all buttons
bool clicked1; // is button 1 clicked?
bool clicked2; // how 'bout button 2?
bool clicked3; // button 3?
bool clicked4; // can't leave out the remaining button
bool justClicked1; // true if just clicked
bool justClicked2; // just clicked is not the same
bool justClicked3; // as being in a down state
bool justClicked4; // it's a transition from up to down
bool justReleased1; // true if just release
bool justReleased2; // just released is not the same
bool justReleased3; // as being in an up state.
bool justReleased4; // it's a transition from down to up
bool visible; // is mouse visible
static Mouse *pInstance;
protected:
Mouse ()
{
mouseStat = dbMouseClick(); // catch status as the mouse is opened
xPos = dbMouseX(); // save initial mouse positions
yPos = dbMouseY();
spriteDrag = -1; // not initially dragging a sprite
visible = true;
clicked1 = mouseStat & 0x01; // update the click status of each button
clicked2 = mouseStat & 0x02;
clicked3 = mouseStat & 0x04;
clicked4 = mouseStat & 0x08;
}
public:
static Mouse *Instance ();
void Sync(void); // catches the mouse up on current status
int X(void); // returns the current mouse x position
int Y(void); // returns the current mouse y postion
int X(int xpos);
int Y(int ypos);
void Position (int xpos, int ypos);
bool ClickStat (int buttonnumber); // returns click status of specified button number
bool Released (int buttonnumber); // returns release status of specified button number
bool ButtonUp(int buttonnumber); // true = button up, false = button down
bool ButtonDown (int buttonnumber); // true = button down, false = button up
bool OverSprite (int spritenumber); // returns true if over the specified sprite
void DragSprite (int spritenumber); // tells the mouse to drag the sprite as long as button 1 is held
void DisplayStat (int xpos, int ypos); // Displays status of the mouse at the given position
bool Visible (bool tf); // set the visibility of the mouse on or off
bool Visible (void); // return the visibility of the mouse
};
#endif
Mouse.cpp
#include <Mouse.h>
Mouse * Mouse::Instance()
{
if (pInstance == NULL) {
pInstance = new Mouse;
}
return pInstance;
}
Mouse * Mouse::pInstance;
void Mouse::Sync(void)
{ // gets current state of the mouse and holds it
// the following are the transitory states and get set depending
// the up/down transition of a button
justClicked1 = justClicked2 = justClicked3 = justClicked4 = false;
justReleased1 = justReleased2 = justReleased3 = justReleased4 = false;
mouseStat = dbMouseClick(); // get the status of all buttons
xPos = dbMouseX(); // get the x/y position of the mouse
yPos = dbMouseY();
// get status of button 1
if (clicked1) { // mouse has been in a down state
if (mouseStat & 0x01){ // and remains down
// do nothing
}else{ // but if it's now up
clicked1 = false; // show it now up
justReleased1 = true; // and indicate just released
}
}else { // mouse has been up
if (mouseStat & 0x01){ // but is now down
clicked1 = true;
justClicked1 = true;
}else{ // mouse is still up
// do nothing
}
} // end else
// get status of button 2
if (clicked2) { // mouse has been in a down state
if (mouseStat & 0x02){ // and remains down
// do nothing
}else{ // but if it's now up
clicked2 = false; // show it now up
justReleased2 = true; // and indicate just released
}
}else { // mouse has been up
if (mouseStat & 0x02){ // but is now down
clicked2 = true;
justClicked2 = true;
}else{ // mouse is still up
// do nothing
}
} // end else
// get status of button 3
if (clicked3) { // mouse has been in a down state
if (mouseStat & 0x04){ // and remains down
// do nothing
}else{ // but if it's now up
clicked3 = false; // show it now up
justReleased3 = true; // and indicate just released
}
}else { // mouse has been up
if (mouseStat & 0x04){ // but is now down
clicked3 = true;
justClicked3 = true;
}else{ // mouse is still up
// do nothing
}
} // end else
// get status of button 4
if (clicked4) { // mouse has been in a down state
if (mouseStat & 0x08){ // and remains down
// do nothing
}else{ // but if it's now up
clicked4 = false; // show it now up
justReleased4 = true; // and indicate just released
}
}else { // mouse has been up
if (mouseStat & 0x08){ // but is now down
clicked4 = true;
justClicked4 = true;
}else{ // mouse is still up
// do nothing
}
}
if (spriteDrag != -1 && !clicked1) spriteDrag = -1;
if (spriteDrag != -1 && clicked1) dbSprite (spriteDrag, xPos, yPos, dbSpriteImage(spriteDrag));
}
int Mouse::X(void)
{
return xPos;
}
int Mouse::Y(void)
{
return yPos;
}
int Mouse::X(int xpos)
{
xPos = xpos;
yPos = 470;
dbPositionMouse(xPos, yPos);
return xpos;
}
int Mouse::Y(int ypos)
{
dbPositionMouse (xPos, yPos = ypos);
return ypos;
}
void Mouse::Position (int xpos, int ypos)
{
dbPositionMouse (xPos = xpos, yPos = ypos);
}
bool Mouse::ClickStat(int buttonnumber)
{
switch (buttonnumber){
case 1: return justClicked1;
break;
case 2: return justClicked2;
break;
case 3: return justClicked3;
break;
case 4: return justClicked4;
break;
default: return false;
}
}
bool Mouse::Released(int buttonnumber)
{
switch (buttonnumber) {
case 1: return justReleased1;
break;
case 2: return justReleased2;
break;
case 3: return justReleased3;
break;
case 4: return justReleased4;
break;
default: return false; // return false if invalid button
}
}
bool Mouse::OverSprite(int spritenumber)
{
int sprx = dbSpriteX(spritenumber) - dbSpriteOffsetX(spritenumber); // get the position and dimensions of the sprite
int spry = dbSpriteY(spritenumber) - dbSpriteOffsetY(spritenumber); // must account for offsets
int sprw = dbSpriteWidth(spritenumber); // get width and height
int sprh = dbSpriteHeight(spritenumber);
// see if mouse is between the extremes of the sprite
if (xPos >= sprx && xPos < sprx + sprw && yPos >= spry && yPos < spry + sprh) return true;
return false;
}
bool Mouse::ButtonUp(int buttonnumber)
{
switch (buttonnumber) { // return the status of the specified button
case 1: return !clicked1;
break;
case 2: return !clicked2;
break;
case 3: return !clicked3;
break;
case 4: return !clicked4;
break;
default: return false; // only if a bad button number is passed
}
}
bool Mouse::ButtonDown (int buttonnumber)
{
switch (buttonnumber) {
case 1: return clicked1;
break;
case 2: return clicked2;
break;
case 3: return clicked3;
break;
case 4: return clicked4;
break;
default: return false; // only if a bad button number is passed
}
}
void Mouse::DisplayStat(int xpos, int ypos)
{ // display the mouse position and the click of each button
// does not reflect down state so the numbers will just flash
char MouseString [128]; // buffer in which to format output
dbSetCursor(xpos, ypos); // move the cursor to the co-ordinates
// format the string with the data
sprintf (MouseString, "x = %d, y = %d %c %c %c %c", xPos, yPos, justClicked1 ? '1' : 'X',
justClicked2 ? '2' : 'X', justClicked3 ? '3' : 'X', justClicked4 ? '4' : 'X');
dbPrint (MouseString); // and output it
}
void Mouse::DragSprite(int spritenumber)
{
spriteDrag = spritenumber; // the sprite number to be dragged
}
bool Mouse::Visible(bool tf)
{
if (tf) dbShowMouse();
else dbHideMouse();
return visible = tf;
}bool Mouse::Visible(void)
{
return visible;
}
And the docs, not really code but it's better than mangling my Word document to add an attachment.
The Mouse Class…..
Overview – This class has had a small overhaul. Some experience in trying to make a single mouse object available to all scopes necessary became difficult. So I’ve implemented it as a singleton. This means that you must declare a mouse object as either a pointer to a single mouse object or as a pointer to such and set it using the Mouse::Instance() function.
Mouse *mousePtr = Mouse::Instance();
Or
Mouse &mouseRef = *Mouse::Instance();
I prefer the latter method because using it requires the more standard syntax of calling member functions using the dot (.) member of operator rather than the pointer (->) member of operator.
It became obvious that the main problem with the mouse functions in Dark GDK was detecting transitory states like when a button was just clicked or just released. In order to track these transitory states it’s necessary to maintain information of the states from one moment to the next. To have to do it for four buttons and two coordinate variables and be able to react before the states changed again is a nightmare. It puts more load on your code. In a normal Windows environment the system traps the actions for you and passes them to your program for action. In my DGDK environment I don’t currently have the luxury. So, in order to keep from having to constantly write global variables to track four buttons it was obvious that to be able to collect all of this in one place with one statement was the way to go. The solution is the Mouse class.
The Mouse class provides data regarding the status of the mouse although it's in a slightly unintuitive manner. It's intended to be used with a mouse object that is monitored within a loop, preferably with a short time between cycles. Basically a Mouse would be used much like the following.
Mouse &myMouse = Mouse::Instance();
while (LoopGDK()){
myMouse.Sync();
// do stuff with mouse data
// do other stuff if you must
}
What happens when you call myMouse.Sync() is that the myMouse object collects the status of the various
aspects of the mouse, mainly the position of the mouse and the up/down status of the four buttons. This data is kept until the next time the Sync() function is called. Other information is extracted and kept such
as whether a button was pushed or released since the last time the Sync() function was run.
Sync () also takes care of moving sprites if one is being dragged by the mouse. This will be discussed a bit later.
All data in the class is private and is only accessible via the public interface. Following are the functions currently available to a Mouse object.
The functions available to the Mouse class are as follows.
// Note: The Mouse constructor described in the following paragraph is no longer available to the programmer. As a singleton the constructors are hidden and only available to the Instance() method that calls the constructor.
Mouse () - This is the constructor, which basically collects the state of the mouse when the Mouse object
is declared.
Mouse *Instance(void) – This is the function that needs to be called in order to either establish the first instance of a Mouse object or return a pointer to the existing instance.
void Sync (void) - The must call function to let the Mouse object know about the status of the system mouse. It holds the information, extracts a bit more and deals with drag requests if present.
int X(void) - Returns the X position of the mouse, as an integer, at the time the Sync() function was called.
int Y(void) - Returns the Y position of the mouse, as an integer, at the time the Sync() function was called.
bool ClickStat (int button) - Returns a true if the button specified has just been pressed. This is not the same thing as a down state. A true is returned only if the button has been pressed since the last call to Sync().
bool Released (int button) - Returns a true if the button specified has just been released. This is not the same as an up state. A true is returned only if the button has been released since the last call to Sync().
bool ButtonUp (int button) - Returns a true if the button specified is in an up position.
bool ButtonDown (int button) - Returns a true if the button specified is currently being pressed.
Note: One or the other of these is probably unnecessary since they're mutually exclusive and opposite states. I decided to keep both regardless as one may make more syntactical sense in a particular piece of code.
bool OverSprite (int sprite) - Returns a true if the mouse is currently positioned over the rectangle that defines the sprite specified in the function parameter. This is only strictly valid for an unrotated sprite but it does take into account any offset values such that it returns a true if the mouse is over where the sprite appears to be. It also hasn't been adjusted for a stretched sprite.
void DragSprite (int sprite) - Tells the mouse to drag the specified sprite as long as button 1 is down. This function sets a flag, of sorts, in the Mouse object telling it what sprite to move. On the next and subsequent calls to Sync(), if button 1 is down, it will the move the sprite wherever the mouse position is. Once button 1 is up the flag is removed and the sprite stays where it was left. When invoked this function will cause the sprite to match up its position co-ordinate with the mouse co-ordinate.
Depending on the program this could cause the sprite to jump to where the mouse it. General practice would involve making sure the sprite is under the mouse and button 1 clicked before invoking this function. It is possible that the mouse can be moved out of the display area and moved back in to recapture the sprite from another position in the display as long as the button is kept down. It's also possible to move the mouse off the display fast enough to leave it somewhere far from the edge where the mouse exited.
bool Visible (bool tf) - Sets the visibility of the mouse and returns what was passed to it.
bool Visible (void) - Returns the current visibility of the mouse cursor.
void DisplayStat (int xpos, int ypos) - Displays the status of the mouse at the x/y postion noted in the function arguments. The status is of the form:
x = ###, y = ### X X X X
The four Xs represent the buttons 1, 2, 3 and 4. When the respective button is pressed the number will flash very briefly to indicate that the button has just been clicked. It may still be in a down state
over time but it won't be "clicked" again until it has been released and re-clicked.
The programmer is required to issue the appropriate dbInk () call to make it display in the proper color.
Bear in mind that the Mouse class is handled as a singleton, so no matter where you declare a pointer to the Mouse object or a reference to it you always get the status from the last time you ran a sync. For your purposes you may want to add some sort of FIFO queue to it so you can pull events in order.
Lilith, Night Butterfly
I'm not a programmer but I play one in the office