#include "Translator.hpp" #include "log/log.hpp" #include "vfs.hpp" #include namespace gui { void recon_long_press(InputEvent &evt, const RawKey &key, const RawKey &prev_key_press, uint32_t time) { if (key.state == RawKey::State::Released && prev_key_press.key_code == key.key_code) { // determine long press if (key.time_release - prev_key_press.time_press >= key_time_longpress_ms) { evt.state = InputEvent::State::keyReleasedLong; } } } InputEvent KeyBaseTranslation::set(RawKey key) { gui::InputEvent evt(key); if (key.state == RawKey::State::Pressed) { evt.state = InputEvent::State::keyPressed; } else if (key.state == RawKey::State::Released) { evt.state = InputEvent::State::keyReleasedShort; } recon_long_press(evt, key, prev_key_press, key_time_longpress_ms); // store last key press/release if (key.state == RawKey::State::Pressed) { prev_key_press = key; } if (key.state != RawKey::State::Released) { prev_key_released = false; } else { prev_key_released = true; } return evt; } bool KeyBaseTranslation::timeout(uint32_t time) { if (!prev_key_released && (prev_key_press.time_press != 0) && (time - prev_key_press.time_press >= key_time_longpress_ms)) { prev_key_timedout = true; return true; } return false; } gui::KeyCode getKeyCode(bsp::KeyCodes code) { switch (code) { case bsp::KeyCodes::NumericKey1: return gui::KeyCode::KEY_1; break; case bsp::KeyCodes::NumericKey2: return gui::KeyCode::KEY_2; break; case bsp::KeyCodes::NumericKey3: return gui::KeyCode::KEY_3; break; case bsp::KeyCodes::NumericKey4: return gui::KeyCode::KEY_4; break; case bsp::KeyCodes::NumericKey5: return gui::KeyCode::KEY_5; break; case bsp::KeyCodes::NumericKey6: return gui::KeyCode::KEY_6; break; case bsp::KeyCodes::NumericKey7: return gui::KeyCode::KEY_7; break; case bsp::KeyCodes::NumericKey8: return gui::KeyCode::KEY_8; break; case bsp::KeyCodes::NumericKey9: return gui::KeyCode::KEY_9; break; case bsp::KeyCodes::NumericKey0: return gui::KeyCode::KEY_0; break; case bsp::KeyCodes::NumericKeyAst: return gui::KeyCode::KEY_AST; break; case bsp::KeyCodes::NumericKeyPnd: return gui::KeyCode::KEY_PND; break; case bsp::KeyCodes::JoystickLeft: return gui::KeyCode::KEY_LEFT; break; case bsp::KeyCodes::JoystickRight: return gui::KeyCode::KEY_RIGHT; break; case bsp::KeyCodes::JoystickUp: return gui::KeyCode::KEY_UP; break; case bsp::KeyCodes::JoystickDown: return gui::KeyCode::KEY_DOWN; break; case bsp::KeyCodes::JoystickEnter: return gui::KeyCode::KEY_ENTER; break; case bsp::KeyCodes::FnLeft: return gui::KeyCode::KEY_LF; break; case bsp::KeyCodes::FnRight: return gui::KeyCode::KEY_RF; break; case bsp::KeyCodes::VolUp: return gui::KeyCode::KEY_VOLUP; break; case bsp::KeyCodes::VolDown: return gui::KeyCode::KEY_VOLDN; break; case bsp::KeyCodes::Torch: return gui::KeyCode::KEY_TORCH; break; case bsp::KeyCodes::SSwitchUp: return gui::KeyCode::SWITCH_UP; break; case bsp::KeyCodes::SSwitchDown: return gui::KeyCode::SWITCH_DN; break; case bsp::KeyCodes::SSwitchMid: return gui::KeyCode::SWITCH_MID; break; default: LOG_ERROR("Unhandled bsp key!"); return gui::KeyCode::KEY_UNDEFINED; } } InputEvent KeyInputSimpleTranslation::translate(RawKey key) { auto evt = KeyBaseTranslation::set(key); // when last action timed out we don't want to handle key release if (prev_key_timedout && key.state == RawKey::State::Released) { evt.state = InputEvent::State::Undefined; prev_key_timedout = false; } evt.keyCode = getKeyCode(key.key_code); return evt; } InputEvent KeyInputSimpleTranslation::translate(uint32_t timeout) { RawKey key; key.state = RawKey::State::Released; key.key_code = prev_key_press.key_code; key.time_press = 0; key.time_release = timeout; InputEvent evt(key); evt.state = InputEvent::State::keyReleasedLong; evt.keyCode = getKeyCode(key.key_code); return evt; } /// profiles cache - load once for all class Profiles { private: const char *profilesFolder = "sys/assets/profiles"; std::map profiles = {}; void loadProfile(const std::string &filepath) { LOG_INFO("Load profile: %s", filepath.c_str()); auto p = Profile(filepath); if (p.getName() != std::string()) { profiles.insert({p.getName(), std::move(p)}); } } std::vector getProfilesList(std::string ext) { std::vector profileFiles; LOG_INFO("Scanning %s profiles folder: %s", ext.c_str(), profilesFolder); auto dirList = vfs.listdir(profilesFolder, ext); for (vfs::DirectoryEntry ent : dirList) { if (ent.attributes != vfs::FileAttributes::Directory) { profileFiles.push_back(std::string(profilesFolder) + "/" + ent.fileName); } } LOG_INFO("Total number of profiles: %d", profileFiles.size()); return profileFiles; } void init() { std::vector profileFiles = getProfilesList(".kprof"); for (std::string mapName : profileFiles) { if (std::size(mapName)) { loadProfile(mapName); } } if (std::size(profiles) == 0) { LOG_ERROR("No keyboard profiles loaded"); } } Profile empty; public: static Profiles &get() { static Profiles *p; if (p == nullptr) { p = new Profiles(); p->init(); } return *p; } static Profile &get(const std::string &name) { // if profile not in profile map -> load if (std::size(name) == 0) { LOG_ERROR("Request for non existend profile: %s", name.c_str()); return get().empty; } if (get().profiles.find(name) == get().profiles.end()) { get().loadProfile(name); } return get().profiles[name]; } }; uint32_t KeyInputMappedTranslation::handle(RawKey key, const std::string &keymap) { // get shortpress if (prev_key_press.key_code != key.key_code) { times = 0; } else if (key.state == RawKey::State::Released) { /// TODO use key_time_cycle_ms from keymap (if exists in keymap...) if (key.time_release - prev_key_press.time_release < key_time_cycle_ms) { ++times; } else { times = 0; } } if (key.state == RawKey::State::Released) { prev_key_press = key; } return Profiles::get(keymap).get(key.key_code, times); } } /* namespace gui */