Modules/Graphics/public/InputCoalescer.hpp
Шурупов Илья Викторович 56615487df Turn two-finger touches into pan, pinch and rotate gestures
TouchGestureTracker follows two fingers and reports the pan, scale and
rotation since the previous update around their midpoint. The Android
window tracks every finger, sends a gesture while two or more touch
the screen and releases the pointer the first finger was holding, so
one finger keeps acting as a pointer. Gestures travel through the input
coalescer, which merges consecutive updates, to a new Gesture UI event
delivered to the widget under the fingers where the gesture began.
Gesture events reach the UI before pointer events from the same frame.
2026-10-17 09:19:48 +03:00

104 lines
2.8 KiB
C++

#pragma once
#include "InputCodes.hpp"
#include "PointerSample.hpp"
#include "TouchGesture.hpp"
#include "Vec.hpp"
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
namespace tp {
class WindowInputObserver;
enum class DeliveryPolicy { Every, Latest, Accumulate };
struct InputDeliveryPolicies {
DeliveryPolicy pointerMotion = DeliveryPolicy::Latest;
DeliveryPolicy scroll = DeliveryPolicy::Accumulate;
};
struct WindowConfigure {
int32_t width = 0;
int32_t height = 0;
bool maximized = false;
bool fullscreen = false;
bool activated = false;
bool tiled = false;
uint32_t serial = 0;
};
struct CoalescingStatistics {
uint64_t received = 0;
uint64_t delivered = 0;
uint64_t configuresReceived = 0;
uint64_t configuresApplied = 0;
};
class InputCoalescer {
public:
InputCoalescer();
~InputCoalescer();
InputCoalescer(const InputCoalescer&) = delete;
InputCoalescer& operator=(const InputCoalescer&) = delete;
[[nodiscard]] WindowInputObserver& recorder();
void setTap(WindowInputObserver* tap) { mTap = tap; }
[[nodiscard]] WindowInputObserver* tap() const { return mTap; }
void setPolicies(const InputDeliveryPolicies& policies) { mPolicies = policies; }
[[nodiscard]] const InputDeliveryPolicies& policies() const { return mPolicies; }
void pointerSample(const PointerSample& sample) { mSample = sample; }
void pointerMoved(Vec2F position);
void pointerLeft();
void pointerButton(InputID button, bool pressed);
void scrolled(Vec2F delta);
void key(InputID key, bool pressed);
void keyRepeat(InputID key);
void text(const std::string& utf8);
void keyboardFocus(bool focused);
void gesture(const TouchGesture& gesture);
void configure(const WindowConfigure& configure);
[[nodiscard]] bool hasPendingConfigure() const { return mHasConfigure; }
[[nodiscard]] WindowConfigure takeConfigure();
[[nodiscard]] bool isEmpty() const { return mEvents.empty(); }
[[nodiscard]] size_t pendingEvents() const { return mEvents.size(); }
void deliver(WindowInputObserver& observer);
[[nodiscard]] const CoalescingStatistics& statistics() const { return mStatistics; }
private:
enum class Kind { Motion, Leave, Button, Scroll, Key, Repeat, Text, Focus, Gesture };
struct Pending {
Kind kind;
Vec2F vector = { 0, 0 };
InputID id = InputID::SPACE;
bool flag = false;
std::string text;
PointerSample sample;
TouchGesture gesture;
};
void push(Pending event, DeliveryPolicy policy);
class Recorder;
std::unique_ptr<Recorder> mRecorder;
WindowInputObserver* mTap = nullptr;
InputDeliveryPolicies mPolicies;
std::vector<Pending> mEvents;
PointerSample mSample;
PointerSample mDeliveredSample;
WindowConfigure mConfigure;
bool mHasConfigure = false;
CoalescingStatistics mStatistics;
};
}