Skip to content

Commit

Permalink
Add support for clipboard and file/text drop events
Browse files Browse the repository at this point in the history
  • Loading branch information
cjhoward committed Dec 15, 2023
1 parent d2d2397 commit 855a839
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 36 deletions.
25 changes: 15 additions & 10 deletions src/engine/app/input-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <engine/event/dispatcher.hpp>
#include <map>
#include <memory>
#include <string>
#include <unordered_set>

namespace app {
Expand All @@ -21,17 +22,13 @@ namespace app {
class input_manager
{
public:
/**
* Allocates and returns an input manager.
*/
/** Allocates and returns an input manager. */
static std::unique_ptr<input_manager> instance();

/// Destructs an input manager.
/** Destructs an input manager. */
virtual ~input_manager() = default;

/**
* Processes input events.
*/
/** Processes input events. */
virtual void update() = 0;

/**
Expand All @@ -49,9 +46,17 @@ class input_manager
virtual void set_relative_mouse_mode(bool enabled) = 0;

/**
* Returns the event dispatcher associated with registered input devices.
* Sets the clipboard text.
*
* @param text UTF-8 text.
*/
virtual void set_clipboard_text(const std::string& text) = 0;

/** Returns UTF-8 text from the clipboard. */
[[nodiscard]] virtual std::string get_clipboard_text() const = 0;

/// @{
/** Returns the event dispatcher associated with registered input devices. */
[[nodiscard]] inline const ::event::dispatcher& get_event_dispatcher() const noexcept
{
return m_event_dispatcher;
Expand Down Expand Up @@ -81,24 +86,24 @@ class input_manager
}

protected:
/// @{
/**
* Registers an input device.
*
* @param device Input device to register.
*/
/// @{
void register_device(input::device& device);
void register_gamepad(input::gamepad& device);
void register_keyboard(input::keyboard& device);
void register_mouse(input::mouse& device);
/// @}

/// @{
/**
* Unregisters an input device.
*
* @param device Input device to unregister.
*/
/// @{
void unregister_device(input::device& device);
void unregister_gamepad(input::gamepad& device);
void unregister_keyboard(input::keyboard& device);
Expand Down
36 changes: 33 additions & 3 deletions src/engine/app/sdl/sdl-input-manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <engine/app/sdl/sdl-input-manager.hpp>
#include <engine/input/application-events.hpp>
#include <engine/input/clipboard-events.hpp>
#include <engine/input/input-update-event.hpp>
#include <engine/debug/log.hpp>
#include <engine/math/functions.hpp>
Expand Down Expand Up @@ -72,7 +73,7 @@ void sdl_input_manager::update()
{
case SDL_QUIT:
debug::log_debug("Application quit requested");
this->m_event_dispatcher.dispatch<input::application_quit_event>({});
m_event_dispatcher.dispatch<input::application_quit_event>({});
break;

default:
Expand All @@ -85,7 +86,7 @@ void sdl_input_manager::update()
{
// Get next display or window event
SDL_Event event;
const int status = SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_KEYDOWN, SDL_LASTEVENT);
const int status = SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_KEYDOWN, SDL_CLIPBOARDUPDATE);

if (!status)
{
Expand Down Expand Up @@ -293,13 +294,19 @@ void sdl_input_manager::update()
break;
}

[[unlikely]] case SDL_CLIPBOARDUPDATE:
{
m_event_dispatcher.dispatch<input::clipboard_updated_event>({});
break;
}

default:
break;
}
}

// Dispatch input update event
this->m_event_dispatcher.dispatch<input::update_event>({});
m_event_dispatcher.dispatch<input::update_event>({});
}

void sdl_input_manager::set_cursor_visible(bool visible)
Expand All @@ -320,4 +327,27 @@ void sdl_input_manager::set_relative_mouse_mode(bool enabled)
}
}

void sdl_input_manager::set_clipboard_text(const std::string& text)
{
if (SDL_SetClipboardText(text.c_str()) != 0)
{
debug::log_error("Failed to set clipboard text: \"{}\"", SDL_GetError());
SDL_ClearError();
}
}

std::string sdl_input_manager::get_clipboard_text() const
{
// Get SDL-allocated text from clipboard
auto sdl_clipboard_text = SDL_GetClipboardText();

// Copy text into string
std::string clipboard_text = sdl_clipboard_text;

// Free SDL-allocated text
SDL_free(sdl_clipboard_text);

return clipboard_text;
}

} // namespace app
10 changes: 4 additions & 6 deletions src/engine/app/sdl/sdl-input-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,17 @@ class sdl_window;
class sdl_input_manager: public input_manager
{
public:
/**
* Constructs an SDL input manager.
*/
/** Constructs an SDL input manager. */
sdl_input_manager();

/**
* Destructs an SDL input manager.
*/
/** Destructs an SDL input manager. */
~sdl_input_manager() override;

void update() override;
void set_cursor_visible(bool visible) override;
void set_relative_mouse_mode(bool enabled) override;
void set_clipboard_text(const std::string& text) override;
[[nodiscard]] std::string get_clipboard_text() const override;

private:
input::keyboard m_keyboard;
Expand Down
82 changes: 81 additions & 1 deletion src/engine/app/sdl/sdl-window-manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ sdl_window_manager::sdl_window_manager()
}
debug::log_trace("Initialized SDL events and video subsystems");

// Disable unused events
SDL_EventState(SDL_AUDIODEVICEADDED, SDL_IGNORE);
SDL_EventState(SDL_AUDIODEVICEREMOVED, SDL_IGNORE);
SDL_EventState(SDL_RENDER_TARGETS_RESET, SDL_IGNORE);
SDL_EventState(SDL_RENDER_DEVICE_RESET, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);

// Query displays
const int display_count = SDL_GetNumVideoDisplays();
if (display_count < 1)
Expand Down Expand Up @@ -117,7 +124,7 @@ void sdl_window_manager::update()

for (;;)
{
// Get next window or display event
// Get next window or displayp event
SDL_Event event;
int status = SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_DISPLAYEVENT, SDL_SYSWMEVENT);

Expand Down Expand Up @@ -387,6 +394,79 @@ void sdl_window_manager::update()
}
}
}

for (;;)
{
// Get next drop event
SDL_Event event;
int status = SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_DROPFILE, SDL_DROPCOMPLETE);

if (!status)
{
break;
}
else if (status < 0)
{
debug::log_error("Failed to peep SDL events: {}", SDL_GetError());
throw std::runtime_error("Failed to peep SDL events");
}

switch (event.type)
{
case SDL_DROPFILE:
{
// Get window
auto window = get_window(SDL_GetWindowFromID(event.drop.windowID));

// Publish drop file event
window->m_drop_file_publisher.publish({window, std::filesystem::path(event.drop.file)});

// Free file path
SDL_free(event.drop.file);

break;
}

case SDL_DROPTEXT:
{
// Get window
auto window = get_window(SDL_GetWindowFromID(event.drop.windowID));

// Publish drop text event
window->m_drop_text_publisher.publish({window, std::string(event.drop.file)});

// Free text
SDL_free(event.drop.file);

break;
}

case SDL_DROPBEGIN:
{
// Get window
auto window = get_window(SDL_GetWindowFromID(event.drop.windowID));

// Publish drop begin event
window->m_drop_begin_publisher.publish({window});

break;
}

case SDL_DROPCOMPLETE:
{
// Get window
auto window = get_window(SDL_GetWindowFromID(event.drop.windowID));

// Publish drop end event
window->m_drop_end_publisher.publish({window});

break;
}

default:
break;
}
}
}

sdl_window* sdl_window_manager::get_window(SDL_Window* internal_window)
Expand Down
44 changes: 44 additions & 0 deletions src/engine/app/window-events.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#define ANTKEEPER_APP_WINDOW_EVENTS_HPP

#include <engine/math/vector.hpp>
#include <filesystem>
#include <string>

namespace app {

Expand Down Expand Up @@ -82,6 +84,48 @@ struct window_resized_event
math::ivec2 size{0, 0};
};

/**
* Event generated when data is about to be dropped onto a window.
*/
struct window_drop_begin_event
{
/// Pointer to the window onto which data has been dropped.
window* window{nullptr};
};

/**
* Event generated when data has finished dropping onto a window.
*/
struct window_drop_end_event
{
/// Pointer to the window onto which data has been dropped.
window* window{nullptr};
};

/**
* Event generated when a file is dropped onto a window.
*/
struct window_drop_file_event
{
/// Pointer to the window onto which a file has been dropped.
window* window{nullptr};

/// Path to the dropped file.
std::filesystem::path file_path;
};

/**
* Event generated when text is dropped onto a window.
*/
struct window_drop_text_event
{
/// Pointer to the window onto which text has been dropped.
window* window{nullptr};

/// String containing the dropped text.
std::string text;
};

} // namespace app

#endif // ANTKEEPER_APP_WINDOW_EVENTS_HPP

0 comments on commit 855a839

Please sign in to comment.