From 074b33a6459740ac9a6762ef74c93ebfebbfe8ff Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 26 Aug 2022 15:06:40 +0200 Subject: [PATCH] [MOS-685] Make small improvements in various places of the code - Forward arguments - Remove unused code - Remove auto return type when it's not needed - Add const to member functions - Use startsWith and endsWith from utils - Allow instantiation of operators only for specific types - Caluclate key mask in compile time --- .../models/AlarmsRepository.cpp | 4 +- .../models/AlarmsRepository.hpp | 4 +- .../widgets/spinners/StringOutputSpinner.hpp | 21 +--- module-db/Database/DatabaseInitializer.cpp | 8 +- module-db/Database/DatabaseInitializer.hpp | 18 --- module-db/tests/DbInitializer.cpp | 8 +- module-gui/gui/Common.hpp | 107 +++++++++--------- module-gui/gui/widgets/BoxLayout.cpp | 15 +-- module-gui/gui/widgets/BoxLayout.hpp | 8 +- module-gui/gui/widgets/Item.cpp | 8 +- module-gui/gui/widgets/Item.hpp | 10 +- .../service-time/AlarmServiceAPI.cpp | 4 +- module-utils/utility/Utils.hpp | 8 +- module-utils/utility/tests/unittest_utils.cpp | 51 ++++++++- .../keymap/include/keymap/KeyMap.hpp | 19 +--- .../GenericLongPressSequence.hpp | 7 +- 16 files changed, 151 insertions(+), 149 deletions(-) diff --git a/module-apps/application-alarm-clock/models/AlarmsRepository.cpp b/module-apps/application-alarm-clock/models/AlarmsRepository.cpp index 1d297ca4d11010a4de74b2956c849f8434447b8a..8ef7511b27e81e98f903153e200ce196c9331210 100644 --- a/module-apps/application-alarm-clock/models/AlarmsRepository.cpp +++ b/module-apps/application-alarm-clock/models/AlarmsRepository.cpp @@ -35,9 +35,9 @@ namespace app::alarmClock } template - void AlarmsDBRepository::GetQuery(const AbstractAlarmsRepository::OnResultCallback &callback, Args... args) + void AlarmsDBRepository::GetQuery(const AbstractAlarmsRepository::OnResultCallback &callback, Args &&...args) { - auto task = async(std::make_unique(args...), service::name::service_time); + auto task = async(std::make_unique(std::forward(args)...), service::name::service_time); auto cb = [callback](auto response) { auto result = dynamic_cast(response); if (result == nullptr) { diff --git a/module-apps/application-alarm-clock/models/AlarmsRepository.hpp b/module-apps/application-alarm-clock/models/AlarmsRepository.hpp index ad42afa06f90700950322cf211c5a33c891911e8..5f6d9d584948ef3d1eab5c758f0aa5c644689d42 100644 --- a/module-apps/application-alarm-clock/models/AlarmsRepository.hpp +++ b/module-apps/application-alarm-clock/models/AlarmsRepository.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -33,7 +33,7 @@ namespace app::alarmClock // void GetQuery(std::unique_ptr query, const AbstractAlarmsRepository::OnResultCallback // &callback); template - void GetQuery(const AbstractAlarmsRepository::OnResultCallback &callback, Args... args); + void GetQuery(const AbstractAlarmsRepository::OnResultCallback &callback, Args &&...args); void add(const AlarmEventRecord &alarm, const OnResultCallback &callback) override; void remove(const AlarmEventRecord &alarm, const OnResultCallback &callback) override; void update(const AlarmEventRecord &alarm, const OnResultCallback &callback) override; diff --git a/module-apps/apps-common/widgets/spinners/StringOutputSpinner.hpp b/module-apps/apps-common/widgets/spinners/StringOutputSpinner.hpp index 35e7f0db150c59d76cb1237e3e3b9c3e654de636..7619f5905315b3e5db71eb415d7898b02ec4c7cb 100644 --- a/module-apps/apps-common/widgets/spinners/StringOutputSpinner.hpp +++ b/module-apps/apps-common/widgets/spinners/StringOutputSpinner.hpp @@ -8,25 +8,6 @@ #include #include -namespace details -{ - template - struct container_data - { - using value = T; - }; - - template - struct container_data>> - { - using value = typename T::value_type; - }; - - template - using container_data_v = typename container_data::value; - -} // namespace details - namespace gui { // This spinner operates on container elements and transforms the current container into a string. @@ -38,7 +19,7 @@ namespace gui { public: using range = typename Container::range; - using value_type = details::container_data_v; + using value_type = typename Container::value_type; explicit StringOutputSpinner(Container &&container, Orientation orientation = Orientation::Vertical) : container{std::move(container)}, orientation{orientation} diff --git a/module-db/Database/DatabaseInitializer.cpp b/module-db/Database/DatabaseInitializer.cpp index ee77fb442e45ba6c2c976eb3533844e3d1dba82b..41b3f347ee4022eec883c537fb856913d98a7ffa 100644 --- a/module-db/Database/DatabaseInitializer.cpp +++ b/module-db/Database/DatabaseInitializer.cpp @@ -3,6 +3,9 @@ #include "DatabaseInitializer.hpp" +#include +#include + #include #include #include @@ -11,7 +14,6 @@ #include #include #include -#include DatabaseInitializer::DatabaseInitializer(Database *db) : db(db) {} @@ -76,11 +78,11 @@ std::vector DatabaseInitializer::readCommands(std::filesystem::path line += c; } else { - if (line.empty() || starts_with(line, std::string("--"))) { + if (line.empty() || utils::startsWith(line, "--")) { line.clear(); continue; } - if (ends_with(line, std::string(";"))) { + if (utils::endsWith(line, ";")) { statements.push_back(currentStatement + line); currentStatement.clear(); line.clear(); diff --git a/module-db/Database/DatabaseInitializer.hpp b/module-db/Database/DatabaseInitializer.hpp index 4ef1ff7d1a07dc17cb962b308a0f2eb585d668e5..80374488ff1b8352e0c08f1390024fb8b799a19b 100644 --- a/module-db/Database/DatabaseInitializer.hpp +++ b/module-db/Database/DatabaseInitializer.hpp @@ -7,24 +7,6 @@ #include #include -namespace -{ - template - inline bool starts_with(const T &str, const T &start) - { - if (start.size() > str.size()) - return false; - return str.compare(0, start.size(), start) == 0; - } - template - inline bool ends_with(const T &str, const T &end) - { - if (end.size() > str.size()) - return false; - return std::equal(end.rbegin(), end.rend(), str.rbegin()); - } -} // namespace - class DatabaseInitializer { class ScopedFile diff --git a/module-db/tests/DbInitializer.cpp b/module-db/tests/DbInitializer.cpp index 680a8da610e19b3faeb0ef23886967a1e9ab8853..afd0fd630e7e9d9cb8352cd822e206493d43b960 100644 --- a/module-db/tests/DbInitializer.cpp +++ b/module-db/tests/DbInitializer.cpp @@ -3,10 +3,12 @@ #include "module-db/Database/DatabaseInitializer.hpp" +#include +#include + #include #include #include -#include DatabaseInitializer::DatabaseInitializer(Database *db) : db(db) {} @@ -62,11 +64,11 @@ std::vector DatabaseInitializer::readCommands(std::filesystem::path line += c; } else { - if (line.empty() || starts_with(line, std::string("--"))) { + if (line.empty() || utils::startsWith(line, "--")) { line.clear(); continue; } - if (ends_with(line, std::string(";"))) { + if (utils::endsWith(line, ";")) { statements.push_back(currentStatement + line); currentStatement.clear(); line.clear(); diff --git a/module-gui/gui/Common.hpp b/module-gui/gui/Common.hpp index 0b48eb27f6a4803d103d53d122057f7ac7cc2d35..c8d09533090cf1c3fa7c23941eb3218d0251ca16 100644 --- a/module-gui/gui/Common.hpp +++ b/module-gui/gui/Common.hpp @@ -79,60 +79,63 @@ namespace gui Horizontal }; - template - bool operator&(const T &lhs, const T &rhs) + // This namespace exists to prevent instantiation of operators for other classes from namespace gui + namespace rectangle_enums { - return static_cast(lhs) & static_cast(rhs); - } - template - T operator|(const T &lhs, const T &rhs) - { - return static_cast(static_cast(lhs) | static_cast(rhs)); - } - template - T operator|=(const T &lhs, const T &rhs) - { - lhs = lhs | rhs; - return lhs; - } - - enum class RectangleEdge - { - None = 0x00, - Top = 0x01, - Bottom = 0x02, - Left = 0x04, - Right = 0x08, - All = 0x0F - }; - - enum class RectangleRoundedCorner - { - None = 0x00, - TopLeft = 0x10, - TopRight = 0x20, - BottomLeft = 0x40, - BottomRight = 0x80, - All = 0xF0, - }; - - enum class RectangleFlatEdge - { - None = 0x00, - TopLeft = 0x01, - TopRight = 0x02, - BottomLeft = 0x04, - BottomRight = 0x08 - }; + enum class RectangleEdge + { + None = 0x00, + Top = 0x01, + Bottom = 0x02, + Left = 0x04, + Right = 0x08, + All = 0x0F + }; + + enum class RectangleFlatEdge + { + None = 0x00, + TopLeft = 0x01, + TopRight = 0x02, + BottomLeft = 0x04, + BottomRight = 0x08 + }; + + enum class RectangleRoundedCorner + { + None = 0x00, + TopLeft = 0x10, + TopRight = 0x20, + BottomLeft = 0x40, + BottomRight = 0x80, + All = 0xF0, + }; + + enum class RectangleYap + { + None = 0x00, + TopLeft = 0x10, + TopRight = 0x20, + BottomLeft = 0x40, + BottomRight = 0x80, + }; + + template + inline bool operator&(const T &lhs, const T &rhs) + { + return static_cast(lhs) & static_cast(rhs); + } + template + inline T operator|(const T &lhs, const T &rhs) + { + return static_cast(static_cast(lhs) | static_cast(rhs)); + } + } // namespace rectangle_enums - enum class RectangleYap - { - None = 0x00, - TopLeft = 0x10, - TopRight = 0x20, - BottomLeft = 0x40, - BottomRight = 0x80, - }; + using rectangle_enums::RectangleEdge; + using rectangle_enums::RectangleFlatEdge; + using rectangle_enums::RectangleRoundedCorner; + using rectangle_enums::RectangleYap; enum class Boundaries { diff --git a/module-gui/gui/widgets/BoxLayout.cpp b/module-gui/gui/widgets/BoxLayout.cpp index 8e1eee67e6ef4beb23c8f294c7b777fa24938eef..736e712aebe1fa05ebc9ee1f80e78293b5ca966e 100644 --- a/module-gui/gui/widgets/BoxLayout.cpp +++ b/module-gui/gui/widgets/BoxLayout.cpp @@ -411,12 +411,7 @@ namespace gui std::list::iterator BoxLayout::nextNavigationItem(std::list::iterator from) { - return std::find_if(from, this->children.end(), [](auto &el) -> bool { - if (el->isActive()) { - return true; - } - return false; - }); + return std::find_if(from, this->children.end(), [](const auto &el) { return el->isActive(); }); } std::list::iterator BoxLayout::getNavigationFocusedItem() @@ -465,7 +460,7 @@ namespace gui } template - auto BoxLayout::handleRequestResize(const Item *child, Length request_w, Length request_h) -> Size + Size BoxLayout::handleRequestResize(const Item *child, Length request_w, Length request_h) { if (parent != nullptr) { auto [w, h] = requestSize(request_w, request_h); @@ -570,7 +565,7 @@ namespace gui return nullptr; } - auto BoxLayout::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool + bool BoxLayout::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) { addFromOutOfDrawAreaList(); resizeItems(); @@ -613,7 +608,7 @@ namespace gui BoxLayout::addWidget(item); } - auto HBox::handleRequestResize(const Item *child, Length request_w, Length request_h) -> Size + Size HBox::handleRequestResize(const Item *child, Length request_w, Length request_h) { return BoxLayout::handleRequestResize(child, request_w, request_h); } @@ -639,7 +634,7 @@ namespace gui BoxLayout::addWidget(item); } - auto VBox::handleRequestResize(const Item *child, Length request_w, Length request_h) -> Size + Size VBox::handleRequestResize(const Item *child, Length request_w, Length request_h) { return BoxLayout::handleRequestResize(child, request_w, request_h); } diff --git a/module-gui/gui/widgets/BoxLayout.hpp b/module-gui/gui/widgets/BoxLayout.hpp index 5864870676fe1d1cfeae903f37177e0e958e8adb..3bc4604fa281e94d335c533dc4e89e195c15c4b2 100644 --- a/module-gui/gui/widgets/BoxLayout.hpp +++ b/module-gui/gui/widgets/BoxLayout.hpp @@ -130,8 +130,8 @@ namespace gui bool setFocusOnElement(unsigned int elementNumber); void setFocusOnLastElement(); template - auto handleRequestResize(const Item *, Length request_w, Length request_h) -> Size; - auto onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) -> bool override; + Size handleRequestResize(const Item *, Length request_w, Length request_h); + bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override; void handleContentChanged() override; /// Get primary sizes used in axis dominant layouts Length getPrimarySizeLeft(); @@ -146,7 +146,7 @@ namespace gui HBox(Item *parent, const uint32_t &x = 0, const uint32_t &y = 0, const uint32_t &w = 0, const uint32_t &h = 0); virtual ~HBox() = default; virtual void addWidget(Item *item) override; - auto handleRequestResize(const Item *, Length request_w, Length request_h) -> Size override; + Size handleRequestResize(const Item *, Length request_w, Length request_h) override; }; class VBox : public BoxLayout @@ -157,7 +157,7 @@ namespace gui VBox(Item *parent, const uint32_t &x = 0, const uint32_t &y = 0, const uint32_t &w = 0, const uint32_t &h = 0); virtual ~VBox() = default; virtual void addWidget(Item *item) override; - auto handleRequestResize(const Item *, Length request_w, Length request_h) -> Size override; + Size handleRequestResize(const Item *, Length request_w, Length request_h) override; }; } /* namespace gui */ diff --git a/module-gui/gui/widgets/Item.cpp b/module-gui/gui/widgets/Item.cpp index eca11436a5b4b77e13d0a3542756b00b94ba8a2d..d6e5a4d9942a63702e3b891e98565106058016cb 100644 --- a/module-gui/gui/widgets/Item.cpp +++ b/module-gui/gui/widgets/Item.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "Item.hpp" @@ -157,7 +157,7 @@ namespace gui setArea({widgetArea.x, y, widgetArea.w, widgetArea.h}); } - auto Item::requestSize(Length request_w, Length request_h) -> Size + Size Item::requestSize(Length request_w, Length request_h) { if (parent == nullptr) { setSize(request_w, request_h); @@ -166,7 +166,7 @@ namespace gui return parent->handleRequestResize(this, request_w, request_h); } - auto Item::handleRequestResize(const Item *it, Length request_w, Length request_h) -> Size + Size Item::handleRequestResize(const Item *it, Length request_w, Length request_h) { if (it == nullptr) { return {0, 0}; @@ -530,7 +530,7 @@ namespace gui return false; } - auto Item::onTimer(sys::Timer &timer) -> bool + bool Item::onTimer(sys::Timer &timer) { if (timerCallback != nullptr) { return timerCallback(*this, timer); diff --git a/module-gui/gui/widgets/Item.hpp b/module-gui/gui/widgets/Item.hpp index f1ed3a21e3d5ccb26d20e09241353d7598684491..9d1a7d8f6c229908983b9f44e5012e4a877f8f71 100644 --- a/module-gui/gui/widgets/Item.hpp +++ b/module-gui/gui/widgets/Item.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -79,7 +79,7 @@ namespace gui BoundingBox drawArea; // drawableArea would be more accurate // maximal bounding box size /// gets bounding box for selected area - auto area(Area which = Area::Normal) -> BoundingBox & + BoundingBox &area(Area which = Area::Normal) { switch (which) { case Area::Min: @@ -268,7 +268,7 @@ namespace gui /// requests bigger size from parent if parent available /// if no parent available - sets size /// @return true if handled positively - virtual auto requestSize(Length request_w, Length request_h) -> Size final; + virtual Size requestSize(Length request_w, Length request_h) final; /// handle for layouts to implement to resize on demand ( i.e. when it needs to expand after /// addition/removal of chars ) /// @@ -282,7 +282,7 @@ namespace gui /// should be handled without infinite loop on resize ( item->setSize -> notify Layout -> layout: item->setSize /// ) /// @return bool requested size granted {w,h} - virtual auto handleRequestResize(const Item *, Length request_w, Length request_h) -> Size; + virtual Size handleRequestResize(const Item *, Length request_w, Length request_h); /// flag informing that content has changed bool contentChanged = false; @@ -392,7 +392,7 @@ namespace gui /// simple check function to determine if item is active && visible. /// @return true if item is active and visible. Otherwise false. - inline bool isActive() + inline bool isActive() const { return (activeItem && visible); } diff --git a/module-services/service-time/AlarmServiceAPI.cpp b/module-services/service-time/AlarmServiceAPI.cpp index 516d69b3f0a39a3b5e4c1280296ccb03b17c255f..37401fcbcb1e50188707b37c9a0468aec216b1a9 100644 --- a/module-services/service-time/AlarmServiceAPI.cpp +++ b/module-services/service-time/AlarmServiceAPI.cpp @@ -14,9 +14,9 @@ namespace alarms namespace AlarmServiceAPI { template - bool sendRequest(sys::Service *serv, Types... messageArgs) + bool sendRequest(sys::Service *serv, Types &&...messageArgs) { - auto msg = std::make_shared(messageArgs...); + auto msg = std::make_shared(std::forward(messageArgs)...); return serv->bus.sendUnicast(msg, service::name::service_time); } diff --git a/module-utils/utility/Utils.hpp b/module-utils/utility/Utils.hpp index 6472ea60f8832278a4749ca067933c61045761e2..6bdb13e05d8d7e63515a5c4714b78f271668802f 100644 --- a/module-utils/utility/Utils.hpp +++ b/module-utils/utility/Utils.hpp @@ -75,10 +75,14 @@ namespace utils return bytes; } + inline bool startsWith(std::string const &str, std::string const &prefix) + { + return prefix.size() <= str.size() && std::equal(prefix.begin(), prefix.end(), str.begin()); + } + inline bool endsWith(std::string const &str, std::string const &suffix) { - return str.size() >= suffix.size() && - std::equal(str.begin() + (str.size() - suffix.size()), str.end(), suffix.begin()); + return suffix.size() <= str.size() && std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()); } static inline std::string removeNewLines(const std::string &s) diff --git a/module-utils/utility/tests/unittest_utils.cpp b/module-utils/utility/tests/unittest_utils.cpp index d5b3e51b32331e2fd6a5fc230b2237a37e8fdb67..703567142f0f7c3d6c119670a9021e02b5d4fd0f 100644 --- a/module-utils/utility/tests/unittest_utils.cpp +++ b/module-utils/utility/tests/unittest_utils.cpp @@ -526,6 +526,44 @@ TEST_CASE("Byte to hex") } } +TEST_CASE("Starts with") +{ + SECTION("Empty string") + { + REQUIRE((utils::startsWith("", "abc") == false)); + } + + SECTION("Empty prefix") + { + REQUIRE((utils::startsWith("abc", "") == true)); + } + + SECTION("Empty string and prefix") + { + REQUIRE((utils::startsWith("", "") == true)); + } + + SECTION("Prefix almost at the beginning of string") + { + REQUIRE((utils::startsWith("Abcde", "bcd") == false)); + } + + SECTION("Prefix containing the beginning of string and more") + { + REQUIRE((utils::startsWith("Abcde", "AAbc") == false)); + } + + SECTION("Prefix at the beginning of string") + { + REQUIRE((utils::startsWith("Abcde", "Ab") == true)); + } + + SECTION("Equal string and prefix") + { + REQUIRE((utils::startsWith("Abc", "Abc") == true)); + } +} + TEST_CASE("Ends with") { SECTION("Empty string") @@ -538,22 +576,27 @@ TEST_CASE("Ends with") REQUIRE((utils::endsWith("abc", "") == true)); } - SECTION("Both empty") + SECTION("Empty string and suffix") { REQUIRE((utils::endsWith("", "") == true)); } - SECTION("No") + SECTION("Suffix almost at the end of string") + { + REQUIRE((utils::endsWith("Abcde", "cd") == false)); + } + + SECTION("Suffix containing the end of string and more") { REQUIRE((utils::endsWith("Abcde", "def") == false)); } - SECTION("Yes") + SECTION("Suffix at the end of string") { REQUIRE((utils::endsWith("Abcde", "de") == true)); } - SECTION("Equal") + SECTION("Equal string and suffix") { REQUIRE((utils::endsWith("Abc", "Abc") == true)); } diff --git a/products/BellHybrid/keymap/include/keymap/KeyMap.hpp b/products/BellHybrid/keymap/include/keymap/KeyMap.hpp index 497076bea664b94d68b17c069fe6c2e18dce65a1..d93bd5c9b53eb6bcf760002af2503d60b072b555 100644 --- a/products/BellHybrid/keymap/include/keymap/KeyMap.hpp +++ b/products/BellHybrid/keymap/include/keymap/KeyMap.hpp @@ -61,29 +61,20 @@ struct KeyStates { states.set(magic_enum::enum_integer(key), value); } - bool state(KeyMap key) + bool state(KeyMap key) const { return states.test(magic_enum::enum_integer(key)); } - std::size_t count() + std::size_t count() const { return states.count(); } - template - bool ifOnlySet(Args... args) + template + bool ifOnlySet() const { - const auto mask = (... | [](auto x) { return KeySet{1UL << magic_enum::enum_integer(x)}; }(args)); - return (states | mask) == mask; - } - - template - bool ifOnlySet(std::array keys) - { - const auto mask = std::accumulate(keys.begin(), keys.end(), KeySet{}, [](auto m, auto val) { - return m | KeySet{1UL << magic_enum::enum_integer(val)}; - }); + constexpr auto mask = KeySet{(... | (1UL << magic_enum::enum_integer(keys)))}; return (states | mask) == mask; } diff --git a/products/BellHybrid/services/evtmgr/internal/key_sequences/GenericLongPressSequence.hpp b/products/BellHybrid/services/evtmgr/internal/key_sequences/GenericLongPressSequence.hpp index 51418239a93ff9d5b6d339c2a11397c4bb896889..3fd958139d0e5e87ea98b14c6652c1f0aa9c8568 100644 --- a/products/BellHybrid/services/evtmgr/internal/key_sequences/GenericLongPressSequence.hpp +++ b/products/BellHybrid/services/evtmgr/internal/key_sequences/GenericLongPressSequence.hpp @@ -13,7 +13,8 @@ template class GenericLongPressSequence : public AbstractKeySequence { - using Keys = std::array; + static constexpr auto keysToScanCount = sizeof...(keys); + enum class State { Idle, @@ -32,7 +33,7 @@ class GenericLongPressSequence : public AbstractKeySequence switch (state) { case State::Idle: - if (keyStates.count() == keysToScanCount && keyStates.ifOnlySet(keysToScan)) { + if (keyStates.count() == keysToScanCount && keyStates.ifOnlySet()) { switch_to_in_progress(); } break; @@ -80,8 +81,6 @@ class GenericLongPressSequence : public AbstractKeySequence timer.start(); } - static constexpr Keys keysToScan = {keys...}; - static constexpr auto keysToScanCount = keysToScan.size(); State state = State::Idle; KeyStates keyStates; sys::TimerHandle timer;