Widget focus bug

Thebluefish

28-01-2013 01:31:47

I've found a bug that I've been trying to fix for the past 2-3 hours now, and I think I've isolated it down to MyGUI. Whenever the window loses focus (switching to another app, alt+tab,etc...) and then I open the main window back up, all of the widgets do not respond to input. This includes keypress, mouse press, hovering, etc... I've verified that OIS is sending the inputs correctly, and even the MyGUI cursor behaves normally, though while I can move the cursor, I must click in the render window before I am able to control any widgets. Any help would be appreciated.

Right now I'm running in VS2010 on Windows 8.

Edit: Debugging some more gives me a bit of insight as to what's happening. Clicking on the title bar or task bar generates a mousePressed event but no mouseReleased event. This is causing MyGUI to think that a widget has control of the mouse. So this is an OIS issue, not a MyGUI issue. My bad!

Temporarily, I've been able to resolve this by adding a function to MyGUI that exposes the mMouseCapture list. When a mouseMoved or mousePressed event is fired, I compare the internal state of all mouse buttons against their current state. If MyGUI thinks they're pressed when they really aren't, I first fire off a mouseReleased event, then fire off whatever actual event is going to happen. Probably tomorrow I'm going to add a couple of checks-and-balances to my OIS wrapper to do this for all mouse and keyboard events so that it's being done on the input level vs the MyGUI level.

Altren

28-01-2013 07:57:16

Usually this is resolved by sending mouse release event whenever window loose focus. Also it is recommended to send key released event as well, since otherwise you will end with key pressed event without key released.

Thebluefish

28-01-2013 23:08:07

Well that simply helps the objects whenever the mouse is held down and then the window loses focus, which isn't a big concern for now. The issue stems from the lack of a mouseReleased event being fired whenever the window regains focus.

Digging even further, this appears to actually be a Direct Input issue rather than OIS. I can see the event fired for when the mouse is pressed on the window, but not when it's released. Stepping through logging events that I hooked into OIS, it appears that the mouse is locked for a split second after clicking on the taskbar window, causing dinput to miss the event completely. Even unbuffered mode gets messed up this way. I fix this by obtaining the current state, comparing, and generating any "missing" events.


// At the end of void Win32Mouse::capture()
DIMOUSESTATE2 curState;
mMouse->GetDeviceState(sizeof(curState), &curState);
bool ishelddown = curState.rgbButtons[0];

// Ensures that the mouse is detected properly
if(isLeftMousedown && !ishelddown)
{
mState.buttons &= ~(1 << 0); //turn the bit flag off
if( mListener && mBuffered )
{
isLeftMousedown = false;
mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)0 );
}
}



bool Win32Mouse::_doMouseClick( int mouseButton, DIDEVICEOBJECTDATA& di )
{
if( di.dwData & 0x80 )
{
mState.buttons |= 1 << mouseButton; //turn the bit flag on
if(mouseButton == 0)isLeftMousedown = true;
if( mListener && mBuffered )
{
return mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
}
}
else
{
mState.buttons &= ~(1 << mouseButton); //turn the bit flag off
if(mouseButton == 0)isLeftMousedown = false;
if( mListener && mBuffered )
{
return mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
}
}

return true;
}


Tested and works perfectly. Now that I am manually obtaining the state, I will be building a mouse button array and doing a full correction. This also inherently fixes problems where mouseReleased events are not being generated when the window goes out of focus.