: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 `_.
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` method. This requires a window handle
of the window that will receive the SpaceDevice events.
#. For every system event received call the :meth:`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
``_. 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()