1 //////////////////////////////// OS Nuetral Headers //////////////// 2 #include "OISInputManager.h" 3 #include "OISException.h" 4 #include "OISKeyboard.h" 5 #include "OISMouse.h" 6 #include "OISJoyStick.h" 7 #include "OISEvents.h" 8 9 //Advanced Usage 10 #include "OISForceFeedback.h" 11 12 #include <iostream> 13 #include <vector> 14 #include <sstream> 15 16 ////////////////////////////////////Needed Windows Headers//////////// 17 #if defined OIS_WIN32_PLATFORM 18 #define WIN32_LEAN_AND_MEAN 19 #include "windows.h" 20 #ifdef min 21 #undef min 22 #endif 23 #include "resource.h" 24 LRESULT DlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); 25 ////////////////////////////////////////////////////////////////////// 26 ////////////////////////////////////Needed Linux Headers////////////// 27 #elif defined OIS_LINUX_PLATFORM 28 #include <X11/Xlib.h> 29 #include <X11/Xatom.h> 30 void checkX11Events(); 31 ////////////////////////////////////////////////////////////////////// 32 ////////////////////////////////////Needed Mac Headers////////////// 33 #elif defined OIS_APPLE_PLATFORM 34 #include <Carbon/Carbon.h> 35 void checkMacEvents(); 36 #endif 37 ////////////////////////////////////////////////////////////////////// 38 using namespace OIS; 39 40 //-- Some local prototypes --// 41 void doStartup(); 42 void handleNonBufferedKeys(); 43 void handleNonBufferedMouse(); 44 void handleNonBufferedJoy( JoyStick* js ); 45 46 //-- Easy access globals --// 47 bool appRunning = true; //Global Exit Flag 48 49 const char *g_DeviceType[6] = {"OISUnknown", "OISKeyboard", "OISMouse", "OISJoyStick", 50 "OISTablet", "OISOther"}; 51 52 InputManager *g_InputManager = 0; //Our Input System 53 Keyboard *g_kb = 0; //Keyboard Device 54 Mouse *g_m = 0; //Mouse Device 55 JoyStick* g_joys[4] = {0,0,0,0}; //This demo supports up to 4 controllers 56 57 //-- OS Specific Globals --// 58 #if defined OIS_WIN32_PLATFORM 59 HWND hWnd = 0; 60 #elif defined OIS_LINUX_PLATFORM 61 Display *xDisp = 0; 62 Window xWin = 0; 63 #elif defined OIS_APPLE_PLATFORM 64 WindowRef mWin = 0; 65 #endif 66 67 //////////// Common Event handler class //////// 68 class EventHandler : public KeyListener, public MouseListener, public JoyStickListener 69 { 70 public: 71 EventHandler() {} 72 ~EventHandler() {} 73 bool keyPressed( const KeyEvent &arg ) { 74 std::cout << " KeyPressed {" << arg.key 75 << ", " << ((Keyboard*)(arg.device))->getAsString(arg.key) 76 << "} || Character (" << (char)arg.text << ")" << std::endl; 77 return true; 78 } 79 bool keyReleased( const KeyEvent &arg ) { 80 if( arg.key == KC_ESCAPE || arg.key == KC_Q ) 81 appRunning = false; 82 std::cout << "KeyReleased {" << ((Keyboard*)(arg.device))->getAsString(arg.key) << "}\n"; 83 return true; 84 } 85 bool mouseMoved( const MouseEvent &arg ) { 86 const OIS::MouseState& s = arg.state; 87 std::cout << "\nMouseMoved: Abs(" 88 << s.X.abs << ", " << s.Y.abs << ", " << s.Z.abs << ") Rel(" 89 << s.X.rel << ", " << s.Y.rel << ", " << s.Z.rel << ")"; 90 return true; 91 } 92 bool mousePressed( const MouseEvent &arg, MouseButtonID id ) { 93 const OIS::MouseState& s = arg.state; 94 std::cout << "\nMouse button #" << id << " pressed. Abs(" 95 << s.X.abs << ", " << s.Y.abs << ", " << s.Z.abs << ") Rel(" 96 << s.X.rel << ", " << s.Y.rel << ", " << s.Z.rel << ")"; 97 return true; 98 } 99 bool mouseReleased( const MouseEvent &arg, MouseButtonID id ) { 100 const OIS::MouseState& s = arg.state; 101 std::cout << "\nMouse button #" << id << " released. Abs(" 102 << s.X.abs << ", " << s.Y.abs << ", " << s.Z.abs << ") Rel(" 103 << s.X.rel << ", " << s.Y.rel << ", " << s.Z.rel << ")"; 104 return true; 105 } 106 bool buttonPressed( const JoyStickEvent &arg, int button ) { 107 std::cout << std::endl << arg.device->vendor() << ". Button Pressed # " << button; 108 return true; 109 } 110 bool buttonReleased( const JoyStickEvent &arg, int button ) { 111 std::cout << std::endl << arg.device->vendor() << ". Button Released # " << button; 112 return true; 113 } 114 bool axisMoved( const JoyStickEvent &arg, int axis ) 115 { 116 //Provide a little dead zone 117 if( arg.state.mAxes[axis].abs > 2500 || arg.state.mAxes[axis].abs < -2500 ) 118 std::cout << std::endl << arg.device->vendor() << ". Axis # " << axis << " Value: " << arg.state.mAxes[axis].abs; 119 return true; 120 } 121 bool povMoved( const JoyStickEvent &arg, int pov ) 122 { 123 std::cout << std::endl << arg.device->vendor() << ". POV" << pov << " "; 124 125 if( arg.state.mPOV[pov].direction & Pov::North ) //Going up 126 std::cout << "North"; 127 else if( arg.state.mPOV[pov].direction & Pov::South ) //Going down 128 std::cout << "South"; 129 130 if( arg.state.mPOV[pov].direction & Pov::East ) //Going right 131 std::cout << "East"; 132 else if( arg.state.mPOV[pov].direction & Pov::West ) //Going left 133 std::cout << "West"; 134 135 if( arg.state.mPOV[pov].direction == Pov::Centered ) //stopped/centered out 136 std::cout << "Centered"; 137 return true; 138 } 139 140 bool vector3Moved( const JoyStickEvent &arg, int index) 141 { 142 std::cout.precision(2); 143 std::cout.flags(std::ios::fixed | std::ios::right); 144 std::cout << std::endl << arg.device->vendor() << ". Orientation # " << index 145 << " X Value: " << arg.state.mVectors[index].x 146 << " Y Value: " << arg.state.mVectors[index].y 147 << " Z Value: " << arg.state.mVectors[index].z; 148 std::cout.precision(); 149 std::cout.flags(); 150 return true; 151 } 152 }; 153 154 //Create a global instance 155 EventHandler handler; 156 157 int main() 158 { 159 std::cout << "\n\n*** OIS Console Demo App is starting up... *** \n"; 160 try 161 { 162 doStartup(); 163 std::cout << "\nStartup done... Hit 'q' or ESC to exit.\n\n"; 164 165 while(appRunning) 166 { 167 //Throttle down CPU usage 168 #if defined OIS_WIN32_PLATFORM 169 Sleep(90); 170 MSG msg; 171 while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) 172 { 173 TranslateMessage( &msg ); 174 DispatchMessage( &msg ); 175 } 176 #elif defined OIS_LINUX_PLATFORM 177 checkX11Events(); 178 usleep( 500 ); 179 #elif defined OIS_APPLE_PLATFORM 180 checkMacEvents(); 181 usleep( 500 ); 182 #endif 183 184 if( g_kb ) 185 { 186 g_kb->capture(); 187 if( !g_kb->buffered() ) 188 handleNonBufferedKeys(); 189 } 190 191 if( g_m ) 192 { 193 g_m->capture(); 194 if( !g_m->buffered() ) 195 handleNonBufferedMouse(); 196 } 197 198 for( int i = 0; i < 4 ; ++i ) 199 { 200 if( g_joys[i] ) 201 { 202 g_joys[i]->capture(); 203 if( !g_joys[i]->buffered() ) 204 handleNonBufferedJoy( g_joys[i] ); 205 } 206 } 207 } 208 } 209 catch( const Exception &ex ) 210 { 211 #if defined OIS_WIN32_PLATFORM 212 MessageBox( NULL, ex.eText, "An exception has occurred!", MB_OK | 213 MB_ICONERROR | MB_TASKMODAL); 214 #else 215 std::cout << "\nOIS Exception Caught!\n" << "\t" << ex.eText << "[Line " 216 << ex.eLine << " in " << ex.eFile << "]\nExiting App"; 217 #endif 218 } 219 catch(std::exception &ex) 220 { 221 std::cout << "Caught std::exception: what = " << ex.what() << std::endl; 222 } 223 224 //Destroying the manager will cleanup unfreed devices 225 std::cout << "Cleaning up...\n"; 226 if( g_InputManager ) 227 InputManager::destroyInputSystem(g_InputManager); 228 229 #if defined OIS_LINUX_PLATFORM 230 // Be nice to X and clean up the x window 231 XDestroyWindow(xDisp, xWin); 232 XCloseDisplay(xDisp); 233 #endif 234 235 std::cout << "\nGoodbye!\n"; 236 return 0; 237 } 238 239 void doStartup() 240 { 241 ParamList pl; 242 243 #if defined OIS_WIN32_PLATFORM 244 //Create a capture window for Input Grabbing 245 hWnd = CreateDialog( 0, MAKEINTRESOURCE(IDD_DIALOG1), 0,(DLGPROC)DlgProc); 246 if( hWnd == NULL ) 247 OIS_EXCEPT(E_General, "Failed to create Win32 Window Dialog!"); 248 249 ShowWindow(hWnd, SW_SHOW); 250 251 std::ostringstream wnd; 252 wnd << (size_t)hWnd; 253 254 pl.insert(std::make_pair( std::string("WINDOW"), wnd.str() )); 255 256 //Default mode is foreground exclusive..but, we want to show mouse - so nonexclusive 257 // pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND" ))); 258 // pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE"))); 259 #elif defined OIS_LINUX_PLATFORM 260 //Connects to default X window 261 if( !(xDisp = XOpenDisplay(0)) ) 262 OIS_EXCEPT(E_General, "Error opening X!"); 263 //Create a window 264 xWin = XCreateSimpleWindow(xDisp, DefaultRootWindow(xDisp), 0, 0, 100, 100, 0, 0, 0); 265 //bind our connection to that window 266 XMapWindow(xDisp, xWin); 267 // XInternAtom 268 //Select what events we want to listen to locally 269 XSelectInput(xDisp, xWin, StructureNotifyMask | SubstructureNotifyMask); 270 Atom wmProto = XInternAtom(xDisp, "WM_PROTOCOLS", False); 271 Atom wmDelete = XInternAtom(xDisp, "WM_DELETE_WINDOW", False); 272 XChangeProperty(xDisp, xWin, wmProto, XA_ATOM, 32, 0, (const unsigned char*)&wmDelete, 1); 273 XEvent evtent; 274 do 275 { 276 XNextEvent(xDisp, &evtent); 277 } while(evtent.type != MapNotify); 278 279 std::ostringstream wnd; 280 wnd << xWin; 281 282 pl.insert(std::make_pair(std::string("WINDOW"), wnd.str())); 283 284 //For this demo, show mouse and do not grab (confine to window) 285 // pl.insert(std::make_pair(std::string("x11_mouse_grab"), std::string("false"))); 286 // pl.insert(std::make_pair(std::string("x11_mouse_hide"), std::string("false"))); 287 #elif defined OIS_APPLE_PLATFORM && !__LP64__ 288 // create the window rect in global coords 289 ::Rect windowRect; 290 windowRect.left = 0; 291 windowRect.top = 0; 292 windowRect.right = 300; 293 windowRect.bottom = 300; 294 295 // set the default attributes for the window 296 WindowAttributes windowAttrs = kWindowStandardDocumentAttributes 297 | kWindowStandardHandlerAttribute 298 | kWindowInWindowMenuAttribute 299 | kWindowHideOnFullScreenAttribute; 300 301 // Create the window 302 CreateNewWindow(kDocumentWindowClass, windowAttrs, &windowRect, &mWin); 303 304 // Color the window background black 305 SetThemeWindowBackground (mWin, kThemeBrushBlack, true); 306 307 // Set the title of our window 308 CFStringRef titleRef = CFStringCreateWithCString( kCFAllocatorDefault, "OIS Input", kCFStringEncodingASCII ); 309 SetWindowTitleWithCFString( mWin, titleRef ); 310 311 // Center our window on the screen 312 RepositionWindow( mWin, NULL, kWindowCenterOnMainScreen ); 313 314 // Install the event handler for the window 315 InstallStandardEventHandler(GetWindowEventTarget(mWin)); 316 317 // This will give our window focus, and not lock it to the terminal 318 ProcessSerialNumber psn = { 0, kCurrentProcess }; 319 TransformProcessType( &psn, kProcessTransformToForegroundApplication ); 320 SetFrontProcess(&psn); 321 322 // Display and select our window 323 ShowWindow(mWin); 324 SelectWindow(mWin); 325 326 std::ostringstream wnd; 327 wnd << (unsigned int)mWin; //cast to int so it gets encoded correctly (else it gets stored as a hex string) 328 std::cout << "WindowRef: " << mWin << " WindowRef as int: " << wnd.str() << "\n"; 329 pl.insert(std::make_pair(std::string("WINDOW"), wnd.str())); 330 #endif 331 332 //This never returns null.. it will raise an exception on errors 333 g_InputManager = InputManager::createInputSystem(pl); 334 335 //Lets enable all addons that were compiled in: 336 g_InputManager->enableAddOnFactory(InputManager::AddOn_All); 337 338 //Print debugging information 339 unsigned int v = g_InputManager->getVersionNumber(); 340 std::cout << "OIS Version: " << (v>>16 ) << "." << ((v>>8) & 0x000000FF) << "." << (v & 0x000000FF) 341 << "\nRelease Name: " << g_InputManager->getVersionName() 342 << "\nManager: " << g_InputManager->inputSystemName() 343 << "\nTotal Keyboards: " << g_InputManager->getNumberOfDevices(OISKeyboard) 344 << "\nTotal Mice: " << g_InputManager->getNumberOfDevices(OISMouse) 345 << "\nTotal JoySticks: " << g_InputManager->getNumberOfDevices(OISJoyStick); 346 347 //List all devices 348 DeviceList list = g_InputManager->listFreeDevices(); 349 for( DeviceList::iterator i = list.begin(); i != list.end(); ++i ) 350 std::cout << "\n\tDevice: " << g_DeviceType[i->first] << " Vendor: " << i->second; 351 352 g_kb = (Keyboard*)g_InputManager->createInputObject( OISKeyboard, true ); 353 g_kb->setEventCallback( &handler ); 354 355 g_m = (Mouse*)g_InputManager->createInputObject( OISMouse, true ); 356 g_m->setEventCallback( &handler ); 357 const MouseState &ms = g_m->getMouseState(); 358 ms.width = 100; 359 ms.height = 100; 360 361 try 362 { 363 //This demo uses at most 4 joysticks - use old way to create (i.e. disregard vendor) 364 int numSticks = std::min(g_InputManager->getNumberOfDevices(OISJoyStick), 4); 365 for( int i = 0; i < numSticks; ++i ) 366 { 367 g_joys[i] = (JoyStick*)g_InputManager->createInputObject( OISJoyStick, true ); 368 g_joys[i]->setEventCallback( &handler ); 369 std::cout << "\n\nCreating Joystick " << (i + 1) 370 << "\n\tAxes: " << g_joys[i]->getNumberOfComponents(OIS_Axis) 371 << "\n\tSliders: " << g_joys[i]->getNumberOfComponents(OIS_Slider) 372 << "\n\tPOV/HATs: " << g_joys[i]->getNumberOfComponents(OIS_POV) 373 << "\n\tButtons: " << g_joys[i]->getNumberOfComponents(OIS_Button) 374 << "\n\tVector3: " << g_joys[i]->getNumberOfComponents(OIS_Vector3); 375 } 376 } 377 catch(OIS::Exception &ex) 378 { 379 std::cout << "\nException raised on joystick creation: " << ex.eText << std::endl; 380 } 381 } 382 383 void handleNonBufferedKeys() 384 { 385 if( g_kb->isKeyDown( KC_ESCAPE ) || g_kb->isKeyDown( KC_Q ) ) 386 appRunning = false; 387 388 if( g_kb->isModifierDown(Keyboard::Shift) ) 389 std::cout << "Shift is down..\n"; 390 if( g_kb->isModifierDown(Keyboard::Alt) ) 391 std::cout << "Alt is down..\n"; 392 if( g_kb->isModifierDown(Keyboard::Ctrl) ) 393 std::cout << "Ctrl is down..\n"; 394 } 395 396 void handleNonBufferedMouse() 397 { 398 //Just dump the current mouse state 399 const MouseState &ms = g_m->getMouseState(); 400 std::cout << "\nMouse: Abs(" << ms.X.abs << " " << ms.Y.abs << " " << ms.Z.abs 401 << ") B: " << ms.buttons << " Rel(" << ms.X.rel << " " << ms.Y.rel << " " << ms.Z.rel << ")"; 402 } 403 404 void handleNonBufferedJoy( JoyStick* js ) 405 { 406 //Just dump the current joy state 407 const JoyStickState &joy = js->getJoyStickState(); 408 for( unsigned int i = 0; i < joy.mAxes.size(); ++i ) 409 std::cout << "\nAxis " << i << " X: " << joy.mAxes[i].abs; 410 } 411 412 #if defined OIS_WIN32_PLATFORM 413 LRESULT DlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 414 { 415 return FALSE; 416 } 417 #endif 418 419 #if defined OIS_LINUX_PLATFORM 420 //This is just here to show that you still recieve x11 events, as the lib only needs mouse/key events 421 void checkX11Events() 422 { 423 if(!appRunning) 424 return; 425 426 XEvent event; 427 428 while(XPending(xDisp) > 0) 429 { 430 XNextEvent(xDisp, &event); 431 //Handle Resize events 432 if(event.type == ConfigureNotify) 433 { 434 if(g_m) 435 { 436 const MouseState &ms = g_m->getMouseState(); 437 ms.width = event.xconfigure.width; 438 ms.height = event.xconfigure.height; 439 } 440 } 441 else if(event.type == ClientMessage || event.type == DestroyNotify) 442 { // We only get DestroyNotify for child windows. However, we regeistered earlier to receive WM_DELETE_MESSAGEs 443 std::cout << "Exiting...\n"; 444 appRunning = false; 445 return; 446 } 447 else 448 { 449 std::cout << "\nUnknown X Event: " << event.type << std::endl; 450 } 451 } 452 } 453 #endif 454 455 #if defined OIS_APPLE_PLATFORM 456 void checkMacEvents() 457 { 458 //TODO - Check for window resize events, and then adjust the members of mousestate 459 EventRef event = NULL; 460 EventTargetRef targetWindow = GetEventDispatcherTarget(); 461 462 if( ReceiveNextEvent( 0, NULL, kEventDurationNoWait, true, &event ) == noErr ) 463 { 464 SendEventToEventTarget(event, targetWindow); 465 std::cout << "Event : " << GetEventKind(event) << "\n"; 466 ReleaseEvent(event); 467 } 468 } 469 #endif 470