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 //Poll x11 for events mouse events
160 while( XPending(display) > 0 )
161 {
162 XNextEvent(display, &event);
163
164 if( event.type == MotionNotify )
165 { //Mouse moved
166 //Ignore out of bounds mouse if we just warped
167 if( mWarped )
168 {
169 if(event.xmotion.x < 5 || event.xmotion.x > mState.width - 5 ||
170 event.xmotion.y < 5 || event.xmotion.y > mState.height - 5)
171 continue;
172 }
173
174 //Compute this frames Relative X & Y motion
175 int dx = event.xmotion.x - oldXMouseX;
176 int dy = event.xmotion.y - oldXMouseY;
177
178 //Store old values for next time to compute relative motion
179 oldXMouseX = event.xmotion.x;
180 oldXMouseY = event.xmotion.y;
181
182 mState.X.abs += dx;
183 mState.Y.abs += dy;
184 mState.X.rel += dx;
185 mState.Y.rel += dy;
186
187 //Check to see if we are grabbing the mouse to the window (requires clipping and warping)
188 if( grabMouse )
189 {
190 if( mState.X.abs < 0 )
191 mState.X.abs = 0;
192 else if( mState.X.abs > mState.width )
193 mState.X.abs = mState.width;
194
195 if( mState.Y.abs < 0 )
196 mState.Y.abs = 0;
197 else if( mState.Y.abs > mState.height )
198 mState.Y.abs = mState.height;
199
200 if( mouseFocusLost == false )
201 {
202 //Keep mouse in window (fudge factor)
203 if(event.xmotion.x < 5 || event.xmotion.x > mState.width - 5 ||
204 event.xmotion.y < 5 || event.xmotion.y > mState.height - 5 )
205 {
206 oldXMouseX = mState.width >> 1; //center x
207 oldXMouseY = mState.height >> 1; //center y
208 XWarpPointer(display, None, window, 0, 0, 0, 0, oldXMouseX, oldXMouseY);
209 mWarped = true;
210 }
211 }
212 }
213 mMoved = true;
214 }
215 else if( event.type == ButtonPress )
216 { //Button down
217 static_cast<LinuxInputManager*>(mCreator)->_setGrabState(true);
218
219 if( event.xbutton.button < 4 )
220 {
221 mState.buttons |= mask[event.xbutton.button];
222 if( mBuffered && mListener )
223 if( mListener->mousePressed( MouseEvent( this, mState ),
224 (MouseButtonID)(mask[event.xbutton.button] >> 1)) == false )
225 return;
226 }
227 }
228 else if( event.type == ButtonRelease )
229 { //Button up
230 if( event.xbutton.button < 4 )
231 {
232 mState.buttons &= ~mask[event.xbutton.button];
233 if( mBuffered && mListener )
234 if( mListener->mouseReleased( MouseEvent( this, mState ),
235 (MouseButtonID)(mask[event.xbutton.button] >> 1)) == false )
236 return;
237 }
238 //The Z axis gets pushed/released pair message (this is up)
239 else if( event.xbutton.button == 4 )
240 {
241 mState.Z.rel += 120;
242 mState.Z.abs += 120;
243 mMoved = true;
244 }
245 //The Z axis gets pushed/released pair message (this is down)
246 else if( event.xbutton.button == 5 )
247 {
248 mState.Z.rel -= 120;
249 mState.Z.abs -= 120;
250 mMoved = true;
251 }
252 }
253 }
254 }
255
256 //-------------------------------------------------------------------//
grab(bool grab)257 void LinuxMouse::grab(bool grab)
258 {
259 if( grab )
260 XGrabPointer(display, window, True, 0, GrabModeAsync, GrabModeAsync, window, None, CurrentTime);
261 else
262 XUngrabPointer(display, CurrentTime);
263 }
264
265 //-------------------------------------------------------------------//
hide(bool hide)266 void LinuxMouse::hide(bool hide)
267 {
268 if( hide )
269 XDefineCursor(display, window, cursor);
270 else
271 XUndefineCursor(display, window);
272 }
273