From 0b7fe504dc93246957aee38c0d93ea1fa1580fab Mon Sep 17 00:00:00 2001 From: Vojtech Bocek Date: Thu, 13 Mar 2014 17:36:52 +0100 Subject: Add support for actions triggered by key combination Change-Id: I9dfa7de40229f00412d63fc9c1eb3a809a6eb2e6 Signed-off-by: Vojtech Bocek --- gui/action.cpp | 54 ++++++++++++++++++++++++++++++++++++++---------- gui/gui.cpp | 31 +++++++++++++-------------- gui/hardwarekeyboard.cpp | 23 ++++++++++++++++++++- gui/objects.hpp | 12 ++++++++--- gui/pages.cpp | 33 ++++++++++++++++++----------- gui/pages.hpp | 10 ++++++--- minuitwrp/events.c | 9 +++++++- twrp-functions.cpp | 20 ++++++++++++++++++ twrp-functions.hpp | 1 + 9 files changed, 145 insertions(+), 48 deletions(-) diff --git a/gui/action.cpp b/gui/action.cpp index 9d7e482ca..94acf188c 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -73,8 +73,6 @@ GUIAction::GUIAction(xml_node<>* node) xml_node<>* actions; xml_attribute<>* attr; - mKey = 0; - if (!node) return; // First, get the action @@ -105,9 +103,12 @@ GUIAction::GUIAction(xml_node<>* node) attr = child->first_attribute("key"); if (attr) { - std::string key = attr->value(); - - mKey = getKeyByName(key); + std::vector keys = TWFunc::Split_String(attr->value(), "+"); + for(size_t i = 0; i < keys.size(); ++i) + { + const int key = getKeyByName(keys[i]); + mKeys[key] = false; + } } else { @@ -135,12 +136,41 @@ int GUIAction::NotifyTouch(TOUCH_STATE state, int x, int y) return 0; } -int GUIAction::NotifyKey(int key) +int GUIAction::NotifyKey(int key, bool down) { - if (!mKey || key != mKey) - return 1; + if (mKeys.empty()) + return 0; + + std::map::iterator itr = mKeys.find(key); + if(itr == mKeys.end()) + return 0; + + bool prevState = itr->second; + itr->second = down; + + // If there is only one key for this action, wait for key up so it + // doesn't trigger with multi-key actions. + // Else, check if all buttons are pressed, then consume their release events + // so they don't trigger one-button actions and reset mKeys pressed status + if(mKeys.size() == 1) { + if(!down && prevState) + doActions(); + } else if(down) { + for(itr = mKeys.begin(); itr != mKeys.end(); ++itr) { + if(!itr->second) + return 0; + } + + // Passed, all req buttons are pressed, reset them and consume release events + HardwareKeyboard *kb = PageManager::GetHardwareKeyboard(); + for(itr = mKeys.begin(); itr != mKeys.end(); ++itr) { + kb->ConsumeKeyRelease(itr->first); + itr->second = false; + } + + doActions(); + } - doActions(); return 0; } @@ -148,7 +178,7 @@ int GUIAction::NotifyVarChange(const std::string& varName, const std::string& va { GUIObject::NotifyVarChange(varName, value); - if (varName.empty() && !isConditionValid() && !mKey && !mActionW) + if (varName.empty() && !isConditionValid() && mKeys.empty() && !mActionW) doActions(); else if((varName.empty() || IsConditionVariable(varName)) && isConditionValid() && isConditionTrue()) doActions(); @@ -380,7 +410,9 @@ int GUIAction::doAction(Action action, int isThreaded /* = 0 */) if (function == "key") { - PageManager::NotifyKey(getKeyByName(arg)); + const int key = getKeyByName(arg); + PageManager::NotifyKey(key, true); + PageManager::NotifyKey(key, false); return 0; } diff --git a/gui/gui.cpp b/gui/gui.cpp index 0164ec393..c0bd008a9 100644 --- a/gui/gui.cpp +++ b/gui/gui.cpp @@ -187,8 +187,8 @@ static void * input_thread(void *cookie) static int x = 0, y = 0; static int lshift = 0, rshift = 0; static struct timeval touchStart; - HardwareKeyboard kb; string seconds; + HardwareKeyboard *kb = PageManager::GetHardwareKeyboard(); MouseCursor *cursor = PageManager::GetMouseCursor(); #ifndef TW_NO_SCREEN_TIMEOUT @@ -249,7 +249,7 @@ static void * input_thread(void *cookie) #endif gettimeofday(&touchStart, NULL); key_repeat = 2; - kb.KeyRepeat(); + kb->KeyRepeat(); #ifndef TW_NO_SCREEN_TIMEOUT blankTimer.resetTimerAndUnblank(); #endif @@ -261,7 +261,7 @@ static void * input_thread(void *cookie) LOGERR("KEY_REPEAT: %d,%d\n", x, y); #endif gettimeofday(&touchStart, NULL); - kb.KeyRepeat(); + kb->KeyRepeat(); #ifndef TW_NO_SCREEN_TIMEOUT blankTimer.resetTimerAndUnblank(); #endif @@ -356,6 +356,9 @@ static void * input_thread(void *cookie) { cursor->GetPos(x, y); +#ifdef _EVENT_LOGGING + LOGERR("TOUCH_RELEASE: %d,%d\n", x, y); +#endif PageManager::NotifyTouch(TOUCH_RELEASE, x, y); touch_and_hold = 0; @@ -371,15 +374,13 @@ static void * input_thread(void *cookie) else if(ev.code == BTN_SIDE) { if(ev.value == 1) - kb.KeyDown(KEY_BACK); + kb->KeyDown(KEY_BACK); else - kb.KeyUp(KEY_BACK); - } - else if (ev.value != 0) - { + kb->KeyUp(KEY_BACK); + } else if (ev.value != 0) { // This is a key press - if (kb.KeyDown(ev.code)) - { + if (kb->KeyDown(ev.code)) { + // Key repeat is enabled for this key key_repeat = 1; touch_and_hold = 0; touch_repeat = 0; @@ -388,9 +389,7 @@ static void * input_thread(void *cookie) #ifndef TW_NO_SCREEN_TIMEOUT blankTimer.resetTimerAndUnblank(); #endif - } - else - { + } else { key_repeat = 0; touch_and_hold = 0; touch_repeat = 0; @@ -399,11 +398,9 @@ static void * input_thread(void *cookie) blankTimer.resetTimerAndUnblank(); #endif } - } - else - { + } else { // This is a key release - kb.KeyUp(ev.code); + kb->KeyUp(ev.code); key_repeat = 0; touch_and_hold = 0; touch_repeat = 0; diff --git a/gui/hardwarekeyboard.cpp b/gui/hardwarekeyboard.cpp index a5a9987ae..f2194938e 100644 --- a/gui/hardwarekeyboard.cpp +++ b/gui/hardwarekeyboard.cpp @@ -38,15 +38,22 @@ HardwareKeyboard::~HardwareKeyboard() int HardwareKeyboard::KeyDown(int key_code) { + mPressedKeys.insert(key_code); + PageManager::NotifyKey(key_code, true); #ifdef _EVENT_LOGGING LOGERR("HardwareKeyboard::KeyDown %i\n", key_code); #endif - PageManager::NotifyKey(key_code); return 0; // 0 = no key repeat anything else turns on key repeat } int HardwareKeyboard::KeyUp(int key_code) { + std::set::iterator itr = mPressedKeys.find(key_code); + if(itr != mPressedKeys.end()) + { + mPressedKeys.erase(itr); + PageManager::NotifyKey(key_code, false); + } #ifdef _EVENT_LOGGING LOGERR("HardwareKeyboard::KeyUp %i\n", key_code); #endif @@ -55,8 +62,22 @@ int HardwareKeyboard::KeyUp(int key_code) int HardwareKeyboard::KeyRepeat(void) { + /* + * Uncomment when key repeats are sent somewhere. + * std::set::iterator itr = mPressedKeys.find(key_code); + * if(itr != mPressedKeys.end()) + * { + * Send repeats somewhere, don't remove itr from mPressedKeys + * } + */ + #ifdef _EVENT_LOGGING LOGERR("HardwareKeyboard::KeyRepeat\n"); #endif return 0; } + +void HardwareKeyboard::ConsumeKeyRelease(int key) +{ + mPressedKeys.erase(key); +} diff --git a/gui/objects.hpp b/gui/objects.hpp index 4942cd7e6..02417154a 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include extern "C" { @@ -101,7 +102,7 @@ public: // NotifyKey - Notify of a key press // Return 0 on success (and consume key), >0 to pass key to next handler, and <0 on error - virtual int NotifyKey(int key) { return 1; } + virtual int NotifyKey(int key, bool down) { return 1; } // GetRenderPos - Returns the current position of the object virtual int GetActionPos(int& x, int& y, int& w, int& h) { x = mActionX; y = mActionY; w = mActionW; h = mActionH; return 0; } @@ -269,7 +270,7 @@ public: public: virtual int NotifyTouch(TOUCH_STATE state, int x, int y); - virtual int NotifyKey(int key); + virtual int NotifyKey(int key, bool down); virtual int NotifyVarChange(const std::string& varName, const std::string& value); virtual int doActions(); @@ -282,7 +283,7 @@ protected: }; std::vector mActions; - int mKey; + std::map mKeys; protected: int getKeyByName(std::string key); @@ -927,6 +928,11 @@ public: virtual int KeyDown(int key_code); virtual int KeyUp(int key_code); virtual int KeyRepeat(void); + + void ConsumeKeyRelease(int key); + +private: + std::set mPressedKeys; }; class GUISliderValue: public GUIObject, public RenderObject, public ActionObject diff --git a/gui/pages.cpp b/gui/pages.cpp index 2953eddb8..398224e17 100644 --- a/gui/pages.cpp +++ b/gui/pages.cpp @@ -55,6 +55,7 @@ std::map PageManager::mPageSets; PageSet* PageManager::mCurrentSet; PageSet* PageManager::mBaseSet = NULL; MouseCursor *PageManager::mMouseCursor = NULL; +HardwareKeyboard *PageManager::mHardwareKeyboard = NULL; // Helper routine to convert a string to a color declaration int ConvertStrToColor(std::string str, COLOR* color) @@ -447,7 +448,7 @@ int Page::NotifyTouch(TOUCH_STATE state, int x, int y) return ret; } -int Page::NotifyKey(int key) +int Page::NotifyKey(int key, bool down) { std::vector::reverse_iterator iter; @@ -455,16 +456,17 @@ int Page::NotifyKey(int key) if (mActions.size() == 0) return 1; + int ret = 1; // We work backwards, from top-most element to bottom-most element for (iter = mActions.rbegin(); iter != mActions.rend(); iter++) { - int ret = (*iter)->NotifyKey(key); - if (ret == 0) - return 0; - else if (ret < 0) - LOGERR("An action handler has returned an error"); + ret = (*iter)->NotifyKey(key, down); + if (ret < 0) { + LOGERR("An action handler has returned an error\n"); + ret = 1; + } } - return 1; + return ret; } int Page::NotifyKeyboard(int key) @@ -719,12 +721,12 @@ int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y) return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1); } -int PageSet::NotifyKey(int key) +int PageSet::NotifyKey(int key, bool down) { if (mOverlayPage) - return (mOverlayPage->NotifyKey(key)); + return (mOverlayPage->NotifyKey(key, down)); - return (mCurrentPage ? mCurrentPage->NotifyKey(key) : -1); + return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1); } int PageSet::NotifyKeyboard(int key) @@ -964,6 +966,13 @@ int PageManager::Render(void) return res; } +HardwareKeyboard *PageManager::GetHardwareKeyboard() +{ + if(!mHardwareKeyboard) + mHardwareKeyboard = new HardwareKeyboard(); + return mHardwareKeyboard; +} + MouseCursor *PageManager::GetMouseCursor() { if(!mMouseCursor) @@ -1002,9 +1011,9 @@ int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y) return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1); } -int PageManager::NotifyKey(int key) +int PageManager::NotifyKey(int key, bool down) { - return (mCurrentSet ? mCurrentSet->NotifyKey(key) : -1); + return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1); } int PageManager::NotifyKeyboard(int key) diff --git a/gui/pages.hpp b/gui/pages.hpp index 23ceee9c8..a9cc0c1d0 100644 --- a/gui/pages.hpp +++ b/gui/pages.hpp @@ -30,6 +30,7 @@ class ActionObject; class InputObject; class MouseCursor; class GUIObject; +class HardwareKeyboard; class Page { @@ -43,7 +44,7 @@ public: virtual int Render(void); virtual int Update(void); virtual int NotifyTouch(TOUCH_STATE state, int x, int y); - virtual int NotifyKey(int key); + virtual int NotifyKey(int key, bool down); virtual int NotifyKeyboard(int key); virtual int SetKeyBoardFocus(int inFocus); virtual int NotifyVarChange(std::string varName, std::string value); @@ -84,7 +85,7 @@ public: int Render(void); int Update(void); int NotifyTouch(TOUCH_STATE state, int x, int y); - int NotifyKey(int key); + int NotifyKey(int key, bool down); int NotifyKeyboard(int key); int SetKeyBoardFocus(int inFocus); int NotifyVarChange(std::string varName, std::string value); @@ -127,7 +128,7 @@ public: static int Render(void); static int Update(void); static int NotifyTouch(TOUCH_STATE state, int x, int y); - static int NotifyKey(int key); + static int NotifyKey(int key, bool down); static int NotifyKeyboard(int key); static int SetKeyBoardFocus(int inFocus); static int NotifyVarChange(std::string varName, std::string value); @@ -135,6 +136,8 @@ public: static MouseCursor *GetMouseCursor(); static void LoadCursorData(xml_node<>* node); + static HardwareKeyboard *GetHardwareKeyboard(); + protected: static PageSet* FindPackage(std::string name); @@ -143,6 +146,7 @@ protected: static PageSet* mCurrentSet; static PageSet* mBaseSet; static MouseCursor *mMouseCursor; + static HardwareKeyboard *mHardwareKeyboard; }; #endif // _PAGES_HEADER_HPP diff --git a/minuitwrp/events.c b/minuitwrp/events.c index 93c41f2d5..eb1490719 100644 --- a/minuitwrp/events.c +++ b/minuitwrp/events.c @@ -384,6 +384,7 @@ static int vk_modify(struct ev *e, struct input_event *ev) { static int downX = -1, downY = -1; static int discard = 0; + static int last_virt_key = 0; static int lastWasSynReport = 0; static int touchReleaseOnNextSynReport = 0; static int use_tracking_id_negative_as_touch_release = 0; // On some devices, type: 3 code: 39 value: -1, aka EV_ABS ABS_MT_TRACKING_ID -1 indicates a true touch release @@ -593,7 +594,11 @@ static int vk_modify(struct ev *e, struct input_event *ev) if (discard) { discard = 0; - return 1; + + // Send the keyUp event + ev->type = EV_KEY; + ev->code = last_virt_key; + ev->value = 0; } return 0; } @@ -651,6 +656,8 @@ static int vk_modify(struct ev *e, struct input_event *ev) ev->code = e->vks[i].scancode; ev->value = 1; + last_virt_key = e->vks[i].scancode; + vibrate(VIBRATOR_TIME_MS); // Mark that all further movement until lift is discard, diff --git a/twrp-functions.cpp b/twrp-functions.cpp index 4551e84b4..fd974d234 100644 --- a/twrp-functions.cpp +++ b/twrp-functions.cpp @@ -1142,4 +1142,24 @@ void TWFunc::Fixup_Time_On_Boot() #endif } +std::vector TWFunc::Split_String(const std::string& str, const std::string& delimiter, bool removeEmpty) +{ + std::vector res; + size_t idx = 0, idx_last = 0; + + while(idx < str.size()) + { + idx = str.find_first_of(delimiter, idx_last); + if(idx == std::string::npos) + idx = str.size(); + + if(idx-idx_last != 0 || !removeEmpty) + res.push_back(str.substr(idx_last, idx-idx_last)); + + idx_last = idx + delimiter.size(); + } + + return res; +} + #endif // ndef BUILD_TWRPTAR_MAIN diff --git a/twrp-functions.hpp b/twrp-functions.hpp index 64a45f55b..ff1176389 100644 --- a/twrp-functions.hpp +++ b/twrp-functions.hpp @@ -80,6 +80,7 @@ public: static string Get_Current_Date(void); // Returns the current date in ccyy-m-dd--hh-nn-ss format static void Auto_Generate_Backup_Name(); // Populates TW_BACKUP_NAME with a backup name based on current date and ro.build.display.id from /system/build.prop static void Fixup_Time_On_Boot(); // Fixes time on devices which need it + static std::vector Split_String(const std::string& str, const std::string& delimiter, bool removeEmpty = true); // Splits string by delimiter private: static void Copy_Log(string Source, string Destination); -- cgit v1.2.3