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, ¤t_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