| 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 | //-------------------------------------------------------------------// | 
|---|
| 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 | //-------------------------------------------------------------------// | 
|---|
| 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 | //-------------------------------------------------------------------// | 
|---|
| 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 | //-------------------------------------------------------------------// | 
|---|
| 103 | void LinuxMouse::setBuffered(bool buffered) | 
|---|
| 104 | { | 
|---|
| 105 |         mBuffered = buffered; | 
|---|
| 106 | } | 
|---|
| 107 |  | 
|---|
| 108 | //-------------------------------------------------------------------// | 
|---|
| 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 | //-------------------------------------------------------------------// | 
|---|
| 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 |                         mState.X.rel = event.xmotion.x - oldXMouseX; | 
|---|
| 176 |                         mState.Y.rel = 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 += mState.X.rel; | 
|---|
| 183 |                         mState.Y.abs += mState.Y.rel; | 
|---|
| 184 |  | 
|---|
| 185 |                         //Check to see if we are grabbing the mouse to the window (requires clipping and warping) | 
|---|
| 186 |                         if( grabMouse ) | 
|---|
| 187 |                         { | 
|---|
| 188 |                                 if( mState.X.abs < 0 ) | 
|---|
| 189 |                                         mState.X.abs = 0; | 
|---|
| 190 |                                 else if( mState.X.abs > mState.width ) | 
|---|
| 191 |                                         mState.X.abs = mState.width; | 
|---|
| 192 |  | 
|---|
| 193 |                                 if( mState.Y.abs < 0 ) | 
|---|
| 194 |                                         mState.Y.abs = 0; | 
|---|
| 195 |                                 else if( mState.Y.abs > mState.height ) | 
|---|
| 196 |                                         mState.Y.abs = mState.height; | 
|---|
| 197 |  | 
|---|
| 198 |                                 if( mouseFocusLost == false ) | 
|---|
| 199 |                                 { | 
|---|
| 200 |                                         //Keep mouse in window (fudge factor) | 
|---|
| 201 |                                         if(event.xmotion.x < 5 || event.xmotion.x > mState.width - 5 || | 
|---|
| 202 |                                            event.xmotion.y < 5 || event.xmotion.y > mState.height - 5 ) | 
|---|
| 203 |                                         { | 
|---|
| 204 |                                                 oldXMouseX = mState.width >> 1;  //center x | 
|---|
| 205 |                                                 oldXMouseY = mState.height >> 1; //center y | 
|---|
| 206 |                                                 XWarpPointer(display, None, window, 0, 0, 0, 0, oldXMouseX, oldXMouseY); | 
|---|
| 207 |                                                 mWarped = true; | 
|---|
| 208 |                                         } | 
|---|
| 209 |                                 } | 
|---|
| 210 |                         } | 
|---|
| 211 |                         mMoved = true; | 
|---|
| 212 |                 } | 
|---|
| 213 |                 else if( event.type == ButtonPress ) | 
|---|
| 214 |                 {       //Button down | 
|---|
| 215 |                         static_cast<LinuxInputManager*>(mCreator)->_setGrabState(true); | 
|---|
| 216 |  | 
|---|
| 217 |                         if( event.xbutton.button < 4 ) | 
|---|
| 218 |                         { | 
|---|
| 219 |                                 mState.buttons |= mask[event.xbutton.button]; | 
|---|
| 220 |                                 if( mBuffered && mListener ) | 
|---|
| 221 |                                         if( mListener->mousePressed( MouseEvent( this, mState ), | 
|---|
| 222 |                                                 (MouseButtonID)(mask[event.xbutton.button] >> 1)) == false ) | 
|---|
| 223 |                                                 return; | 
|---|
| 224 |                         } | 
|---|
| 225 |                 } | 
|---|
| 226 |                 else if( event.type == ButtonRelease ) | 
|---|
| 227 |                 {       //Button up | 
|---|
| 228 |                         if( event.xbutton.button < 4 ) | 
|---|
| 229 |                         { | 
|---|
| 230 |                                 mState.buttons &= ~mask[event.xbutton.button]; | 
|---|
| 231 |                                 if( mBuffered && mListener ) | 
|---|
| 232 |                                         if( mListener->mouseReleased( MouseEvent( this, mState ), | 
|---|
| 233 |                                                 (MouseButtonID)(mask[event.xbutton.button] >> 1)) == false ) | 
|---|
| 234 |                                                 return; | 
|---|
| 235 |                         } | 
|---|
| 236 |                         //The Z axis gets pushed/released pair message (this is up) | 
|---|
| 237 |                         else if( event.xbutton.button == 4 ) | 
|---|
| 238 |                         { | 
|---|
| 239 |                                 mState.Z.rel += 120; | 
|---|
| 240 |                                 mState.Z.abs += 120; | 
|---|
| 241 |                                 mMoved = true; | 
|---|
| 242 |                         } | 
|---|
| 243 |                         //The Z axis gets pushed/released pair message (this is down) | 
|---|
| 244 |                         else if( event.xbutton.button == 5 ) | 
|---|
| 245 |                         { | 
|---|
| 246 |                                 mState.Z.rel -= 120; | 
|---|
| 247 |                                 mState.Z.abs -= 120; | 
|---|
| 248 |                                 mMoved = true; | 
|---|
| 249 |                         } | 
|---|
| 250 |                 } | 
|---|
| 251 |         } | 
|---|
| 252 | } | 
|---|
| 253 |  | 
|---|
| 254 | //-------------------------------------------------------------------// | 
|---|
| 255 | void LinuxMouse::grab(bool grab) | 
|---|
| 256 | { | 
|---|
| 257 |         if( grab ) | 
|---|
| 258 |                 XGrabPointer(display, window, True, 0, GrabModeAsync, GrabModeAsync, window, None, CurrentTime); | 
|---|
| 259 |         else | 
|---|
| 260 |                 XUngrabPointer(display, CurrentTime); | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | //-------------------------------------------------------------------// | 
|---|
| 264 | void LinuxMouse::hide(bool hide) | 
|---|
| 265 | { | 
|---|
| 266 |         if( hide ) | 
|---|
| 267 |                 XDefineCursor(display, window, cursor); | 
|---|
| 268 |         else | 
|---|
| 269 |                 XUndefineCursor(display, window); | 
|---|
| 270 | } | 
|---|