| [1505] | 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 | } | 
|---|