From: Hosang Kim Date: Mon, 12 Apr 2021 10:45:34 +0000 (+0900) Subject: libaurum: add synchronize API X-Git-Tag: submit/tizen/20210525.032747~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=373712d219167dad48d10c76e4cd3fc98c36fc63;p=platform%2Fcore%2Fuifw%2Faurum.git libaurum: add synchronize API Add two api for synchronize, waitForEvents, sendKeyAndWaitForEvents. sample: mDevice->sendKeyAndWaitForEvents("Left", A11yEvent::EVENT_STATE_CHANGED_FOCUSED, 5000) mDevice->waitForEvents(A11yEvent::EVENT_WINDOW_DEACTIVATE, 5000) Change-Id: If3886af4b2331f5e50f35e1dfcd27780c9618b93 --- diff --git a/libaurum/inc/A11yEvent.h b/libaurum/inc/A11yEvent.h new file mode 100644 index 0000000..43da498 --- /dev/null +++ b/libaurum/inc/A11yEvent.h @@ -0,0 +1,49 @@ +#pragma once +#include "bitmask.h" + +#include + +enum class A11yEvent { + EVENT_NONE = 0x00000, + EVENT_WINDOW_CREATE = 0x00001, + EVENT_WINDOW_CLOSE = 0x00002, + EVENT_WINDOW_MINIMIZE = 0x00004, + EVENT_WINDOW_MAXIMIZE = 0x00008, + EVENT_WINDOW_RESTORE = 0x00010, + EVENT_WINDOW_ACTIVATE = 0x00020, + EVENT_WINDOW_DEACTIVATE = 0x00040, + EVENT_WINDOW_RAISE = 0x00080, + EVENT_WINDOW_LOWER = 0x00100, + EVENT_WINDOW_MOVE = 0x00200, + EVENT_WINDOW_RESIZE = 0x00400, + + EVENT_TEXT_CHANGED_INSERT = 0x00800, + EVENT_TEXT_CHANGED_DELETE = 0x01000, + + EVENT_STATE_CHANGED_VISIBLE = 0x02000, + EVENT_STATE_CHANGED_FOCUSED = 0x04000, + EVENT_STATE_CHANGED_CHECKED = 0x08000, + EVENT_STATE_CHANGED_PRESSED = 0x10000, + EVENT_STATE_CHANGED_SELECTED = 0x20000, +}; + +enableEnumClassBitfield(A11yEvent); + +class A11yEventInfo { +public: + A11yEventInfo(); + A11yEventInfo(A11yEvent event, std::string name = "", std::string pkg = ""); + A11yEventInfo(std::string event, std::string name = "", std::string pkg = ""); + ~A11yEventInfo(); +public: + A11yEvent getEvent(); + A11yEvent getEvent(std::string event); + std::string getName(); + std::string getPkg(); + +protected: + const A11yEvent mEvent; + const std::string mName; + const std::string mPkg; +}; + diff --git a/libaurum/inc/Accessibility/AccessibleWatcher.h b/libaurum/inc/Accessibility/AccessibleWatcher.h index d767742..e695057 100644 --- a/libaurum/inc/Accessibility/AccessibleWatcher.h +++ b/libaurum/inc/Accessibility/AccessibleWatcher.h @@ -6,6 +6,8 @@ #include "AccessibleNode.h" #include "AccessibleUtils.h" #include "IEventSource.h" +#include "Runnable.h" +#include "A11yEvent.h" #include #include @@ -57,6 +59,12 @@ public: */ virtual std::vector> getApplications(void) const = 0; + /**s + * @brief TBD + * @since_tizen 6.5 + */ + virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) = 0; + public: /** * @brief TBD @@ -92,4 +100,4 @@ private: * @brief TBD */ std::mutex mLock; -}; \ No newline at end of file +}; diff --git a/libaurum/inc/Impl/Accessibility/AtspiAccessibleWatcher.h b/libaurum/inc/Impl/Accessibility/AtspiAccessibleWatcher.h index 3eb3566..3d8294f 100644 --- a/libaurum/inc/Impl/Accessibility/AtspiAccessibleWatcher.h +++ b/libaurum/inc/Impl/Accessibility/AtspiAccessibleWatcher.h @@ -97,6 +97,12 @@ public: */ virtual std::vector> getApplications(void) const override; + /** + * @brief TBD + * @since_tizen 6.5 + */ + virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) override; + public: /** * @brief TBD @@ -140,6 +146,11 @@ public: */ void onObjectDefunct(AtspiAccessible* node) override; + /** + * @brief TBD + * @since_tizen 6.5 + */ + static void onEventListener(AtspiEvent *event, void *user_data); private: /** * @brief TBD @@ -167,12 +178,25 @@ private: void print_debug(); -private: + /** + * @brief TBD + * @since_tizen 6.5 + */ + void addEventListener(AtspiEventListener *listener, A11yEvent type); + + /** + * @brief TBD + * @since_tizen 6.5 + */ + void removeEventListener(AtspiEventListener *listener, A11yEvent type); + +public: /** * @brief TBD */ - static AtspiEventListener * listener; + static guint timeoutId; +private: /** * @brief TBD */ @@ -198,4 +222,13 @@ private: */ std::map mWindowAppMap; -}; \ No newline at end of file + /** + * @brief TBD + */ + static GThread * mEventThread; + + /** + * @brief TBD + */ + static std::vector> mEventQueue; +}; diff --git a/libaurum/inc/Impl/Accessibility/MockAccessibleWatcher.h b/libaurum/inc/Impl/Accessibility/MockAccessibleWatcher.h index 5262cf2..c183248 100644 --- a/libaurum/inc/Impl/Accessibility/MockAccessibleWatcher.h +++ b/libaurum/inc/Impl/Accessibility/MockAccessibleWatcher.h @@ -42,6 +42,12 @@ public: */ virtual std::vector> getApplications(void) const override; + /** + * @brief TBD + * @since_tizen 6.5 + */ + virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) override; + public: /** * @brief TBD @@ -60,4 +66,4 @@ private: * @brief TBD */ std::vector> mApplicationList; -}; \ No newline at end of file +}; diff --git a/libaurum/inc/Runnable/Runnable.h b/libaurum/inc/Runnable/Runnable.h new file mode 100644 index 0000000..354c90f --- /dev/null +++ b/libaurum/inc/Runnable/Runnable.h @@ -0,0 +1,9 @@ +#pragma once + +class Runnable +{ +public: + virtual ~Runnable() { } + virtual void run() const = 0; +}; + diff --git a/libaurum/inc/Runnable/Runnables.h b/libaurum/inc/Runnable/Runnables.h new file mode 100644 index 0000000..1428466 --- /dev/null +++ b/libaurum/inc/Runnable/Runnables.h @@ -0,0 +1,3 @@ +#pragma once + +#include "SendKeyRunnable.h" diff --git a/libaurum/inc/Runnable/SendKeyRunnable.h b/libaurum/inc/Runnable/SendKeyRunnable.h new file mode 100644 index 0000000..57cf886 --- /dev/null +++ b/libaurum/inc/Runnable/SendKeyRunnable.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include "Runnable.h" + +class SendKeyRunnable : public Runnable { +protected: + std::string mKeycode; + +public: + SendKeyRunnable(std::string keycode); + void run() const override; +}; diff --git a/libaurum/inc/UiDevice.h b/libaurum/inc/UiDevice.h index ce9fd1f..504ceff 100644 --- a/libaurum/inc/UiDevice.h +++ b/libaurum/inc/UiDevice.h @@ -10,6 +10,9 @@ #include "AccessibleNode.h" #include "Waiter.h" +#include "Runnable.h" +#include "A11yEvent.h" + #include #include @@ -158,6 +161,23 @@ public: std::shared_ptr waitFor( const std::function(const ISearchable *)> condition) const; + + /** + * @brief TBD + * @since_tizen 6.5 + */ + bool waitForEvents( + const A11yEvent type, const int timeout) const; + + /** + * @brief TBD + * @since_tizen 6.5 + */ + bool sendKeyAndWaitForEvents( + const std::string keycode, const A11yEvent type, const int timeout) const; +private: + bool executeAndWaitForEvents( + const Runnable *cmd, const A11yEvent type, const int timeout) const; public: /** * @brief TBD @@ -206,4 +226,4 @@ private: * @brief TBD */ const Waiter *mWaiter; -}; \ No newline at end of file +}; diff --git a/libaurum/inc/bitmask.h b/libaurum/inc/bitmask.h new file mode 100644 index 0000000..0dda2f6 --- /dev/null +++ b/libaurum/inc/bitmask.h @@ -0,0 +1,72 @@ +#pragma once +#include + +template +struct enable_bitmask_operators{ + static const bool enable=false; +}; + +#define enableEnumClassBitfield(E) template<> \ + struct enable_bitmask_operators{ \ + static const bool enable=true; \ + } + +template +typename std::enable_if_t::enable,E> +operator|(E lhs,E rhs){ + typedef typename std::underlying_type_t underlying; + return static_cast( + static_cast(lhs) | static_cast(rhs)); +} + +template +typename std::enable_if_t::enable,E> +operator&(E lhs,E rhs){ + typedef typename std::underlying_type_t underlying; + return static_cast( + static_cast(lhs) & static_cast(rhs)); +} + +template +typename std::enable_if_t::enable,E> +operator^(E lhs,E rhs){ + typedef typename std::underlying_type_t underlying; + return static_cast( + static_cast(lhs) ^ static_cast(rhs)); +} + +template +typename std::enable_if_t::enable,E> +operator~(E lhs){ + typedef typename std::underlying_type_t underlying; + return static_cast( + ~static_cast(lhs)); +} + +template +typename std::enable_if_t::enable,E&> +operator|=(E& lhs,E rhs){ + typedef typename std::underlying_type_t underlying; + lhs=static_cast( + static_cast(lhs) | static_cast(rhs)); + return lhs; +} + +template +typename std::enable_if_t::enable,E&> +operator&=(E& lhs,E rhs){ + typedef typename std::underlying_type_t underlying; + lhs=static_cast( + static_cast(lhs) & static_cast(rhs)); + return lhs; +} + +template +typename std::enable_if_t::enable,E&> +operator^=(E& lhs,E rhs){ + typedef typename std::underlying_type_t underlying; + lhs=static_cast( + static_cast(lhs) ^ static_cast(rhs)); + return lhs; +} + diff --git a/libaurum/meson.build b/libaurum/meson.build index 83417cb..85afdb3 100644 --- a/libaurum/meson.build +++ b/libaurum/meson.build @@ -9,6 +9,8 @@ libaurum_install_inc = [ './inc/Waiter.h', './inc/ISearchable.h', './inc/IDevice.h', + './inc/A11yEvent.h', + './inc/bitmask.h', './inc/Accessibility/AccessibleNode.h', './inc/Accessibility/AccessibleUtils.h', './inc/Accessibility/AccessibleWatcher.h', @@ -16,6 +18,7 @@ libaurum_install_inc = [ './inc/Accessibility/AccessibleWindow.h', './inc/Accessibility/IEventConsumer.h', './inc/Accessibility/IEventSource.h', + './inc/Runnable/Runnable.h', './inc/Misc/Point2D.h', './inc/Misc/Rect.h', './inc/Aurum.h', @@ -27,6 +30,7 @@ libaurum_inc = [ include_directories('./inc/Impl'), include_directories('./inc/Impl/Accessibility'), include_directories('./inc/Misc'), + include_directories('./inc/Runnable/'), root_inc, loguru_inc, ] diff --git a/libaurum/src/A11yEvent.cc b/libaurum/src/A11yEvent.cc new file mode 100644 index 0000000..325d6fb --- /dev/null +++ b/libaurum/src/A11yEvent.cc @@ -0,0 +1,65 @@ +#include "A11yEvent.h" + +#include + +A11yEventInfo::A11yEventInfo() : A11yEventInfo(A11yEvent::EVENT_NONE, nullptr, nullptr) {} + +A11yEventInfo::~A11yEventInfo() {} + +A11yEventInfo::A11yEventInfo(A11yEvent event, std::string name, std::string pkg) + : mEvent(event), + mName(name), + mPkg(pkg) +{ +} + +A11yEventInfo::A11yEventInfo(std::string event, std::string name, std::string pkg) + : mEvent(getEvent(event)), + mName(name), + mPkg(pkg) +{ +} + + +static std::unordered_map const table = { {"window:create", A11yEvent::EVENT_WINDOW_CREATE}, + {"window:close", A11yEvent::EVENT_WINDOW_CLOSE}, + {"window:minimize", A11yEvent::EVENT_WINDOW_MINIMIZE}, + {"window:maxmize", A11yEvent::EVENT_WINDOW_MAXIMIZE}, + {"window:restore", A11yEvent::EVENT_WINDOW_RESTORE}, + {"window:activate", A11yEvent::EVENT_WINDOW_ACTIVATE}, + {"window:deactivate", A11yEvent::EVENT_WINDOW_DEACTIVATE}, + {"window:raise", A11yEvent::EVENT_WINDOW_RAISE}, + {"window:lower", A11yEvent::EVENT_WINDOW_LOWER}, + {"window:resize", A11yEvent::EVENT_WINDOW_RESIZE}, + {"window:move", A11yEvent::EVENT_WINDOW_MOVE}, + {"object:text-changed:insert", A11yEvent::EVENT_TEXT_CHANGED_INSERT}, + {"object:text-changed:delete", A11yEvent::EVENT_TEXT_CHANGED_DELETE}, + {"object:state-changed:VISIBLE", A11yEvent::EVENT_STATE_CHANGED_VISIBLE}, + {"object:state-changed:focused", A11yEvent::EVENT_STATE_CHANGED_FOCUSED}, + {"object:state-changed:checked", A11yEvent::EVENT_STATE_CHANGED_CHECKED}, + {"object:state-changed:pressed", A11yEvent::EVENT_STATE_CHANGED_PRESSED}, + {"object:state-changed:selected", A11yEvent::EVENT_STATE_CHANGED_SELECTED} }; + +A11yEvent A11yEventInfo::getEvent() +{ + return mEvent; +} + +A11yEvent A11yEventInfo::getEvent(std::string event) +{ + auto it = table.find(event); + if (it != table.end()) { + return it->second; + } + return A11yEvent::EVENT_NONE; +} + +std::string A11yEventInfo::getName() +{ + return mName; +} + +std::string A11yEventInfo::getPkg() +{ + return mPkg; +} diff --git a/libaurum/src/Impl/Accessibility/AtspiAccessibleNode.cc b/libaurum/src/Impl/Accessibility/AtspiAccessibleNode.cc index 2cf3fe1..1b2c4db 100644 --- a/libaurum/src/Impl/Accessibility/AtspiAccessibleNode.cc +++ b/libaurum/src/Impl/Accessibility/AtspiAccessibleNode.cc @@ -398,4 +398,4 @@ void AtspiAccessibleNode::setFeatureProperty(AtspiStateType type) default: break; } -} \ No newline at end of file +} diff --git a/libaurum/src/Impl/Accessibility/AtspiAccessibleWatcher.cc b/libaurum/src/Impl/Accessibility/AtspiAccessibleWatcher.cc index 59dfe94..0925ef6 100644 --- a/libaurum/src/Impl/Accessibility/AtspiAccessibleWatcher.cc +++ b/libaurum/src/Impl/Accessibility/AtspiAccessibleWatcher.cc @@ -5,10 +5,14 @@ #include "AtspiAccessibleNode.h" #include "AtspiWrapper.h" #include +#include +#include +#include #include -AtspiEventListener *AtspiAccessibleWatcher::listener = nullptr; +std::vector> AtspiAccessibleWatcher::mEventQueue; +GThread *AtspiAccessibleWatcher::mEventThread = nullptr; static bool iShowingNode(AtspiAccessible *node) { @@ -40,7 +44,6 @@ findActiveNode(AtspiAccessible *node, int depth, std::vector ret{}; if (iShowingNode(node)) { - g_object_ref(node); char *name = AtspiWrapper::Atspi_accessible_get_name(node, NULL); if (name) { LOG_SCOPE_F(INFO, "%s", name); @@ -67,6 +70,27 @@ findActiveNode(AtspiAccessible *node, int depth, return ret; } +static gpointer _event_thread_loop (gpointer data) +{ + LOG_F(INFO, "event thread start"); + AtspiEventListener * listener = + atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiEvents, NULL, NULL); + + atspi_event_listener_register(listener, "window:", NULL); + atspi_event_listener_register(listener, "object:state-changed:focused", NULL); + atspi_event_listener_register(listener, "object:text-changed:insert", NULL); + + atspi_event_main(); +end: + LOG_F(INFO, "event thread end"); + atspi_event_listener_deregister(listener, "object:state-changed:focused", NULL); + atspi_event_listener_deregister(listener, "object:text-changed:insert", NULL); + atspi_event_listener_deregister(listener, "window:", NULL); + + g_object_unref(listener); + + return NULL; +} AtspiAccessibleWatcher::AtspiAccessibleWatcher() : mDbusProxy{nullptr} { @@ -75,11 +99,7 @@ AtspiAccessibleWatcher::AtspiAccessibleWatcher() atspi_set_main_context (g_main_context_default ()); atspi_init(); - listener = - atspi_event_listener_new(AtspiAccessibleWatcher::onAtspiEvents, this, NULL); - - atspi_event_listener_register(listener, "window:", NULL); - atspi_event_listener_register(listener, "object:", NULL); + mEventThread = g_thread_new("AtspiEventThread", _event_thread_loop, nullptr); mDbusProxy = g_dbus_proxy_new_for_bus_sync( G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, @@ -93,7 +113,6 @@ AtspiAccessibleWatcher::AtspiAccessibleWatcher() g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - g_variant_unref(enabled_variant); g_variant_unref(result); } @@ -108,23 +127,38 @@ AtspiAccessibleWatcher::~AtspiAccessibleWatcher() g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); - atspi_event_listener_deregister(listener, "window:", NULL); - atspi_event_listener_deregister(listener, "object:", NULL); - - g_object_unref(listener); g_object_unref(mDbusProxy); - g_variant_unref(enabled_variant); g_variant_unref(result); atspi_event_quit(); + g_thread_join(mEventThread); atspi_exit(); } - void AtspiAccessibleWatcher::onAtspiEvents(AtspiEvent *event, void *user_data) { AtspiWrapper::lock(); - char *name = NULL, *pname = NULL; + if (!event->source) + { + AtspiWrapper::unlock(); + return; + } + char *name = NULL, *pkg = NULL; + name = AtspiWrapper::Atspi_accessible_get_name(event->source, NULL); + + AtspiAccessible *app = AtspiWrapper::Atspi_accessible_get_application(event->source, NULL); + if (app) + { + pkg = AtspiWrapper::Atspi_accessible_get_name(app, NULL); + g_object_unref(app); + } + else + pkg = strdup(""); + + mEventQueue.push_back(std::make_shared(std::string(event->type), std::string(name), std::string(pkg))); + if (name) free(name); + if (pkg) free(pkg); +/* char *name = NULL, *pname = NULL; AtspiAccessibleWatcher *instance = (AtspiAccessibleWatcher *)user_data; if (!event->source) @@ -159,7 +193,7 @@ void AtspiAccessibleWatcher::onAtspiEvents(AtspiEvent *event, void *user_data) static_cast(event->source)); } if (name) free(name); - if (pname) free(pname); + if (pname) free(pname);*/ AtspiWrapper::unlock(); } @@ -268,6 +302,47 @@ std::vector> AtspiAccessibleWatcher::getA return ret; } +#define COMPARE(A, B) \ + (B != A11yEvent::EVENT_NONE) && ((A & B) == B) + +bool AtspiAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) +{ + AtspiWrapper::lock(); + mEventQueue.clear(); + AtspiWrapper::unlock(); + if (cmd) + cmd->run(); + + std::chrono::system_clock::time_point start = + std::chrono::system_clock::now(); + while (true) + { + std::vector> localEvents; + AtspiWrapper::lock(); + localEvents.assign(mEventQueue.begin(), mEventQueue.end()); + mEventQueue.clear(); + AtspiWrapper::unlock(); + + if (!localEvents.empty()) + { + for (const auto &event : localEvents) { + if (COMPARE(type, event->getEvent())) + { + LOG_F(INFO, "type %d == %d name %s pkg %s",static_cast(type), static_cast(event->getEvent()), event->getName().c_str(), event->getPkg().c_str()); + return true; + } + } + } + if ((std::chrono::system_clock::now() - start) > + std::chrono::milliseconds{timeout}) + break; + std::this_thread::sleep_for( + std::chrono::milliseconds{100}); + } + + return false; +} + bool AtspiAccessibleWatcher::removeFromActivatedList(AtspiAccessible *node) { LOG_SCOPE_F(INFO,"remove from activelist node %p", node); diff --git a/libaurum/src/Impl/Accessibility/MockAccessibleWatcher.cc b/libaurum/src/Impl/Accessibility/MockAccessibleWatcher.cc index 68f7f54..379a25b 100644 --- a/libaurum/src/Impl/Accessibility/MockAccessibleWatcher.cc +++ b/libaurum/src/Impl/Accessibility/MockAccessibleWatcher.cc @@ -37,4 +37,9 @@ std::shared_ptr MockAccessibleWatcher::addApplication std::shared_ptr app = std::make_shared(appNode); this->addApplication(app); return app; -} \ No newline at end of file +} + +bool MockAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout) +{ + return true; +} diff --git a/libaurum/src/Runnable/SendKeyRunnable.cc b/libaurum/src/Runnable/SendKeyRunnable.cc new file mode 100644 index 0000000..88e1fef --- /dev/null +++ b/libaurum/src/Runnable/SendKeyRunnable.cc @@ -0,0 +1,18 @@ +#include "SendKeyRunnable.h" + +#include +#include + +SendKeyRunnable::SendKeyRunnable(std::string keycode) + : mKeycode{keycode} +{ +} + +void SendKeyRunnable::run() const +{ + LOG_F(INFO, "sendKey %s",mKeycode.c_str()); + std::shared_ptr mDevice = UiDevice::getInstance(); + mDevice->pressKeyCode(mKeycode.c_str(), KeyRequestType::PRESS); + mDevice->pressKeyCode(mKeycode.c_str(), KeyRequestType::RELEASE); +} + diff --git a/libaurum/src/Runnable/meson.build b/libaurum/src/Runnable/meson.build new file mode 100644 index 0000000..f92c75d --- /dev/null +++ b/libaurum/src/Runnable/meson.build @@ -0,0 +1,3 @@ +libaurum_src += [ + files('SendKeyRunnable.cc') +] diff --git a/libaurum/src/UiDevice.cc b/libaurum/src/UiDevice.cc index 6b6a788..b9b5ab4 100644 --- a/libaurum/src/UiDevice.cc +++ b/libaurum/src/UiDevice.cc @@ -7,6 +7,8 @@ #endif #include "MockDeviceImpl.h" +#include "Runnables.h" + #include #include #include @@ -121,6 +123,25 @@ bool UiDevice::waitForIdle() const return true; } +bool UiDevice::waitForEvents( + const A11yEvent type, const int timeout) const +{ + return executeAndWaitForEvents(NULL, type, timeout); +} + +bool UiDevice::executeAndWaitForEvents( + const Runnable *cmd, const A11yEvent type, const int timeout) const +{ + return AccessibleWatcher::getInstance()->executeAndWaitForEvents(cmd, type, timeout); +} + +bool UiDevice::sendKeyAndWaitForEvents( + const std::string keycode, const A11yEvent type, const int timeout) const +{ + std::unique_ptr cmd = std::make_unique(keycode); + return executeAndWaitForEvents(cmd.get(), type, timeout); +} + bool UiDevice::click(const int x, const int y) { bool result = mDeviceImpl->click(x, y); diff --git a/libaurum/src/meson.build b/libaurum/src/meson.build index be6ee85..0a651e5 100644 --- a/libaurum/src/meson.build +++ b/libaurum/src/meson.build @@ -8,7 +8,9 @@ libaurum_src += [ files('Until.cc'), files('Waiter.cc'), files('PartialMatch.cc'), + files('A11yEvent.cc'), ] subdir('Accessibility') -subdir('Impl') \ No newline at end of file +subdir('Impl') +subdir('Runnable')