Removed the hacks to detect emulated mouse in NinjaSnowWar.

Modify SDL to remove Android & iOS emulated mouse events, and to detect Windows emulated mouse events and disregard them.
Fixed touch handling in UI.
Added Button::IsPressed() function.
This commit is contained in:
Lasse Öörni 2013-07-14 14:33:51 +00:00
Родитель 4f5763125c
Коммит 6d852735b2
11 изменённых файлов: 222 добавлений и 96 удалений

Просмотреть файл

@ -53,7 +53,6 @@ uint clientNodeID = 0;
int clientScore = 0;
bool touchEnabled = false;
float timeSinceLastTouch = 1.0;
int touchButtonSize = 96;
int touchButtonBorder = 12;
int moveTouchID = -1;
@ -89,7 +88,6 @@ void Start()
SubscribeToEvent("Kill", "HandleKill");
SubscribeToEvent("ScreenMode", "HandleScreenMode");
SubscribeToEvent("TouchBegin", "HandleTouchBegin");
SubscribeToEvent("TouchMove", "HandleTouchMove");
SubscribeToEvent("TouchEnd", "HandleTouchEnd");
if (singlePlayer)
@ -404,7 +402,6 @@ void SpawnPlayer(Connection@ connection)
void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
float timeStep = eventData["TimeStep"].GetFloat();
timeSinceLastTouch += timeStep;
UpdateControls();
CheckEndAndRestart();
@ -463,8 +460,6 @@ void HandleTouchBegin(StringHash eventType, VariantMap& eventData)
if (!touchEnabled)
InitTouchInput();
timeSinceLastTouch = 0.0;
int touchID = eventData["TouchID"].GetInt();
IntVector2 pos(eventData["X"].GetInt(), eventData["Y"].GetInt());
UIElement@ element = ui.GetElementAt(pos, false);
@ -477,11 +472,6 @@ void HandleTouchBegin(StringHash eventType, VariantMap& eventData)
rotateTouchID = touchID;
}
void HandleTouchMove(StringHash eventType, VariantMap& eventData)
{
timeSinceLastTouch = 0.0;
}
void HandleTouchEnd(StringHash eventType, VariantMap& eventData)
{
int touchID = eventData["TouchID"].GetInt();
@ -1004,14 +994,10 @@ void UpdateControls()
playerControls.Set(CTRL_JUMP, true);
}
// Touch is also emulated as mouse. Before using mouse for actions, make sure there has been some time since last touch
if (timeSinceLastTouch > 0.5)
{
if (input.mouseButtonDown[MOUSEB_LEFT] || input.mouseButtonPress[MOUSEB_LEFT])
playerControls.Set(CTRL_FIRE, true);
if (input.mouseButtonDown[MOUSEB_RIGHT] || input.mouseButtonPress[MOUSEB_RIGHT])
playerControls.Set(CTRL_JUMP, true);
}
playerControls.yaw += mouseSensitivity * input.mouseMoveX;
playerControls.pitch += mouseSensitivity * input.mouseMoveY;

Просмотреть файл

@ -1116,8 +1116,6 @@ To get joystick input, the joystick(s) must first be explicitly opened using \re
From the input subsystem you can also query whether the application window has input focus, or is minimized.
Note that touch events also create emulated mouse events. This can not be prevented on the Windows platform, so the SDL library also emulates it on other platforms for consistency. Refer to the NinjaSnowWar example on how to prevent unwanted control in case you want to support both mouse and touch.
\page Audio %Audio
The Audio subsystem implements an audio output stream. Once it has been initialized, the following operations are supported:

Просмотреть файл

@ -136,17 +136,17 @@ void Input::Update()
// Check for relative mode mouse move
if (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))
{
// Make sure the mouse move is not an emulated touch
if (!GetNumTouches())
{
IntVector2 mousePosition = GetMousePosition();
mouseMove_ = mousePosition - lastMousePosition_;
// Recenter the mouse cursor manually
IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
if (mousePosition != center)
{
SetMousePosition(center);
lastMousePosition_ = center;
}
// Send mouse move event if necessary
if (mouseMove_ != IntVector2::ZERO)
@ -174,9 +174,6 @@ void Input::Update()
}
}
}
else
suppressNextMouseMove_ = true;
}
}
void Input::SetMouseVisible(bool enable)
@ -683,15 +680,19 @@ void Input::HandleSDLEvent(void* sdlEvent)
case SDL_FINGERUP:
{
int touchID = evt.tfinger.fingerId & 0x7ffffff;
touches_.Erase(touchID);
TouchState& state = touches_[touchID];
using namespace TouchEnd;
VariantMap eventData;
// Do not trust the position in the finger up event. Instead use the last position stored in the
// touch structure
eventData[P_TOUCHID] = touchID;
eventData[P_X] = evt.tfinger.x * graphics_->GetWidth();
eventData[P_Y] = evt.tfinger.y * graphics_->GetHeight();
eventData[P_X] = state.position_.x_;
eventData[P_Y] = state.position_.y_;
touches_.Erase(touchID);
SendEvent(E_TOUCHEND, eventData);
}
break;

Просмотреть файл

@ -1047,6 +1047,7 @@ template <class T> void RegisterButton(asIScriptEngine* engine, const char* clas
engine->RegisterObjectMethod(className, "float get_repeatDelay() const", asMETHOD(T, GetRepeatDelay), asCALL_THISCALL);
engine->RegisterObjectMethod(className, "void set_repeatRate(float)", asMETHOD(T, SetRepeatRate), asCALL_THISCALL);
engine->RegisterObjectMethod(className, "float get_repeatRate() const", asMETHOD(T, GetRepeatRate), asCALL_THISCALL);
engine->RegisterObjectMethod(className, "bool get_pressed() const", asMETHOD(T, IsPressed), asCALL_THISCALL);
}
}

Просмотреть файл

@ -97,9 +97,7 @@ void Button::GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexDat
void Button::OnHover(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers, Cursor* cursor)
{
BorderImage::OnHover(position, screenPosition, buttons, qualifiers, cursor);
if (pressed_)
{
if (!(buttons & MOUSEB_LEFT))
if (pressed_ && !(buttons & MOUSEB_LEFT))
{
SetPressed(false);
@ -110,7 +108,6 @@ void Button::OnHover(const IntVector2& position, const IntVector2& screenPositio
SendEvent(E_RELEASED, eventData);
}
}
}
void Button::OnClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers, Cursor* cursor)
{

Просмотреть файл

@ -74,6 +74,8 @@ public:
float GetRepeatDelay() const { return repeatDelay_; }
/// Return repeat rate.
float GetRepeatRate() const { return repeatRate_; }
/// Return whether is currently pressed.
bool IsPressed() const { return pressed_; }
protected:
/// Set new pressed state.

Просмотреть файл

@ -71,6 +71,7 @@ UI::UI(Context* context) :
mouseButtons_(0),
qualifiers_(0),
initialized_(false),
usingTouchInput_(false),
#ifdef WIN32
nonFocusedMouseWheel_(false), // Default MS Windows behaviour
#else
@ -89,6 +90,9 @@ UI::UI(Context* context) :
SubscribeToEvent(E_MOUSEBUTTONUP, HANDLER(UI, HandleMouseButtonUp));
SubscribeToEvent(E_MOUSEMOVE, HANDLER(UI, HandleMouseMove));
SubscribeToEvent(E_MOUSEWHEEL, HANDLER(UI, HandleMouseWheel));
SubscribeToEvent(E_TOUCHBEGIN, HANDLER(UI, HandleTouchBegin));
SubscribeToEvent(E_TOUCHEND, HANDLER(UI, HandleTouchEnd));
SubscribeToEvent(E_TOUCHMOVE, HANDLER(UI, HandleTouchMove));
SubscribeToEvent(E_KEYDOWN, HANDLER(UI, HandleKeyDown));
SubscribeToEvent(E_CHAR, HANDLER(UI, HandleChar));
@ -265,7 +269,8 @@ void UI::Update(float timeStep)
bool cursorVisible;
GetCursorPositionAndVisible(cursorPos, cursorVisible);
if (cursorVisible)
// Mouse hover
if (!usingTouchInput_ && cursorVisible)
{
WeakPtr<UIElement> element(GetElementAt(cursorPos));
@ -307,9 +312,8 @@ void UI::Update(float timeStep)
// Touch hover
Input* input = GetSubsystem<Input>();
if (input)
{
unsigned numTouches = input->GetNumTouches();
for (unsigned i = 0; i < numTouches; ++i)
{
TouchState* touch = input->GetTouch(i);
@ -317,7 +321,6 @@ void UI::Update(float timeStep)
if (element && element->IsEnabled())
element->OnHover(element->ScreenToElement(touch->position_), touch->position_, MOUSEB_LEFT, 0, 0);
}
}
Update(timeStep, rootElement_);
Update(timeStep, rootModalElement_);
@ -490,8 +493,7 @@ UIElement* UI::GetFrontElement() const
IntVector2 UI::GetCursorPosition() const
{
Input* input = GetSubsystem<Input>();
return (input->IsMouseVisible() || !cursor_) ? input->GetMousePosition() : cursor_->GetPosition();
return cursor_ ? cursor_->GetPosition() : GetSubsystem<Input>()->GetMousePosition();
}
bool UI::HasModalElement() const
@ -761,18 +763,17 @@ UIElement* UI::GetFocusableElement(UIElement* element)
void UI::GetCursorPositionAndVisible(IntVector2& pos, bool& visible)
{
Input* input = GetSubsystem<Input>();
if (input->IsMouseVisible() || !cursor_)
{
pos = input->GetMousePosition();
visible = input->IsMouseVisible();
}
else
if (cursor_)
{
pos = cursor_->GetPosition();
visible = cursor_->IsVisible();
}
else
{
Input* input = GetSubsystem<Input>();
pos = input->GetMousePosition();
visible = input->IsMouseVisible();
}
}
void UI::SetCursorShape(CursorShape shape)
@ -817,6 +818,7 @@ void UI::HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
{
mouseButtons_ = eventData[MouseButtonDown::P_BUTTONS].GetInt();
qualifiers_ = eventData[MouseButtonDown::P_QUALIFIERS].GetInt();
usingTouchInput_ = false;
IntVector2 cursorPos;
bool cursorVisible;
@ -923,6 +925,7 @@ void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData)
mouseButtons_ = eventData[P_BUTTONS].GetInt();
qualifiers_ = eventData[P_QUALIFIERS].GetInt();
usingTouchInput_ = false;
Input* input = GetSubsystem<Input>();
const IntVector2& rootSize = rootElement_->GetSize();
@ -976,6 +979,7 @@ void UI::HandleMouseWheel(StringHash eventType, VariantMap& eventData)
mouseButtons_ = eventData[P_BUTTONS].GetInt();
qualifiers_ = eventData[P_QUALIFIERS].GetInt();
int delta = eventData[P_WHEEL].GetInt();
usingTouchInput_ = false;
IntVector2 cursorPos;
bool cursorVisible;
@ -1012,6 +1016,119 @@ void UI::HandleMouseWheel(StringHash eventType, VariantMap& eventData)
}
}
void UI::HandleTouchBegin(StringHash eventType, VariantMap& eventData)
{
using namespace TouchBegin;
IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
WeakPtr<UIElement> element(GetElementAt(pos));
usingTouchInput_ = true;
if (element)
{
// Handle focusing & bringing to front
SetFocusElement(element);
element->BringToFront();
// Handle click
element->OnClick(element->ScreenToElement(pos), pos, MOUSEB_LEFT, 0, 0);
// Handle start of drag. OnClick() may have caused destruction of the element, so check the pointer again
if (element && !dragElement_ )
{
dragElement_ = element;
element->OnDragBegin(element->ScreenToElement(pos), pos, MOUSEB_LEFT, 0, 0);
SendDragEvent(E_DRAGBEGIN, element, pos);
}
}
else
{
// If clicked over no element, or a disabled element, lose focus
SetFocusElement(0);
}
VariantMap clickEventData;
clickEventData[UIMouseClick::P_ELEMENT] = (void*)element.Get();
clickEventData[UIMouseClick::P_X] = pos.x_;
clickEventData[UIMouseClick::P_Y] = pos.y_;
clickEventData[UIMouseClick::P_BUTTON] = MOUSEB_LEFT;
clickEventData[UIMouseClick::P_BUTTONS] = MOUSEB_LEFT;
clickEventData[UIMouseClick::P_QUALIFIERS] = 0;
SendEvent(E_UIMOUSECLICK, clickEventData);
}
void UI::HandleTouchEnd(StringHash eventType, VariantMap& eventData)
{
using namespace TouchEnd;
IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
// Transmit hover end to the position where the finger was lifted
UIElement* element = GetElementAt(pos);
if (element && element->IsEnabled())
element->OnHover(element->ScreenToElement(pos), pos, 0, 0, 0);
if (dragElement_)
{
if (dragElement_->IsEnabled() && dragElement_->IsVisible())
{
dragElement_->OnDragEnd(dragElement_->ScreenToElement(pos), pos, cursor_);
SendDragEvent(E_DRAGEND, dragElement_, pos);
// Drag and drop finish
bool dragSource = dragElement_ && (dragElement_->GetDragDropMode() & DD_SOURCE) != 0;
if (dragSource)
{
WeakPtr<UIElement> target(GetElementAt(pos));
bool dragTarget = target && (target->GetDragDropMode() & DD_TARGET) != 0;
bool dragDropFinish = dragSource && dragTarget && target != dragElement_;
if (dragDropFinish)
{
bool accept = target->OnDragDropFinish(dragElement_);
// OnDragDropFinish() may have caused destruction of the elements, so check the pointers again
if (accept && dragElement_ && target)
{
using namespace DragDropFinish;
VariantMap eventData;
eventData[P_SOURCE] = (void*)dragElement_.Get();
eventData[P_TARGET] = (void*)target.Get();
eventData[P_ACCEPT] = accept;
SendEvent(E_DRAGDROPFINISH, eventData);
}
}
}
}
dragElement_.Reset();
}
}
void UI::HandleTouchMove(StringHash eventType, VariantMap& eventData)
{
using namespace TouchMove;
IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
usingTouchInput_ = true;
if (dragElement_)
{
if (dragElement_->IsEnabled() && dragElement_->IsVisible())
{
dragElement_->OnDragMove(dragElement_->ScreenToElement(pos), pos, MOUSEB_LEFT, 0, 0);
SendDragEvent(E_DRAGMOVE, dragElement_, pos);
}
else
{
dragElement_->OnDragEnd(dragElement_->ScreenToElement(pos), pos, 0);
SendDragEvent(E_DRAGEND, dragElement_, pos);
dragElement_.Reset();
}
}
}
void UI::HandleKeyDown(StringHash eventType, VariantMap& eventData)
{
using namespace KeyDown;

Просмотреть файл

@ -133,6 +133,12 @@ private:
void HandleMouseMove(StringHash eventType, VariantMap& eventData);
/// Handle mouse wheel event.
void HandleMouseWheel(StringHash eventType, VariantMap& eventData);
/// Handle touch begin event.
void HandleTouchBegin(StringHash eventType, VariantMap& eventData);
/// Handle touch end event.
void HandleTouchEnd(StringHash eventType, VariantMap& eventData);
/// Handle touch move event.
void HandleTouchMove(StringHash eventType, VariantMap& eventData);
/// Handle keypress event.
void HandleKeyDown(StringHash eventType, VariantMap& eventData);
/// Handle character event.
@ -188,6 +194,8 @@ private:
int qualifiers_;
/// Initialized flag.
bool initialized_;
/// Touch used flag.
bool usingTouchInput_;
/// Flag to switch mouse wheel event to be sent to non-focused element at cursor.
bool nonFocusedMouseWheel_;
/// Non-modal batch size (used internally for rendering).

Просмотреть файл

@ -18,6 +18,9 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// Modified by Lasse Oorni for Urho3D
#include "SDL_config.h"
#if SDL_VIDEO_DRIVER_ANDROID
@ -75,11 +78,12 @@ void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int actio
if (!leftFingerDown) {
Android_GetWindowCoordinates(x, y, &window_x, &window_y);
// Urho3D: do not send emulated mouse events
/* send moved event */
SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
//SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
/* send mouse down event */
SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
//SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
leftFingerDown = fingerId;
}
@ -90,7 +94,7 @@ void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int actio
Android_GetWindowCoordinates(x, y, &window_x, &window_y);
/* send moved event */
SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
//SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
}
SDL_SendTouchMotion(touchDeviceId, fingerId, x, y, p);
break;
@ -98,7 +102,7 @@ void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int actio
case ACTION_POINTER_1_UP:
if (fingerId == leftFingerDown) {
/* send mouse up */
SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
//SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
leftFingerDown = 0;
}
SDL_SendTouch(touchDeviceId, fingerId, SDL_FALSE, x, y, p);

Просмотреть файл

@ -18,6 +18,9 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// Modified by Lasse Oorni for Urho3D
#include "SDL_config.h"
#if SDL_VIDEO_DRIVER_UIKIT
@ -88,11 +91,12 @@
if (!leftFingerDown) {
CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
// Urho3D: do not send emulated mouse events
/* send moved event */
SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
//SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
/* send mouse down event */
SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
//SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
leftFingerDown = touch;
}
@ -128,7 +132,7 @@
while(touch) {
if (touch == leftFingerDown) {
/* send mouse up */
SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
//SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
leftFingerDown = nil;
}
@ -171,7 +175,7 @@
CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
/* send moved event */
SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
//SDL_SendMouseMotion(NULL, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
}
CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];

Просмотреть файл

@ -18,6 +18,9 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// Modified by Lasse Oorni for Urho3D
#include "SDL_config.h"
#if SDL_VIDEO_DRIVER_WINDOWS
@ -262,6 +265,11 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
SDL_WindowData *data;
LRESULT returnCode = -1;
// Urho3D: detect emulated mouse events
// Note: if we move mouse cursor manually (relative mouse motion with hidden cursor) we may get emulated mouse
// events with zero extra info, so we should only center the cursor when it has actually moved
BOOL emulatedMouse = (GetMessageExtraInfo() & 0xffffff00) == 0xff515700;
/* Send a SDL_SYSWMEVENT if the application wants them */
if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
SDL_SysWMmsg wmmsg;
@ -382,7 +390,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
break;
case WM_MOUSEMOVE:
if( !SDL_GetMouse()->relative_mode )
if( !emulatedMouse && !SDL_GetMouse()->relative_mode )
SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
/* don't break here, fall through to check the wParam like the button presses */
case WM_LBUTTONUP:
@ -393,7 +401,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN:
if( !SDL_GetMouse()->relative_mode )
if( !emulatedMouse && !SDL_GetMouse()->relative_mode )
WIN_CheckWParamMouseButtons( wParam, data );
break;