Skip to content

Commit

Permalink
Better keyboard support for SDL
Browse files Browse the repository at this point in the history
  • Loading branch information
ubald committed Sep 30, 2017
1 parent f6a7d19 commit 900e90f
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 123 deletions.
3 changes: 3 additions & 0 deletions psychic-ui/Application.cpp
Expand Up @@ -40,4 +40,7 @@ namespace psychic_ui {
return _stencilBits;
}

void SystemWindow::startTextInput() {}

void SystemWindow::stopTextInput() {}
}
5 changes: 4 additions & 1 deletion psychic-ui/Application.hpp
Expand Up @@ -45,6 +45,9 @@ namespace psychic_ui {
virtual void setSize(int width, int height) = 0;
virtual void setPosition(int x, int y) = 0;

virtual void startTextInput();
virtual void stopTextInput();

protected:
Application *_application;
std::shared_ptr<Window> _window;
Expand All @@ -54,7 +57,7 @@ namespace psychic_ui {
int _windowDragMouseY{0};
int _windowDragOffsetX{0};
int _windowDragOffsetY{0};

double _lastInteraction{0};
int _stencilBits{8};
int _samples{4};
Expand Down
31 changes: 31 additions & 0 deletions psychic-ui/Div.cpp
Expand Up @@ -1371,6 +1371,37 @@ namespace psychic_ui {
return ret == Out ? Over : ret;
}

MouseEventStatus Div::doubleClick(const int mouseX, const int mouseY, const int button, const int modifiers) {
if (!_visible || !boundsContains(mouseX, mouseY)) {
return Out;
}

if (!_mouseDown) {
return Over;
}

int localMouseX = mouseX - _x - _scrollX;
int localMouseY = mouseY - _y - _scrollY;
MouseEventStatus ret = Out;

if (_mouseChildren) {
for (auto &child: _children) {
auto res = child->doubleClick(localMouseX, localMouseY, button, modifiers);
if (res != Out) {
ret = res;
break;
}
}
}

if (_mouseEnabled && ret != Handled && onDoubleClick.hasSubscriptions()) {
onDoubleClick();
ret = Handled;
}

return ret == Out ? Over : ret;
}

// endregion

// region Move
Expand Down
37 changes: 20 additions & 17 deletions psychic-ui/Div.hpp
Expand Up @@ -5,6 +5,7 @@
#include <vector>
#include <unordered_set>
#include <yoga/Yoga.h>
#include <unicode/unistr.h>
#include <SkCanvas.h>
#include <SkRRect.h>
#include "psychic-ui.hpp"
Expand All @@ -26,17 +27,17 @@ namespace psychic_ui {
/**
* Mouse was outside the component
*/
Out,
Out,

/**
* Mouse was over the component but no event was handled
*/
Over,
Over,

/**
* Mouse is over the component and an event was handled
*/
Handled
Handled
};

/**
Expand Down Expand Up @@ -174,15 +175,15 @@ namespace psychic_ui {
void removeAll();

/**
* Get the childat index
* @param index Index of the child to retreive
* Get the child at index
* @param index Index of the child to retrieve
* @return Const pointer to the Div at index
*/
const Div *at(unsigned int index) const;

/**
* Get the childat index
* @param index Index of the child to retreive
* Get the child at index
* @param index Index of the child to retrieve
* @return Pointer to the Div at index
*/
Div *at(unsigned int index);
Expand All @@ -192,7 +193,7 @@ namespace psychic_ui {
* @param child Shared pointer to a child
* @return Index of the child
*/
int childIndex(const std::shared_ptr<Div> child) const;
int childIndex(std::shared_ptr<Div> child) const;

/**
* Get the index of a child by pointer
Expand Down Expand Up @@ -409,6 +410,7 @@ namespace psychic_ui {
Signal<> onMouseOut{};
Signal<const int, const int, const double, const double> onMouseScroll{};
Signal<> onClick{};
Signal<> onDoubleClick{};

// endregion

Expand All @@ -423,18 +425,19 @@ namespace psychic_ui {
virtual MouseEventStatus mouseDown(int mouseX, int mouseY, int button, int modifiers);
virtual MouseEventStatus mouseUp(int mouseX, int mouseY, int button, int modifiers);
virtual MouseEventStatus click(int mouseX, int mouseY, int button, int modifiers);
virtual MouseEventStatus doubleClick(int mouseX, int mouseY, int button, int modifiers);
virtual MouseEventStatus mouseScrolled(int mouseX, int mouseY, double scrollX, double scrollY);

using KeySlot = std::shared_ptr<Slot<Key>>;
using CharSlot = std::shared_ptr<Slot<unsigned int>>;
using KeySlot = std::shared_ptr<Slot<Key, Mod>>;
using CharSlot = std::shared_ptr<Slot<const UnicodeString &>>;
using FocusSlot = std::shared_ptr<Slot<>>;

Signal<Key> onKeyDown{};
Signal<Key> onKeyRepeat{};
Signal<Key> onKeyUp{};
Signal<unsigned int> onCharacter{};
Signal<> onFocus{};
Signal<> onBlur{};
Signal<Key, Mod> onKeyDown{};
Signal<Key, Mod> onKeyRepeat{};
Signal<Key, Mod> onKeyUp{};
Signal<const UnicodeString &> onCharacter{};
Signal<> onFocus{};
Signal<> onBlur{};

// endregion

Expand All @@ -460,7 +463,6 @@ namespace psychic_ui {

// region Hierarchy


/**
* Set the parent of that div
* Used internally when adding/removing a child to/from a parent
Expand Down Expand Up @@ -679,6 +681,7 @@ namespace psychic_ui {
bool _mouseDown{false};



// endregion

private:
Expand Down
69 changes: 53 additions & 16 deletions psychic-ui/Window.cpp
Expand Up @@ -390,54 +390,91 @@ namespace psychic_ui {

// endregion

// region MouseEvents

MouseEventStatus Window::mouseButton(int mouseX, int mouseY, int button, bool down, int modifiers) {
auto res = Div::mouseButton(mouseX, mouseY, button, down, modifiers);

if (down) {
mouseDown(mouseX, mouseY, button, modifiers);
} else {
click(mouseX, mouseY, button, modifiers);

auto now = std::chrono::high_resolution_clock::now();
double delta = std::chrono::duration_cast<std::chrono::milliseconds>(now - _lastClick).count();
if (delta <= 500) {
doubleClick(mouseX, mouseY, button, modifiers);
}
_lastClick = now;

mouseUp(mouseX, mouseY, button, modifiers);
}

return res;
}

// endregion

// region Keyboard Events

bool Window::keyDown(Key key) {
void Window::startTextInput() {
if (_systemWindow) {
_systemWindow->startTextInput();
}
}

void Window::stopTextInput() {
if (_systemWindow) {
_systemWindow->stopTextInput();
}
}

bool Window::keyDown(Key key, Mod mod) {
// Go backwards since we want to cancel as soon as possible when a child handles it
for (auto focused = _focusPath.rbegin(); focused != _focusPath.rend(); ++focused) {
// Everyone in the focus path gets the key events, focusEnabled or not
Div *component = (*focused);
if (component->onKeyDown.hasSubscriptions()) {
component->onKeyDown(key);
Div *div = (*focused);
if (div->onKeyDown.hasSubscriptions()) {
div->onKeyDown(key, mod);
return true;
}
}
return false;
}

bool Window::keyRepeat(Key key) {
bool Window::keyRepeat(Key key, Mod mod) {
// Go backwards since we want to cancel as soon as possible when a child handles it
for (auto focused = _focusPath.rbegin(); focused != _focusPath.rend(); ++focused) {
// Everyone in the focus path gets the key events, focusEnabled or not
Div *component = (*focused);
if (component->onKeyRepeat.hasSubscriptions()) {
component->onKeyRepeat(key);
Div *div = (*focused);
if (div->onKeyRepeat.hasSubscriptions()) {
div->onKeyRepeat(key, mod);
return true;
}
}
return false;
}

bool Window::keyUp(Key key) {
bool Window::keyUp(Key key, Mod mod) {
// Go backwards since we want to cancel as soon as possible when a child handles it
for (auto focused = _focusPath.rbegin(); focused != _focusPath.rend(); ++focused) {
// Everyone in the focus path gets the key events, focusEnabled or not
Div *component = (*focused);
if (component->onKeyUp.hasSubscriptions()) {
component->onKeyUp(key);
Div *div = (*focused);
if (div->onKeyUp.hasSubscriptions()) {
div->onKeyUp(key, mod);
return true;
}
}
return false;
}

bool Window::keyboardCharacterEvent(unsigned int codepoint) {
bool Window::keyboardCharacterEvent(const UnicodeString &character) {
// Go backwards since we want to cancel as soon as possible when a child handles it
for (auto focused = _focusPath.rbegin(); focused != _focusPath.rend(); ++focused) {
// Only the focusEnabled divs get the character events
Div *component = (*focused);
if (component->onCharacter.hasSubscriptions()) {
component->onCharacter(codepoint);
Div *div = (*focused);
if (div->onCharacter.hasSubscriptions()) {
div->onCharacter(character);
return true;
}
}
Expand Down
33 changes: 24 additions & 9 deletions psychic-ui/Window.hpp
Expand Up @@ -4,6 +4,7 @@
#include <chrono>
#include <memory>
#include <unordered_map>
#include <unicode/unistr.h>
#include "GrContext.h"
#include "SkSurface.h"
#include "SkCanvas.h"
Expand Down Expand Up @@ -64,7 +65,7 @@ namespace psychic_ui {
virtual void drawContents();
void drawComponents();

void openMenu(const std::vector<std::shared_ptr<MenuItem>> &items, const int x, const int y);
void openMenu(const std::vector<std::shared_ptr<MenuItem>> &items, int x, int y);
void closeMenu();

std::shared_ptr<Div> appContainer() const {
Expand Down Expand Up @@ -112,7 +113,10 @@ namespace psychic_ui {

// endregion



// region Window Delegate

virtual void windowMoved(int x, int y);
virtual void windowResized(int width, int height);
virtual void windowActivated();
Expand All @@ -124,11 +128,22 @@ namespace psychic_ui {

virtual bool dropEvent(const std::vector<std::string> & /* filenames */) { return false; /* To be overridden */ }

// endregion

// region Mouse
MouseEventStatus mouseButton(int mouseX, int mouseY, int button, bool down, int modifiers) override;
std::chrono::time_point<std::chrono::high_resolution_clock> _lastClick{};
// endregion

// region Keyboard

void startTextInput();
void stopTextInput();

bool keyDown(Key key);
bool keyRepeat(Key key);
bool keyUp(Key key);
bool keyboardCharacterEvent(unsigned int codepoint);
bool keyDown(Key key, Mod mod);
bool keyRepeat(Key key, Mod mod);
bool keyUp(Key key, Mod mod);
bool keyboardCharacterEvent(const UnicodeString &character);

// endregion

Expand All @@ -146,9 +161,9 @@ namespace psychic_ui {
// region Rendering

SystemWindow *_systemWindow{nullptr};
GrContext *_sk_context{nullptr};
SkSurface *_sk_surface{nullptr};
SkCanvas *_sk_canvas{nullptr};
GrContext *_sk_context{nullptr};
SkSurface *_sk_surface{nullptr};
SkCanvas *_sk_canvas{nullptr};

// endregion

Expand Down Expand Up @@ -186,7 +201,7 @@ namespace psychic_ui {

// region Focus

std::vector<Div*> _focusPath{};
std::vector<Div *> _focusPath{};

// endregion

Expand Down

0 comments on commit 900e90f

Please sign in to comment.