SpaceControl DLL  Version 2.8.9
API documentation for the SpaceControl 3D input devices
SpaceControl DLL Documentation

1. Introduction

A SpaceController is a device like a mouse for manipulating objects on a computer screen. In difference to a mouse the SpaceController has six degrees of freedom: translation in all three axes of space (x, y, z) and rotation around all of these axes. Therefore the SpaceController is the ideal equipment for moving and rotating objects in virtual 3D environments like CAD applications or moving the camera in GoogleEarth e. g.

Necessary for operation is the SpaceControl software. Basically this is a background process (the "SC-Daemon") which fetches the data produced by the device and delivers it to the applications interested in the data. Furthermore it reads the configuration data from a file, sends the data to the device during the initializing process and configures the device when the user changes the parameters with the user interface ("SC-GUI").

To enable other applications getting data from and writing data to the SpaceController the SC-Daemon provides an application programming interface, the SC-API. You just have to include the API's header file spc_ctrlr.h into your sources and link the SC-DLL (files "spc_ctrlr_32.dll" and "spc_ctrlr_64.dll" under Windows, or the shared library files "" and "" under Linux, or the dynamic library files "libspc_ctrlr_32.dylib" and "libspc_ctrlr_64.dylib" under OS X) to your application to have access to a set of functions described in this document.

If using Microsoft's Visual Studio you will need to generate library files for linking the SC-DLL. This is done by the commands

lib /machine:i386 /def:spc_ctrlr_32.def /out:spc_ctrlr_32.lib
lib /machine:x64 /def:spc_ctrlr_64.def /out:spc_ctrlr_64.lib

For other compilers look into their documentation how to generate the library files.

2. Basic Usage

2.1 Minimal Application and More Detailed Example

The minimal application to see data from the device is shown here (without error checking):

#include <iostream> // for using cout
#include "spc_ctrlr.h" // for using the SpaceControl API
int main(int argc, char** argv)
int cnt = 100, t, r, evt;
short x, y, z, a, b, c;
long tvSec, tvUsec;
scConnect2(true, NULL); // connect to the SC-Daemon
while (--cnt >= 0)
{ // get data from the daemon in an "endless" loop:
scFetchStdData(0, &x, &y, &z, &a, &b, &c, &t, &r, &evt, &tvSec, &tvUsec);
std::cout << "*** " << cnt
<< ", x: " << x << ", y: " << y << ", z: " << z
<< ", a: " << a << ", b: " << b << ", c: " << c
<< ", evt: " << evt << endl;
scDisconnect(); // disconnect from the daemon
return 0;

The more detailed example for getting or sending data from/to the SC-Daemon follows below; you have to perform these steps:

  • Establish the connection to the daemon. After this you can use all other DLL functions.
  • Get information about the connected SpaceControl devices. The devices are numbered with indices starting from 0, you will need these indices to identify a device a message is to be sent to.
  • Call DLL functions as needed, e. g. get the cap's data and other events in an endless loop.
  • Break the loop if you want to stop your application.
  • Disconnect from the daemon.
  • Exit your application.

These steps are shown in the following example (for a detailed list of all API functions see spc_ctrlr.h.):

#include <iostream> // for using cout
#include "spc_ctrlr.h" // for using the SpaceControl API
using namespace std;
int main(int argc, char** argv)
ScStatus status; // error code of an SC-API function
int devNum; // number of devices connected to the computer
int usedDevNum; // number of devices used by the driver
int maxDevIdx; // index of the last device connected to the computer
ScDevInfo sdi; // info about a device
int devIdx; // ID of a SpaceControl device
int cnt; // counter for leaving our "endless" loop below
short x, y, z, a, b, c; // space coordinates of the cap
int t; // low-, mid-, high-flags of translation
int r; // low-, mid-, high-flags of rotation
int evt; // event generated by the daemon
long tvSec; // time the driver has generated the message (seconds since jan 01 1970)
long tvUsec; // additional microseconds since tvSec
// connect to the daemon:
status = scConnect2(true, NULL);
if (status == SC_OK)
cout << "*** Connection with daemon established." << endl;
cout << "*** Error in scConnect(), status = " << scStatusToStr(status) << endl;
// get the number of connected devices:
status = scGetDevNum(&devNum, &usedDevNum, &maxDevIdx);
if (status == SC_OK)
cout << "*** Number of devices connected: " << devNum << endl
<< "*** Number of devices used: " << usedDevNum << endl
<< "*** Max. device index: " << maxDevIdx << endl;
cout << "*** Error in scGetDevNum(), status = " << scStatusToStr(status) << endl;
// get the serial no. of all devices to identify the one you want to
// communicate with:
for (int i = 0; i <= maxDevIdx; i++)
status = scGetDevInfo(i, &sdi);
if (status == SC_OK)
cout << "*** ID: " << sdi.mId
<< ", serialNo: " << sdi.mSerialNo
<< ", description: " << sdi.mDescrptn << endl;
cout << "*** Error in scGetDevNum(), status = " << scStatusToStr(status) << endl;
// say, we want the data from device 0:
devIdx = 0;
// fetch the data 100 times (move the cap and press some keys during this time):
cnt = 100;
while (--cnt >= 0)
// fetch the data:
status = scFetchStdData(devIdx, &x, &y, &z, &a, &b, &c, &t, &r, &evt, &tvSec, &tvUsec);
if (status == SC_OK)
cout << "*** " << cnt
<< ", x: " << x << ", y: " << y << ", z: " << z
<< ", a: " << a << ", b: " << b << ", c: " << c
<< ", evt: " << evt << endl;
cout << "*** " << cnt
<< ", Error in scFetchStdData(), status = " << scStatusToStr(status) << endl;
// and disconnect from the daemon:
status = scDisconnect();
if (status == SC_OK)
cout << "*** Connection with daemon ended." << endl;
cout << "*** Error in scDisconnect(), status = " << scStatusToStr(status) << endl;
return 0;

You may get some logging output besides the couts given above. This is generated by some API's internal functions and could be configured with the spc_ctrlr_dll.ini file in your home directory.

Notice that scFetchStdData() will wait 30 ms (this delay can be configured with the user interface) and return with status SC_COMMUNICATION_ERROR if the cap is not moved or no key is pressed in this time. This is no true error in this case.

Hint: The SC-Daemon monitors the desktop and is able to send data to all connected applications or to the one in the foreground only. This mechanism is controlled by setting the first parameter of scConnect2() to true or false. If set to true the data is sent to all connected applications even if they are not in the foreground; if set to false only the foreground application will get data. And there can arise a problem because another application may be in the foreground as you might expect: If you start your program from within a console the console is the foreground process and not your application! If the parameter is set to false your application will not receive the data therefore. The same may happen if your application is started within a development environment like Visual Studio. To avoid this start your application directly via double click out of an Explorer window.

2.2 Threads

As said scFetchStdData() pauses your application for 30 ms if no data is there. This may cause a significant slow down of your application. To avoid this you should put the call into a separate thread. Since thread creation and handling differs a lot in Windows on one side and Linux and OS X on the other the sample code is not printed here; see the sample project "sc_test_thread" mentioned in section 6 below instead.

2.3 Using a Callback Function

If you do not need the flexibility in creating your own thread you can let the SC-API do this for you. In this case you have to provide a callback function for each connected device which is called automatically each time a new data packet from the device is received. The device's data packet is handed over in the parameters. The minimal application using that approach is this:

#include <iostream> // for using cout
#include "spc_ctrlr.h" // for using the SpaceControl API
// define your callback function with this signature:
int myCallbackFunction(short x, short y, short z,
short a, short b, short c,
int traLmh, int rotLmh, int event,
long tvSec, long tvUsec)
// do with the data what you want, we just print some axes here:
printf("x: %d, y: %d, z: %d\n", x, y, z);
return 0; // all other return values are allowed but logged as an error if logging is on
int main(int argc, char** argv)
int cnt = 10; // counter for the "endless" loop
// connect to the daemon:
scConnect2(true, NULL);
// read data from device with index 0 with your callback function defined above:
scTransferCallbackFunction(0, myCallbackFunction);
// let do your application its other work, we just sleep ten times a second here:
while (--cnt >= 0)
std::cout << "*** " << cnt << endl;
scDisconnect(); // disconnect from the daemon
return 0;

When calling scTransferCallbackFunction() the API creates two threads. The first one reads the data from the device, the second one calls your callback function as soon as new data is available. This design avoids time lags if your callback function needs more time than the time between two data packets. In this case some data packets may be ignored.

3. Error Handling

Each API function returns a status code out of the enumeration ScStatus. The status codes are as follows:

  • SC_OK: The API function has been successfully executed.
  • SC_COMMUNICATION_ERROR: This error is returned if the answer for a request is not given innert a timeout time. This may happen if the communication is interrupted between the application and the daemon or between the daemon and the device.
  • SC_WRONG_DEVICE_INDEX: Most API functions need the device's index as a parameter for communication [an exception is scConnect2() e. g., there is no device involved in connecting the application with the daemon]. If a device index is given which is not available any longer (may be the user has unplugged the device) you get this error code.
  • SC_PARAMETER_OUT_OF_RANGE: The API functions check their parameters to some extent. If a function detects a parameter too big or too small this error is returned.
  • SC_FILE_IO_ERROR: This code is returned by scSaveDevPars() only in case saving the device parameters to file failed.
  • SC_KEYSTROKE_ERROR: This code is returned by scPressKey() and scRelKey() when simulating the key action failed.
  • SC_APPL_NOT_FOUND: This code is returned by scSetState() when an application name is given not known by the daemon.
  • SC_REGISTRY_ERROR: This code is returned by the functions accessing the Windows registry (not available with Linux).
  • SC_NOT_SUPPORTED: There will be other devices than our SpaceController in the future. Not all devices will have the same features (e. g. a display), and not all API functions will be applicable. This code is returned when an API function is not supported by a device. Not used yet.
  • SC_EXEC_CMD_ERROR: Not used yet.
  • SC_THREAD_ERROR: This code is returned by scTransferCallbackFunction() when the creation of one or both of the threads fails.

4. Deployment

When using the SpaceControl DLLs your application will become hooked on them. But it is not a good idea to link them statically to your code and deliver the DLLs with your application: Your customer may install a new SpaceControl driver software expecting newer DLLs. (We try to make newer versions as compatible as possible with older releases, but 100 percent compatibility can not be guaranteed.) Therefore it is much better to use the DLLs delivered with our driver installer.

This can be achieved by loading the DLLs dynmically using the Windows API function LoadLibrary(). Before doing this you should check if the SpaceControl driver is installed and if yes where. This can be done by checking the Windows registry key "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\sc_daemon.exe"; its value is the SpaceControl driver's installation folder, the DLLs are located in the subfolders "libs\win32" and "libs\win64" in it.

The folders' paths are added additionally to the environment variable PATH by our installer. Windows is able to find the DLLs by itself and just linking the libraries to your code [rather than calling LoadLibrary()] will also work therefore.

5. Deeper Integration

Some applications are even better ingegrated: They provide their menu structure for displaying it in the SpaceControl's Control Panel and for using it to redefine the SpaceController's keys with the application's menu items (as done by our plug-ins). This is not possible with the information given here. Furthermore, the daemon must be aware of such plug-ins. If you want to integrate your application in such deepness, please, contact our support.

6. Sample Projects

In the installation folder ("C:\Program Files (x86)\SpaceControl" under Windows if not changed) you will find the file "". It contains a Workspace with three sample projects, created with Visual Studio 2008 (Windows driver), Xcode 5 (OS X driver) or Netbeans 7.4 (Linux driver):

  • sc_test_minimal: This is the minimal console application described in section 2.1 Minimal Application and More Detailed Example.
  • sc_test_thread: This is a little application using a separate thread for fetching the device's data as mentioned in section 2.2 Threads. You should use this approach to avoid slowing down your application while waiting for the data.
  • sc_test_callback: This is the console application described in section 2.3 Using a Callback Function using a callback function to get the data.

7. Change Log

16 August 2017, Version 2.8.9:

  • Some internal changes concerning the use of more than one device concurrently. Not relevant for using the API.
  • This change log is added to the documentation finally.

9 March 2016, Version 2.8.3:

  • Some modifications due to the daemon's new remote control feature. Not relevant for using the API.

15 July 2015, Version 2.8.1:

  • New ScStatus code SC_WRONG_USER. The daemon prevents connections from a user who has not started the daemon due to security reasons.

5 November 2014, Version 2.7.0:

  • Function scRegisterCallbackFunction() renamed to scTransferCallbackFunction() to make sure the function is appended in the library at the end.

16 July 2014, Version 2.6.3:

  • New API function scRegisterCallbackFunction(). If a callback function is handed over the DLL creates some threads by itself and calls the function each time a new data packet is received.

16 January 2014, Version 2.6.1:

  • Some sample projects are delivered together with the API.
  • New API functions scGetDaemonPar() and scSetDaemonPar() to access the parameters in file "daemon.ini".

10 April 2013, Version 2.5.1:

12 September 2012, Version 2.3.2:

24 November 2011, Version 2.2.1:

15 July 2011, Version 2.1.2:

  • scLoadDevPars() delivers valid (default) values even if the function returns with an error.
  • New API function scTriggerFunction() for triggering functions listed in the SpaceControl panel's function tree.

1 February 2011, Version 2.0.0:

  • scSetState() should be provided with an application's process ID to avoid sending data to a second instance not in the foreground.

5 October 2010, Version 1.4.3 beta:

20 April 2010, Version 1.4.0:

  • scFetchStdData() and scGetStdData() return a time stamp now when the message was generated by the daemon.

15 January 2010, Version 1.2.1:

  • scFetchStdData() returns SC_WRONG_DEVICE_INDEX in case of device index < 0.
  • Bugfixes in the Java wrapper functions.

15 June 2009, Version 1.1.1:

17 March 2009, Version 1.0.1:

  • First published release.
Friedemann Seebass

SpaceControl Copyright (c) SpaceControl GmbH & Co. KG, Am Technologiepark 10, D-82229 Seefeld
Generated by Doxygen