mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-27 21:19:18 +00:00
[lua] Add onkeydown/onkeyup events to canvas widget
This commit is contained in:
parent
420278d5a4
commit
17825921e0
@ -182,6 +182,7 @@ if(ENABLE_SCRIPTING)
|
||||
script/image_iterator_class.cpp
|
||||
script/image_spec_class.cpp
|
||||
script/images_class.cpp
|
||||
script/keys.cpp
|
||||
script/layer_class.cpp
|
||||
script/layers_class.cpp
|
||||
script/luacpp.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2022 Igara Studio S.A.
|
||||
// Copyright (c) 2022-2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -29,6 +29,15 @@ ui::WidgetType Canvas::Type()
|
||||
return type;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Canvas::s_stopKeyEventPropagation = false;
|
||||
|
||||
// static
|
||||
void Canvas::stopKeyEventPropagation()
|
||||
{
|
||||
s_stopKeyEventPropagation = true;
|
||||
}
|
||||
|
||||
Canvas::Canvas() : ui::Widget(Type())
|
||||
{
|
||||
}
|
||||
@ -64,6 +73,26 @@ bool Canvas::onProcessMessage(ui::Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
||||
case ui::kKeyDownMessage:
|
||||
if (hasFocus()) {
|
||||
s_stopKeyEventPropagation = false;
|
||||
auto keyMsg = static_cast<ui::KeyMessage*>(msg);
|
||||
KeyDown(keyMsg);
|
||||
if (s_stopKeyEventPropagation)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ui::kKeyUpMessage:
|
||||
if (hasFocus()) {
|
||||
s_stopKeyEventPropagation = false;
|
||||
auto keyMsg = static_cast<ui::KeyMessage*>(msg);
|
||||
KeyUp(keyMsg);
|
||||
if (s_stopKeyEventPropagation)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ui::kSetCursorMessage:
|
||||
ui::set_mouse_cursor(m_cursorType);
|
||||
return true;
|
||||
@ -78,6 +107,9 @@ bool Canvas::onProcessMessage(ui::Message* msg)
|
||||
if (!hasCapture())
|
||||
captureMouse();
|
||||
|
||||
if (isFocusStop() && !hasFocus())
|
||||
requestFocus();
|
||||
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
MouseDown(mouseMsg);
|
||||
break;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2022 Igara Studio S.A.
|
||||
// Copyright (c) 2022-2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -36,13 +36,19 @@ public:
|
||||
}
|
||||
|
||||
obs::signal<void(GraphicsContext&)> Paint;
|
||||
obs::signal<void(ui::KeyMessage*)> KeyDown;
|
||||
obs::signal<void(ui::KeyMessage*)> KeyUp;
|
||||
obs::signal<void(ui::MouseMessage*)> MouseMove;
|
||||
obs::signal<void(ui::MouseMessage*)> MouseDown;
|
||||
obs::signal<void(ui::MouseMessage*)> MouseUp;
|
||||
obs::signal<void(ui::MouseMessage*)> Wheel;
|
||||
obs::signal<void(ui::TouchMessage*)> TouchMagnify;
|
||||
|
||||
static void stopKeyEventPropagation();
|
||||
|
||||
private:
|
||||
static bool s_stopKeyEventPropagation;
|
||||
|
||||
void onInitTheme(ui::InitThemeEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onResize(ui::ResizeEvent& ev) override;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -16,6 +16,7 @@
|
||||
#include "app/script/canvas_widget.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "app/script/graphics_context.h"
|
||||
#include "app/script/keys.h"
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/color_shades.h"
|
||||
@ -914,6 +915,7 @@ int Dialog_canvas(lua_State* L)
|
||||
|
||||
widget->setSizeHint(sz);
|
||||
|
||||
bool handleKeyEvents = false;
|
||||
if (lua_istable(L, 2)) {
|
||||
int type = lua_getfield(L, 2, "onpaint");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
@ -927,6 +929,47 @@ int Dialog_canvas(lua_State* L)
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Auxiliary callbacks used in Canvas events
|
||||
auto keyCallback =
|
||||
[](lua_State* L, ui::KeyMessage* msg) {
|
||||
ASSERT(msg->recipient());
|
||||
if (!msg->recipient())
|
||||
return;
|
||||
|
||||
// Key modifiers
|
||||
lua_pushboolean(L, msg->modifiers() & ui::kKeyAltModifier);
|
||||
lua_setfield(L, -2, "altKey");
|
||||
|
||||
lua_pushboolean(L, msg->modifiers() & (ui::kKeyCmdModifier | ui::kKeyWinModifier));
|
||||
lua_setfield(L, -2, "metaKey");
|
||||
|
||||
lua_pushboolean(L, msg->modifiers() & ui::kKeyCtrlModifier);
|
||||
lua_setfield(L, -2, "ctrlKey");
|
||||
|
||||
lua_pushboolean(L, msg->modifiers() & ui::kKeyShiftModifier);
|
||||
lua_setfield(L, -2, "shiftKey");
|
||||
|
||||
lua_pushboolean(L, msg->modifiers() & ui::kKeySpaceModifier);
|
||||
lua_setfield(L, -2, "spaceKey");
|
||||
|
||||
// KeyMessage specifics
|
||||
lua_pushinteger(L, msg->repeat());
|
||||
lua_setfield(L, -2, "repeat");
|
||||
|
||||
// TODO improve this (create an Event metatable)
|
||||
lua_pushcfunction(L, [](lua_State*) -> int {
|
||||
Canvas::stopKeyEventPropagation();
|
||||
return 0;
|
||||
});
|
||||
lua_setfield(L, -2, "stopPropagation");
|
||||
|
||||
std::wstring keyString(1, (wchar_t)msg->unicodeChar());
|
||||
lua_pushstring(L, base::to_utf8(keyString).c_str());
|
||||
lua_setfield(L, -2, "key");
|
||||
|
||||
lua_pushstring(L, vkcode_to_code(msg->scancode()));
|
||||
lua_setfield(L, -2, "code");
|
||||
};
|
||||
|
||||
auto mouseCallback =
|
||||
[](lua_State* L, ui::MouseMessage* msg) {
|
||||
ASSERT(msg->recipient());
|
||||
@ -970,6 +1013,20 @@ int Dialog_canvas(lua_State* L)
|
||||
lua_setfield(L, -2, "magnification");
|
||||
};
|
||||
|
||||
type = lua_getfield(L, 2, "onkeydown");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
Dialog_connect_signal(L, 1, widget->KeyDown, keyCallback);
|
||||
handleKeyEvents = true;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
type = lua_getfield(L, 2, "onkeyup");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
Dialog_connect_signal(L, 1, widget->KeyUp, keyCallback);
|
||||
handleKeyEvents = true;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
type = lua_getfield(L, 2, "onmousemove");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
Dialog_connect_signal(L, 1, widget->MouseMove, mouseCallback);
|
||||
@ -1000,6 +1057,11 @@ int Dialog_canvas(lua_State* L)
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
// If this canvas handle keydown/up events, we set it as a focus
|
||||
// stop.
|
||||
if (handleKeyEvents)
|
||||
widget->setFocusStop(true);
|
||||
}
|
||||
|
||||
return Dialog_add_widget(L, widget);
|
||||
|
165
src/app/script/keys.cpp
Normal file
165
src/app/script/keys.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ui/keys.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
// Same order that os::KeyScancode
|
||||
// Based on code values of the KeyboardEvent on web code:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values
|
||||
static const char* vkcode_to_code_table[] = {
|
||||
"Unidentified",
|
||||
"KeyA",
|
||||
"KeyB",
|
||||
"KeyC",
|
||||
"KeyD",
|
||||
"KeyE",
|
||||
"KeyF",
|
||||
"KeyG",
|
||||
"KeyH",
|
||||
"KeyI",
|
||||
"KeyJ",
|
||||
"KeyK",
|
||||
"KeyL",
|
||||
"KeyM",
|
||||
"KeyN",
|
||||
"KeyO",
|
||||
"KeyP",
|
||||
"KeyQ",
|
||||
"KeyR",
|
||||
"KeyS",
|
||||
"KeyT",
|
||||
"KeyU",
|
||||
"KeyV",
|
||||
"KeyW",
|
||||
"KeyX",
|
||||
"KeyY",
|
||||
"KeyZ",
|
||||
"Digit0",
|
||||
"Digit1",
|
||||
"Digit2",
|
||||
"Digit3",
|
||||
"Digit4",
|
||||
"Digit5",
|
||||
"Digit6",
|
||||
"Digit7",
|
||||
"Digit8",
|
||||
"Digit9",
|
||||
"Numpad0",
|
||||
"Numpad1",
|
||||
"Numpad2",
|
||||
"Numpad3",
|
||||
"Numpad4",
|
||||
"Numpad5",
|
||||
"Numpad6",
|
||||
"Numpad7",
|
||||
"Numpad8",
|
||||
"Numpad9",
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"F5",
|
||||
"F6",
|
||||
"F7",
|
||||
"F8",
|
||||
"F9",
|
||||
"F10",
|
||||
"F11",
|
||||
"F12",
|
||||
"Escape",
|
||||
"Backquote",
|
||||
"Minus",
|
||||
"Equal",
|
||||
"Backspace",
|
||||
"Tab",
|
||||
"BracketLeft",
|
||||
"BracketRight",
|
||||
"Enter",
|
||||
"Semicolon",
|
||||
"Quote",
|
||||
"Backslash",
|
||||
nullptr, // kKeyBackslash2,
|
||||
"Comma",
|
||||
"Period",
|
||||
"Slash",
|
||||
"Space",
|
||||
"Insert",
|
||||
"Delete",
|
||||
"Home",
|
||||
"End",
|
||||
"PageUp",
|
||||
"PageDown",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"ArrowUp",
|
||||
"ArrowDown",
|
||||
"NumpadDivide",
|
||||
"NumpadMultiply",
|
||||
"NumpadSubtract",
|
||||
"NumpadAdd",
|
||||
"NumpadComma",
|
||||
"NumpadEnter",
|
||||
"PrintScreen",
|
||||
"Pause",
|
||||
nullptr, // kKeyAbntC1
|
||||
"IntlYen",
|
||||
"KanaMode",
|
||||
"Convert",
|
||||
"NonConvert",
|
||||
nullptr, // kKeyAt
|
||||
nullptr, // kKeyCircumflex
|
||||
nullptr, // kKeyColon2
|
||||
nullptr, // kKeyKanji
|
||||
"NumpadEqual", // kKeyEqualsPad
|
||||
"Backquote",
|
||||
nullptr, // kKeySemicolon
|
||||
nullptr, // kKeyUnknown1
|
||||
nullptr, // kKeyUnknown2
|
||||
nullptr, // kKeyUnknown3
|
||||
nullptr, // kKeyUnknown4
|
||||
nullptr, // kKeyUnknown5
|
||||
nullptr, // kKeyUnknown6
|
||||
nullptr, // kKeyUnknown7
|
||||
nullptr, // kKeyUnknown8
|
||||
"ShiftLeft",
|
||||
"ShiftRight",
|
||||
"ControlLeft",
|
||||
"ControlRight",
|
||||
"AltLeft",
|
||||
"AltRight"
|
||||
"MetaLeft",
|
||||
"MetaRight",
|
||||
"ContextMenu",
|
||||
"MetaLeft", // kKeyCommand
|
||||
"ScrollLock",
|
||||
"NumLock",
|
||||
"CapsLock",
|
||||
};
|
||||
|
||||
static int vkcode_to_code_table_size =
|
||||
sizeof(vkcode_to_code_table) / sizeof(vkcode_to_code_table[0]);
|
||||
|
||||
const char* vkcode_to_code(const ui::KeyScancode vkcode)
|
||||
{
|
||||
if (vkcode >= 0 &&
|
||||
vkcode < vkcode_to_code_table_size &&
|
||||
vkcode_to_code_table[vkcode]) {
|
||||
return vkcode_to_code_table[vkcode];
|
||||
}
|
||||
else {
|
||||
return vkcode_to_code_table[0];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
21
src/app/script/keys.h
Normal file
21
src/app/script/keys.h
Normal file
@ -0,0 +1,21 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_SCRIPT_KEYS_H_INCLUDED
|
||||
#define APP_SCRIPT_KEYS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "ui/keys.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
const char* vkcode_to_code(const ui::KeyScancode vkcode);
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user