/**************************************************************************** Copyright (c) 2007,Radon Labs GmbH Copyright (c) 2011-2013,WebJet Business Division,CYOU http://www.genesis-3d.com.cn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "input/input_stdneb.h" #include "input/base/inputserverbase.h" #include "input/inputhandler.h" #include "input/inputkeyboard.h" #include "input/inputmouse.h" #include "input/inputtouchscreen.h" #include "input/inputgamepad.h" namespace Input { __ImplementClass(Input::InputServerBase, 'IPSB', Core::RefCounted); using namespace Input; using namespace Util; //------------------------------------------------------------------------------ /** */ InputServerBase::InputServerBase() : isOpen(false), inBeginFrame(false), isQuitRequested(false), inputHandlersLockCount(0), maxNumLocalPlayers(4), defaultGamePad(InputGamePad::GetMaxNumPlayers()), creatorThreadId(Threading::Thread::GetMyThreadId()) { // empty } //------------------------------------------------------------------------------ /** */ InputServerBase::~InputServerBase() { if (this->IsOpen()) { this->Close(); } } //------------------------------------------------------------------------------ /** Setup the maximum number of local players for this application. The default number is 1. This defines the number of game pad objects created and queried. */ void InputServerBase::SetMaxNumLocalPlayers(SizeT num) { n_assert(!this->isOpen); n_assert(num <= InputGamePad::GetMaxNumPlayers()); this->maxNumLocalPlayers = num; } //------------------------------------------------------------------------------ /** */ void InputServerBase::Open() { n_assert(!this->isOpen); n_assert(!this->inBeginFrame); this->isOpen = true; SizeT count = mInputSourceList.Size(); for ( IndexT index = 0; index < count; ++index ) { mInputSourceList[index]->Open(this); } } //------------------------------------------------------------------------------ /** */ void InputServerBase::Close() { n_assert(this->IsOpen()); // remove all input handlers IndexT i; for (i = 0; i < this->inputHandlers.Size(); i++) { this->inputHandlers[i].Value()->OnRemove(); } this->inputHandlers.Clear(); this->keyboardCaptureHandler = 0; this->mouseCaptureHandler = 0; // release default input handlers this->defaultKeyboard = 0; this->defaultMouse = 0; this->defaultGamePad.Fill(0); SizeT count = mInputSourceList.Size(); for ( IndexT index = 0; index < count; ++index ) { mInputSourceList[index]->Close(); } this->isOpen = false; } //------------------------------------------------------------------------------ /** */ void InputServerBase::Reset() { InputEvent resetEvent; resetEvent.SetType(InputEvent::Reset); this->PutEvent(resetEvent); if (this->mouseCaptureHandler.isvalid()) { this->ReleaseMouseCapture(this->mouseCaptureHandler); } if (this->keyboardCaptureHandler.isvalid()) { this->ReleaseKeyboardCapture(this->keyboardCaptureHandler); } } //------------------------------------------------------------------------------ /** */ void InputServerBase::AttachInputHandler(InputPriority::Code pri, const GPtr& inputHandler) { n_assert(0 == this->inputHandlersLockCount); // make sure the input handler isn't attached yet IndexT i; for (i = 0; i < this->inputHandlers.Size(); i++) { n_assert(inputHandler != this->inputHandlers[i].Value()); } // add a new entry to the sorted input handler array KeyValuePair > kvp(pri, inputHandler); this->inputHandlers.InsertSorted(kvp); inputHandler->OnAttach(this); } //------------------------------------------------------------------------------ /** */ void InputServerBase::RemoveInputHandler(const GPtr& inputHandler) { n_assert(0 == this->inputHandlersLockCount); // check if the input handler currently captures input if (this->mouseCaptureHandler.isvalid() && (this->mouseCaptureHandler == inputHandler)) { this->ReleaseMouseCapture(inputHandler); } if (this->keyboardCaptureHandler.isvalid() && (this->keyboardCaptureHandler == inputHandler)) { this->ReleaseKeyboardCapture(inputHandler); } // remove input handler IndexT i; for (i = 0; i < this->inputHandlers.Size(); i++) { if (inputHandler == this->inputHandlers[i].Value()) { this->inputHandlers[i].Value()->OnRemove(); this->inputHandlers.EraseIndex(i); return; } } } void InputServerBase::AttachInputSource( const GPtr& inputSource) { n_assert( !inputSource->IsOpen() ); // make sure the input handler isn't attached yet SizeT count = mInputSourceList.Size(); for (IndexT i = 0; i < count; i++) { n_assert(inputSource != this->mInputSourceList[i] ); } mInputSourceList.Append( inputSource ); if ( this->IsOpen() ) { inputSource->Open(this); } } void InputServerBase::RemoveInputSource( const GPtr& inputSource) { IndexT findIndex = InvalidIndex; SizeT count = mInputSourceList.Size(); for (IndexT i = 0; i < count; i++) { if( inputSource == this->mInputSourceList[i] ) { findIndex = i; break; } } if ( findIndex != InvalidIndex ) { mInputSourceList.EraseIndex(findIndex); if ( inputSource->IsOpen() ) { inputSource->Close(); } } } //------------------------------------------------------------------------------ /** */ void InputServerBase::BeginFrame() { n_assert(!this->inBeginFrame); this->inBeginFrame = true; // first handler, then source. because hander maybe clear all input status // notify input handlers this->inputHandlersLockCount++; IndexT i; for (i = 0; i < this->inputHandlers.Size(); i++) { this->inputHandlers[i].Value()->OnBeginFrame(); } this->inputHandlersLockCount--; // notify input source { SizeT count = mInputSourceList.Size(); for ( IndexT index = 0; index < count; ++index ) { mInputSourceList[index]->BeginFrame(); } } } //------------------------------------------------------------------------------ /** */ void InputServerBase::OnFrame() { // empty } //------------------------------------------------------------------------------ /** Call this somewhere towards the end of frame, when it is guaraneteed that noone needs input anymore. */ void InputServerBase::EndFrame() { n_assert(this->inBeginFrame); // notify input handlers this->inputHandlersLockCount++; IndexT i; for (i = 0; i < this->inputHandlers.Size(); i++) { this->inputHandlers[i].Value()->OnEndFrame(); } this->inputHandlersLockCount--; this->inBeginFrame = false; } //------------------------------------------------------------------------------ /** NOTE: MouseMove and RawMouseMove events will be distributed to all input handlers regardless of mouse capture state! */ void InputServerBase::PutEvent(const InputEvent& inputEvent) { n_assert2(creatorThreadId == Threading::Thread::GetMyThreadId(), "PutEvent can't be called from any thread but the creator thread!"); // check for mouse capture if (this->mouseCaptureHandler.isvalid()) { // route mouse events exclusively to mouse capture handler switch (inputEvent.GetType()) { // do not route this events exclusively case InputEvent::BeginMouseCapture: case InputEvent::EndMouseCapture: break; case InputEvent::AppDisplayMini: case InputEvent::AppLoseFocus: case InputEvent::Reset: this->ReleaseMouseCapture(this->mouseCaptureHandler); break; case InputEvent::MouseButtonDown: case InputEvent::MouseButtonUp: case InputEvent::MouseButtonDoubleClick: case InputEvent::MouseWheelForward: case InputEvent::MouseWheelBackward: this->mouseCaptureHandler->OnEvent(inputEvent); return; default: break; } } // check for keyboard capture if (this->keyboardCaptureHandler.isvalid()) { // route keyboard events exclusively to keyboard capture handler switch (inputEvent.GetType()) { // do not route this events exclusively case InputEvent::BeginKeyboardCapture: case InputEvent::EndKeyboardCapture: break; case InputEvent::AppDisplayMini: case InputEvent::AppLoseFocus: case InputEvent::Reset: this->ReleaseKeyboardCapture(this->keyboardCaptureHandler); break; case InputEvent::KeyDown: case InputEvent::KeyUp: case InputEvent::Character: this->keyboardCaptureHandler->OnEvent(inputEvent); return; default: break; } } // normal input event handling this->inputHandlersLockCount++; IndexT i; for (i = 0; i < this->inputHandlers.Size(); i++) { if (!this->inputHandlers[i].Value()->OnEvent(inputEvent)) { break; } } this->inputHandlersLockCount--; } //------------------------------------------------------------------------------ /** Obtain the mouse capture. All mouse input will go exclusively to the capture input handler until ReleaseMouseCapture() is called. */ void InputServerBase::ObtainMouseCapture(const GPtr& inputHandler) { if (this->mouseCaptureHandler.isvalid()) { this->mouseCaptureHandler->OnReleaseCapture(); this->mouseCaptureHandler = 0; } this->mouseCaptureHandler = inputHandler; this->mouseCaptureHandler->OnObtainCapture(); } //------------------------------------------------------------------------------ /** Release the mouse capture. The provided pointer must match the current capture input handler. */ void InputServerBase::ReleaseMouseCapture(const GPtr& inputHandler) { if (this->mouseCaptureHandler.isvalid() && (this->mouseCaptureHandler == inputHandler)) { this->mouseCaptureHandler->OnReleaseCapture(); this->mouseCaptureHandler = 0; } } //------------------------------------------------------------------------------ /** */ const GPtr& InputServerBase::GetMouseCaptureHandler() const { return this->mouseCaptureHandler; } //------------------------------------------------------------------------------ /** This clears the currently set mouse capture (if exists). */ void InputServerBase::ClearMouseCapture() { if (this->mouseCaptureHandler.isvalid()) { this->mouseCaptureHandler->OnReleaseCapture(); this->mouseCaptureHandler = 0; } } //------------------------------------------------------------------------------ /** This clears the currently set keyboard capture (if exists). */ void InputServerBase::ClearKeyboardCapture() { if (this->keyboardCaptureHandler.isvalid()) { this->keyboardCaptureHandler->OnReleaseCapture(); this->keyboardCaptureHandler = 0; } } //------------------------------------------------------------------------------ /** This clears the mouse and keyboards captures, if set. */ void InputServerBase::ClearCapture() { this->ClearMouseCapture(); this->ClearKeyboardCapture(); } //------------------------------------------------------------------------------ /** Obtain the keyboard capture. All keyboard input will go exclusively to the capture input handler until ReleaseKeyboardCapture() is called. */ void InputServerBase::ObtainKeyboardCapture(const GPtr& inputHandler) { if (this->keyboardCaptureHandler.isvalid()) { this->keyboardCaptureHandler->OnReleaseCapture(); this->keyboardCaptureHandler = 0; } this->keyboardCaptureHandler = inputHandler; this->keyboardCaptureHandler->OnObtainCapture(); } //------------------------------------------------------------------------------ /** Release the mouse capture. The provided pointer must match the current capture input handler. */ void InputServerBase::ReleaseKeyboardCapture(const GPtr& inputHandler) { if (this->keyboardCaptureHandler.isvalid() && (this->keyboardCaptureHandler == inputHandler)) { this->keyboardCaptureHandler->OnReleaseCapture(); this->keyboardCaptureHandler = 0; } } //------------------------------------------------------------------------------ /** */ const GPtr& InputServerBase::GetKeyboardCaptureHandler() const { return this->keyboardCaptureHandler; } //------------------------------------------------------------------------------ /** */ GPtr InputServerBase::GetDefaultGamePad(IndexT playerIndex) const { this->critSect.Enter(); n_assert(playerIndex < this->maxNumLocalPlayers); GPtr result = this->defaultGamePad[playerIndex]; this->critSect.Leave(); return result; } } // namespace Input