Where's the SDK?

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

Moderator: Moderators

ngomes
Moderator
Moderator
Posts: 3336
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes »

Hi kitsu,

I think, in the end, the solution is to provide a module to expose the 3D mouse data in Python programs. This will require some knowledge on how to "connect" to the data in the different platforms (which 3Dx has aplenty) and how build the Python module (which we do not). We are more than happy to help the community to develop such a module.

To answer your questions. You do not need to catch any messages. That's all done by the COM server. The protocol between the app and driver uses registered window messages.

That "__hook" statement is an "attribute." This is Microsoft's approach to hide some of the nitty gritty of using the IConnectionPoint interface.

Note that the 3DxInput (the COM API) has two modes of operation: you can poll data (as in the Python example in this topic) or you can register to receive "events" (and use the IConnectionPoint interface directly or inderectely). Most of the high level scripting language are able to hide the use of these standard interfaces.

Unfortunately, not being a Python developer myself, I cannot provide much assistance on how to go about using a COM object in that language.
kitsu
Posts: 7
Joined: Thu Aug 09, 2007 1:28 pm

Post by kitsu »

Thanks for the quick reply. I guess using a lower level module wouldn't be terrible. Is there a .dll supporting c calling syntax available? The Python ctypes module allows Python programs to dynamically load shared libraries (whether they are .dll or Linux .so or whatever) and call arbitrary functions. The COM library I'm using actually uses ctypes to build all its modules - which is why some of the raw implementation details are still exposed.

While wandering through MSDN I found this:
http://msdn2.microsoft.com/en-us/library/ms680112.aspx
which gives a little more insight into how COM relates to the event loop. I still haven't managed to translate their example code into something comprehensible though.
here: http://msdn2.microsoft.com/en-us/library/ms644928.aspx
is nearly a verbatim replication of the code in one of the 3Dx SDK examples. I still don't understand exactly what it is doing, but I guess it is what I need to get my code working. It is a big ugly chunk of code, but I will see if I can translate it.
calli
Posts: 12
Joined: Tue Aug 07, 2007 4:27 am

Post by calli »

ngomes wrote: Note that the 3DxInput (the COM API) has two modes of operation: you can poll data (as in the Python example in this topic)
But the polling does not work in the examples...

Carsten
kitsu
Posts: 7
Joined: Thu Aug 09, 2007 1:28 pm

Post by kitsu »

Oops, nevermind. I had a beer and everything fell together*. The following code prints out nice floating point value as I move the cap.

Code: Select all

import comtypes.client as client
from ctypes import *

import logging
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)

types = { # What others?
	0:"Unknown",
	6:"SpaceNavigator",
	4:"SpaceExplorer",
	25:"SpaceTravler",
	29:"SpacePilot"
}

class POINT(Structure):
    """Point struct used in Win32 api functions."""
    _fields_ = [("x", c_long),
                ("y", c_long)]

class MSG(Structure):
    """Message struct used in Win32 api functions."""
    _fields_ = [("hWnd", c_ulong),
                ("message", c_uint),
                ("wParam", c_ulong),
                ("lParam", c_ulong),
                ("time", c_ulong),
                ("pt", POINT)]
    
def PumpWaitingMessages():
    """Windows API function."""
    user32 = windll.user32
    msg = MSG()
    PM_REMOVE = 0x0001
    while user32.PeekMessageA(byref(msg), 0, 0, 0, PM_REMOVE):
        user32.TranslateMessage(byref(msg))
        user32.DispatchMessageA(byref(msg))

def GetMessage():
    """Windows API function."""
    #BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
    user32 = windll.user32
    msg = MSG()
    user32.GetMessageW(byref(msg), None, 0, 0)
    return msg

def DispatchMessage(msg):
    """Windows API function."""
    user32 = windll.user32
    user32.DispatchMessageW(byref(msg))

class KeyListener:
    """Catch and print keyboard events.

    Note: some keys either don't send events or give bad key codes.
    """
    def __init__(self, keyboard):
        self.exit = False
        self.keyboard = keyboard
        self.exitCode = 1

    def cont(self):
        return not self.exit
    
    def KeyDown(self, this, code):
        print 'Keydown: %s, %s' %(code, self.keyboard.GetKeyName(code))
        if code == self.exitCode:
            self.exit = True

    def KeyUp(self, this, code):
        print 'Keyup: %s, %s' %(code, self.keyboard.GetKeyName(code))

class SensorListener:
    """Catch and print sensor events."""
    def __init__(self, sensor):
        self.sensor = sensor
    
    def SensorInput(self, this, inval=None):
        print "Rot: ",
        print self.sensor.Rotation.X,
        print self.sensor.Rotation.Y,
        print self.sensor.Rotation.Z
        print "Trans: ",
        print self.sensor.Translation.X,
        print self.sensor.Translation.Y,
        print self.sensor.Translation.Z

# Get device
device = client.CreateObject("TDxInput.Device")
print types[device.Type],

if not device.Connect(): # Returns failed
	print ": Connected!"

# Setup keyboard listener
keyboard = device.Keyboard
listener = KeyListener(keyboard)
client.GetEvents(keyboard, listener)

# Setup sensor listener
sensor = device.Sensor
client.GetEvents(sensor, SensorListener(sensor))

# Start event loop
while listener.cont():
    msg = GetMessage()
    DispatchMessage(msg)
    #PumpWaitingMessages()
    

Note that there is a error in the comtypes 0.3.2 GetEvents function which causes it to miss all events. I've reported it to the mailing list, but until it is fixed use comtypes 0.2.1.

If you are using pywin32 you should be able to fine the GetMessage, DispatchMessage, and TranslateMessage functions in win32event module.

One continuing problem I've had though is that some key events don't seem to be working correctly. I have the SpaceExplorer - the model with the second most buttons BTW. I'm guessing that the esc, ctrl, etc keys are generating normal keycodes like a keyboard? What are the key codes for 2d and 'fit' though. I think 32 is the keycode for 'fit', but keyboard.GetKeyName(code) raises a undefined COM error?

* This poster neither endorses nor encourages the consumption of alcohol, except in cases involving the Component Object Model or the Window's API*
calli
Posts: 12
Joined: Tue Aug 07, 2007 4:27 am

Post by calli »

My Hero!

Thanks to beer! ;-)
Carsten
kitsu
Posts: 7
Joined: Thu Aug 09, 2007 1:28 pm

Post by kitsu »

I just noticed something interesting this morning - pressing the 2d button toggles sensor.Rotation between outputing all zeros or meaningful values. It seems this behavior is at 'hardware' level (or at least not exposed via COM).

In future releases it might be nice to have a settable 2d attribute in the sensor object. Otherwise there is no way to change the value at run time. It would be fine if I could create arbitrary configuration preference files, but as it is now any software I write will be stuck with the general preferences.

Actually I just peeked and it looks like the configurations are just plain text files? I suppose I can go fake my own then, but I would prefer a nice API to protect me from future format changes. Depending on undocumented file formats sucks :(
etr9j
Posts: 2
Joined: Fri Apr 03, 2009 8:09 pm

Post by etr9j »

I know this post fairly old, but I'm trying to get python working with my navigator and this script seems like it's the best bet. I can get it working to a point. Running the script shows "SpaceNavigator : Connected!" but that's it - I don't get values printing out.

It might have to do with version issues, since I'm using a newer version of comtypes than described. It might also be that some subtle changes in python itself since this post might be to blame (I'm working in python 2.5 at the moment).

But since it works to some degree I hope it might be something less complicated. It looks like the listeners aren't working even though there isn't an error.

Anyone have any ideas?
etr9j
Posts: 2
Joined: Fri Apr 03, 2009 8:09 pm

Post by etr9j »

Okay, looks like it was a version issue. For this to work you really need comtypes 0.2.1. I was using 0.6.0 thinking any bugs in this function was resolved by now, but it seems that the 0.2.1 GetEvents is a bit more involved. With a little searching I found v 0.2.1 here.
Post Reply