Add support for actions triggered by key combination
Change-Id: I9dfa7de40229f00412d63fc9c1eb3a809a6eb2e6
Signed-off-by: Vojtech Bocek <vbocek@gmail.com>
diff --git a/gui/action.cpp b/gui/action.cpp
index 9d7e482..94acf18 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -73,8 +73,6 @@
xml_node<>* actions;
xml_attribute<>* attr;
- mKey = 0;
-
if (!node) return;
// First, get the action
@@ -105,9 +103,12 @@
attr = child->first_attribute("key");
if (attr)
{
- std::string key = attr->value();
-
- mKey = getKeyByName(key);
+ std::vector<std::string> 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 @@
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;
- doActions();
+ std::map<int, bool>::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();
+ }
+
return 0;
}
@@ -148,7 +178,7 @@
{
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 @@
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 0164ec3..c0bd008 100644
--- a/gui/gui.cpp
+++ b/gui/gui.cpp
@@ -187,8 +187,8 @@
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 @@
#endif
gettimeofday(&touchStart, NULL);
key_repeat = 2;
- kb.KeyRepeat();
+ kb->KeyRepeat();
#ifndef TW_NO_SCREEN_TIMEOUT
blankTimer.resetTimerAndUnblank();
#endif
@@ -261,7 +261,7 @@
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 @@
{
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 @@
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 @@
#ifndef TW_NO_SCREEN_TIMEOUT
blankTimer.resetTimerAndUnblank();
#endif
- }
- else
- {
+ } else {
key_repeat = 0;
touch_and_hold = 0;
touch_repeat = 0;
@@ -399,11 +398,9 @@
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 a5a9987..f219493 100644
--- a/gui/hardwarekeyboard.cpp
+++ b/gui/hardwarekeyboard.cpp
@@ -38,15 +38,22 @@
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<int>::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::KeyRepeat(void)
{
+ /*
+ * Uncomment when key repeats are sent somewhere.
+ * std::set<int>::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 4942cd7..0241715 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -25,6 +25,7 @@
#include <vector>
#include <string>
#include <map>
+#include <set>
#include <time.h>
extern "C" {
@@ -101,7 +102,7 @@
// 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:
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 @@
};
std::vector<Action> mActions;
- int mKey;
+ std::map<int, bool> mKeys;
protected:
int getKeyByName(std::string key);
@@ -927,6 +928,11 @@
virtual int KeyDown(int key_code);
virtual int KeyUp(int key_code);
virtual int KeyRepeat(void);
+
+ void ConsumeKeyRelease(int key);
+
+private:
+ std::set<int> mPressedKeys;
};
class GUISliderValue: public GUIObject, public RenderObject, public ActionObject
diff --git a/gui/pages.cpp b/gui/pages.cpp
index 2953edd..398224e 100644
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -55,6 +55,7 @@
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 @@
return ret;
}
-int Page::NotifyKey(int key)
+int Page::NotifyKey(int key, bool down)
{
std::vector<ActionObject*>::reverse_iterator iter;
@@ -455,16 +456,17 @@
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 @@
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 @@
return res;
}
+HardwareKeyboard *PageManager::GetHardwareKeyboard()
+{
+ if(!mHardwareKeyboard)
+ mHardwareKeyboard = new HardwareKeyboard();
+ return mHardwareKeyboard;
+}
+
MouseCursor *PageManager::GetMouseCursor()
{
if(!mMouseCursor)
@@ -1002,9 +1011,9 @@
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 23ceee9..a9cc0c1 100644
--- a/gui/pages.hpp
+++ b/gui/pages.hpp
@@ -30,6 +30,7 @@
class InputObject;
class MouseCursor;
class GUIObject;
+class HardwareKeyboard;
class Page
{
@@ -43,7 +44,7 @@
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 @@
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 @@
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 @@
static MouseCursor *GetMouseCursor();
static void LoadCursorData(xml_node<>* node);
+ static HardwareKeyboard *GetHardwareKeyboard();
+
protected:
static PageSet* FindPackage(std::string name);
@@ -143,6 +146,7 @@
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 93c41f2..eb14907 100644
--- a/minuitwrp/events.c
+++ b/minuitwrp/events.c
@@ -384,6 +384,7 @@
{
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 @@
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 @@
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 4551e84..fd974d2 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -1142,4 +1142,24 @@
#endif
}
+std::vector<std::string> TWFunc::Split_String(const std::string& str, const std::string& delimiter, bool removeEmpty)
+{
+ std::vector<std::string> 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 64a45f5..ff11763 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -80,6 +80,7 @@
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<std::string> 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);