Qt4 and COM, events only on text console

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

Moderator: Moderators

Post Reply
chrislu
Posts: 11
Joined: Sun Jun 07, 2009 8:58 am

Qt4 and COM, events only on text console

Post by chrislu »

Hi,
i am trying to get input data from a space navigator via the COM interface. the initialization is running without any errors but i was getting no input events (__hook or polling) in the Qt4 application but i noticed when the startup console is in the focus everything works fine. when the actual window is in focus no events come through.

i tried to initialize the device in the application constructor, as well as on other location during the runtime to be sure that it gets initialized in the window context and not prior window creation. i also tried the winEvent and winEventFilter methods without success the events only come through when the console window is in focus.

i looked at the spacenav library and could not find anything different the way they access the device.

are there any examples using qt or qt4 in special?

regards
-chris
chrislu
Posts: 11
Joined: Sun Jun 07, 2009 8:58 am

Post by chrislu »

the strangest thing is, i get the input events regardless what is in focus as long as the qt window is not in focus.

could some of the developers look into this?

here some sample code:

Code: Select all


#ifndef SCM_INPUT_SPACE_NAVIGATOR_DEVICE_H_INCLUDED
#define SCM_INPUT_SPACE_NAVIGATOR_DEVICE_H_INCLUDED

#include <scm/core/numeric_types.h>
#include <scm/core/pointer_types.h>
#include <scm/core/math.h>

#include <scm/core/platform/platform.h>
#include <scm/core/utilities/platform_warning_disable.h>

class space_navigator_impl;

namespace scm {
namespace inp {

class __scm_export(input) space_navigator
{
public:
    space_navigator();
    virtual ~space_navigator();

    void                update();
    void                reset();

    const math::mat4f&  rotation() const;
    const math::mat4f&  translation() const;


protected:

private:
    math::vec3f         _rotation_sensitivity;
    math::vec3f         _translation_sensitivity;

    math::mat4f         _rotation;
    math::mat4f         _translation;

    shared_ptr<space_navigator_impl>   _device;

    friend class space_navigator_impl;
}; // class space_navigator

} // namespace inp
} // namespace scm

#include <scm/core/utilities/platform_warning_enable.h>

#endif // SCM_INPUT_SPACE_NAVIGATOR_DEVICE_H_INCLUDED

Code: Select all


#include "space_navigator_device.h"

#if SCM_PLATFORM == SCM_PLATFORM_WINDOWS

// com stuff for the driver callbacks
//#include <scm/core/platform/windows.h>

#define _ATL_ATTRIBUTES 1
#define _WIN32_DCOM

#ifndef WINVER			// Allow use of features specific to Windows XP or later.
#define WINVER 0x0501		// Change this to to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT		// Allow use of features specific to WinXP or later.
#define _WIN32_WINNT 0x0501	// (was 0x0501) Change to target other versions of Windows
#endif						

#ifndef _WIN32_WINDOWS		// Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0410 // Change this to target Windows Me or later.
#endif

#ifndef _WIN32_IE			// Allow use of features specific to IE 6.0 or later.
#define _WIN32_IE 0x0600	// Change this to target other versions of IE.
#endif

#define _ATL_APARTMENT_THREADED
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// some CString constructors will be explicit
//#define _ATL_APARTMENT_THREADED
//#define _ATL_NO_AUTOMATIC_NAMESPACE
//
//#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// some CString constructors will be explicit

#include <atlbase.h>
#include <atlcom.h>
#include <atlwin.h>
#include <atltypes.h>
#include <atlctl.h>
#include <atlhost.h>
#include <atlstr.h>

using namespace ATL;

#import "progid:TDxInput.Device" embedded_idl no_namespace
// end com stuff

#endif SCM_PLATFORM == SCM_PLATFORM_WINDOWS

#include <iostream>

#include <scm/log.h>
#include <scm/gl/math/math.h>

[module(type=dll, name = "scm_input_sn")]
[event_receiver(com)]
class space_navigator_impl
{
public:
    space_navigator_impl(scm::inp::space_navigator*const d = 0);
    virtual ~space_navigator_impl();

public:
    HRESULT             on_sensor_input();
    HRESULT             on_key_down(int k);
    HRESULT             on_key_up(int k);

    void                update();

private:
    CComPtr<ISensor>    _3d_sensor;
    CComPtr<IKeyboard>  _3d_keyboard;

    scm::inp::space_navigator*const _device;
};

space_navigator_impl::space_navigator_impl(scm::inp::space_navigator*const d)
  : _device(d)
{
    HRESULT hr=::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (!SUCCEEDED(hr)) {
        CString strError;
        strError.FormatMessage (_T("Error 0x%x"), hr);
        scm::err() << scm::log_level(scm::logging::ll_error)
                   << "space_navigator_impl::space_navigator_impl()"
                   << "CoInitializeEx failed: " << strError << std::endl;
    }

    CComPtr<IUnknown> _3DxDevice;

    hr = _3DxDevice.CoCreateInstance(__uuidof(Device));
    if (!SUCCEEDED(hr)) {
        CString strError;
        strError.FormatMessage (_T("Error 0x%x"), hr);
        scm::err() << scm::log_level(scm::logging::ll_error)
                   << "space_navigator_impl::space_navigator_impl()"
                   << "_3DxDevice.CoCreateInstance failed: " << strError << std::endl;
    }
    else {
        CComPtr<ISimpleDevice> _3DxSimpleDevice;

        hr = _3DxDevice.QueryInterface(&_3DxSimpleDevice);
        if (!SUCCEEDED(hr)) {
            CString strError;
            strError.FormatMessage (_T("Error 0x%x"), hr);
            scm::err() << scm::log_level(scm::logging::ll_error)
                       << "space_navigator_impl::space_navigator_impl()"
                       << "_3DxDevice.QueryInterface failed: " << strError << std::endl;
        }
        else {
            // Get the interfaces to the sensor and the keyboard;
            hr = _3DxSimpleDevice->get_Sensor(&_3d_sensor);
            hr = _3DxSimpleDevice->get_Keyboard(&_3d_keyboard);

            // Associate a configuration with this device
            //_3DxSimpleDevice->LoadPreferences(L"scm_input_sn");

            hr = __hook(&_ISensorEvents::SensorInput, _3d_sensor, 
                        &space_navigator_impl::on_sensor_input);

            hr = __hook(&_IKeyboardEvents::KeyDown, _3d_keyboard, 
                        &space_navigator_impl::on_key_down);

            hr = __hook(&_IKeyboardEvents::KeyUp, _3d_keyboard, 
                        &space_navigator_impl::on_key_up);

            // Connect to the driver
            hr = _3DxSimpleDevice->Connect();
            if (!SUCCEEDED(hr)) {
                CString strError;
                strError.FormatMessage (_T("Error 0x%x"), hr);
                scm::err() << scm::log_level(scm::logging::ll_error)
                           << "space_navigator_impl::space_navigator_impl()"
                           << "_3DxSimpleDevice.Connect failed: " << strError << std::endl;
            }
            else {
                scm::out() << "space_navigator_impl::space_navigator_impl(): successfully connected to _3DxSimpleDevice driver" << std::endl;
            }
        }
        //_3DxDevice.Release();
    }
}

space_navigator_impl::~space_navigator_impl()
{
    HRESULT hr = E_FAIL;

    CComPtr<IDispatch> _3DxDevice;
    if (_3d_sensor) {
        hr = _3d_sensor->get_Device(&_3DxDevice);
    }
    else if (_3d_keyboard) {
        hr = _3d_keyboard->get_Device(&_3DxDevice);
    }

    if (SUCCEEDED(hr)) {
        CComPtr<ISimpleDevice> _3DxSimpleDevice;
        hr = _3DxDevice.QueryInterface(&_3DxSimpleDevice);
        if (SUCCEEDED(hr)) {
            _3DxSimpleDevice->Disconnect();
            _3DxSimpleDevice.Release();
        }
    }

    if (_3d_sensor) {
        // unhook (unadvise) the sensor event sink
        __unhook(&_ISensorEvents::SensorInput, _3d_sensor, 
                 &space_navigator_impl::on_sensor_input);
        _3d_sensor.Release();
    }

    if (_3d_keyboard) {
        __unhook(&_IKeyboardEvents::KeyDown, _3d_keyboard,
                 &space_navigator_impl::on_key_down);
        __unhook(&_IKeyboardEvents::KeyUp, _3d_keyboard,
                 &space_navigator_impl::on_key_up);
        _3d_keyboard.Release();
    }
}
void
space_navigator_impl::update()
{
    static DWORD last_time_stamp = 0;

    using namespace scm;
    using namespace scm::math;

    CComPtr<IAngleAxis> rotation;
    CComPtr<IVector3D>  translation;
    double              rotation_angle;
    double              translation_length;

    _3d_sensor->get_Rotation(&rotation);
    _3d_sensor->get_Translation(&translation);
    rotation->get_Angle(&rotation_angle);
    translation->get_Length(&translation_length);


    std::cout << "update impl" << std::endl;
    if (   rotation_angle > 0.0
        || translation_length > 0.0) {
        double time_factor = 1.0;

    std::cout << "update impl" << std::endl;
        DWORD time_stamp = ::GetTickCount();
        if (last_time_stamp) {
            double  period;
            _3d_sensor->get_Period(&period);
            time_factor = (double)(time_stamp - last_time_stamp) / period;
        }
        last_time_stamp = time_stamp;


        // translation
        vec3d  trans_vec;
        translation->get_X(&trans_vec.x);
        translation->get_Y(&trans_vec.y);
        translation->get_Z(&trans_vec.z);

        trans_vec *= vec3d(_device->_translation_sensitivity) * time_factor;
        translate(_device->_translation, math::vec3f(trans_vec));


        // rotation
        vec3d  rot_axis;
        rotation->get_X(&rot_axis.x);
        rotation->get_Y(&rot_axis.y);
        rotation->get_Z(&rot_axis.z);

        rotation_angle *= time_factor;
        rotate(_device->_rotation, (float)rotation_angle, math::vec3f(rot_axis));

        std::cout << _device->_rotation << std::endl;
    }
    rotation.Release();
    translation.Release();
}

HRESULT
space_navigator_impl::on_sensor_input()
{
    if (!_device) {
        return (S_FALSE);
    }

    update();

    return (S_OK);
}

HRESULT
space_navigator_impl::on_key_down(int k)
{
    return (S_OK);
}

HRESULT
space_navigator_impl::on_key_up(int k)
{
    return (S_OK);
}


namespace scm {
namespace inp {

namespace detail {


} // namespace detail

space_navigator::space_navigator()
{
    _rotation_sensitivity    = math::vec3f::one();
    _translation_sensitivity = math::vec3f::one();

    _rotation    = math::mat4f::identity();
    _translation = math::mat4f::identity();

    _device = make_shared<space_navigator_impl>(this);
}

space_navigator::~space_navigator()
{
    _device.reset();
}

void
space_navigator::update()
{
    //std::cout << "update dev" << std::endl;
    _device->update();
}

void
space_navigator::reset()
{
    _rotation    = math::mat4f::identity();
    _translation = math::mat4f::identity();
}

const math::mat4f&
space_navigator::rotation() const
{
    return (_rotation);
}

const math::mat4f&
space_navigator::translation() const
{
    return (_translation);
}

} // namespace inp
} // namespace scm

Code: Select all


#include <iostream>

#include <QtGui/QApplication>
#include <QtGui/QWidget>

#include <scm/input/devices/space_navigator_device.h>

class test_widget : public QWidget
{
public:
    test_widget() : QWidget() {
        _dev = new scm::inp::space_navigator;
    }
    void init_now() {
        //_dev = new scm::inp::space_navigator;
    }

    scm::inp::space_navigator*        _dev;
};


int main(int argc, char **argv)
{
    QApplication                    app(argc, argv);

    test_widget _window;
    _window.resize(1024, 768);
    _window.show();
    //_window.init_now();

    return app.exec();
}

chrislu
Posts: 11
Joined: Sun Jun 07, 2009 8:58 am

Post by chrislu »

please could a driver developer look into this simple example. the only qt you need is in the last code segment of my previous post.

any help would be greatly appreciated.
jwick
Moderator
Moderator
Posts: 3455
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hi chrislu,

We've been discussing this internally. We don't have experience with Qt. It appears that your events are getting discarded by Qt.

Several people have tried to get 3Dx devices to work with Qt over the years (search the forum). As I recall the only successful effort involved using a Qt callback to take a look at the events before they get to the Qt main loop. Certainly if they get there, they will be discarded as unrecognized. You can also use windows methods to hook into the msg loop before they get sent to Qt.

You may have better luck using the old C/C++ SDK if you need to look at the events. You can download this from the archive section under your device on our web site. It removes the complexity of COM.

It may be helpful to use Spy to see where the events are going.

If you do get this to work, please post your solution for the benefit of other Qt developers.

Thanks.
Jim
3Dx Software Development
chrislu
Posts: 11
Joined: Sun Jun 07, 2009 8:58 am

Post by chrislu »

hi,

i allready tried overriding winEvent() of the widget and winEventFilter() of the application but as i said there is _nothing_ coming through. These functions are supposed to look at the events before Qt handles/discards them, but there is nothing coming in these functions when using the space navigator. Again the hooks fire when another window is in focus that is not a Qt4 window.

I am out of stuff to try and going to an SDK that is not officially supported anymore is not a desirable option.

Maybe the COM idea of the SDK must be revisited... But i am still hoping for a resolution.
jwick
Moderator
Moderator
Posts: 3455
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

We still support the old SDK.

Take a look at the driver log file (3DxWare.log) to see what hwnd is getting registered. That may help you diagnose just where those events are going.
chrislu
Posts: 11
Joined: Sun Jun 07, 2009 8:58 am

Post by chrislu »

hi,
i just tried your suggestion enabling the log file. this is the result:

Code: Select all

9:42:1.958: UdCtl: Protocol 30 request to open connection for hwnd 0x50eda.
9:42:1.958: UdCtl: App transport list: 9:42:1.958: 50 9:42:1.958: 30 9:42:1.958: 
9:42:1.963: UdUi:TlReadConfigFile: Reading file: C:\Program Files\3Dconnexion\3Dconnexion 3DxSoftware\3DxWare64\EN_US\profiles\default\any.scg
9:42:1.971: UdUi:TlReadConfigFile: Reading file: C:\Program Files\3Dconnexion\3Dconnexion 3DxSoftware\3DxWare64\EN_US\profiles\default\any.scg
9:42:2.011: UdArbitrate:  New Target: hWnd: 0x50eda, Class Name: 3DxInput:Default, AppName (SiOpen): app_volume_rendering.exe, ExeName: app_volume_rendering.exe
9:42:2.011: UdCtl: Open accepted on protocol 30 for application: app_volume_rendering.exe(app_volume_rendering.exe)
9:42:2.011: UdUi:HandleSyncCommand: rec'd SI_SYNC_ITEM_QUERY
9:42:2.011: UdUi:HandleSyncCommand: SI_SYNC_ITEM_QUERY rejected.  APP_CONTROLS_BUTTONS==FALSE
9:42:2.018: UdCtl: Protocol 30 request to open connection for hwnd 0x140e5a.
9:42:2.018: UdCtl: App transport list: 9:42:2.018: 50 9:42:2.018: 30 9:42:2.018: 
9:42:2.018: UdCtl: Open accepted on protocol 30 for application: app_volume_rendering.exe(app_volume_rendering.exe)
9:42:2.021: UdArbitrate:  New Target: hWnd: 0x140e5a, Class Name: 3DxInput:Default, AppName (SiOpen): app_volume_rendering.exe, ExeName: app_volume_rendering.exe
9:42:2.021: UdUi:HandleSyncCommand: rec'd SI_SYNC_ITEM_QUERY
9:42:2.021: UdUi:HandleSyncCommand: SI_SYNC_ITEM_QUERY rejected.  APP_CONTROLS_BUTTONS==FALSE
9:42:4.998: UdCtl: Closed application app_volume_rendering.exe on protocol 30.
9:42:4.998: kbdtrans: UdTransClose request made
9:42:4.998: UdCtl: Closed application app_volume_rendering.exe on protocol 50.
9:42:5.003: UdUi:TlReadConfigFile: Reading file: C:\Program Files\3Dconnexion\3Dconnexion 3DxSoftware\3DxWare64\EN_US\profiles\default\any.scg
9:42:5.013: UdUi:TlReadConfigFile: Reading file: C:\Program Files\3Dconnexion\3Dconnexion 3DxSoftware\3DxWare64\EN_US\profiles\default\any.scg
9:42:5.066: UdArbitrate:  New Target: hWnd: 0x50eda, Class Name: 3DxInput:Default, AppName (SiOpen): app_volume_rendering.exe, ExeName: app_volume_rendering.exe
9:42:5.068: UdCtl: Closed application app_volume_rendering.exe on protocol 30.
9:42:5.068: kbdtrans: UdTransClose request made
9:42:5.068: UdCtl: Closed application app_volume_rendering.exe on protocol 50.
I again looked what goes through the winEvent() and winEventFilter() methods of Qt but i couldn't find anything to hinder Qt discarding something related to the SpaceNavigator.
jwick
Moderator
Moderator
Posts: 3455
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Can you put together an extremely simple example that shows this problem so we can diagnose your situation?
I'll PM an email address to you.
jwick
Moderator
Moderator
Posts: 3455
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Chris,

(from the 3DxInput developer)
The problem was the [module] attribute placed before the space_navigator_impl class. This was causing the atl attribute to inject code into that class to initialize the atl module base class(es). Thus the space_navigator_impl class was being initialized twice - implicitly at startup and then explicitly due to the widget creation - hence the two connections we saw. The atl base module class was actually asserting because of this double initialization. So I fixed the double initialization/placement of the [module] attribute and now it works correctly.
chrislu
Posts: 11
Joined: Sun Jun 07, 2009 8:58 am

Post by chrislu »

Thank you!

But one more question. Where exactly do i have to place the [module] attribute to fix this?
jwick
Moderator
Moderator
Posts: 3455
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

I've forwarded the fixed project back to you.
chrislu
Posts: 11
Joined: Sun Jun 07, 2009 8:58 am

Post by chrislu »

ok thank you.

just to show the solution: from my example code in the second post, the following has to be changed:

Code: Select all

using namespace ATL;

#import "progid:TDxInput.Device" embedded_idl no_namespace
// end com stuff

#endif SCM_PLATFORM == SCM_PLATFORM_WINDOWS

[module(type=dll, name = "scm_input_sn")]
[event_receiver(com)]
class space_navigator_impl
{
public:
    space_navigator_impl(scm::inp::space_navigator*const d = 0);
    virtual ~space_navigator_impl();
...
to the following:

Code: Select all

using namespace ATL;

#import "progid:TDxInput.Device" embedded_idl no_namespace
// end com stuff

#endif SCM_PLATFORM == SCM_PLATFORM_WINDOWS

[module(type=dll, name = "scm_input_sn")]
class CAtlSCMModule // The atl module class which the module attribute belongs to
{
};

[event_receiver(com)]
class space_navigator_impl
{
public:
    space_navigator_impl(scm::inp::space_navigator*const d = 0);
    virtual ~space_navigator_impl();
...
Post Reply