Skip to content

Commit

Permalink
Adjust mouse and gesture handling
Browse files Browse the repository at this point in the history
  • Loading branch information
peak3d committed Mar 23, 2020
1 parent fe157eb commit d3282a0
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 25 deletions.
25 changes: 21 additions & 4 deletions xbmc/guilib/GUIBaseContainer.cpp
Expand Up @@ -86,8 +86,6 @@ void CGUIBaseContainer::Process(unsigned int currentTime, CDirtyRegionList &dirt
// update our auto-scrolling as necessary
UpdateAutoScrolling(currentTime);

ValidateOffset();

if (m_bInvalidated)
UpdateLayout();

Expand Down Expand Up @@ -690,7 +688,6 @@ CGUIListItemLayout *CGUIBaseContainer::GetFocusedLayout() const
bool CGUIBaseContainer::OnMouseOver(const CPoint &point)
{
// select the item under the pointer
SelectItemFromPoint(point - CPoint(m_posX, m_posY));
return CGUIControl::OnMouseOver(point);
}

Expand All @@ -700,9 +697,11 @@ EVENT_RESULT CGUIBaseContainer::OnMouseEvent(const CPoint &point, const CMouseEv
event.m_id == ACTION_MOUSE_DOUBLE_CLICK ||
event.m_id == ACTION_MOUSE_RIGHT_CLICK)
{
int select = GetSelectedItem();
if (SelectItemFromPoint(point - CPoint(m_posX, m_posY)))
{
OnClick(event.m_id);
if (event.m_id != ACTION_MOUSE_RIGHT_CLICK || select == GetSelectedItem())
OnClick(event.m_id);
return EVENT_RESULT_HANDLED;
}
}
Expand All @@ -718,6 +717,8 @@ EVENT_RESULT CGUIBaseContainer::OnMouseEvent(const CPoint &point, const CMouseEv
}
else if (event.m_id == ACTION_GESTURE_NOTIFY)
{
m_waitForScrollEnd = true;
m_lastScrollValue = m_scroller.GetValue();
return (m_orientation == HORIZONTAL) ? EVENT_RESULT_PAN_HORIZONTAL : EVENT_RESULT_PAN_VERTICAL;
}
else if (event.m_id == ACTION_GESTURE_BEGIN)
Expand All @@ -733,8 +734,21 @@ EVENT_RESULT CGUIBaseContainer::OnMouseEvent(const CPoint &point, const CMouseEv
int offset = MathUtils::round_int(m_scroller.GetValue() / size);
m_lastScrollStartTimer.Stop();
m_scrollTimer.Start();
int absCursor = GetCursor() + GetOffset();
SetOffset(offset);
ValidateOffset();
SetCursor(absCursor - GetOffset());
// Notify Application if Inertial scrolling reaches lists end
if (m_waitForScrollEnd)
{
if (fabs(m_scroller.GetValue() - m_lastScrollValue) < 0.001f)
{
m_waitForScrollEnd = false;
return EVENT_RESULT_UNHANDLED;
}
else
m_lastScrollValue = m_scroller.GetValue();
}
return EVENT_RESULT_HANDLED;
}
else if (event.m_id == ACTION_GESTURE_END || event.m_id == ACTION_GESTURE_ABORT)
Expand All @@ -751,6 +765,9 @@ EVENT_RESULT CGUIBaseContainer::OnMouseEvent(const CPoint &point, const CMouseEv
else
SetOffset(toOffset-1);
ScrollToOffset(toOffset);
ValidateOffset();
SetFocus(true);
m_waitForScrollEnd = false;
return EVENT_RESULT_HANDLED;
}
return EVENT_RESULT_UNHANDLED;
Expand Down
3 changes: 3 additions & 0 deletions xbmc/guilib/GUIBaseContainer.h
Expand Up @@ -226,6 +226,9 @@ class CGUIBaseContainer : public IGUIContainer
std::string m_match;
float m_scrollItemsPerFrame;

bool m_waitForScrollEnd = false;
float m_lastScrollValue;

static const int letter_match_timeout = 1000;
};

Expand Down
5 changes: 3 additions & 2 deletions xbmc/guilib/GUIFixedListContainer.cpp
Expand Up @@ -105,16 +105,17 @@ void CGUIFixedListContainer::Scroll(int amount)
// increase or decrease the offset within [-minCursor, m_items.size() - maxCursor]
int minCursor, maxCursor;
GetCursorRange(minCursor, maxCursor);
int nextCursor = GetCursor() + amount;
int offset = GetOffset() + amount;
if (offset < -minCursor)
{
offset = -minCursor;
SetCursor(minCursor);
SetCursor(nextCursor < minCursor ? minCursor : nextCursor);
}
if (offset > (int)m_items.size() - 1 - maxCursor)
{
offset = m_items.size() - 1 - maxCursor;
SetCursor(maxCursor);
SetCursor(nextCursor > maxCursor ? maxCursor : nextCursor);
}
ScrollToOffset(offset);
}
Expand Down
36 changes: 26 additions & 10 deletions xbmc/input/InertialScrollingHandler.cpp
Expand Up @@ -14,18 +14,21 @@
#include "guilib/GUIComponent.h"
#include "guilib/GUIWindowManager.h"
#include "input/Key.h"
#include "input/touch/generic/GenericTouchInputHandler.h"
#include "utils/TimeUtils.h"
#include "utils/log.h"
#include "windowing/WinSystem.h"

#include <cmath>
#include <numeric>

//time for reaching velocity 0 in secs
// time for reaching velocity 0 in secs
#define TIME_TO_ZERO_SPEED 1.0f
//minimum speed for doing inertial scroll is 100 pixels / s
#define MINIMUM_SPEED_FOR_INERTIA 100
//maximum time between last movement and gesture end in ms to consider as moving
// minimum speed for doing inertial scroll is 100 pixels / s
#define MINIMUM_SPEED_FOR_INERTIA 200
// maximum speed for reducing time to zero
#define MAXIMUM_SPEED_FOR_REDUCTION 750
// maximum time between last movement and gesture end in ms to consider as moving
#define MAXIMUM_DELAY_FOR_INERTIA 200

CInertialScrollingHandler::CInertialScrollingHandler()
Expand Down Expand Up @@ -95,10 +98,20 @@ bool CInertialScrollingHandler::CheckForInertialScrolling(const CAction* action)
auto velocityX = velocitySum.x / m_panPoints.size();
auto velocityY = velocitySum.y / m_panPoints.size();

CLog::LogF(LOGDEBUG, "Avg touch velocity: %f,%f up to and including touch at %u ms ago", velocityX, velocityY, m_panPoints.front().TimeElapsed());
m_timeToZero = TIME_TO_ZERO_SPEED;
auto velocityMax = std::max(std::abs(velocityX), std::abs(velocityY));
float dpiScale = CGenericTouchInputHandler::GetInstance().GetScreenDPI() / 160.0f;

if (std::abs(velocityX) > MINIMUM_SPEED_FOR_INERTIA || std::abs(velocityY) > MINIMUM_SPEED_FOR_INERTIA)
CLog::LogF(LOGDEBUG,
"Avg touch velocity: %0.4f,%0.4f up to and including touch at %u ms ago with "
"dpiScale: %0.4lf",
velocityX, velocityY, m_panPoints.front().TimeElapsed(), dpiScale);

if (velocityMax > MINIMUM_SPEED_FOR_INERTIA * dpiScale)
{
if (velocityMax < MAXIMUM_SPEED_FOR_REDUCTION * dpiScale)
m_timeToZero = (m_timeToZero * velocityMax) / (MAXIMUM_SPEED_FOR_REDUCTION * dpiScale);

bool inertialRequested = false;
CGUIMessage message(GUI_MSG_GESTURE_NOTIFY, 0, 0, static_cast<int> (velocityX), static_cast<int> (velocityY));

Expand Down Expand Up @@ -130,8 +143,8 @@ bool CInertialScrollingHandler::CheckForInertialScrolling(const CAction* action)
//calc deacceleration for fullstop in TIME_TO_ZERO_SPEED secs
//v = a*t + v0 -> set v = 0 because we want to stop scrolling
//a = -v0 / t
m_inertialDeacceleration.x = -1*m_iFlickVelocity.x/TIME_TO_ZERO_SPEED;
m_inertialDeacceleration.y = -1*m_iFlickVelocity.y/TIME_TO_ZERO_SPEED;
m_inertialDeacceleration.x = -1 * m_iFlickVelocity.x / m_timeToZero;
m_inertialDeacceleration.y = -1 * m_iFlickVelocity.y / m_timeToZero;

//CLog::Log(LOGDEBUG, "initial pos: %f,%f velocity: %f,%f dec: %f,%f", m_iLastGesturePoint.x, m_iLastGesturePoint.y, m_iFlickVelocity.x, m_iFlickVelocity.y, m_inertialDeacceleration.x, m_inertialDeacceleration.y);
m_inertialStartTime = CTimeUtils::GetFrameTime();//start time of inertial scrolling
Expand Down Expand Up @@ -162,7 +175,7 @@ bool CInertialScrollingHandler::ProcessInertialScroll(float frameTime)
float absoluteInertialTime = (CTimeUtils::GetFrameTime() - m_inertialStartTime)/(float)1000;

//as long as we aren't over the overall inertial scroll time - do the deacceleration
if ( absoluteInertialTime < TIME_TO_ZERO_SPEED )
if (absoluteInertialTime < m_timeToZero)
{
//v = s/t -> s = t * v
xMovement = frameTime * m_iFlickVelocity.x;
Expand All @@ -174,7 +187,10 @@ bool CInertialScrollingHandler::ProcessInertialScroll(float frameTime)

//CLog::Log(LOGDEBUG, "@%f: %f,%f offset: %f, %f velocity: %f,%f dec: %f,%f", absoluteInertialTime, m_iLastGesturePoint.x, m_iLastGesturePoint.y, xMovement, yMovement, m_iFlickVelocity.x, m_iFlickVelocity.y, m_inertialDeacceleration.x, m_inertialDeacceleration.y);
//fire the pan action
g_application.OnAction(CAction(ACTION_GESTURE_PAN, 0, m_iLastGesturePoint.x, m_iLastGesturePoint.y, xMovement, yMovement, m_iFlickVelocity.x, m_iFlickVelocity.y));
if (!g_application.OnAction(CAction(ACTION_GESTURE_PAN, 0, m_iLastGesturePoint.x,
m_iLastGesturePoint.y, xMovement, yMovement,
m_iFlickVelocity.x, m_iFlickVelocity.y)))
m_bAborting = true; //we are done

//calc new velocity based on deacceleration
//v = a*t + v0
Expand Down
1 change: 1 addition & 0 deletions xbmc/input/InertialScrollingHandler.h
Expand Up @@ -45,4 +45,5 @@ class CInertialScrollingHandler
CPoint m_iLastGesturePoint;
CVector m_inertialDeacceleration;
unsigned int m_inertialStartTime = 0;
float m_timeToZero = 0.0f;
};
1 change: 1 addition & 0 deletions xbmc/input/touch/ITouchInputHandler.h
Expand Up @@ -86,6 +86,7 @@ class ITouchInputHandler : public ITouchInputHandling
virtual bool UpdateTouchPointer(int32_t pointer, float x, float y, int64_t time, float size = 0.0f) { return false; }

void SetScreenDPI(float dpi) { if (dpi > 0.0f) m_dpi = dpi; }
float GetScreenDPI() { return m_dpi; }

protected:
/*!
Expand Down
2 changes: 1 addition & 1 deletion xbmc/input/touch/generic/GenericTouchInputHandler.cpp
Expand Up @@ -19,7 +19,7 @@

namespace
{
constexpr int TOUCH_HOLD_TIMEOUT = 1000;
constexpr int TOUCH_HOLD_TIMEOUT = 500;
}

CGenericTouchInputHandler::CGenericTouchInputHandler()
Expand Down
11 changes: 7 additions & 4 deletions xbmc/platform/android/activity/XBMCApp.cpp
Expand Up @@ -139,10 +139,11 @@ float CXBMCApp::m_refreshRate = 0.0f;

uint32_t CXBMCApp::m_playback_state = PLAYBACK_STATE_STOPPED;

CXBMCApp::CXBMCApp(ANativeActivity* nativeActivity)
: CJNIMainActivity(nativeActivity)
, CJNIBroadcastReceiver(CJNIContext::getPackageName() + ".XBMCBroadcastReceiver")
, m_videosurfaceInUse(false)
CXBMCApp::CXBMCApp(ANativeActivity* nativeActivity, IInputHandler& inputHandler)
: CJNIMainActivity(nativeActivity),
CJNIBroadcastReceiver(CJNIContext::getPackageName() + ".XBMCBroadcastReceiver"),
m_inputHandler(inputHandler),
m_videosurfaceInUse(false)
{
m_xbmcappinstance = this;
m_activity = nativeActivity;
Expand Down Expand Up @@ -370,6 +371,7 @@ void CXBMCApp::Initialize()
CServiceBroker::GetAnnouncementManager()->AddAnnouncer(CXBMCApp::get());
runNativeOnUiThread(RegisterDisplayListener, nullptr);
m_activityManager.reset(new CJNIActivityManager(getSystemService(CJNIContext::ACTIVITY_SERVICE)));
m_inputHandler.setDPI(GetDPI());
}

void CXBMCApp::Deinitialize()
Expand Down Expand Up @@ -1433,6 +1435,7 @@ void CXBMCApp::onDisplayChanged(int displayId)
winSystemAndroid->UpdateDisplayModes();

m_displayChangeEvent.Set();
m_inputHandler.setDPI(GetDPI());
android_printf("%s: ", __PRETTY_FUNCTION__);
}

Expand Down
3 changes: 2 additions & 1 deletion xbmc/platform/android/activity/XBMCApp.h
Expand Up @@ -85,7 +85,7 @@ class CXBMCApp
, public CJNISurfaceHolderCallback
{
public:
explicit CXBMCApp(ANativeActivity *nativeActivity);
explicit CXBMCApp(ANativeActivity* nativeActivity, IInputHandler& inputhandler);
~CXBMCApp() override;
static CXBMCApp* get() { return m_xbmcappinstance; }

Expand Down Expand Up @@ -224,6 +224,7 @@ class CXBMCApp
static void RegisterDisplayListener(CVariant*);

static ANativeActivity *m_activity;
IInputHandler& m_inputHandler;
static CJNIWakeLock *m_wakeLock;
static int m_batteryLevel;
static bool m_hasFocus;
Expand Down
5 changes: 2 additions & 3 deletions xbmc/platform/android/activity/android_main.cpp
Expand Up @@ -100,12 +100,11 @@ extern void android_main(struct android_app* state)
state->inputPollSource.process = process_input;

CEventLoop eventLoop(state);
CXBMCApp xbmcApp(state->activity);
IInputHandler inputHandler;
CXBMCApp xbmcApp(state->activity, inputHandler);
if (xbmcApp.isValid())
{
start_logger("Kodi");

IInputHandler inputHandler;
eventLoop.run(xbmcApp, inputHandler);
}
else
Expand Down

0 comments on commit d3282a0

Please sign in to comment.