PageRenderTime 22ms CodeModel.GetById 1ms app.highlight 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/ois/src/linux/LinuxJoyStickEvents.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 305 lines | 212 code | 41 blank | 52 comment | 52 complexity | 74562448066e3d605674f891abca41d5 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 "OISConfig.h"
 24
 25#include "linux/LinuxJoyStickEvents.h"
 26#include "linux/LinuxInputManager.h"
 27#include "linux/LinuxForceFeedback.h"
 28#include "linux/EventHelpers.h"
 29
 30#include "OISEvents.h"
 31#include "OISException.h"
 32
 33#include <fcntl.h>        //Needed to Open a file descriptor
 34#include <cassert>	
 35#include <linux/input.h>
 36
 37
 38#include <sstream>
 39# include <iostream>
 40using namespace std;
 41
 42using namespace OIS;
 43
 44//#define OIS_LINUX_JOY_DEBUG
 45
 46//-------------------------------------------------------------------//
 47LinuxJoyStick::LinuxJoyStick(InputManager* creator, bool buffered, const JoyStickInfo& js)
 48	: JoyStick(js.vendor, buffered, js.devId, creator)
 49{
 50	mJoyStick = js.joyFileD;
 51
 52	mState.mAxes.clear();
 53	mState.mAxes.resize(js.axes);
 54	mState.mButtons.clear();
 55	mState.mButtons.resize(js.buttons);
 56
 57	mPOVs = js.hats;
 58
 59	mButtonMap = js.button_map;
 60	mAxisMap = js.axis_map;
 61	mRanges = js.axis_range;
 62
 63	ff_effect = 0;
 64}
 65
 66//-------------------------------------------------------------------//
 67LinuxJoyStick::~LinuxJoyStick()
 68{
 69	EventUtils::removeForceFeedback( &ff_effect );
 70}
 71
 72//-------------------------------------------------------------------//
 73void LinuxJoyStick::_initialize()
 74{
 75	//Clear old joy state
 76	mState.mAxes.resize(mAxisMap.size());
 77	mState.clear();
 78
 79	//This will create and new us a force feedback structure if it exists
 80	EventUtils::enumerateForceFeedback( mJoyStick, &ff_effect );
 81
 82	if( mJoyStick == -1 )
 83		OIS_EXCEPT(E_InputDeviceNonExistant, "LinuxJoyStick::_initialize() >> JoyStick Not Found!");
 84}
 85
 86//-------------------------------------------------------------------//
 87void LinuxJoyStick::capture()
 88{
 89	static const short POV_MASK[8] = {0,0,1,1,2,2,3,3};
 90
 91	//Used to determine if an axis has been changed and needs an event
 92	bool axisMoved[32] = {false, false, false, false, false, false, false, false, false, false, false, false, false,
 93						  false, false, false, false, false, false, false, false, false, false, false, false, false,
 94						  false, false, false, false, false, false};
 95
 96	//We are in non blocking mode - we just read once, and try to fill up buffer
 97	input_event js[JOY_BUFFERSIZE];
 98	while(true)
 99	{
100		int ret = read(mJoyStick, &js, sizeof(struct input_event) * JOY_BUFFERSIZE);
101        if( ret < 0 )
102			break;
103
104		//Determine how many whole events re read up
105		ret /= sizeof(struct input_event);
106		for(int i = 0; i < ret; ++i)
107		{
108			switch(js[i].type)
109			{
110			case EV_KEY:  //Button
111			{
112				int button = mButtonMap[js[i].code];
113
114				#ifdef OIS_LINUX_JOY_DEBUG
115				  cout << "\nButton Code: " << js[i].code << ", OIS Value: " << button << endl;
116				#endif
117
118				//Check to see whether push or released event...
119				if(js[i].value)
120				{
121					mState.mButtons[button] = true;
122					if( mBuffered && mListener )
123						if(!mListener->buttonPressed(JoyStickEvent(this,mState), button)) return;
124				}
125				else
126				{
127					mState.mButtons[button] = false;
128					if( mBuffered && mListener )
129						if(!mListener->buttonReleased(JoyStickEvent(this,mState), button)) return;
130				}
131				break;
132			}
133
134			case EV_ABS:  //Absolute Axis
135			{
136				//A Stick (BrakeDefine is the highest possible Axis)
137				if( js[i].code <= ABS_BRAKE )
138				{
139					int axis = mAxisMap[js[i].code];
140					assert( axis < 32 && "Too many axes (Max supported is 32). Report this to OIS forums!" );
141
142					axisMoved[axis] = true;
143
144					//check for rescaling:
145					if( mRanges[axis].min == JoyStick::MIN_AXIS && mRanges[axis].max != JoyStick::MAX_AXIS )
146					{	//Scale is perfect
147						mState.mAxes[axis].abs = js[i].value;
148					}
149					else
150					{	//Rescale
151						float proportion = (float)(js[i].value-mRanges[axis].max)/(float)(mRanges[axis].min-mRanges[axis].max);
152						mState.mAxes[axis].abs = (int)(32767.0f - (65535.0f * proportion));
153					}
154				}
155				else if( js[i].code <= ABS_HAT3Y ) //A POV - Max four POVs allowed
156				{
157					//Normalise the POV to between 0-7
158					//Even is X Axis, Odd is Y Axis
159					unsigned char LinuxPovNumber = js[i].code - 16;
160					short OIS_POVIndex = POV_MASK[LinuxPovNumber];
161
162					//Handle X Axis first (Even) (left right)
163					if((LinuxPovNumber & 0x0001) == 0)
164					{
165						//Why do this? Because, we use a bit field, and when this axis is east,
166						//it can't possibly be west too. So clear out the two X axes, then refil
167						//it in with the new direction bit.
168						//Clear the East/West Bit Flags first
169						mState.mPOV[OIS_POVIndex].direction &= 0x11110011;
170						if( js[i].value == -1 )	//Left
171							mState.mPOV[OIS_POVIndex].direction |= Pov::West;
172						else if( js[i].value == 1 ) //Right
173							mState.mPOV[OIS_POVIndex].direction |= Pov::East;
174					}
175					//Handle Y Axis (Odd) (up down)
176					else
177					{
178						//Clear the North/South Bit Flags first
179						mState.mPOV[OIS_POVIndex].direction &= 0x11111100;
180						if( js[i].value == -1 )	//Up
181							mState.mPOV[OIS_POVIndex].direction |= Pov::North;
182						else if( js[i].value == 1 ) //Down
183							mState.mPOV[OIS_POVIndex].direction |= Pov::South;
184					}
185
186					if( mBuffered && mListener )
187						if( mListener->povMoved( JoyStickEvent(this,mState), OIS_POVIndex) == false )
188							return;
189				}
190				break;
191			}
192
193			
194			case EV_REL: //Relative Axes (Do any joystick actually have a relative axis?)
195	#ifdef OIS_LINUX_JOY_DEBUG
196				cout << "\nWarning: Relatives axes not supported yet" << endl;
197	#endif
198				break;
199			default: break;
200			}
201		}
202	}
203
204	//All axes and POVs are combined into one movement per pair per captured frame
205	if( mBuffered && mListener )
206	{
207		for( int i = 0; i < 32; ++i )
208			if( axisMoved[i] )
209				if( mListener->axisMoved( JoyStickEvent(this,mState), i) == false )
210					return;
211	}
212}
213
214//-------------------------------------------------------------------//
215void LinuxJoyStick::setBuffered(bool buffered)
216{
217	if( buffered != mBuffered )
218	{
219		mBuffered = buffered;
220		_initialize();
221	}
222}
223
224//-------------------------------------------------------------------//
225JoyStickInfo LinuxJoyStick::_getJoyInfo()
226{
227	JoyStickInfo js;
228
229	js.devId = mDevID;
230	js.joyFileD = mJoyStick;
231	js.vendor = mVendor;
232	js.axes = (int)mState.mAxes.size();
233	js.buttons = (int)mState.mButtons.size();
234	js.hats = mPOVs;
235	js.button_map = mButtonMap;
236	js.axis_map = mAxisMap;
237	js.axis_range = mRanges;
238
239	return js;
240}
241
242//-------------------------------------------------------------------//
243JoyStickInfoList LinuxJoyStick::_scanJoys()
244{
245	JoyStickInfoList joys;
246
247	//Search through all of the event devices.. and identify which ones are joysticks
248	//xxx move this to InputManager, as it can also scan all other events
249	for(int i = 0; i < 64; ++i )
250	{
251		stringstream s;
252		s << "/dev/input/event" << i;
253		int fd = open( s.str().c_str(), O_RDWR |O_NONBLOCK );
254		if(fd == -1)
255			continue;
256
257        #ifdef OIS_LINUX_JOY_DEBUG
258		  cout << "Opening " << s.str() << "..." << endl;
259        #endif
260		try
261		{
262			JoyStickInfo js;
263			if( EventUtils::isJoyStick(fd, js) )
264			{
265				joys.push_back(js);
266                #ifdef OIS_LINUX_JOY_DEBUG
267                  cout << "=> Joystick added to list." << endl;
268                #endif
269			}
270			else
271			{
272                #ifdef OIS_LINUX_JOY_DEBUG
273                  cout << "=> Not a joystick." << endl;
274                #endif
275				close(fd);
276			}
277		}
278		catch(...)
279		{
280            #ifdef OIS_LINUX_JOY_DEBUG
281              cout << "Exception caught!!" << endl;
282            #endif
283			close(fd);
284		}
285	}
286
287	return joys;
288}
289
290//-------------------------------------------------------------------//
291void LinuxJoyStick::_clearJoys(JoyStickInfoList &joys)
292{
293	for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i)
294		close(i->joyFileD);
295	joys.clear();
296}
297
298//-------------------------------------------------------------------//
299Interface* LinuxJoyStick::queryInterface(Interface::IType type)
300{
301	if( ff_effect && type == Interface::ForceFeedback )
302		return ff_effect;
303
304	return 0;
305}