File indexing completed on 2024-11-10 04:57:08

0001 /*
0002     SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "shakedetector.h"
0008 
0009 #include <cmath>
0010 
0011 ShakeDetector::ShakeDetector()
0012 {
0013 }
0014 
0015 quint64 ShakeDetector::interval() const
0016 {
0017     return m_interval;
0018 }
0019 
0020 void ShakeDetector::setInterval(quint64 interval)
0021 {
0022     m_interval = interval;
0023 }
0024 
0025 qreal ShakeDetector::sensitivity() const
0026 {
0027     return m_sensitivity;
0028 }
0029 
0030 void ShakeDetector::setSensitivity(qreal sensitivity)
0031 {
0032     m_sensitivity = sensitivity;
0033 }
0034 
0035 std::optional<qreal> ShakeDetector::update(QMouseEvent *event)
0036 {
0037     // Prune the old entries in the history.
0038     auto it = m_history.begin();
0039     for (; it != m_history.end(); ++it) {
0040         if (event->timestamp() - it->timestamp < m_interval) {
0041             break;
0042         }
0043     }
0044     if (it != m_history.begin()) {
0045         m_history.erase(m_history.begin(), it);
0046     }
0047 
0048     m_history.emplace_back(HistoryItem{
0049         .position = event->localPos(),
0050         .timestamp = event->timestamp(),
0051     });
0052 
0053     qreal left = m_history[0].position.x();
0054     qreal top = m_history[0].position.y();
0055     qreal right = m_history[0].position.x();
0056     qreal bottom = m_history[0].position.y();
0057     qreal distance = 0;
0058 
0059     for (size_t i = 1; i < m_history.size(); ++i) {
0060         // Compute the length of the mouse path.
0061         const qreal deltaX = m_history.at(i).position.x() - m_history.at(i - 1).position.x();
0062         const qreal deltaY = m_history.at(i).position.y() - m_history.at(i - 1).position.y();
0063         distance += std::sqrt(deltaX * deltaX + deltaY * deltaY);
0064 
0065         // Compute the bounds of the mouse path.
0066         left = std::min(left, m_history.at(i).position.x());
0067         top = std::min(top, m_history.at(i).position.y());
0068         right = std::max(right, m_history.at(i).position.x());
0069         bottom = std::max(bottom, m_history.at(i).position.y());
0070     }
0071 
0072     const qreal boundsWidth = right - left;
0073     const qreal boundsHeight = bottom - top;
0074     const qreal diagonal = std::sqrt(boundsWidth * boundsWidth + boundsHeight * boundsHeight);
0075     if (diagonal < 100) {
0076         return std::nullopt;
0077     }
0078 
0079     const qreal shakeFactor = distance / diagonal;
0080     if (shakeFactor > m_sensitivity) {
0081         return shakeFactor - m_sensitivity;
0082     }
0083 
0084     return std::nullopt;
0085 }