:mod:`spacedevice` --- Wrapper around the 3Dconnexion Developer's Kits ====================================================================== .. module:: cgkit.spacedevice :synopsis: Wrapper around the 3Dconnexion Developer's Kits The :mod:`spacedevice` module allows applications to support 3D input devices such as a SpaceMouse or a SpaceBall. The module wraps the 3DxWare SDK by 3Dconnexion. For a more detailed description of the SDK see the documentation that is part of the `SDK <http://www.3dconnexion.com/sdk.htm>`_. The module has to be used in conjunction with a GUI toolkit as there must be a window that receives the 3D input device events. In principle, any GUI toolkit can be used as long as it allows obtaining the native window handle and accessing system events. The steps necessary to use a 3D input device are as follows: #. Create a :class:`SpaceDevice` object. #. Open the device using the :meth:`open<SpaceDevice.open>` method. This requires a window handle of the window that will receive the SpaceDevice events. #. For every system event received call the :meth:`translateWin32Event<SpaceDevice.translateWin32Event>` method and check if the event was generated by a SpaceDevice. If it was, check for the event type and process the event. #. When the application terminates, call the :meth:`close` method to close the device. .. function:: available() Returns ``True`` if the module functionality is available. Currently, this function will only return ``True`` under Windows and if the functionality was enabled during compilation. If this function returns ``False``, an exception will be raised whenever you try to instantiate a class from this module. .. class:: SpaceDevice() The :class:`SpaceDevice` class provides the interface to the 3DxWare library that is used to communicate with the 3D input device. The constructor of this class calls the SDK function :cfunc:`SiInitialize` to initialize the 3DxWare library. The destructor closes the device if it is open and calls :cfunc:`SiTerminate`. .. method:: SpaceDevice.open(appname, hwnd, devID=SI_ANY_DEVICE) Establish a connection to a 3D input device. *appname* is a string containing the application name, *hwnd* is the native window handle (as an integer) of the window that should receive the events. *devID* is the device id. An exception is thrown if a connection cannot be established. This method calls the SDK functions :cfunc:`SiOpenWinInit` and :cfunc:`SiOpen`. .. method:: SpaceDevice.close() Close the connection to a device. The function returns immediately if there is no open connection. This method calls the SDK function :cfunc:`SiClose`. .. method:: SpaceDevice.translateWin32Event(msgid, wparam, lparam) Translates a Win32 event into a SpaceDevice event. The return value is a tuple (*RetVal*, *EventType*, *Data*). *RetVal* is an object of type ``RetVal`` that represents an enumeration. It is ``RetVal.IS_EVENT`` if the event was generated by a 3D input device, otherwise it is ``RetVal.NOT_EVENT``. *EventType* is an object of type ``EventType`` that again represents an enumeration. It can take one of the following values: * ``EventType.BUTTON_EVENT`` * ``EventType.MOTION_EVENT`` * ``EventType.ZERO_EVENT`` * ``EventType.EXCEPTION_EVENT`` The contents of the third value, *Data*, depend on the event type: +---------------------+---------------------------------------+ | Event type | Data | +=====================+=======================================+ | ``BUTTON_EVENT`` | (*pressed*, *released*) | +---------------------+---------------------------------------+ | ``MOTION_EVENT`` | (*translation*, *rotation*, *period*) | +---------------------+---------------------------------------+ | ``ZERO_EVENT`` | ``None`` | +---------------------+---------------------------------------+ | ``EXCEPTION_EVENT`` | ``None`` | +---------------------+---------------------------------------+ *pressed* and *released* are each lists that contain the numbers of the button that were either pressed or released. *translation* is a 3-tuple containing the translation vector and *rotation* is a 3-tuple containing the rotation vector. *period* contains the time in milliseconds since the last device event. This method calls the SDK functions :cfunc:`SiGetEventWinInit` and :cfunc:`SiGetEvent`. .. method:: SpaceDevice.beep(s) Causes the device to emit a sequence of tones and pauses that is encoded in the string *s*. Lowercase letters represent a tone, uppercase letters represent a pause. The closer the letter is to the beginning of the alphabet the shorter the pause or tone. This method calls the SDK function :cfunc:`SiBeep`. .. method:: SpaceDevice.getDeviceID() Return the device id of the currently open device. This method calls the SDK function :cfunc:`SiGetDeviceID`. .. method:: SpaceDevice.getDeviceInfo() Return information about the currently open device. The return value is a 5-tuple (*device type*, *numButtons*, *numDegrees*, *canBeep*, *firmware*). This method calls the SDK function :cfunc:`SiGetDeviceInfo`. .. method:: SpaceDevice.getDriverInfo() Return version information about the driver. The return value is a 5-tuple (*major*, *minor*, *build*, *versionstr*, *datestr*). This method calls the SDK function :cfunc:`SiGetDriverInfo`. .. method:: SpaceDevice.getNumDevices() Return the number of input devices detected by the driver. This method calls the SDK function :cfunc:`SiGetNumDevices`. .. method:: SpaceDevice.rezero() Causes the input device's current setting to be defined as the rest position. This method calls the SDK function :cfunc:`SiRezero`. .. method:: SpaceDevice.setUIMode(show) Change the state of the driver menu window from within an application. The function has to be called before a call to :meth:`open`. *show* is a boolean that specifies if the driver menu should be displayed or not. This method calls the function :cfunc:`SiSetUiMode`. .. note:: The module uses the SDK by 3Dconnexion which can be found at `<http://www.3dconnexion.com/sdk.htm>`_. The following is the copyright information of the SDK: *(C) 1998-2001 3Dconnexion* *Permission to use, copy, modify, and distribute this software for all purposes and without fees is hereby granted provided that this copyright notice appears in all copies. Permission to modify this software is granted and 3Dconnexion will support such modifications only if said modifications are approved by 3Dconnexion* Example ------- Here is a code example that uses pygame (you need at least version 1.7.1) as GUI toolkit. It simply prints the input device events to the console. :: ###################################################################### # SpaceDevice demo # # This demo demonstrates the usage of the SpaceDevice object in the # cgkit.spacedevice module which can be used to access events from # a SpaceMouse or SpaceBall. You can use this module to add support # for a SpaceDevice in your own Python application. The demo simply # prints the events generated from a SpaceDevice to the console. # # This demo uses pygame as GUI toolkit (v1.7.1 is required). # You can use any other GUI toolkit as long as it 1) lets you obtain # the native window handle of a window and 2) provides access to # system events. ###################################################################### import sys import pygame from pygame.locals import * from cgkit import spacedevice # handleSystemEvent def handleSystemEvent(evt): """Handle a system event. evt is a pygame event object that contains a system event. The function first checks if the event was generated by a SpaceDevice and if it was, it prints the event data. """ # sdev is the global SpaceDevice object global sdev # Translate the system event into a SpaceDevice event... res, evttype, data = sdev.translateWin32Event(evt.msg, evt.wparam, evt.lparam) # Check if the event actually was an event generated from # the SpaceMouse or SpaceBall... print res if res!=spacedevice.RetVal.IS_EVENT: return # Motion event? if evttype==spacedevice.EventType.MOTION_EVENT: t,r,period = data print "Motion: trans:%s rot:%s period:%d"%(t, r, period) # Button event? elif evttype==spacedevice.EventType.BUTTON_EVENT: pressed, released = data print "Button: pressed:%s released:%s"%(pressed, released) # Zero event? elif evttype==spacedevice.EventType.ZERO_EVENT: print "Zero" ###################################################################### # Check if cgkit was compiled with SpaceDevice support... if not spacedevice.available(): print "No SpaceDevice functionality available" sys.exit(1) # Initialize pygame... passed, failed = pygame.init() if failed>0: print "Error initializing pygame" sys.exit(1) # Open a window... pygame.display.set_caption("SpaceDevice demo") srf = pygame.display.set_mode((640,480)) # Enable system events... pygame.event.set_allowed(SYSWMEVENT) # Initialize the Space Device... sdev = spacedevice.SpaceDevice() info = pygame.display.get_wm_info() hwnd = info["window"] sdev.open("Demo", hwnd) # Print some information about the driver and the device... major, minor, build, versionstr, datestr = sdev.getDriverInfo() print "Driver info:" print "------------" print "%s, v%d.%d.%d, %s\n"%(versionstr, major, minor, build, datestr) devtyp, numbuttons, numdegrees, canbeep, firmware = sdev.getDeviceInfo() print "Device info:" print "------------" print "Device ID:",sdev.getDeviceID() print "Type :",devtyp print "#Buttons :",numbuttons print "#Degrees :",numdegrees print "Can beep :",canbeep print "Firmware :",firmware print "" # Event loop... running = True while running: # Get a list of events... events = pygame.event.get() # Process the events... for evt in events: # Close button? if evt.type==QUIT: running=False # Escape key? elif evt.type==KEYDOWN and evt.key==27: running=False # System event? elif evt.type==SYSWMEVENT: handleSystemEvent(evt) # Close the SpaceDevice sdev.close()