Files
2026-08-16 18:24:52 +07:00

844 lines
23 KiB
C++

// 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<ModifierKey>& 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<ModifierKey>& 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<uint32_t> (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<MouseButton> (1 << index);
}
[[nodiscard]] bool has (MouseButton pos) const
{
return static_cast<bool> (static_cast<uint32_t> (data) & static_cast<uint32_t> (pos));
}
[[nodiscard]] bool empty () const { return data == MouseButton::None; }
void add (MouseButton pos)
{
data =
static_cast<MouseButton> (static_cast<uint32_t> (data) | static_cast<uint32_t> (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 EventT, typename OutputT = MousePositionEvent,
typename MousePositionEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, 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<MousePositionEventT*> (&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 EventT, typename OutputT = MouseEvent,
typename MouseEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, 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<MouseEventT*> (&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 EventT, typename OutputT = MouseDownEvent,
typename MouseDownEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseDownEventT* asMouseDownEvent (EventT& event)
{
switch (event.type)
{
case EventType::MouseDown:
[[fallthrough]];
case EventType::MouseMove:
[[fallthrough]];
case EventType::MouseUp:
return static_cast<MouseDownEventT*> (&event);
default:
break;
}
return nullptr;
}
//------------------------------------------------------------------------
/** event as modifier event or nullpointer if not a modifier event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = ModifierEvent,
typename ModifierEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, 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<ModifierEventT*> (&event);
default:
break;
}
return nullptr;
}
//------------------------------------------------------------------------
/** event as keyboard event or nullpointer if not a keyboard event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = KeyboardEvent,
typename KeyboardEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline KeyboardEventT* asKeyboardEvent (EventT& event)
{
switch (event.type)
{
case EventType::KeyDown:
[[fallthrough]];
case EventType::KeyUp:
return static_cast<KeyboardEventT*> (&event);
default:
break;
}
return nullptr;
}
//------------------------------------------------------------------------
/** cast event to a mouse position event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MousePositionEvent,
typename MousePositionEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MousePositionEventT& castMousePositionEvent (EventT& event)
{
vstgui_assert (event.type >= EventType::MouseDown && event.type <= EventType::ZoomGesture);
return static_cast<MousePositionEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseEvent,
typename MouseEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseEventT& castMouseEvent (EventT& event)
{
vstgui_assert (event.type >= EventType::MouseDown && event.type <= EventType::MouseExit);
return static_cast<MouseEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse down event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseDownEvent,
typename MouseDownEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseDownEventT& castMouseDownEvent (EventT& event)
{
vstgui_assert (event.type == EventType::MouseDown);
return static_cast<MouseDownEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse move event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseMoveEvent,
typename MouseMoveEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseMoveEventT& castMouseMoveEvent (EventT& event)
{
vstgui_assert (event.type == EventType::MouseMove);
return static_cast<MouseMoveEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse up event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseUpEvent,
typename MouseUpEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseUpEventT& castMouseUpEvent (EventT& event)
{
vstgui_assert (event.type == EventType::MouseUp);
return static_cast<MouseUpEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse enter event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseEnterEvent,
typename MouseEnterEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseEnterEventT& castMouseEnterEvent (EventT& event)
{
vstgui_assert (event.type == EventType::MouseEnter);
return static_cast<MouseEnterEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse exit event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseExitEvent,
typename MouseExitEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseExitEventT& castMouseExitEvent (EventT& event)
{
vstgui_assert (event.type == EventType::MouseExit);
return static_cast<MouseExitEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse cancel event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseCancelEvent,
typename MouseCancelEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseCancelEventT& castMouseCancelEvent (EventT& event)
{
vstgui_assert (event.type == EventType::MouseCancel);
return static_cast<MouseCancelEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse wheel event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = MouseWheelEvent,
typename MouseWheelEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline MouseWheelEventT& castMouseWheelEvent (EventT& event)
{
vstgui_assert (event.type == EventType::MouseWheel);
return static_cast<MouseWheelEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a zoom gesture event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = ZoomGestureEvent,
typename ZoomGestureEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline ZoomGestureEventT& castZoomGestureEvent (EventT& event)
{
vstgui_assert (event.type == EventType::ZoomGesture);
return static_cast<ZoomGestureEventT&> (event);
}
//------------------------------------------------------------------------
/** cast event to a mouse wheel event
* @ingroup new_in_4_11
*/
template<typename EventT, typename OutputT = KeyboardEvent,
typename KeyboardEventT = typename std::conditional<
std::is_const_v<EventT>, typename std::add_const_t<OutputT>, OutputT>::type>
inline KeyboardEventT& castKeyboardEvent (EventT& event)
{
vstgui_assert (event.type == EventType::KeyDown || event.type == EventType::KeyUp);
return static_cast<KeyboardEventT&> (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<uint32_t> (key);
if (k <= static_cast<uint32_t> (VirtualKey::Equals))
return static_cast<unsigned char> (k);
return 0;
}
inline VirtualKey fromVstVirtualKey (uint32_t key)
{
auto k = static_cast<VirtualKey> (key);
if (k <= VirtualKey::Equals)
return k;
return VirtualKey::None;
}
VstKeyCode toVstKeyCode (const KeyboardEvent& event);
#endif
//------------------------------------------------------------------------
} // VSTGUI