infinipaint/src/InputManager.hpp
2026-04-07 20:21:41 +03:00

447 lines
14 KiB
C++

#pragma once
#include <Eigen/Dense>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_properties.h>
#include <SDL3/SDL_touch.h>
#include <array>
#include "RichText/TextStyleModifier.hpp"
#include "RichText/TextBox.hpp"
#include "TimePoint.hpp"
#include <Helpers/Hashes.hpp>
#include <unordered_map>
#include <nlohmann/json.hpp>
#include <queue>
#include <Helpers/CallbackManager.hpp>
#include "UndoManager.hpp"
#include <SDL3/SDL.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keycode.h>
#include <Helpers/SCollision.hpp>
#include "CustomEvents.hpp"
using namespace Eigen;
class MainProgram;
struct InputManagerCallPasteInfo {
std::optional<Vector2f> pastePosition;
bool allowRichText = true;
};
struct InputManager {
InputManager(MainProgram& initMain);
void update();
void frame_reset(const Vector2i& windowSize);
// Just renamed SDL3 cursor types, but if we need to change to a different backend we can
// translate this enum to different commands in main.cpp
enum class SystemCursorType : unsigned {
DEFAULT = 0,
TEXT,
WAIT,
CROSSHAIR,
PROGRESS,
NWSE_RESIZE,
NESW_RESIZE,
EW_RESIZE,
NS_RESIZE,
MOVE,
NOT_ALLOWED,
POINTER,
NW_RESIZE,
N_RESIZE,
NE_RESIZE,
E_RESIZE,
SE_RESIZE,
S_RESIZE,
SW_RESIZE,
W_RESIZE
} cursorIcon;
bool hideCursor = false;
bool toggleFullscreen = false;
struct KeyData {
bool held = false;
std::chrono::steady_clock::time_point lastPressTime;
};
struct Mouse {
void set_pos(const Vector2f& newPos);
Vector2f pos = {0, 0};
bool leftDown = false;
bool rightDown = false;
bool middleDown = false;
} mouse;
struct Touch {
uint8_t leftClicksSaved = 0;
uint8_t fingerTapsSaved = 0;
std::chrono::steady_clock::time_point lastLeftClickTime;
std::chrono::steady_clock::time_point lastFingerTapTime;
std::vector<SDL_TouchFingerEvent> fingers;
enum TypeOfTouchEvent {
NO_TOUCH_EVENT,
ONE_FINGER_EVENT,
TWO_FINGER_EVENT,
EVENT_DONE
} touchEventType = EVENT_DONE;
} touch;
struct Pen {
bool inProximity = false;
bool isDown = false;
bool isEraser = false;
float pressure = 0.0f;
uint8_t leftClicksSaved = 0;
Vector2f previousPos;
std::chrono::steady_clock::time_point lastPenLeftClickTime;
std::array<KeyData, 256> buttons;
} pen;
bool isTouchDevice = true;
enum AndroidInputType : int {
ANDROIDTEXT_TYPE_CLASS_DATETIME = 0x00000004,
ANDROIDTEXT_TYPE_CLASS_NUMBER = 0x00000002,
ANDROIDTEXT_TYPE_CLASS_PHONE = 0x00000003,
ANDROIDTEXT_TYPE_CLASS_TEXT = 0x00000001,
ANDROIDTEXT_TYPE_DATETIME_VARIATION_DATE = 0x00000010,
ANDROIDTEXT_TYPE_DATETIME_VARIATION_NORMAL = 0x00000000,
ANDROIDTEXT_TYPE_DATETIME_VARIATION_TIME = 0x00000020,
ANDROIDTEXT_TYPE_MASK_CLASS = 0x0000000f,
ANDROIDTEXT_TYPE_MASK_FLAGS = 0x00fff000,
ANDROIDTEXT_TYPE_MASK_VARIATION = 0x00000ff0,
ANDROIDTEXT_TYPE_NULL = 0x00000000,
ANDROIDTEXT_TYPE_NUMBER_FLAG_DECIMAL = 0x00002000,
ANDROIDTEXT_TYPE_NUMBER_FLAG_SIGNED = 0x00001000,
ANDROIDTEXT_TYPE_NUMBER_VARIATION_NORMAL = 0x00000000,
ANDROIDTEXT_TYPE_NUMBER_VARIATION_PASSWORD = 0x00000010,
ANDROIDTEXT_TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000,
ANDROIDTEXT_TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000,
ANDROIDTEXT_TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000,
ANDROIDTEXT_TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000,
ANDROIDTEXT_TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000,
ANDROIDTEXT_TYPE_TEXT_FLAG_ENABLE_TEXT_CONVERSION_SUGGESTIONS = 0x00100000,
ANDROIDTEXT_TYPE_TEXT_FLAG_ENABLE_TEXT_SUGGESTION_SELECTED = 0x00200000,
ANDROIDTEXT_TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000,
ANDROIDTEXT_TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000,
ANDROIDTEXT_TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000,
ANDROIDTEXT_TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x00000020,
ANDROIDTEXT_TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030,
ANDROIDTEXT_TYPE_TEXT_VARIATION_FILTER = 0x000000b0,
ANDROIDTEXT_TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x00000050,
ANDROIDTEXT_TYPE_TEXT_VARIATION_NORMAL = 0x00000000,
ANDROIDTEXT_TYPE_TEXT_VARIATION_PASSWORD = 0x00000080,
ANDROIDTEXT_TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000060,
ANDROIDTEXT_TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0,
ANDROIDTEXT_TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000070,
ANDROIDTEXT_TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x00000040,
ANDROIDTEXT_TYPE_TEXT_VARIATION_URI = 0x00000010,
ANDROIDTEXT_TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 0x00000090,
ANDROIDTEXT_TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x000000a0,
ANDROIDTEXT_TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 0x000000d0,
ANDROIDTEXT_TYPE_TEXT_VARIATION_WEB_PASSWORD = 0x000000e0
};
struct TextInputProperties {
SDL_TextInputType inputType;
SDL_Capitalization capitalization;
bool autocorrect;
bool multiline;
int androidInputType;
};
unsigned set_text_box_front(const std::optional<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps);
unsigned set_text_box_back(const std::optional<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps);
void remove_text_box(unsigned textboxID);
struct Text {
bool is_accepting_input();
std::optional<unsigned> current_textbox_editing_id();
private:
struct TextBoxInfo {
std::optional<SCollision::AABB<float>> rect;
TextInputProperties textInputProperties;
unsigned id;
};
void update_accepting_input(SDL_Window* window);
std::optional<SDL_PropertiesID> propID;
std::deque<TextBoxInfo> textBoxes;
unsigned get_id();
friend struct InputManager;
} text;
#ifdef __APPLE__
SDL_Keymod CTRL_MOD = SDL_KMOD_GUI;
#else
SDL_Keymod CTRL_MOD = SDL_KMOD_CTRL;
#endif
enum KeyCodeEnum : unsigned {
// Assignable
KEY_CAMERA_ROTATE_CLOCKWISE = 0,
KEY_CAMERA_ROTATE_COUNTERCLOCKWISE,
KEY_DRAW_DELETE,
KEY_UNDO,
KEY_REDO,
KEY_NOGUI,
KEY_FULLSCREEN,
KEY_SAVE,
KEY_SAVE_AS,
KEY_COPY,
KEY_CUT,
KEY_PASTE,
KEY_PASTE_IMAGE,
KEY_DRAW_TOOL_BRUSH,
KEY_DRAW_TOOL_ERASER,
KEY_DRAW_TOOL_ZOOM,
KEY_DRAW_TOOL_PAN,
KEY_DRAW_TOOL_LASSOSELECT,
KEY_DRAW_TOOL_TEXTBOX,
KEY_DRAW_TOOL_RECTANGLE,
KEY_DRAW_TOOL_ELLIPSE,
KEY_DRAW_TOOL_RECTSELECT,
KEY_DRAW_TOOL_EYEDROPPER,
KEY_DRAW_TOOL_SCREENSHOT,
KEY_DRAW_TOOL_LINE,
KEY_SHOW_METRICS,
KEY_OPEN_CHAT,
KEY_SHOW_PLAYER_LIST,
KEY_HOLD_TO_PAN,
KEY_HOLD_TO_ZOOM,
KEY_DESELECT_AND_EDIT_TOOL,
KEY_ASSIGNABLE_COUNT, // Not a real key
// Unassignable
KEY_TEXT_BACKSPACE,
KEY_TEXT_DELETE,
KEY_TEXT_HOME,
KEY_TEXT_END,
KEY_TEXT_COPY,
KEY_TEXT_CUT,
KEY_TEXT_PASTE,
KEY_TEXT_TAB,
KEY_TEXT_SELECTALL,
KEY_TEXT_UNDO,
KEY_TEXT_REDO,
KEY_GENERIC_UP,
KEY_GENERIC_DOWN,
KEY_GENERIC_LEFT,
KEY_GENERIC_RIGHT,
KEY_GENERIC_ENTER,
KEY_GENERIC_ESCAPE,
KEY_GENERIC_LSHIFT,
KEY_GENERIC_LALT,
KEY_GENERIC_LCTRL,
KEY_GENERIC_LMETA,
KEY_COUNT
};
typedef unsigned KeyCode;
bool ctrl_or_meta_held();
uint32_t make_generic_key_mod(SDL_Keymod m);
void set_key_up(const SDL_KeyboardEvent& e, KeyCode kCode);
void set_key_down(const SDL_KeyboardEvent& e, KeyCode kCode);
std::vector<Vector2f> get_multiple_finger_positions();
std::vector<Vector2f> get_multiple_finger_motions();
void touch_finger_do_mouse_down();
void touch_finger_do_mouse_up(const SDL_TouchFingerEvent& f);
void touch_finger_do_mouse_motion(const SDL_TouchFingerEvent& f);
void backend_open_infinipaint_file_event();
void backend_paste_event();
void backend_input_text_event(const std::string& str);
void backend_drop_file_event(const SDL_DropEvent& e);
void backend_drop_text_event(const SDL_DropEvent& e);
void backend_mouse_button_up_update(const SDL_MouseButtonEvent& e);
void backend_mouse_button_down_update(const SDL_MouseButtonEvent& e);
void backend_mouse_motion_update(const SDL_MouseMotionEvent& e);
void backend_mouse_wheel_update(const SDL_MouseWheelEvent& e);
void backend_key_up_update(const SDL_KeyboardEvent& e);
void backend_key_down_update(const SDL_KeyboardEvent& e);
void backend_pen_button_down_update(const SDL_PenButtonEvent& e);
void backend_pen_button_up_update(const SDL_PenButtonEvent& e);
void backend_pen_touch_down_update(const SDL_PenTouchEvent& e);
void backend_pen_touch_up_update(const SDL_PenTouchEvent& e);
void backend_pen_motion_update(const SDL_PenMotionEvent& e);
void backend_pen_axis_update(const SDL_PenAxisEvent& e);
void backend_touch_finger_down_update(const SDL_TouchFingerEvent& e);
void backend_touch_finger_up_update(const SDL_TouchFingerEvent& e);
void backend_touch_finger_motion_update(const SDL_TouchFingerEvent& e);
void backend_window_resize_update(const SDL_WindowEvent& e);
void backend_window_scale_update(const SDL_WindowEvent& e);
void set_clipboard_str(std::string_view s);
void set_clipboard_plain_and_richtext_pair(const std::pair<std::string, RichText::TextData>& plainAndRichtextPair);
std::string get_clipboard_str_SDL();
void get_clipboard_image_data_SDL(const std::function<void(std::string_view data)>& callback);
void call_paste(CustomEvents::PasteEventDataType type, const InputManagerCallPasteInfo& info = {});
void process_text_paste(const std::string& pasteStr, bool allowRichText);
std::optional<RichText::TextData> lastCopiedRichText;
std::string key_assignment_to_str(const Vector2ui32& k) const;
Vector2ui32 key_assignment_from_str(const std::string& s) const;
const KeyData& key(KeyCode kCode);
struct TextCallbackArgs {
std::string str;
};
struct KeyCallbackArgs {
KeyCode key;
bool down;
bool repeat;
};
std::unordered_map<Vector2ui32, KeyCode> keyAssignments;
std::unordered_map<Vector2ui32, KeyCode> defaultKeyAssignments;
std::array<KeyData, KEY_COUNT> keys;
enum class MouseButton : uint8_t {
LEFT = 1,
MIDDLE,
RIGHT
} button;
enum class MouseDeviceType {
MOUSE,
PEN,
TOUCH
};
struct MouseButtonCallbackArgs {
MouseDeviceType deviceType;
MouseButton button;
bool down;
uint8_t clicks;
Vector2f pos;
};
struct MouseMotionCallbackArgs {
MouseDeviceType deviceType;
Vector2f pos;
Vector2f move;
};
struct MouseWheelCallbackArgs {
Vector2f mousePos;
Vector2f amount;
Vector2i tickAmount;
};
struct PenButtonCallbackArgs {
uint8_t button;
bool down;
Vector2f pos;
};
struct PenTouchCallbackArgs {
bool down;
bool eraser;
Vector2f pos;
};
struct PenMotionCallbackArgs {
Vector2f pos;
Vector2f move;
};
struct PenAxisCallbackArgs {
Vector2f pos;
SDL_PenAxis axis;
float value;
};
struct DropCallbackArgs {
Vector2f pos;
const char* source;
const char* data;
};
struct MultiFingerTouchCallbackArgs {
bool down;
std::vector<Vector2f> pos;
};
struct MultiFingerMotionCallbackArgs {
std::vector<Vector2f> pos;
std::vector<Vector2f> move;
};
struct FingerTouchCallbackArgs {
SDL_FingerID fingerID;
bool down;
Vector2f pos;
size_t fingerDownCount;
int fingerTapCount;
};
struct FingerMotionCallbackArgs {
SDL_FingerID fingerID;
Vector2f pos;
Vector2f move;
size_t fingerDownCount;
};
struct WindowResizeCallbackArgs {
Vector2i size;
float density;
};
struct WindowScaleCallbackArgs {
float scale;
};
MainProgram& main;
};
NLOHMANN_JSON_SERIALIZE_ENUM(InputManager::KeyCodeEnum, {
{InputManager::KEY_CAMERA_ROTATE_CLOCKWISE, "Rotate Canvas CW"},
{InputManager::KEY_CAMERA_ROTATE_COUNTERCLOCKWISE, "Rotate Canvas CCW"},
{InputManager::KEY_DRAW_DELETE, "Delete Selection"},
{InputManager::KEY_UNDO, "Undo"},
{InputManager::KEY_REDO, "Redo"},
{InputManager::KEY_NOGUI, "Toggle GUI"},
{InputManager::KEY_FULLSCREEN, "Toggle Fullscreen"},
{InputManager::KEY_SAVE, "Save"},
{InputManager::KEY_SAVE_AS, "Save As"},
{InputManager::KEY_COPY, "Copy"},
{InputManager::KEY_CUT, "Cut"},
{InputManager::KEY_PASTE, "Paste"},
{InputManager::KEY_PASTE_IMAGE, "Paste Image"},
{InputManager::KEY_DRAW_TOOL_BRUSH, "Brush Tool"},
{InputManager::KEY_DRAW_TOOL_ERASER, "Eraser Tool"},
{InputManager::KEY_DRAW_TOOL_ZOOM, "Zoom Tool"},
{InputManager::KEY_DRAW_TOOL_LASSOSELECT, "Lasso Select Tool"},
{InputManager::KEY_DRAW_TOOL_PAN, "Pan Tool"},
{InputManager::KEY_DRAW_TOOL_TEXTBOX, "Textbox Tool"},
{InputManager::KEY_DRAW_TOOL_RECTANGLE, "Rectangle Tool"},
{InputManager::KEY_DRAW_TOOL_ELLIPSE, "Ellipse Tool"},
{InputManager::KEY_DRAW_TOOL_RECTSELECT, "Rect Select Tool"},
{InputManager::KEY_DRAW_TOOL_EYEDROPPER, "Color Select Tool"},
{InputManager::KEY_DRAW_TOOL_SCREENSHOT, "Take Screenshot"},
{InputManager::KEY_DRAW_TOOL_LINE, "Line Tool"},
{InputManager::KEY_SHOW_METRICS, "Show Metrics"},
{InputManager::KEY_OPEN_CHAT, "Open Chat"},
{InputManager::KEY_SHOW_PLAYER_LIST, "Show Player List"},
{InputManager::KEY_HOLD_TO_PAN, "Hold to Pan"},
{InputManager::KEY_HOLD_TO_ZOOM, "Hold to Zoom"},
{InputManager::KEY_DESELECT_AND_EDIT_TOOL, "Deselect selection / Edit Tool"}
})