Click here to Skip to main content
Click here to Skip to main content

Support Multiple Mouse Inputs in a Dialog Box

, 2 Apr 2009
Rate this:
Please Sign up or sign in to vote.
Multiple mouse support in an MFC dialog project using VC++ 6.0!

Introduction

I wanted to add multiple mouse inputs to my applications. I've written several multi-player games which use Nintendo's Wiimote, and have found that it is easiest to develop the apps using mice first, then add Wiimote support later. Microsoft just released a new MultiPoint SDK, but it doesn't support C++, and I wanted to add this support to some older apps I wrote in VC++ 6.0. So maybe, this will help someone else.

There are several apps I've released on my blog (nwpodcast.blogspot.com) that use or will use this with mice or Wiimotes, and I've always enjoyed CodeProject, so I thought I'd contribute.

Background

There are several options out there of drivers people have written - a Google search for "MouseParty", "raw_mouse", and "ManyMouse" will help you learn more about what is available. I chose to use Ryan Gordon's "ManyMouse" code. You can find it here: http://icculus.org/manymouse/. It provides the raw button, mouse-wheel, and movement data to use.

You must use XP or greater to have the OS actually see multiple mouse devices, though I haven't actually confirmed this.

Using the code

For my MFC-based Dialog project, I simply created a new ManyMouse object, and then monitored and maintained the individual cursors for each mouse manually. I tried to document the demo code because that is the best way to see how it works.

First, we init the ManyMouse object like this:

int m_mice = ManyMouse_Init();

The next thing is to override the mouse related messages from Windows - like WM_LBUTTONDOWN and WM_MOUSEMOVE. In these functions we just detect which mouse moved, and adjust the tracking cursor data for each:

void CManyMouseDlgDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
    CString junk;

    if(m_2cursors){
    //mask out 2nd mouse movement from primary mouse to avoid cursor movement
        ManyMouseEvent event;
        while (ManyMouse_PollEvent(&event))        {
            if (event.type == MANYMOUSE_EVENT_BUTTON){
                if(event.device == 1){ //primary mouse device
                    m_m0=TRUE;
                    m_hit = m_cursor1point;
                    Invalidate(FALSE); //must do this to paint the message...
                    return;
                }
                if(event.device == 0){ //2nd mouse device
                    m_m1=TRUE;
                    m_hit = m_cursor2point;
                    Invalidate(FALSE); //must do this to paint the message...
                    return; //don't pass on the lbutton event if mouse1 did it...
                }
            }
        } //end while
    }
}

void CManyMouseDlgDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
    if(m_2cursors){
    //mask out 2nd mouse movement from primary mouse to avoid cursor movement
        ManyMouseEvent event;
        while (ManyMouse_PollEvent(&event))        {
            if (event.type == MANYMOUSE_EVENT_RELMOTION)    {
                if(event.device == 1){ //main mouse moved, don't do anything!
                    if(event.item == 0) { //item = 0 means movement in X axis
                        m_cursor1point.x = m_cursor1point.x + event.value; }
                    else { //item = 1 means movement in the Y axis
                        m_cursor1point.y = m_cursor1point.y + event.value; }

                    m_cursor1moved = TRUE;
                }
                if(event.device == 0){
                    if(event.item == 0) { //item = 0 means movement in X axis
                        m_cursor2point.x = m_cursor2point.x + event.value; }
                    else { //item = 1 means movement in the Y axis
                        m_cursor2point.y = m_cursor2point.y + event.value; }
                    m_cursor2moved = TRUE;
                }//endif device=1
            }//endif type = relmotion
        }//end while 
        Invalidate(FALSE); //must do this to paint the message...
    } else {//endif 2cursors
        CDialog::OnMouseMove(nFlags, point); //act normal for mouse0
    }
}

Note that I keep it pretty simple and exposed - it can be cleaned up quite a bit, but this is to explain it, right? The other thing to note is that I invalidate the window to force it to redraw and allow me to manually draw in the multiple cursors or indicate if we had a button press:

if(m_m0){
    junk.Format("Button 0 FIRED!");
    m_m0 = FALSE;
    dc.TextOut(m_hit.x,m_hit.y,junk); 
}

if(m_2cursors){    //draw the 2nd cursor
    if(m_cursor2moved){  //redraw the 2nd cursor
        dc.MoveTo(((int)m_cursor2point.x-20), (int)m_cursor2point.y);
        dc.LineTo(((int)m_cursor2point.x+20),(int)m_cursor2point.y);//horizontal hair
        dc.MoveTo((int)m_cursor2point.x, (int)m_cursor2point.y-20);
        dc.LineTo((int)m_cursor2point.x, (int)m_cursor2point.y+20);//vertical hair
        m_cursor2moved = FALSE;
    }
}

That is basically it. Yeah, it is crude, and yeah, managed C++, C#, or the SDK are better ways to go, but I wanted to figure out how to make it work.

Points of interest

Couple of things to look out for:

First, the VC++ 6.0 compiler has bugs, and they show up in the form of Link and Build Errors. "fatal error LNK2005:" shows up so you have to tell the compiler to use the "Force file output" option in the Customization feature for the Project settings.

The next joy of the 6.0 compiler is a debug bug causing a "fatal error LNK1103:" error. This only happens for the debug version build, and not for the release, so to overcome it, the MS recommendation is 'don't do a debug build'.

Finally, after you have added Ryan Gordon's ManyMouse .c and .h files to your MFC project, you have to tell the compiler to not use pre-compiler processing for each of those files.

You should be able to build and test the application now. Plug in a second USB mouse and have fun testing it.

History

  • Rev. 1.0 - First release. No future releases planned Wink | ;-)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

P.Opdahl
Engineer
United States United States
Always trying something new. blog tries to keep up (nwpodcast.blogspot.com)

Comments and Discussions

 
GeneralMy vote of 3 Pinmemberbuyong7-Sep-11 21:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 2 Apr 2009
Article Copyright 2009 by P.Opdahl
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid