PageRenderTime 43ms CodeModel.GetById 14ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ois/src/linux/EventHelpers.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 377 lines | 267 code | 55 blank | 55 comment | 60 complexity | 66760ca66a275a71c915d036d2510929 MD5 | raw file
  1/*
  2The zlib/libpng License
  3
  4Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
  5
  6This software is provided 'as-is', without any express or implied warranty. In no event will
  7the authors be held liable for any damages arising from the use of this software.
  8
  9Permission is granted to anyone to use this software for any purpose, including commercial
 10applications, and to alter it and redistribute it freely, subject to the following
 11restrictions:
 12
 13    1. The origin of this software must not be misrepresented; you must not claim that
 14		you wrote the original software. If you use this software in a product,
 15		an acknowledgment in the product documentation would be appreciated but is
 16		not required.
 17
 18    2. Altered source versions must be plainly marked as such, and must not be
 19		misrepresented as being the original software.
 20
 21    3. This notice may not be removed or altered from any source distribution.
 22*/
 23#include "linux/EventHelpers.h"
 24#include "linux/LinuxPrereqs.h"
 25#include "linux/LinuxForceFeedback.h"
 26#include "OISException.h"
 27#include "OISJoyStick.h"
 28
 29#include <linux/input.h>
 30#include <cstring>
 31
 32//#define OIS_LINUX_JOY_DEBUG
 33
 34#ifdef OIS_LINUX_JOY_DEBUG
 35# include <iostream>
 36#endif
 37
 38using namespace std;
 39using namespace OIS;
 40
 41class DeviceComponentInfo
 42{
 43public:
 44	vector<int> buttons, relAxes, absAxes, hats;
 45};
 46
 47bool inline isBitSet(unsigned char bits[], unsigned int bit)
 48{
 49  return (bits[(bit)/(sizeof(unsigned char)*8)] >> ((bit)%(sizeof(unsigned char)*8))) & 1;
 50}
 51
 52//-----------------------------------------------------------------------------//
 53DeviceComponentInfo getComponentInfo( int deviceID )
 54{
 55	unsigned char ev_bits[1 + EV_MAX/8/sizeof(unsigned char)];
 56	memset( ev_bits, 0, sizeof(ev_bits) );
 57
 58	//Read "all" (hence 0) components of the device
 59#ifdef OIS_LINUX_JOY_DEBUG
 60	cout << "EventUtils::getComponentInfo(" << deviceID 
 61		 << ") : Reading device events features" << endl;
 62#endif
 63	if (ioctl(deviceID, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1)
 64		OIS_EXCEPT( E_General, "Could not read device events features");
 65
 66	DeviceComponentInfo components;
 67
 68	for (int i = 0; i < EV_MAX; i++)
 69	{
 70		if( isBitSet(ev_bits, i) )
 71		{
 72		    // Absolute axis.
 73		    if(i == EV_ABS)
 74			{
 75			    unsigned char abs_bits[1 + ABS_MAX/8/sizeof(unsigned char)];
 76			    memset( abs_bits, 0, sizeof(abs_bits) );
 77
 78#ifdef OIS_LINUX_JOY_DEBUG
 79				cout << "EventUtils::getComponentInfo(" << deviceID 
 80					 << ") : Reading device absolute axis features" << endl;
 81#endif
 82
 83				if (ioctl(deviceID, EVIOCGBIT(i, sizeof(abs_bits)), abs_bits) == -1)
 84				    OIS_EXCEPT( E_General, "Could not read device absolute axis features");
 85
 86				for (int j = 0; j < ABS_MAX; j++)
 87				{
 88				    if( isBitSet(abs_bits, j) )
 89					{
 90						//input_absinfo abInfo;
 91						//ioctl( fd, EVIOCGABS(j), abInfo );
 92						if( j >= ABS_HAT0X && j <= ABS_HAT3Y )
 93						{
 94							components.hats.push_back(j);
 95						}
 96						else
 97						{
 98							components.absAxes.push_back(j);
 99							//input_absinfo absinfo;
100							//ioctl(deviceID, EVIOCGABS(j), &absinfo);
101							//We cannot actually change these values :|
102							//absinfo.minimum = JoyStick::MIN_AXIS;
103							//absinfo.maximum = JoyStick::MAX_AXIS;
104							//ioctl(deviceID, EVIOCSABS(j), &absinfo);
105						}
106					}
107				}
108			}
109			else if(i == EV_REL)
110			{
111			    unsigned char rel_bits[1 + REL_MAX/8/sizeof(unsigned char)];
112				memset( rel_bits, 0, sizeof(rel_bits) );
113				
114#ifdef OIS_LINUX_JOY_DEBUG
115				cout << "EventUtils::getComponentInfo(" << deviceID 
116					 << ") : Reading device relative axis features" << endl;
117#endif
118
119				if (ioctl(deviceID, EVIOCGBIT(i, sizeof(rel_bits)), rel_bits) == -1)
120				    OIS_EXCEPT( E_General, "Could not read device relative axis features");
121				
122				for (int j = 0; j < REL_MAX; j++)
123				{
124				    if( isBitSet(rel_bits, j) )
125					{
126					    components.relAxes.push_back(j);
127					}
128				}
129			}
130			else if(i == EV_KEY)
131			{
132			    unsigned char key_bits[1 + KEY_MAX/8/sizeof(unsigned char)];
133				memset( key_bits, 0, sizeof(key_bits) );
134				
135#ifdef OIS_LINUX_JOY_DEBUG
136				cout << "EventUtils::getComponentInfo(" << deviceID 
137					 << ") : Reading device buttons features" << endl;
138#endif
139
140				if (ioctl(deviceID, EVIOCGBIT(i, sizeof(key_bits)), key_bits) == -1)
141				    OIS_EXCEPT( E_General, "Could not read device buttons features");
142				
143				for (int j = 0; j < KEY_MAX; j++)
144				{
145				    if( isBitSet(key_bits, j) )
146					{
147					    components.buttons.push_back(j);
148					}
149				}
150			}
151		}
152	}
153
154	return components;
155}
156
157//-----------------------------------------------------------------------------//
158bool EventUtils::isJoyStick( int deviceID, JoyStickInfo &js )
159{
160	if( deviceID == -1 ) 
161		OIS_EXCEPT( E_General, "Error with File Descriptor" );
162
163	DeviceComponentInfo info = getComponentInfo( deviceID );
164
165	int buttons = 0;
166	bool joyButtonFound = false;
167	js.button_map.clear();
168
169	#ifdef OIS_LINUX_JOY_DEBUG
170	cout << endl << "Displaying ButtonMapping Status:" << endl;
171	#endif
172	for(vector<int>::iterator i = info.buttons.begin(), e = info.buttons.end(); i != e; ++i )
173	{
174		//Check to ensure we find at least one joy only button
175		if( (*i >= BTN_JOYSTICK && *i < BTN_GAMEPAD)  
176			|| (*i >= BTN_GAMEPAD && *i < BTN_DIGI)
177			|| (*i >= BTN_WHEEL && *i < KEY_OK) )
178			joyButtonFound = true;
179
180		js.button_map[*i] = buttons++;
181
182		#ifdef OIS_LINUX_JOY_DEBUG
183		  cout << "Button Mapping ID (hex): " << hex << *i 
184			   << " OIS Button Num: " << dec << buttons-1 << endl;
185		#endif
186	}
187	#ifdef OIS_LINUX_JOY_DEBUG
188	cout << endl;
189	#endif
190
191	//Joy Buttons found, so it must be a joystick or pad
192	if( joyButtonFound )
193	{
194		js.joyFileD = deviceID;
195		js.vendor = getName(deviceID);
196		js.buttons = buttons;
197		js.axes = info.relAxes.size() + info.absAxes.size();
198		js.hats = info.hats.size();
199		#ifdef OIS_LINUX_JOY_DEBUG
200		  cout << endl << "Device name:" << js.vendor << endl;
201		  cout << "Device unique Id:" << getUniqueId(deviceID) << endl;
202		  cout << "Device physical location:" << getPhysicalLocation(deviceID) << endl;
203		#endif
204
205		//Map the Axes
206		#ifdef OIS_LINUX_JOY_DEBUG
207		  cout << endl << "Displaying AxisMapping Status:" << endl;
208		#endif
209		int axes = 0;
210		for(vector<int>::iterator i = info.absAxes.begin(), e = info.absAxes.end(); i != e; ++i )
211		{
212			js.axis_map[*i] = axes;
213
214#ifdef OIS_LINUX_JOY_DEBUG
215			cout << "EventUtils::isJoyStick(" << deviceID 
216					  << ") : Reading device absolute axis #" << *i << " features" << endl;
217#endif
218
219			input_absinfo absinfo;
220			if (ioctl(deviceID, EVIOCGABS(*i), &absinfo) == -1)
221				OIS_EXCEPT( E_General, "Could not read device absolute axis features");
222			js.axis_range[axes] = Range(absinfo.minimum, absinfo.maximum);
223
224			#ifdef OIS_LINUX_JOY_DEBUG
225			  cout << "Axis Mapping ID (hex): " << hex << *i 
226				   << " OIS Axis Num: " << dec << axes << endl;
227			#endif
228
229			++axes;
230		}
231	}
232
233	return joyButtonFound;
234}
235
236//-----------------------------------------------------------------------------//
237string EventUtils::getName( int deviceID )
238{
239#ifdef OIS_LINUX_JOY_DEBUG
240	cout << "EventUtils::getName(" << deviceID 
241		 << ") : Reading device name" << endl;
242#endif
243
244	char name[OIS_DEVICE_NAME];
245	if (ioctl(deviceID, EVIOCGNAME(OIS_DEVICE_NAME), name) == -1)
246		OIS_EXCEPT( E_General, "Could not read device name");
247	return string(name);
248}
249
250//-----------------------------------------------------------------------------//
251string EventUtils::getUniqueId( int deviceID )
252{
253#ifdef OIS_LINUX_JOY_DEBUG
254	cout << "EventUtils::getUniqueId(" << deviceID 
255		 << ") : Reading device unique Id" << endl;
256#endif
257
258#define OIS_DEVICE_UNIQUE_ID 128
259	char uId[OIS_DEVICE_UNIQUE_ID];
260	if (ioctl(deviceID, EVIOCGUNIQ(OIS_DEVICE_UNIQUE_ID), uId) == -1)
261		OIS_EXCEPT( E_General, "Could not read device unique Id");
262	return string(uId);
263}
264
265//-----------------------------------------------------------------------------//
266string EventUtils::getPhysicalLocation( int deviceID )
267{
268#ifdef OIS_LINUX_JOY_DEBUG
269	cout << "EventUtils::getPhysicalLocation(" << deviceID 
270		 << ") : Reading device physical location" << endl;
271#endif
272
273#define OIS_DEVICE_PHYSICAL_LOCATION 128
274	char physLoc[OIS_DEVICE_PHYSICAL_LOCATION];
275	if (ioctl(deviceID, EVIOCGPHYS(OIS_DEVICE_PHYSICAL_LOCATION), physLoc) == -1)
276		OIS_EXCEPT( E_General, "Could not read device physical location");
277	return string(physLoc);
278}
279
280//-----------------------------------------------------------------------------//
281void EventUtils::enumerateForceFeedback( int deviceID, LinuxForceFeedback** ff )
282{
283	//Linux Event to OIS Event Mappings
284	map<int, Effect::EType> typeMap;
285	typeMap[FF_CONSTANT] = Effect::Constant;
286	typeMap[FF_RAMP]     = Effect::Ramp;
287	typeMap[FF_SPRING]   = Effect::Spring;
288	typeMap[FF_FRICTION] = Effect::Friction;
289	typeMap[FF_SQUARE]   = Effect::Square;
290	typeMap[FF_TRIANGLE] = Effect::Triangle;
291	typeMap[FF_SINE]     = Effect::Sine;
292	typeMap[FF_SAW_UP]   = Effect::SawToothUp;
293	typeMap[FF_SAW_DOWN] = Effect::SawToothDown;
294	typeMap[FF_DAMPER]   = Effect::Damper;
295	typeMap[FF_INERTIA]  = Effect::Inertia;
296	typeMap[FF_CUSTOM]   = Effect::Custom;
297
298	map<int, Effect::EForce> forceMap;
299	forceMap[FF_CONSTANT] = Effect::ConstantForce;
300	forceMap[FF_RAMP]     = Effect::RampForce;
301	forceMap[FF_SPRING]   = Effect::ConditionalForce;
302	forceMap[FF_FRICTION] = Effect::ConditionalForce;
303	forceMap[FF_SQUARE]   = Effect::PeriodicForce;
304	forceMap[FF_TRIANGLE] = Effect::PeriodicForce;
305	forceMap[FF_SINE]     = Effect::PeriodicForce;
306	forceMap[FF_SAW_UP]   = Effect::PeriodicForce;
307	forceMap[FF_SAW_DOWN] = Effect::PeriodicForce;
308	forceMap[FF_DAMPER]   = Effect::ConditionalForce;
309	forceMap[FF_INERTIA]  = Effect::ConditionalForce;
310	forceMap[FF_CUSTOM]   = Effect::CustomForce;
311
312	//Remove any previously existing memory and create fresh
313	removeForceFeedback( ff );
314	*ff = new LinuxForceFeedback(deviceID);
315
316	//Read overall force feedback features
317	unsigned char ff_bits[1 + FF_MAX/8/sizeof(unsigned char)];
318	memset(ff_bits, 0, sizeof(ff_bits));
319
320#ifdef OIS_LINUX_JOY_DEBUG
321	cout << "EventUtils::enumerateForceFeedback(" << deviceID 
322		 << ") : Reading device force feedback features" << endl;
323#endif
324
325	if (ioctl(deviceID, EVIOCGBIT(EV_FF, sizeof(ff_bits)), ff_bits) == -1)
326		OIS_EXCEPT( E_General, "Could not read device force feedback features");
327
328
329    #ifdef OIS_LINUX_JOY_DEBUG
330	cout << "FF bits: " << hex;
331	for (int i = 0; i < sizeof(ff_bits); i++)
332		cout << (int)ff_bits[i];
333	cout << endl << dec;
334    #endif
335
336	//FF Axes
337	//if( isBitSet(ff_bits, ABS_X) ) //X Axis
338	//if( isBitSet(ff_bits, ABS_Y) ) //Y Axis
339	//if( isBitSet(ff_bits, ABS_WHEEL) ) //Wheel
340
341	//FF Effects
342	for( int effect = FF_EFFECT_MIN; effect <= FF_WAVEFORM_MAX; effect++ )
343	{
344		// The RUMBLE force type is ignored, as periodic force one is more powerfull.
345		// The PERIODIC force type is processed later, for each associated periodic effect type.
346		if (effect == FF_RUMBLE || effect == FF_PERIODIC)
347			continue;
348
349		if(isBitSet(ff_bits, effect))
350		{
351			#ifdef OIS_LINUX_JOY_DEBUG
352		    cout << "  Effect Type: " << Effect::getEffectTypeName(typeMap[effect]) << endl;
353			#endif
354
355			(*ff)->_addEffectTypes( forceMap[effect], typeMap[effect] );
356		}
357	}
358
359	//FF device properties
360	if (isBitSet(ff_bits, FF_GAIN))
361		(*ff)->_setGainSupport(true);
362		
363	if (isBitSet(ff_bits, FF_AUTOCENTER))
364		(*ff)->_setAutoCenterSupport(true);
365
366	//Check to see if any effects were added, else destroy the pointer
367	const ForceFeedback::SupportedEffectList &list = (*ff)->getSupportedEffects();
368	if( list.size() == 0 )
369		removeForceFeedback( ff );
370}
371
372//-----------------------------------------------------------------------------//
373void EventUtils::removeForceFeedback( LinuxForceFeedback** ff )
374{
375	delete *ff;
376	*ff = 0;
377}