├── Images ├── XboxOne_LT.png ├── XboxOne_Left_Stick.png ├── XboxOne_RT.png ├── XboxOne_Right_Stick.png └── controller.png ├── LICENSE ├── README.md ├── mtJoystick.c ├── mtJoystick.h ├── mtXboxController.c └── mtXboxController.h /Images/XboxOne_LT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MauriceGit/XBox_Controller_Linux_Interface/00584fa809ef2400a3fd2d55c2ee7390153d3b37/Images/XboxOne_LT.png -------------------------------------------------------------------------------- /Images/XboxOne_Left_Stick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MauriceGit/XBox_Controller_Linux_Interface/00584fa809ef2400a3fd2d55c2ee7390153d3b37/Images/XboxOne_Left_Stick.png -------------------------------------------------------------------------------- /Images/XboxOne_RT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MauriceGit/XBox_Controller_Linux_Interface/00584fa809ef2400a3fd2d55c2ee7390153d3b37/Images/XboxOne_RT.png -------------------------------------------------------------------------------- /Images/XboxOne_Right_Stick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MauriceGit/XBox_Controller_Linux_Interface/00584fa809ef2400a3fd2d55c2ee7390153d3b37/Images/XboxOne_Right_Stick.png -------------------------------------------------------------------------------- /Images/controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MauriceGit/XBox_Controller_Linux_Interface/00584fa809ef2400a3fd2d55c2ee7390153d3b37/Images/controller.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, 2016 Maurice Tollmien 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux Interface for an XBox One Controller 2 | 3 | This is a linux interface, to integrate the Xbox-Controller directly into your favorite project. 4 | If you require different mappings or axes, please see the linux 5 | programs: **jscal** and **jstest-gtk** to change the mapping on the controller. 6 | 7 | It is also recommended, to calibrate the controller before using it. This is also done with: **jscal** or **jstest-gtk**. 8 | 9 | This library possibly works with other joystick devices but is only tested with the XBox controller. 10 | 11 | # Library Dependencies 12 | 13 | Because some vector and quaternion based math is required to calculate the joystick movements, I provide the appropriate libraries needed to use Xbox-Controller here: 14 | 15 | **Quaternion library:** [https://github.com/MauriceGit/Quaternion_Library](https://github.com/MauriceGit/Quaternion_Library). 16 | 17 | **Vector library:** [https://github.com/MauriceGit/Vector_Library](https://github.com/MauriceGit/Vector_Library). 18 | 19 | Just place the .c and .h files in the same directory and compile them with your project. 20 | 21 | # Functionality 22 | 23 | The only interface and functions you should use, are the documented as function heads in the **mtXboxController.h** file. 24 | More documentation about these functions are found above the apropriate function bodies in **mtXboxController.c**. 25 | 26 | Function | Description | 27 | --- | --- 28 | `int mtInitJoyControl(char* name)` | This function MUST be called before any other. It initialises the usb stream connection. 29 | `int mtFinishJoyControl()` | This function should be called after any interaction with the Controller is finished. 30 | `void mtCalcJoyCameraMovement(double interval)` | This function should be called in very short intervals, to allow a very smooth joystick handling. The parameter is the time since the last call to this method. 31 | `MTVec3D mtGetJoyPosition()` | The current position is retreived (of the camera or object, controlled via the Controller). 32 | `MTVec3D mtGetJoyUp()` | The current up-vector is retreived (of the camera or object, controlled via the Controller). 33 | `MTVec3D mtGetJoyCenter()` | The current center point is retreived (of the camera or object, controlled via the Controller). 34 | 35 | # Calibration 36 | 37 | There are two constants, to change the sensitivity of the joystick input. They are found in the `mtXboxController.h` and can be 38 | changed at will. Please ensure, that these values are of floating point. 39 | 40 | Changes might be necessary depending on your application and size of your virtual environment. 41 | 42 | 43 | 44 | Name | Default Value | Description 45 | --- | --- | --- 46 | `MT_XBOX_TRANS_NORMALISATION` | 500000.0 | The smaller this value, the faster the translation will get. Affected are: Right stick, LT Axis and RT Axis (See: [Controller Assignment](#controller-assignment)). 47 | `MT_XBOX_TURN_NORMALISATION` | 2000.0 | The smaller this value, the faster Pitch and Yaw will be. Left stick is affected (See: [Controller Assignment](#controller-assignment)). 48 | 49 | The following constants will affect the axis and give them an offset (if value > 0). 50 | The offset could be used, to for example ignore the negative axis values. 51 | 52 | Name | Default Value | Assignment 53 | --- | --- | --- 54 | `MT_AXIS_2_OFFSET` | 32768 | LT Axis 55 | `MT_AXIS_3_OFFSET` | 0 | Left stick 56 | `MT_AXIS_4_OFFSET` | 0 | Right stick 57 | `MT_AXIS_5_OFFSET` | 32768 | RT Axis 58 | 59 | See also: [Controller Assignment](#controller-assignment). 60 | 61 | # What about the Buttons? 62 | 63 | You might have noticed that we ignored any buttons from your Controller and the `mtXboxController` does in fact not give you any interface 64 | for buttons. Reason for that is, that this controller interface acts as an abstraction level for the transformation of axis movements 65 | to 3D orientation calculation, that internally uses Quaternions. 66 | 67 | Buttons don't need fancy calculations and abstractions around them. So if you like to implement actions for your Xbox Controller buttons, 68 | just include the `mtJoystick.h` and call the appropriate function directly (`int getButtonValue(int buttonNumber, short * value)`). 69 | 70 | 71 | # Usage 72 | 73 | This library can be used to control a camera or object in a 3D environment. 74 | 75 | The following example uses the Controller to move the camera in an OpenGL context. 76 | 77 | ```c 78 | // This is done right at the start of your program, before entering the main loop. 79 | char* jsSource = "/dev/input/js0"; 80 | if (!mtInitJoyControl(jsSource)) { 81 | // Error. Initialisation failed. 82 | } 83 | 84 | ... 85 | 86 | // In GLUT or GLFW, there is a timer, allowing us to get the time interval between 87 | // two frames. We need this interval, to update the camera position via the Controller 88 | float interval = ... 89 | mtCalcJoyMovement(interval); 90 | 91 | ... 92 | 93 | // Later, we want to set our camera position and direction with gluLookAt(). 94 | // The result of our functions fit exactly into this scheme. 95 | MTVec3D cam = mtGetJoyPosition(); 96 | MTVec3D center = mtGetJoyCenter(); 97 | MTVec3D up = mtGetJoyUp(); 98 | gluLookAt (cam.x, cam.y, cam.z, 99 | center.x, center.y, center.z, 100 | up.x, up.y, up.z); 101 | 102 | ... 103 | 104 | // Don't forget, to nicely kill the controller ;) 105 | mtFinishJoyControl(); 106 | ``` 107 | 108 | # Controller Assignment 109 | 110 | All code is tested with the XBox One controller (see following image). 111 | 112 | ![XBox Controller](https://github.com/MauriceGit/XBox_Controller_Linux_Interface/blob/master/Images/controller.png "XBox controller") 113 | 114 | The following axes are assigned: 115 | 116 | Axis | Assignment 117 | --- | --- 118 | ![LT Axis](https://github.com/MauriceGit/XBox_Controller_Linux_Interface/blob/master/Images/XboxOne_LT.png "LT Axis") | Increases the height of the object/camera along the Y axis. 119 | ![RT Axis](https://github.com/MauriceGit/XBox_Controller_Linux_Interface/blob/master/Images/XboxOne_RT.png "RT Axis") | Decreases the height of the object/camera along the Y axis. 120 | ![Left Stick](https://github.com/MauriceGit/XBox_Controller_Linux_Interface/blob/master/Images/XboxOne_Left_Stick.png "Left Stick") | Controls the Pitch and Yaw axis. (Front/Back: Pitch, Left/Right: Yaw). 121 | ![Right Stick](https://github.com/MauriceGit/XBox_Controller_Linux_Interface/blob/master/Images/XboxOne_Right_Stick.png "Right Stick") | Moves the object/camera on the X/Z plane relative to the current position and orientation. Front/Back/Left/Right accordingly. 122 | 123 | 124 | -------------------------------------------------------------------------------- /mtJoystick.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mtJoystick.c 3 | * 4 | * Implements Joystick control for Linux newer than 2.2.x. 5 | * This implementation can handle a maxium of: 6 | * - 256 axes 7 | * - 256 Buttons 8 | * 9 | * Allows to read the following attributes: 10 | * - Device name 11 | * - Axis count 12 | * - Button count 13 | * - Axis status (-32768/32767) (signed short) 14 | * - Button status (0/1) 15 | * 16 | * Reading of those values is event based. 17 | * 18 | * Author: Maurice Tollmien, Mervyn McCreight 19 | * 20 | * Last change: 10.09.2016 21 | */ 22 | 23 | 24 | /* System header */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "mtJoystick.h" 34 | 35 | 36 | /* Array of open device streams! */ 37 | JoystickDevice g_device; 38 | 39 | /** 40 | * Changes the correction coefficients to calibrate a Joystick. 41 | * This can also be done, using the Linux programs: jstest-gtk or jscal 42 | */ 43 | int setCalibrationCoefficients(int a,int b,int c,int d,int t,int prec) { 44 | struct js_corr corr[8]; 45 | 46 | int i = 0; 47 | 48 | for (i=0; i<8; ++i) { 49 | 50 | corr[i].type = t; 51 | corr[i].prec = prec; 52 | corr[i].coef[0] = a; 53 | corr[i].coef[1] = b; 54 | corr[i].coef[2] = c; 55 | corr[i].coef[3] = d; 56 | 57 | printf("corr.type = %d, corr.prec = %d, corr.a = %d, corr.b = %d, corr.c = %d, corr.d = %d\n", corr[i].type, corr[i].prec, corr[i].coef[0], corr[i].coef[1], corr[i].coef[2], corr[i].coef[3]); 58 | } 59 | 60 | /* set correction */ 61 | if (ioctl(g_device.fd, JSIOCSCORR, &corr)) { 62 | return 0; 63 | } 64 | 65 | return 1; 66 | } 67 | 68 | /** 69 | * Frees the allocated memory for any device data. 70 | * 71 | * @return 0 on failure. Otherwise success. 72 | */ 73 | static int freeDeviceMemory() { 74 | 75 | free(g_device.axisValues); 76 | free(g_device.buttonValues); 77 | 78 | return (g_device.axisValues == NULL) && (g_device.buttonValues == NULL); 79 | } 80 | 81 | /** 82 | * Opens the joystick device stream for reading. 83 | * @param devname Path to device (Most common: /dev/input/js0) 84 | * 85 | * @return 0 on failure. Otherwise success. 86 | */ 87 | static int openDeviceStream(const char * devname) { 88 | /* 89 | * Opens device in blocking mode. 90 | * If the return value is invalid or no device is connected, 91 | * -1 is returned as error value. 92 | */ 93 | g_device.fd = open(devname, O_RDONLY); 94 | 95 | if (g_device.fd == -1) { 96 | fprintf(stderr, "Error opening device: %s\n", devname); 97 | return 0; 98 | } 99 | 100 | /* 101 | * Changes into a NON-BLOCKING-MODE. 102 | * A "read" is now put onto the driver stack and doesn't wait 103 | * for a triggered event. 104 | */ 105 | fcntl(g_device.fd, F_SETFL, O_NONBLOCK); 106 | 107 | return 1; 108 | } 109 | 110 | /** 111 | * Determines the following device data and saves them internally: 112 | * - Axis count (IOCTL operation: JSIOCGAXES) 113 | * - Button count (IOCTL operation: JSIOCGBUTTONS) 114 | * - Device name (IOCTL operation: JSIOCGNAME(length)) 115 | * - Driver version (IOCTL operation: JSIOCGVERSION) 116 | * 117 | * @return 0 on failure. Otherwise success. 118 | */ 119 | static int getJoystickInformation() { 120 | /* the device must be opened ! */ 121 | if (g_device.fd == -1) { 122 | fprintf(stderr, "getJoystickInformation: Device not opened!\n"); 123 | return 0; 124 | } 125 | 126 | /* Read device name and save it */ 127 | if (ioctl (g_device.fd, JSIOCGNAME(JOY_NAME_LENGTH), &g_device.name) < 0) { 128 | strncpy(g_device.name, "Unknown Device", sizeof(g_device.name)); 129 | } 130 | 131 | /* Read and save available Axis count */ 132 | ioctl(g_device.fd, JSIOCGAXES, &g_device.axisNumber); 133 | 134 | /* Read and save available Button count */ 135 | ioctl(g_device.fd, JSIOCGBUTTONS, &g_device.buttonNumber); 136 | 137 | /* Read and save driver version */ 138 | ioctl(g_device.fd, JSIOCGVERSION, &g_device.driverVersion); 139 | 140 | return 1; 141 | } 142 | 143 | /** 144 | * Allocates memory for the dynamic arrays for the data structure to manage 145 | * axes and buttons. 146 | * 147 | * @return 0 on failure. Otherwise success. 148 | */ 149 | static int allocateDeviceValueMemory() { 150 | /* dynamic array of axis values */ 151 | g_device.axisValues = (short *)calloc(g_device.axisNumber, sizeof(short)); 152 | 153 | if (g_device.axisValues == NULL) { 154 | fprintf(stderr, "allocateDeviceValueMemory: Error allocating memory for the axis!\n"); 155 | return 0; 156 | } 157 | 158 | /* dynamic Array for button values */ 159 | g_device.buttonValues = (short *)calloc(g_device.buttonNumber, sizeof(short)); 160 | 161 | if (g_device.buttonValues == NULL) { 162 | fprintf(stderr, "allocateDeviceValueMemory: Error allocating memory for the buttons!\n"); 163 | return 0; 164 | } 165 | 166 | return 1; 167 | } 168 | 169 | /** 170 | * Starts a connection to the given device and allocates the correspondent memory. 171 | * 172 | * @return 0 on failure. Otherwise success. 173 | */ 174 | int startDeviceConnection(const char * devname) { 175 | if (!openDeviceStream(devname)) { 176 | return 0; 177 | } 178 | 179 | if (!getJoystickInformation()) { 180 | return 0; 181 | } 182 | 183 | if (!allocateDeviceValueMemory()) { 184 | return 0; 185 | } 186 | 187 | return 1; 188 | } 189 | 190 | /** 191 | * Closes the connection to a device and frees memory. 192 | * 193 | * @return 0 on failure. Otherwise success. 194 | */ 195 | int endDeviceConnection() { 196 | close(g_device.fd); 197 | return freeDeviceMemory(); 198 | } 199 | 200 | /** 201 | * Prints the following Joystick information to stdout: 202 | * - Device name 203 | * - Driver version 204 | * - Axis count 205 | * - Button count 206 | */ 207 | void printJoystickInformation() { 208 | fprintf(stdout, "-------------------------------------\n"); 209 | fprintf(stdout, "Device Name:\t%s\n", g_device.name); 210 | fprintf(stdout, "Driver Version:\t%i\n", g_device.driverVersion); 211 | fprintf(stdout, "-------------------------------------\n"); 212 | fprintf(stdout, "Number of Axis:\t%d\n", g_device.axisNumber); 213 | fprintf(stdout, "Number of Buttons:\t%d\n", g_device.buttonNumber); 214 | } 215 | 216 | /** 217 | * Handles one Joystick event. 218 | * 219 | * @param e the Joystick event. 220 | */ 221 | static void processEvent(struct js_event e) { 222 | /* 223 | * Interprets event. 224 | * The JS_EVENT_INIT bits will be deactivated as we do not want to distinguish 225 | * between synthetic and real events. 226 | */ 227 | switch (e.type & ~JS_EVENT_INIT) { 228 | case JS_EVENT_AXIS: 229 | //printf("axis: %i, value: %i\n", e.number, e.value); 230 | g_device.axisValues[e.number] = e.value; 231 | 232 | break; 233 | 234 | case JS_EVENT_BUTTON: 235 | //printf("button: %i, value: %i\n", e.number, e.value); 236 | g_device.buttonValues[e.number] = e.value; 237 | 238 | break; 239 | default: 240 | break; 241 | } 242 | } 243 | 244 | /** 245 | * Reads a joystick event and updates the correspondent values 246 | * accordingly. 247 | * 248 | * Strukture of js_events: 249 | * 250 | * time : unsigned int - event timestamp in ms 251 | * value : short - the new value 252 | * type : char - the type of the event 253 | * number : char - number of the relevant axis/button 254 | * 255 | * possible values for 'type' are: 256 | * 257 | * JS_EVENT_BUTTON (0x01) - a button event 258 | * JS_EVENT_AXIS (0x02) - an axis event 259 | * JS_EVENT_INIT (0x80) - Initial status of the device 260 | */ 261 | void handleJoystickEvents() { 262 | struct js_event jsEvent; 263 | 264 | /* read all events from the driver stack! */ 265 | while (read(g_device.fd, &jsEvent, sizeof(struct js_event)) > 0) { 266 | processEvent(jsEvent); 267 | } 268 | } 269 | 270 | /** 271 | * Reads the value of an axis to 'value'. 272 | * 273 | * @param axisNumber the relevant axis to be read. 274 | * @param value the read value of the axis 275 | * 276 | * @return 0 on failure. Otherwise success. 277 | */ 278 | int getAxisValue(int axisNumber, short * value) { 279 | if (axisNumber <= g_device.axisNumber) { 280 | (*value) = g_device.axisValues[axisNumber]; 281 | return 1; 282 | } 283 | 284 | fprintf(stderr, "getAxisValue: Invalid axis number\n"); 285 | (*value) = 0; 286 | return 0; 287 | } 288 | 289 | 290 | /** 291 | * Reads the value of a button to 'value'. 292 | * 293 | * @param buttonNumber the relevant button to be read. 294 | * @param value the read button value. 295 | * 296 | * @return 0 on failure. Otherwise success. 297 | */ 298 | int getButtonValue(int buttonNumber, short * value) { 299 | if (buttonNumber <= g_device.buttonNumber) { 300 | (*value) = g_device.buttonValues[buttonNumber]; 301 | return 1; 302 | } 303 | 304 | fprintf(stderr, "getButtonValue: Invalid button number\n"); 305 | (*value) = 0; 306 | return 0; 307 | } 308 | 309 | /* 310 | * MODULE TEST 311 | int main(void) { 312 | 313 | short testvalue = 2000; 314 | 315 | if (!startDeviceConnection("/dev/input/js0")) exit(1); 316 | printJoystickInformation(); 317 | 318 | setCalibrationCoefficients(24617, 40917, 21844, 21844, 1, 255); 319 | 320 | while (1) { 321 | int i = 0; 322 | handleJoystickEvents(); 323 | 324 | for (i=0; i 8 | #include 9 | #include 10 | #include "mtXboxController.h" 11 | #include "mtVector.h" 12 | #include "mtQuaternions.h" 13 | #include "mtJoystick.h" 14 | 15 | MTVec3D G_JoyUpVector; 16 | MTVec3D G_JoyViewVector; 17 | MTVec3D G_JoyTranslation; 18 | MTVec3D G_JoyPosition; 19 | 20 | MTVec3D mtGetJoyPosition () { 21 | return G_JoyPosition; 22 | } 23 | 24 | MTVec3D mtGetJoyUp() { 25 | return G_JoyUpVector; 26 | } 27 | 28 | MTVec3D mtGetJoyCenter() { 29 | return mtAddVectorVector(G_JoyViewVector, G_JoyPosition); 30 | } 31 | 32 | short getTranslationAxisValue(int axis) { 33 | if (axis <= 5) { 34 | short v; 35 | if (!getAxisValue(axis, &v)) { 36 | printf("ERROR reading a translation axis value!\n"); 37 | return 0; 38 | } 39 | return v; 40 | } 41 | printf("ERROR wrong axis value\n"); 42 | return 0; 43 | } 44 | 45 | /** 46 | * This is unique to the XBox controller! If posToAngle does not work out on another joystick, 47 | * get creative. 48 | */ 49 | float posToAngle(short pos, double factor) { 50 | 51 | if (pos < 1000 && pos > -1000) { 52 | pos = 0; 53 | } 54 | 55 | float value = log(abs(pos) <= 1 && abs(pos) >= 0 ? 1 : abs(pos)*factor) / MT_XBOX_TURN_NORMALISATION; 56 | if (pos <= 0) { 57 | value *= -1; 58 | } 59 | 60 | return value; 61 | } 62 | 63 | /** 64 | * Returns a normalised Quaternion with the Joystick movements. 65 | */ 66 | MTQuaternion getQuaternion(MTVec3D jawAxis, MTVec3D turnAxis, double minJawAngle, double maxJawAngle, double factor) { 67 | short a,b; 68 | 69 | /* Right now, we are only interested in these two axes. If you want to use more 70 | * than these two, just add some short variables and read the axis-values accordingly. Easy. */ 71 | if (!( 72 | getAxisValue(0, &a) 73 | && getAxisValue(1, &b) 74 | )) { 75 | printf("ERROR reading an axis value!\n"); 76 | MTQuaternion q; 77 | return q; 78 | } 79 | 80 | double angle = posToAngle(b, factor); 81 | angle = (angle > 0.0 && angle < minJawAngle) ? 0.0 : angle; 82 | angle = (angle < 0.0 && angle > maxJawAngle) ? 0.0 : angle; 83 | 84 | 85 | MTQuaternion qB = mtCreateQuaternion(jawAxis, angle); 86 | MTQuaternion qA = mtCreateQuaternion(turnAxis, -posToAngle(a, factor)); 87 | 88 | MTQuaternion qRes = mtAddQuaternionQuaternion(&qA, &qB); 89 | 90 | mtNormQuaternion(&qRes); 91 | return qRes; 92 | } 93 | 94 | /** 95 | * Calculates all relevant joystick/gamepad stuff and rotates, moves the camera accordingly. 96 | */ 97 | void mtCalcJoyMovement (double interval) 98 | { 99 | // This pulls and handles all usb-stream joystick events. 100 | handleJoystickEvents(); 101 | 102 | MTVec3D sideDirection = mtNormVector3D(mtCrossProduct3D(G_JoyViewVector, G_JoyUpVector)); 103 | 104 | double maxAngle = MT_MAX_ANGLE - mtAngleVectorVector(G_JoyViewVector, G_JoyUpVector); // around 90° -- +70° 105 | double minAngle = MT_MIN_ANGLE - mtAngleVectorVector(G_JoyViewVector, G_JoyUpVector); // around 90° -- -70° 106 | 107 | maxAngle = maxAngle < 0 ? -1.0 : maxAngle; 108 | minAngle = minAngle > 0 ? 1.0 : minAngle; 109 | 110 | MTQuaternion q = getQuaternion(sideDirection, mtToVector3D(0, 1, 0), minAngle, maxAngle, interval); 111 | 112 | G_JoyViewVector = mtRotatePointWithQuaternion(q, G_JoyViewVector); 113 | 114 | double forwardTranslation = -(getTranslationAxisValue(4) + MT_AXIS_4_OFFSET) / MT_XBOX_TRANS_NORMALISATION; 115 | MTVec3D forwardVec = mtNormVector3D(mtToVector3D(G_JoyViewVector.x, 0, G_JoyViewVector.z)); 116 | G_JoyTranslation = mtAddVectorVector(G_JoyTranslation, mtMultiplyVectorScalar(forwardVec, forwardTranslation)); 117 | 118 | double sideTranslation = (getTranslationAxisValue(3) + MT_AXIS_3_OFFSET) / MT_XBOX_TRANS_NORMALISATION; 119 | MTVec3D sideVec = mtNormVector3D(mtToVector3D(sideDirection.x, 0, sideDirection.z)); 120 | G_JoyTranslation = mtAddVectorVector(G_JoyTranslation, mtMultiplyVectorScalar(sideVec, sideTranslation)); 121 | 122 | MTVec3D upDirection = mtToVector3D(0, 1, 0); 123 | double upTranslation = (getTranslationAxisValue(2) + MT_AXIS_2_OFFSET) / MT_XBOX_TRANS_NORMALISATION; 124 | G_JoyTranslation = mtAddVectorVector(G_JoyTranslation, mtMultiplyVectorScalar(upDirection, upTranslation)); 125 | 126 | MTVec3D downDirection = mtToVector3D(0, -1, 0); 127 | double downTranslation = (getTranslationAxisValue(5) + MT_AXIS_5_OFFSET) / MT_XBOX_TRANS_NORMALISATION; 128 | G_JoyTranslation = mtAddVectorVector(G_JoyTranslation, mtMultiplyVectorScalar(downDirection, downTranslation)); 129 | 130 | G_JoyPosition = G_JoyTranslation; 131 | 132 | G_JoyViewVector = mtNormVector3D(G_JoyViewVector); 133 | 134 | } 135 | 136 | /** 137 | * Initialisation of the camera and hmd module for js input. 138 | */ 139 | int mtInitJoyControl (char* name) 140 | { 141 | G_JoyUpVector = mtToVector3D(0, 1, 0); 142 | G_JoyViewVector = mtToVector3D(-MT_START_POS_X, -MT_START_POS_Y, -MT_START_POS_Z); 143 | G_JoyViewVector = mtNormVector3D(G_JoyViewVector); 144 | 145 | G_JoyTranslation = mtToVector3D(0,0,0); 146 | G_JoyPosition = mtToVector3D(MT_START_POS_X, MT_START_POS_Y, MT_START_POS_Z); 147 | 148 | if (!startDeviceConnection(name)) { 149 | printf("ERROR: joystick could not be initialized.\n"); 150 | return 0; 151 | } 152 | 153 | return 1; 154 | } 155 | 156 | /** 157 | * Closes the hmd module connection to the joystick. 158 | */ 159 | int mtFinishJoyControl() 160 | { 161 | return endDeviceConnection(); 162 | } 163 | 164 | 165 | -------------------------------------------------------------------------------- /mtXboxController.h: -------------------------------------------------------------------------------- 1 | #ifndef __JOYSTICKCAMERA_H__ 2 | #define __JOYSTICKCAMERA_H__ 3 | /** 4 | * Implementation of a Camera controlled by an X-Box controller (And possibly other joysticks). 5 | * 6 | * All operations are prefixed with 'mt' to avoid name clashes and get an 7 | * attempt for a unique prefix. 8 | * 9 | * This module is tested exclusively for an X-Box controller and can be used out-of-the-box. 10 | * It might work with other joysticks. 11 | * If the camera/object is moving by its own, consider calibrating it (jscal / jstest-gtk). 12 | * 13 | * @author Maurice Tollmien 14 | */ 15 | 16 | #include "mtVector.h" 17 | 18 | #define MT_START_POS_X -30.0 19 | #define MT_START_POS_Y 0.0 20 | #define MT_START_POS_Z 70.0 21 | 22 | #define MT_MAX_ANGLE 179.0 23 | #define MT_MIN_ANGLE 1.0 24 | 25 | #define MT_XBOX_TRANS_NORMALISATION 500000.0 26 | #define MT_XBOX_TURN_NORMALISATION 2000.0 27 | 28 | #define MT_AXIS_2_OFFSET 32768 29 | #define MT_AXIS_3_OFFSET 0 30 | #define MT_AXIS_4_OFFSET 0 31 | #define MT_AXIS_5_OFFSET 32768 32 | 33 | MTVec3D mtGetJoyPosition (); 34 | MTVec3D mtGetJoyUp(); 35 | MTVec3D mtGetJoyCenter(); 36 | 37 | void mtCalcJoyMovement(double interval); 38 | 39 | int mtInitJoyControl (char* name); 40 | int mtFinishJoyControl(); 41 | 42 | #endif 43 | --------------------------------------------------------------------------------