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