nestopia/source/win32/NstManagerInputCursor.cpp

245 lines
6.6 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include "resource/resource.h"
#include "NstWindowParam.hpp"
#include "NstManager.hpp"
#include "NstManagerInput.hpp"
namespace Nestopia
{
namespace Managers
{
Input::Cursor::Cursor(Window::Custom& w,const Screening& i,const Screening& o)
:
hCursor ( Resource::Cursor::GetArrow() ),
hCurrent ( Resource::Cursor::GetArrow() ),
deadline ( NO_DEADLINE ),
window ( w ),
wheel ( WHEEL_MAX ),
getInputRect ( i ),
getOutputRect ( o ),
gun ( IDC_CURSOR_GUN ),
primaryButtonId ( ::GetSystemMetrics( SM_SWAPBUTTON ) ? VK_RBUTTON : VK_LBUTTON ),
secondaryButtonId ( primaryButtonId == VK_LBUTTON ? VK_RBUTTON : VK_LBUTTON )
{
static const Window::MsgHandler::Entry<Input::Cursor> messages[] =
{
{ WM_SETCURSOR, &Cursor::OnSetCursor },
{ WM_MOUSEMOVE, &Cursor::OnNop },
{ WM_LBUTTONDOWN, &Cursor::OnNop },
{ WM_RBUTTONDOWN, &Cursor::OnRButtonDownNop },
{ WM_LBUTTONUP, &Cursor::OnNop },
{ WM_RBUTTONUP, &Cursor::OnNop },
{ WM_MOUSEWHEEL, &Cursor::OnWheel }
};
window.Messages().Add( this, messages );
}
Input::Cursor::~Cursor()
{
window.Messages().Remove( this );
}
void Input::Cursor::Acquire(Emulator& emulator)
{
bool autoHide = false;
bool usesRButton = false;
if
(
Nes::Input(emulator).IsControllerConnected( Nes::Input::ZAPPER ) ||
Nes::Input(emulator).IsControllerConnected( Nes::Input::BANDAIHYPERSHOT )
)
{
hCursor = gun;
usesRButton = true;
}
else if (Nes::Input(emulator).IsControllerConnected( Nes::Input::POWERGLOVE ))
{
hCursor = NULL;
usesRButton = true;
}
else if
(
Nes::Input(emulator).IsControllerConnected( Nes::Input::PADDLE ) ||
Nes::Input(emulator).IsControllerConnected( Nes::Input::HORITRACK ) ||
Nes::Input(emulator).IsControllerConnected( Nes::Input::PACHINKO ) ||
Nes::Input(emulator).IsControllerConnected( Nes::Input::OEKAKIDSTABLET ) ||
Nes::Input(emulator).IsControllerConnected( Nes::Input::MOUSE )
)
{
hCursor = NULL;
}
else
{
hCursor = Resource::Cursor::GetArrow();
autoHide = true;
}
Window::MsgHandler& router = window.Messages();
router[ WM_MOUSEMOVE ].Set( this, autoHide ? &Cursor::OnMouseMove : &Cursor::OnNop );
router[ WM_LBUTTONDOWN ].Set( this, autoHide ? &Cursor::OnLButtonDown : &Cursor::OnNop );
router[ WM_LBUTTONUP ].Set( this, autoHide ? &Cursor::OnButtonUp : &Cursor::OnNop );
router[ WM_RBUTTONDOWN ].Set( this, autoHide ? &Cursor::OnRButtonDown : usesRButton ? &Cursor::OnNop : &Cursor::OnRButtonDownNop );
router[ WM_RBUTTONUP ].Set( this, autoHide ? &Cursor::OnButtonUp : &Cursor::OnNop );
hCurrent = hCursor;
deadline = autoHide ? ::GetTickCount() + TIME_OUT : NO_DEADLINE;
}
void Input::Cursor::Unacquire()
{
deadline = NO_DEADLINE;
hCurrent = hCursor = Resource::Cursor::GetArrow();
Window::MsgHandler& router = window.Messages();
router[ WM_MOUSEMOVE ].Set( this, &Cursor::OnNop );
router[ WM_LBUTTONDOWN ].Set( this, &Cursor::OnNop );
router[ WM_LBUTTONUP ].Set( this, &Cursor::OnNop );
router[ WM_RBUTTONDOWN ].Set( this, &Cursor::OnRButtonDownNop );
router[ WM_RBUTTONUP ].Set( this, &Cursor::OnNop );
}
void Input::Cursor::AutoHide()
{
deadline = NO_DEADLINE;
if (window.Active())
{
Window::Point pos;
::GetCursorPos( &pos );
if (Window::Rect(window.PictureCoordinates()).ScreenTransform(window).Inside( pos ))
::SetCursor( hCurrent=NULL );
}
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("t", on)
#endif
bool Input::Cursor::Poll(uint& x,uint& y,uint& lbutton,uint* const rbutton) const
{
POINT mouse;
::GetCursorPos( &mouse );
Window::Rect output;
getOutputRect( output );
if (output.Inside( mouse ))
{
Window::Rect input;
getInputRect( input );
x = input.left + (mouse.x - output.left) * (uint(input.Width())-1) / output.Width();
y = input.top + (mouse.y - output.top) * (uint(input.Height())-1) / output.Height();
if (window.Active())
{
lbutton = ::GetAsyncKeyState( primaryButtonId ) & 0x8000U;
if (rbutton)
*rbutton = ::GetAsyncKeyState( secondaryButtonId ) & 0x8000U;
return true;
}
}
lbutton = 0;
if (rbutton)
*rbutton = 0;
return false;
}
ibool Input::Cursor::OnNop(Window::Param&)
{
return true;
}
ibool Input::Cursor::OnSetCursor(Window::Param& param)
{
if (LOWORD(param.lParam) == HTCLIENT)
{
param.lResult = true;
::SetCursor( hCurrent );
return true;
}
return false;
}
ibool Input::Cursor::OnMouseMove(Window::Param&)
{
hCurrent = hCursor;
deadline = ::GetTickCount() + TIME_OUT;
return true;
}
ibool Input::Cursor::OnLButtonDown(Window::Param&)
{
deadline = NO_DEADLINE;
::SetCursor( hCurrent=hCursor );
return true;
}
ibool Input::Cursor::OnRButtonDown(Window::Param&)
{
deadline = NO_DEADLINE;
::SetCursor( hCurrent=hCursor );
window.SendCommand( IDM_VIEW_MENU );
return true;
}
ibool Input::Cursor::OnRButtonDownNop(Window::Param&)
{
window.SendCommand( IDM_VIEW_MENU );
return true;
}
ibool Input::Cursor::OnButtonUp(Window::Param&)
{
::SetCursor( hCurrent=hCursor );
deadline = ::GetTickCount() + TIME_OUT;
return true;
}
ibool Input::Cursor::OnWheel(Window::Param& param)
{
wheel += GET_WHEEL_DELTA_WPARAM(param.wParam);
wheel = NST_CLAMP(wheel,WHEEL_MIN,WHEEL_MAX);
return true;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
}
}