// This file is part of VSTGUI. It is subject to the license terms // in the LICENSE file found in the top-level directory of this // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE #pragma once #include "vstguifwd.h" #include "cbuttonstate.h" #include "cpoint.h" #if VSTGUI_ENABLE_DEPRECATED_METHODS #include "vstkeycode.h" #endif //------------------------------------------------------------------------ namespace VSTGUI { //------------------------------------------------------------------------ /** EventType * @ingroup new_in_4_11 */ enum class EventType : uint32_t { Unknown, MouseDown, MouseMove, MouseUp, MouseCancel, MouseEnter, MouseExit, MouseWheel, ZoomGesture, KeyUp, KeyDown, }; //------------------------------------------------------------------------ /** EventConsumeState * @ingroup new_in_4_11 */ struct EventConsumeState { static constexpr uint32_t NotHandled = 0; static constexpr uint32_t Handled = 1; static constexpr uint32_t Last = 2; void operator= (bool state) { if (state) data |= Handled; else data &= ~Handled; } [[nodiscard]] operator bool () { return data & Handled; } void reset () { data = NotHandled; } uint32_t data {NotHandled}; }; //------------------------------------------------------------------------ /** Event * @ingroup new_in_4_11 */ struct Event { Event () noexcept; Event (const Event&) = delete; Event& operator= (const Event&) = delete; Event (Event&&) = default; Event& operator= (Event&&) = default; /** Type */ EventType type {EventType::Unknown}; /** Unique ID*/ uint64_t id; /** Timestamp */ uint64_t timestamp; /** Consumed? If this is true, event dispatching is stopped. */ EventConsumeState consumed; }; //------------------------------------------------------------------------ inline const Event& noEvent () { static Event e; return e; } //------------------------------------------------------------------------ /** Modifiers * @ingroup new_in_4_11 */ struct Modifiers { Modifiers () = default; Modifiers (const Modifiers&) = default; Modifiers (const std::initializer_list& modifiers) { for (auto& mod : modifiers) data |= cast (mod); } explicit Modifiers (ModifierKey modifier) : data (cast (modifier)) {} Modifiers& operator= (const Modifiers&) = default; /** test if no modifier key is set */ [[nodiscard]] bool empty () const { return data == 0; } /** test if modifier key is set */ [[nodiscard]] bool has (ModifierKey modifier) const { return data & cast (modifier); } /** test if modifier key is set exclusively */ [[nodiscard]] bool is (ModifierKey modifier) const { return data == cast (modifier); } /** test if the modifier keys are set exclusively */ [[nodiscard]] bool is (const std::initializer_list& modifiers) const { uint32_t d = 0; for (auto& mod : modifiers) d |= cast (mod); return data == d; } /** test if modifier key is set */ [[nodiscard]] bool operator| (ModifierKey modifier) const { return has (modifier); } /** test if modifier key is set exclusively */ [[nodiscard]] bool operator== (ModifierKey modifier) const { return is (modifier); } /** add a modifier key */ void add (ModifierKey modifier) { data |= cast (modifier); } /** remove a modifier key */ void remove (ModifierKey modifier) { data &= ~cast (modifier); } /** clear all modifiers */ void clear () { data = 0; } /** set to one modifier key */ [[nodiscard]] Modifiers& operator= (ModifierKey modifier) { data = cast (modifier); return *this; } /** check if equal to other modifiers */ [[nodiscard]] bool operator== (const Modifiers& other) const { return data == other.data; } /** check if different to other modifiers */ [[nodiscard]] bool operator!= (const Modifiers& other) const { return data != other.data; } private: static uint32_t cast (ModifierKey mod) { return static_cast (mod); } uint32_t data {0}; }; //------------------------------------------------------------------------ /** ModifierEvent * @ingroup new_in_4_11 */ struct ModifierEvent : Event { /** pressed modifiers */ Modifiers modifiers {}; }; //------------------------------------------------------------------------ /** MousePositionEvent * @ingroup new_in_4_11 */ struct MousePositionEvent : ModifierEvent { CPoint mousePosition; }; //------------------------------------------------------------------------ /** MouseButton * @ingroup new_in_4_11 */ enum class MouseButton : uint32_t { None = 0, Left = 1 << 1, Middle = 1 << 2, Right = 1 << 3, Fourth = 1 << 4, Fifth = 1 << 5, }; //------------------------------------------------------------------------ /** MouseEventButtonState * @ingroup new_in_4_11 */ struct MouseEventButtonState { [[nodiscard]] bool isLeft () const { return data == MouseButton::Left; } [[nodiscard]] bool isMiddle () const { return data == MouseButton::Middle; } [[nodiscard]] bool isRight () const { return data == MouseButton::Right; } [[nodiscard]] bool is (MouseButton pos) const { return data == pos; } [[nodiscard]] bool isOther (uint32_t index) const { return data == static_cast (1 << index); } [[nodiscard]] bool has (MouseButton pos) const { return static_cast (static_cast (data) & static_cast (pos)); } [[nodiscard]] bool empty () const { return data == MouseButton::None; } void add (MouseButton pos) { data = static_cast (static_cast (data) | static_cast (pos)); } void set (MouseButton pos) { data = pos; } void clear () { data = MouseButton::None; } MouseEventButtonState () = default; MouseEventButtonState (const MouseEventButtonState&) = default; MouseEventButtonState (MouseButton pos) { set (pos); } MouseEventButtonState& operator= (const MouseEventButtonState&) = default; [[nodiscard]] bool operator== (const MouseEventButtonState& other) const { return data == other.data; } [[nodiscard]] bool operator!= (const MouseEventButtonState& other) const { return data != other.data; } private: MouseButton data {MouseButton::None}; }; //------------------------------------------------------------------------ /** MouseEvent * @ingroup new_in_4_11 */ struct MouseEvent : MousePositionEvent { MouseEventButtonState buttonState; }; //------------------------------------------------------------------------ /** MouseEnterEvent * @ingroup new_in_4_11 */ struct MouseEnterEvent : MouseEvent { MouseEnterEvent () { type = EventType::MouseEnter; } MouseEnterEvent (CPoint pos, MouseEventButtonState buttons, Modifiers mods) : MouseEnterEvent () { mousePosition = pos; buttonState = buttons; modifiers = mods; } MouseEnterEvent (const MouseEvent& e) : MouseEnterEvent (e.mousePosition, e.buttonState, e.modifiers) { } }; //------------------------------------------------------------------------ /** MouseExitEvent * @ingroup new_in_4_11 */ struct MouseExitEvent : MouseEvent { MouseExitEvent () { type = EventType::MouseExit; } MouseExitEvent (CPoint pos, MouseEventButtonState buttons, Modifiers mods) : MouseExitEvent () { mousePosition = pos; buttonState = buttons; modifiers = mods; } MouseExitEvent (const MouseEvent& e) : MouseExitEvent (e.mousePosition, e.buttonState, e.modifiers) { } }; //------------------------------------------------------------------------ /** MouseDownUpMoveEvent * @ingroup new_in_4_11 */ struct MouseDownUpMoveEvent : MouseEvent { uint32_t clickCount {0}; void ignoreFollowUpMoveAndUpEvents (bool state) { if (state) consumed.data |= IgnoreFollowUpEventsMask; else consumed.data &= ~IgnoreFollowUpEventsMask; } [[nodiscard]] bool ignoreFollowUpMoveAndUpEvents () { return consumed.data & IgnoreFollowUpEventsMask; } static constexpr uint32_t IgnoreFollowUpEvents = EventConsumeState::Last; static constexpr uint32_t IgnoreFollowUpEventsMask = 1 << IgnoreFollowUpEvents; protected: MouseDownUpMoveEvent () = default; MouseDownUpMoveEvent (const CPoint& pos, MouseEventButtonState buttons, Modifiers mods = {}) { mousePosition = pos; buttonState = buttons; modifiers = mods; } }; //------------------------------------------------------------------------ /** MouseDownEvent * @ingroup new_in_4_11 */ struct MouseDownEvent : MouseDownUpMoveEvent { MouseDownEvent () { type = EventType::MouseDown; } MouseDownEvent (const CPoint& pos, MouseEventButtonState buttons) : MouseDownUpMoveEvent (pos, buttons) { type = EventType::MouseDown; } }; //------------------------------------------------------------------------ /** MouseUpEvent * @ingroup new_in_4_11 */ struct MouseUpEvent : MouseDownUpMoveEvent { MouseUpEvent () { type = EventType::MouseUp; } MouseUpEvent (const CPoint& pos, MouseEventButtonState buttons) : MouseDownUpMoveEvent (pos, buttons) { type = EventType::MouseUp; } }; //------------------------------------------------------------------------ /** MouseMoveEvent * @ingroup new_in_4_11 */ struct MouseMoveEvent : MouseDownUpMoveEvent { MouseMoveEvent () { type = EventType::MouseMove; } MouseMoveEvent (const CPoint& pos, MouseEventButtonState buttons = {}) : MouseDownUpMoveEvent (pos, buttons) { type = EventType::MouseMove; } MouseMoveEvent (const MouseDownUpMoveEvent& other) : MouseDownUpMoveEvent (other.mousePosition, other.buttonState, other.modifiers) { type = EventType::MouseMove; } }; //------------------------------------------------------------------------ /** MouseCancelEvent * @ingroup new_in_4_11 */ struct MouseCancelEvent : Event { MouseCancelEvent () { type = EventType::MouseCancel; } }; //------------------------------------------------------------------------ /** MouseWheelEvent * @ingroup new_in_4_11 */ struct MouseWheelEvent : MousePositionEvent { enum Flags : uint32_t { /** deltaX and deltaY are inverted */ DirectionInvertedFromDevice = 1 << 0, /** indicates a precise scroll event where deltaX and deltaY are multiplied by 0.1. If you * divide the deltas by 0.1 you will get exact pixel movement. */ PreciseDeltas = 1 << 1, }; CCoord deltaX {0.}; CCoord deltaY {0.}; uint32_t flags {0}; MouseWheelEvent () { type = EventType::MouseWheel; } }; //------------------------------------------------------------------------ /** GestureEvent * @ingroup new_in_4_11 */ struct GestureEvent : MousePositionEvent { enum class Phase : uint32_t { Unknown, Begin, Changed, End, }; Phase phase {Phase::Unknown}; }; //------------------------------------------------------------------------ /** ZoomGestureEvent * @ingroup new_in_4_11 */ struct ZoomGestureEvent : GestureEvent { double zoom; ZoomGestureEvent () { type = EventType::ZoomGesture; } }; //------------------------------------------------------------------------ // Keyboard Events //------------------------------------------------------------------------ /** VirtualKey * @ingroup new_in_4_11 */ enum class VirtualKey : uint32_t { None = 0, Back, Tab, Clear, Return, Pause, Escape, Space, Next, End, Home, Left, Up, Right, Down, PageUp, PageDown, Select, Print, Enter, Snapshot, Insert, Delete, Help, NumPad0, NumPad1, NumPad2, NumPad3, NumPad4, NumPad5, NumPad6, NumPad7, NumPad8, NumPad9, Multiply, Add, Separator, Subtract, Decimal, Divide, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, NumLock, Scroll, ShiftModifier, ControlModifier, AltModifier, Equals, // DO NOT CHANGE THE ORDER ABOVE }; //------------------------------------------------------------------------ /** ModifierKey * @ingroup new_in_4_11 */ enum class ModifierKey : uint32_t { /** the left or right shift key */ Shift = 1 << 0, /** the alternate key */ Alt = 1 << 1, /** the control key (Command key on macOS and control key on other platforms) */ Control = 1 << 2, /** the super key (Control key on macOS, Windows key on Windows and Super key on other platforms)*/ Super = 1 << 3, None = 0 }; //------------------------------------------------------------------------ /** KeyboardEvent * @ingroup new_in_4_11 */ struct KeyboardEvent : ModifierEvent { /** UTF-32 character */ char32_t character {0}; /** virtual key */ VirtualKey virt {VirtualKey::None}; /** indicates for a key down event if this is a repeated key down */ bool isRepeat {false}; KeyboardEvent (EventType t = EventType::KeyDown) { type = t; } }; //------------------------------------------------------------------------ /** event as mouse position event or nullpointer if not a mouse position event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MousePositionEventT* asMousePositionEvent (EventT& event) { switch (event.type) { case EventType::ZoomGesture: [[fallthrough]]; case EventType::MouseWheel: [[fallthrough]]; case EventType::MouseDown: [[fallthrough]]; case EventType::MouseMove: [[fallthrough]]; case EventType::MouseUp: [[fallthrough]]; case EventType::MouseEnter: [[fallthrough]]; case EventType::MouseExit: return static_cast (&event); default: break; } return nullptr; } //------------------------------------------------------------------------ /** event as mouse position event or nullpointer if not a mouse position event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseEventT* asMouseEvent (EventT& event) { switch (event.type) { case EventType::MouseDown: [[fallthrough]]; case EventType::MouseMove: [[fallthrough]]; case EventType::MouseUp: [[fallthrough]]; case EventType::MouseEnter: [[fallthrough]]; case EventType::MouseExit: return static_cast (&event); default: break; } return nullptr; } //------------------------------------------------------------------------ /** event as mouse down event or nullpointer if not a mouse down event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseDownEventT* asMouseDownEvent (EventT& event) { switch (event.type) { case EventType::MouseDown: [[fallthrough]]; case EventType::MouseMove: [[fallthrough]]; case EventType::MouseUp: return static_cast (&event); default: break; } return nullptr; } //------------------------------------------------------------------------ /** event as modifier event or nullpointer if not a modifier event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline ModifierEventT* asModifierEvent (EventT& event) { switch (event.type) { case EventType::KeyDown: [[fallthrough]]; case EventType::KeyUp: [[fallthrough]]; case EventType::MouseEnter: [[fallthrough]]; case EventType::MouseExit: [[fallthrough]]; case EventType::MouseWheel: [[fallthrough]]; case EventType::MouseDown: [[fallthrough]]; case EventType::MouseMove: [[fallthrough]]; case EventType::MouseUp: return static_cast (&event); default: break; } return nullptr; } //------------------------------------------------------------------------ /** event as keyboard event or nullpointer if not a keyboard event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline KeyboardEventT* asKeyboardEvent (EventT& event) { switch (event.type) { case EventType::KeyDown: [[fallthrough]]; case EventType::KeyUp: return static_cast (&event); default: break; } return nullptr; } //------------------------------------------------------------------------ /** cast event to a mouse position event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MousePositionEventT& castMousePositionEvent (EventT& event) { vstgui_assert (event.type >= EventType::MouseDown && event.type <= EventType::ZoomGesture); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseEventT& castMouseEvent (EventT& event) { vstgui_assert (event.type >= EventType::MouseDown && event.type <= EventType::MouseExit); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse down event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseDownEventT& castMouseDownEvent (EventT& event) { vstgui_assert (event.type == EventType::MouseDown); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse move event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseMoveEventT& castMouseMoveEvent (EventT& event) { vstgui_assert (event.type == EventType::MouseMove); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse up event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseUpEventT& castMouseUpEvent (EventT& event) { vstgui_assert (event.type == EventType::MouseUp); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse enter event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseEnterEventT& castMouseEnterEvent (EventT& event) { vstgui_assert (event.type == EventType::MouseEnter); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse exit event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseExitEventT& castMouseExitEvent (EventT& event) { vstgui_assert (event.type == EventType::MouseExit); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse cancel event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseCancelEventT& castMouseCancelEvent (EventT& event) { vstgui_assert (event.type == EventType::MouseCancel); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse wheel event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline MouseWheelEventT& castMouseWheelEvent (EventT& event) { vstgui_assert (event.type == EventType::MouseWheel); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a zoom gesture event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline ZoomGestureEventT& castZoomGestureEvent (EventT& event) { vstgui_assert (event.type == EventType::ZoomGesture); return static_cast (event); } //------------------------------------------------------------------------ /** cast event to a mouse wheel event * @ingroup new_in_4_11 */ template, typename std::add_const_t, OutputT>::type> inline KeyboardEventT& castKeyboardEvent (EventT& event) { vstgui_assert (event.type == EventType::KeyDown || event.type == EventType::KeyUp); return static_cast (event); } //------------------------------------------------------------------------ /** convert from new Modifiers to old CButtonState * @ingroup new_in_4_11 */ CButtonState buttonStateFromEventModifiers (const Modifiers& mods); //------------------------------------------------------------------------ /** convert from new MouseEvent to old CButtonState * @ingroup new_in_4_11 */ CButtonState buttonStateFromMouseEvent (const MouseEvent& event); #if VSTGUI_ENABLE_DEPRECATED_METHODS //------------------------------------------------------------------------ /** helper function to convert from new VirtualKey to old VstVirtualKey * * returns 0 if key cannot be mapped * @ingroup new_in_4_11 */ inline unsigned char toVstVirtualKey (VirtualKey key) { auto k = static_cast (key); if (k <= static_cast (VirtualKey::Equals)) return static_cast (k); return 0; } inline VirtualKey fromVstVirtualKey (uint32_t key) { auto k = static_cast (key); if (k <= VirtualKey::Equals) return k; return VirtualKey::None; } VstKeyCode toVstKeyCode (const KeyboardEvent& event); #endif //------------------------------------------------------------------------ } // VSTGUI