1 /*
2 The zlib/libpng License
3 
4 Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
5 
6 This software is provided 'as-is', without any express or implied warranty. In no event will
7 the authors be held liable for any damages arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose, including commercial
10 applications, and to alter it and redistribute it freely, subject to the following
11 restrictions:
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 friosom any source distribution.
22 */
23 #include "linux/LinuxMouse.h"
24 #include "linux/LinuxInputManager.h"
25 #include "OISException.h"
26 #include "OISEvents.h"
27 
28 using namespace OIS;
29 
30 //-------------------------------------------------------------------//
LinuxMouse(InputManager * creator,bool buffered,bool grab,bool hide)31 LinuxMouse::LinuxMouse(InputManager* creator, bool buffered, bool grab, bool hide)
32 	: Mouse(creator->inputSystemName(), buffered, 0, creator)
33 {
34 	display = 0;
35 	window = 0;
36 	cursor = 0;
37 
38 	grabMouse = grab;
39 	hideMouse = hide;
40 
41 	static_cast<LinuxInputManager*>(mCreator)->_setMouseUsed(true);
42 }
43 
44 //-------------------------------------------------------------------//
_initialize()45 void LinuxMouse::_initialize()
46 {
47 	//Clear old state
48 	mState.clear();
49 	mMoved  = false;
50 	mWarped = false;
51 
52 	//6 is just some random value... hardly ever would anyone have a window smaller than 6
53 	oldXMouseX = oldXMouseY = 6;
54 	oldXMouseZ = 0;
55 
56 	if( display ) XCloseDisplay(display);
57 	display = 0;
58 	window = static_cast<LinuxInputManager*>(mCreator)->_getWindow();
59 
60 	//Create our local X mListener connection
61 	if( !(display = XOpenDisplay(0)) )
62 		OIS_EXCEPT(E_General, "LinuxMouse::_initialize >> Error opening X!");
63 
64 	//Set it to recieve Mouse Input events
65 	if( XSelectInput(display, window, ButtonPressMask | ButtonReleaseMask | PointerMotionMask) == BadWindow )
66 		OIS_EXCEPT(E_General, "LinuxMouse::_initialize >> X error!");
67 
68 	//Warp mouse inside window
69 	XWarpPointer(display,None,window,0,0,0,0, 6,6);
70 
71 	//Create a blank cursor:
72 	Pixmap bm_no;
73 	XColor black, dummy;
74 	Colormap colormap;
75 	static char no_data[] = { 0,0,0,0,0,0,0,0 };
76 
77 	colormap = DefaultColormap( display, DefaultScreen(display) );
78 	XAllocNamedColor( display, colormap, "black", &black, &dummy );
79 	bm_no = XCreateBitmapFromData( display, window, no_data, 8, 8 );
80 	cursor = XCreatePixmapCursor( display, bm_no, bm_no, &black, &black, 0, 0 );
81 
82 	grab( grabMouse );
83 	hide( hideMouse );
84 
85 	mouseFocusLost = false;
86 }
87 
88 //-------------------------------------------------------------------//
~LinuxMouse()89 LinuxMouse::~LinuxMouse()
90 {
91 	if( display )
92 	{
93 		grab(false);
94 		hide(false);
95 		XFreeCursor(display, cursor);
96 		XCloseDisplay(display);
97 	}
98 
99 	static_cast<LinuxInputManager*>(mCreator)->_setMouseUsed(false);
100 }
101 
102 //-------------------------------------------------------------------//
setBuffered(bool buffered)103 void LinuxMouse::setBuffered(bool buffered)
104 {
105 	mBuffered = buffered;
106 }
107 
108 //-------------------------------------------------------------------//
capture()109 void LinuxMouse::capture()
110 {
111 	//Clear out last frames values
112 	mState.X.rel = 0;
113 	mState.Y.rel = 0;
114 	mState.Z.rel = 0;
115 
116 	_processXEvents();
117 
118 	mWarped = false;
119 
120 	if( mMoved == true )
121 	{
122 		if( mBuffered && mListener )
123 			mListener->mouseMoved( MouseEvent( this, mState ) );
124 
125 		mMoved = false;
126 	}
127 
128 	//Check for losing/gaining mouse grab focus (alt-tab, etc)
129 	if( grabMouse )
130 	{
131 		if( static_cast<LinuxInputManager*>(mCreator)->_getGrabState() )
132 		{
133 			if( mouseFocusLost )	//We just regained mouse grab focus
134 			{
135 				grab( true );
136 				hide( hideMouse );
137 				mouseFocusLost = false;
138 			}
139 		}
140 		else
141 		{
142 			if( mouseFocusLost == false )	//We just lost mouse grab focus
143 			{
144 				grab( false );
145 				hide( false );
146 				mouseFocusLost = true;
147 			}
148 		}
149 	}
150 }
151 
152 //-------------------------------------------------------------------//
_processXEvents()153 void LinuxMouse::_processXEvents()
154 {
155 	//X11 Button Events: 1=left 2=middle 3=right; Our Bit Postion: 1=Left 2=Right 3=Middle
156 	char mask[4] = {0,1,4,2};
157 	XEvent event;
158 
159 	Window u1; int u2;
160 	Window current_win;
161 	int x, y;
162 	unsigned int mmask;
163 
164 	if (XQueryPointer(display, window, &u1, &current_win, &u2, &u2, &x, &y, &mmask))
165 	{
166 		//Ignore out of bounds mouse if we just warped
167 		if(mWarped && (x < 5 || x > mState.width - 5 || y < 5 || y > mState.height - 5))
168 		{
169 			// ignored
170  		}
171 		else if (!(oldXMouseX == x && oldXMouseY == y))
172 		{
173 			//Compute this frames Relative X & Y motion
174 			mState.X.rel = x - oldXMouseX;
175 			mState.Y.rel = y - oldXMouseY;
176 
177 			//Store old values for next time to compute relative motion
178 			oldXMouseX = x;
179 			oldXMouseY = y;
180 
181 			mState.X.abs += mState.X.rel;
182 			mState.Y.abs += mState.Y.rel;
183 
184 			//Check to see if we are grabbing the mouse to the window (requires clipping and warping)
185 			if( grabMouse )
186 			{
187 				if( mState.X.abs < 0 )
188 					mState.X.abs = 0;
189 				else if( mState.X.abs > mState.width )
190 					mState.X.abs = mState.width;
191 
192 				if( mState.Y.abs < 0 )
193 					mState.Y.abs = 0;
194 				else if( mState.Y.abs > mState.height )
195 					mState.Y.abs = mState.height;
196 
197 				if( mouseFocusLost == false )
198 				{
199 					//Keep mouse in window (fudge factor)
200 					if(x < 5 || x > mState.width - 5 ||
201 					   y < 5 || y > mState.height - 5 )
202 					{
203 						oldXMouseX = mState.width >> 1;  //center x
204 						oldXMouseY = mState.height >> 1; //center y
205 						XWarpPointer(display, None, window, 0, 0, 0, 0, oldXMouseX, oldXMouseY);
206 						mWarped = true;
207 					}
208 				}
209 			}
210 			mMoved = true;
211 		}
212 	}
213 
214 
215 	//Poll x11 for events mouse events
216 	while( XPending(display) > 0 )
217 	{
218 		XNextEvent(display, &event);
219 
220 		if( event.type == ButtonPress )
221 		{   //Button down
222 			static_cast<LinuxInputManager*>(mCreator)->_setGrabState(true);
223 
224 			if( event.xbutton.button < 4 )
225 			{
226 				mState.buttons |= mask[event.xbutton.button];
227 				if( mBuffered && mListener )
228 					if( mListener->mousePressed( MouseEvent( this, mState ),
229 						(MouseButtonID)(mask[event.xbutton.button] >> 1)) == false )
230 						return;
231 			}
232 		}
233 		else if( event.type == ButtonRelease )
234 		{	//Button up
235 			if( event.xbutton.button < 4 )
236 			{
237 				mState.buttons &= ~mask[event.xbutton.button];
238 				if( mBuffered && mListener )
239 					if( mListener->mouseReleased( MouseEvent( this, mState ),
240 						(MouseButtonID)(mask[event.xbutton.button] >> 1)) == false )
241 						return;
242 			}
243 			//The Z axis gets pushed/released pair message (this is up)
244 			else if( event.xbutton.button == 4 )
245 			{
246 				mState.Z.rel += 120;
247 				mState.Z.abs += 120;
248 				mMoved = true;
249 			}
250 			//The Z axis gets pushed/released pair message (this is down)
251 			else if( event.xbutton.button == 5 )
252 			{
253 				mState.Z.rel -= 120;
254 				mState.Z.abs -= 120;
255 				mMoved = true;
256 			}
257 		}
258 	}
259 }
260 
261 //-------------------------------------------------------------------//
grab(bool grab)262 void LinuxMouse::grab(bool grab)
263 {
264 	if( grab )
265 		XGrabPointer(display, window, True, 0, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
266 	else
267 		XUngrabPointer(display, CurrentTime);
268 }
269 
270 //-------------------------------------------------------------------//
hide(bool hide)271 void LinuxMouse::hide(bool hide)
272 {
273 	if( hide )
274 		XDefineCursor(display, window, cursor);
275 	else
276 		XUndefineCursor(display, window);
277 }
278