Compatibility with MFC ActiveX w/DirectX

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

Post Reply
Bruce Marx
Posts: 2
Joined: Tue Feb 20, 2007 3:08 pm
Location: California

Compatibility with MFC ActiveX w/DirectX

Post by Bruce Marx »

Hi,

The bottom line is that I can read the movements but all of the buttons register as button #1 when pressed, and have not been able to synchronize any GUI functions.

I have been adding the SpacePilot to an application as a simple 3D joystick controller to control a cursor and to use the function buttons. In order to get windows messages, I had to grab the device exclusively with SiGrabDevice(), apparently because the DirectX window is above the application window pointed to by GetSafeHwd(). This gave me a response to movement and button events, but where the movement data is accurate, the buttons all register as button number 1 being pressed or released. I used the MFC code example as a template and the MFC example works with the same GUI loaded into the controller.


The combination of DirectX and MFC ActiveX have caused problems with other controllers and devices in the past, and since I'm an engineer and not a professional programmer I often need help seeing the obvious.

I would appreciate any suggestions or special concerns for this problem or any other experiences with this application combination.


Bruce


CODE:

bool CCGCIAPPCtrl::initSpacePilot() // initialize space pilot controller
{
SiOpenData Si_oData; // si open data structure

if( SiInitialize() != SPW_NO_ERROR ) // initialize the 3dxware input library
{
MessageBox( (LPCTSTR) "SpacePilot DLL Load Failure", 0, 0);
b_SpacePilotPresent = false;
return false;
}

SiOpenWinInit( &Si_oData, GetSafeHwnd() ); // initialize windows specific data

if(( m_SpacePilotHdl = SiOpen("CGCI", SI_ANY_DEVICE, SI_NO_MASK, SI_EVENT, &Si_oData)) == NULL) // open data and get device handle
{
SiTerminate();
MessageBox( (LPCTSTR) "SpacePilot Open Failed", 0, 0);
b_SpacePilotPresent = false;
return false;
}
else b_SpacePilotPresent = true;

SiGrabDevice(m_SpacePilotHdl, SPW_TRUE); // exclusively use the spacepilot with this application

SiSetUiMode(&m_SpacePilotHdl, SI_UI_ALL_CONTROLS); // bring up the application GUI

return true;
}




LONG CCGCIAPPCtrl::On3DxWare( WPARAM wParam, LPARAM lParam ) // SpacePilot message call
{
SiSpwEvent Si_event; // event structure
SiGetEventData Si_eData; // event data structure
// Si_TestString = "event happened";
int num; // number of button pressed

SiGetEventWinInit( &Si_eData, WM_3DXWARE, wParam, lParam ); // decode 3dxware event

if( SiGetEvent(m_SpacePilotHdl, 0, &Si_eData, &Si_event) == SI_IS_EVENT )
{
switch (Si_event.type)
{
case SI_MOTION_EVENT:
SpacePilotDirection.x = (float) Si_event.u.spwData.mData[SI_TX] / 1000.0f;
SpacePilotDirection.y = (float) Si_event.u.spwData.mData[SI_TZ] / 1000.0f;
SpacePilotDirection.z = (float) Si_event.u.spwData.mData[SI_TY] / 1000.0f;
SpacePilotRotation.x = (float) Si_event.u.spwData.mData[SI_RX] / 3000.0f;
SpacePilotRotation.y = (float) Si_event.u.spwData.mData[SI_RZ] / 3000.0f;
SpacePilotRotation.z = (float) Si_event.u.spwData.mData[SI_RY] / 3000.0f;
// Si_TestString = "";
InvalidateControl();
break;

case SI_ZERO_EVENT:
break;

case SI_BUTTON_EVENT:

if( num = SiButtonPressed(&Si_event) != SI_NO_BUTTON )
{
Si_TestString.Format( _T("Button %d Pressed"), num);
}

if( num = SiButtonReleased(&Si_event) != SI_NO_BUTTON )
{
Si_TestString.Format( _T("Button %d Released"), num);
}

InvalidateControl();
break;

case SI_SYNC_EVENT:

SiSyncSetButtonName( m_SpacePilotHdl, 4, L"Headlight" );

break;

default:
break;
}
}

return (TRUE);
}
jwick
Moderator
Moderator
Posts: 3331
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hi Bruce,

You are correct, you need to use SiGrabDevice because of the windows layering issue.

You're getting a 1 for num because of C operator precedence. The expression isn't being evaluated the way you think it is. You need some more parens. Change the statements as such:

if ( (num= SiButtonPressed (&Si_event) ) != SI_NO_BUTTON)

Or better yet (I'm not sure about that SI_NO_BUTTON return value):

/* Look for Button Presses */
switch( num = SiButtonPressed ( &Si_Event ) )
{
case 1: ...
case 2:
...
}
Bruce Marx
Posts: 2
Joined: Tue Feb 20, 2007 3:08 pm
Location: California

Post by Bruce Marx »

Thank You, that cured the buttons. My dumb mistake.

I've only started the menu synchronization, and it's clearly not as simple as setting


SiSyncSetInfoLine(m_SpacePilotHdl, -1, L"CGCI");
SiSyncSetButtonName( m_SpacePilotHdl, 1, L"MOVEMENT MENU");
SiSyncSetButtonName( m_SpacePilotHdl, 2, L"Zoom In");
SiSyncSetButtonName( m_SpacePilotHdl, 3, L"Zoom Out");
SiSyncSetButtonName( m_SpacePilotHdl, 4, L"Headlight" );
SiSyncSetButtonName( m_SpacePilotHdl, 5, L"Rotation ON" );
SiSyncSetButtonName( m_SpacePilotHdl, 6, L"Movement ON" );



these lines in the code, either in the SI_SYNC_EVENT or initialization. I will go through all of the synchronization steps in the documentation. Ideally I would like to dynamically change the titles for different menus, but keep all of the functions as "Button #". Are there any special considerations in the synchronization of the menu titles when working under SiGrabDevice in a window that is under the DirectX panel?
jwick
Moderator
Moderator
Posts: 3331
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hi Bruce,

There are two things you must do for synchronization to work.

1) Make sure the config file you are using has APP_CONTROLS_BUTTONS = TRUE. If you don't, the driver will ignore all attempts to sync. Turning on the log file will log everything that is happening in the syncing process.

2) Set all the buttons to "pass thru", either in the config file (set to Button 1, Button 2, Button 3, etc.) or use the Synch API to set them to pass thru SiSyncSetButtonAssignment(..., 0).

Jim
3Dx Software Development
Post Reply