We help IT Professionals succeed at work.

# emulate two mice like on an iPhone -

on
Hi,

I've heard on iPhones that it's possible to stick both fingers next to each other on the display, then drag your fingers away from one another to signal a 'zoom in' operation.

I'm wondering if this can be emulated using a standard win32 mouse message loop? For testing, I can hook up two mice to simulate two fingers. To signal this gesture, I would need to register two sets of mouse move messages with a timestamp difference of only a few milliseconds - and one mouse move message has to be moving away from the other mouse move message over time to qualify as this type of gesture.

This is really just for fun as I was trying to figure out how the iPhone people would do it (I'm not really going to make a user interface like this! for PC!).

To start I was thinking something like:

struct  MM {
int ,_x;
int m_y;
DateTime m_timestamp;
};

list<MM> m_Moves;
void CMyWindow::OnMouseDown(int x, int y)
{
m_Moves.clear();
}

void CMyWindow::OnMouseMove(int x, int y)
{
m_Moves.push_back(MM(x, y, now());
}

void CMyWindow::OnMouseUp(Int x, int y)
{
// Now run through all the generated mouse move messages,
// and see if they fit the gesture pattern we're looking for.

// Sort all the mouse move messages by timestamp.
m_Moves.sort(datetime);

For the first message, see if there is another message in the list at about the
same timestamp. Record the x,y distance between them. Then look for the
next timestamp, and a mouse message at about the same timestamp. Get
their x,y distance. If less than the 1st, it's not our gesture. If greater or
equal, keep going. If later timestamped messages keep growing further
apart in their x,y distance, we can consider it a match. Do this for some
threshold like 3 message pair checks.
}

I'd have to sit down and put some work into the above initial idea. I can see the need to eliminate a lot of 'noisy' mouse move messages - somehow average them as a lot may be generated and if all used, could throw off the interpretation.

Just wondering if you all had any other initial idea, or does this seem like a doable thing?

Thanks
Comment
Watch Question

## View Solution Only

Commented:
Hmm or even simpler - if two mouse downs and two mouse ups are registered, check the distance between the two mouse down points, and the two mouse up points:

vector<Point> m_MouseDown;
vector<Point> m_MouseUp;

void CMyView::OnMouseDown(int x, int y)
{
// Should happen twice before a call to OnMouseUp().
m_MouseDown.push_back(x,y);
}

void CMyView::OnMouseUp(int x, int y)
{
// Push on the release point, this can happen twice!
m_MouseUp.push_back(x, y);

// Now if we had two mouse downs and ups....
if (m_MouseDown.size() > 1 &&
m_MouseUp.size() > 1))
{
double dStart = DistanceBetween2Pts(m_MouseDown);
double dEnd   = DistanceBetween2Pts(m_MouseUp);
if (dEnd > dStart) {
// Yes it was the gesture we want!
}
}

m_MouseDown.clear();
m_MouseUp.clear();
}

That looks a lot easier.
Senior Software Engineer (Avast)
SILVER EXPERT

Commented:
>> This is really just for fun
Hi DJ, maybe you just need to get out more ;-)

>> does this seem like a doable thing?
I have no idea if this is doable; however, some people on the following thread seem to imply it is but it would involve the use of DirectX.
http://www.experts-exchange.com/Programming/Game/Game_UI/Q_21058086.html

-Rx.
BRONZE EXPERT
Top Expert 2012
Commented:
Hm, why don't you check for two mouse buttons instead of two mice, that seems way easier to me. The trick would be to check the time differenc between WM_LBUTTONDOWN' and 'WM_RBUTTONDOWN' (as well as their 'up' counterparts) and discard teh operation if it is too long. That way, you could

void CMyView::OnLButtonDownOnLButtonDown(
UINT nFlags,
CPoint point
)
{
m_lLButtonTime = GetMessageTime();

CheckButtonAction();
}

void CMyView::OnRButtonDownOnLButtonDown(
UINT nFlags,
CPoint point
)
{
m_lRButtonTime = GetMessageTime();

CheckButtonAction();
}

void CMyView::CheckButtonAction()
{

if (abs(m_lButtonTime - m_RButtonTime) < BUTTON_TRESHOLD))
{
StartZoomMode();
}
}