Move input handling into the main thread

This also makes the hardwarekeyboard.cpp file that I created for
the Asus Transformer tablets with a keyboard dock the default
hardware keyboard handler. USB keyboards should work properly now
if present for keyboard input.

Change-Id: I724606e91ffe2a55265a9d1cb1ec714de244d38b
diff --git a/gui/gui.cpp b/gui/gui.cpp
index 6b3b9c9..da3e5e5 100644
--- a/gui/gui.cpp
+++ b/gui/gui.cpp
@@ -67,7 +67,7 @@
 static TWAtomicInt gGuiConsoleTerminate;
 static TWAtomicInt gForceRender;
 const int gNoAnimation = 1;
-static int gGuiInputRunning = 0;
+static int gGuiInputInit = 0;
 blanktimer blankTimer;
 int ors_read_fd = -1;
 
@@ -172,16 +172,8 @@
 #endif
 }
 
-static void * input_thread(void *cookie)
+void input_init(void)
 {
-	int drag = 0;
-	static int touch_and_hold = 0, dontwait = 0;
-	static int touch_repeat = 0, key_repeat = 0;
-	static int x = 0, y = 0;
-	static struct timeval touchStart;
-	HardwareKeyboard *kb = PageManager::GetHardwareKeyboard();
-	MouseCursor *cursor = PageManager::GetMouseCursor();
-
 #ifndef TW_NO_SCREEN_TIMEOUT
 	{
 		string seconds;
@@ -192,29 +184,72 @@
 #else
 	LOGINFO("Skipping screen timeout: TW_NO_SCREEN_TIMEOUT is set\n");
 #endif
+	gGuiInputInit = 1;
+}
 
-	for (;;)
+enum touch_status_enum {
+	TS_NONE = 0,
+	TS_TOUCH_AND_HOLD = 1,
+	TS_TOUCH_REPEAT = 2,
+};
+
+enum key_status_enum {
+	KS_NONE = 0,
+	KS_KEY_PRESSED = 1,
+	KS_KEY_REPEAT = 2,
+};
+
+enum action_state_enum {
+	AS_IN_ACTION_AREA = 0,
+	AS_NO_ACTION = 1,
+};
+
+void get_input(int send_drag)
+{
+	static touch_status_enum touch_status = TS_NONE;
+	static key_status_enum key_status = KS_NONE;
+	static int x = 0, y = 0; // x and y coordinates
+	static struct timeval touchStart; // used to track time for long press / key repeat
+	static HardwareKeyboard *kb = PageManager::GetHardwareKeyboard();
+	static MouseCursor *cursor = PageManager::GetMouseCursor();
+	struct input_event ev;
+	static action_state_enum state = AS_NO_ACTION; // 1 means that we've touched in an empty area (no action) while 0 means we've touched a spot with an action
+	int ret = 0; // return value from ev_get
+
+	if (send_drag) {
+		// This allows us to only send one NotifyTouch event per render
+		// cycle to reduce overhead and perceived input latency.
+		static int prevx = 0, prevy = 0; // these track where the last drag notice was so that we don't send duplicate drag notices
+		if (touch_status && (x != prevx || y != prevy)) {
+			prevx = x;
+			prevy = y;
+			if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
+				state = AS_NO_ACTION;
+			else
+				state = AS_IN_ACTION_AREA;
+		}
+		return;
+	}
+
+	ret = ev_get(&ev);
+
+	if (ret < 0)
 	{
-		// wait for the next event
-		struct input_event ev;
-		int state = 0, ret = 0;
-
-		ret = ev_get(&ev, dontwait);
-
-		if (ret < 0)
-		{
+		// This path means that we did not get any new touch data, but
+		// we do not get new touch data if you press and hold on either
+		// the screen or on a keyboard key or mouse button
+		if (touch_status || key_status) {
+			// touch and key repeat section
 			struct timeval curTime;
-			gettimeofday(&curTime, NULL);
 			long mtime, seconds, useconds;
-
+			gettimeofday(&curTime, NULL);
 			seconds = curTime.tv_sec - touchStart.tv_sec;
 			useconds = curTime.tv_usec - touchStart.tv_usec;
-
 			mtime = ((seconds) * 1000 + useconds / 1000.0) + 0.5;
-			if (touch_and_hold && mtime > 500)
+
+			if (touch_status == TS_TOUCH_AND_HOLD && mtime > 500)
 			{
-				touch_and_hold = 0;
-				touch_repeat = 1;
+				touch_status = TS_TOUCH_REPEAT;
 				gettimeofday(&touchStart, NULL);
 #ifdef _EVENT_LOGGING
 				LOGERR("TOUCH_HOLD: %d,%d\n", x, y);
@@ -222,7 +257,7 @@
 				PageManager::NotifyTouch(TOUCH_HOLD, x, y);
 				blankTimer.resetTimerAndUnblank();
 			}
-			else if (touch_repeat && mtime > 100)
+			else if (touch_status == TS_TOUCH_REPEAT && mtime > 100)
 			{
 #ifdef _EVENT_LOGGING
 				LOGERR("TOUCH_REPEAT: %d,%d\n", x, y);
@@ -231,18 +266,18 @@
 				PageManager::NotifyTouch(TOUCH_REPEAT, x, y);
 				blankTimer.resetTimerAndUnblank();
 			}
-			else if (key_repeat == 1 && mtime > 500)
+			else if (key_status == KS_KEY_PRESSED && mtime > 500)
 			{
 #ifdef _EVENT_LOGGING
 				LOGERR("KEY_HOLD: %d,%d\n", x, y);
 #endif
 				gettimeofday(&touchStart, NULL);
-				key_repeat = 2;
+				key_status = KS_KEY_REPEAT;
 				kb->KeyRepeat();
 				blankTimer.resetTimerAndUnblank();
 
 			}
-			else if (key_repeat == 2 && mtime > 100)
+			else if (key_status == KS_KEY_REPEAT && mtime > 100)
 			{
 #ifdef _EVENT_LOGGING
 				LOGERR("KEY_REPEAT: %d,%d\n", x, y);
@@ -251,160 +286,145 @@
 				kb->KeyRepeat();
 				blankTimer.resetTimerAndUnblank();
 			}
+		} else {
+			return; // nothing is pressed so do nothing and exit
 		}
-		else if (ev.type == EV_ABS)
+	}
+	else if (ev.type == EV_ABS)
+	{
+
+		x = ev.value >> 16;
+		y = ev.value & 0xFFFF;
+
+		if (ev.code == 0)
 		{
-
-			x = ev.value >> 16;
-			y = ev.value & 0xFFFF;
-
-			if (ev.code == 0)
+			if (state == AS_IN_ACTION_AREA)
 			{
-				if (state == 0)
-				{
 #ifdef _EVENT_LOGGING
-					LOGERR("TOUCH_RELEASE: %d,%d\n", x, y);
+				LOGERR("TOUCH_RELEASE: %d,%d\n", x, y);
 #endif
-					PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
-					blankTimer.resetTimerAndUnblank();
-					touch_and_hold = 0;
-					touch_repeat = 0;
-					if (!key_repeat)
-						dontwait = 0;
+				PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
+				blankTimer.resetTimerAndUnblank();
+			}
+			touch_status = TS_NONE;
+		}
+		else
+		{
+			if (!touch_status)
+			{
+				if (x != 0 && y != 0) {
+#ifdef _EVENT_LOGGING
+					LOGERR("TOUCH_START: %d,%d\n", x, y);
+#endif
+					if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
+						state = AS_NO_ACTION;
+					else
+						state = AS_IN_ACTION_AREA;
+					touch_status = TS_TOUCH_AND_HOLD;
+					gettimeofday(&touchStart, NULL);
 				}
-				state = 0;
-				drag = 0;
+				blankTimer.resetTimerAndUnblank();
 			}
 			else
 			{
-				if (!drag)
+				if (state == AS_IN_ACTION_AREA)
 				{
-					if (x != 0 && y != 0) {
 #ifdef _EVENT_LOGGING
-						LOGERR("TOUCH_START: %d,%d\n", x, y);
+					LOGERR("TOUCH_DRAG: %d,%d\n", x, y);
 #endif
-						if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
-							state = 1;
-						drag = 1;
-						touch_and_hold = 1;
-						dontwait = 1;
-						key_repeat = 0;
-						gettimeofday(&touchStart, NULL);
-					}
 					blankTimer.resetTimerAndUnblank();
 				}
-				else
-				{
-					if (state == 0)
-					{
-#ifdef _EVENT_LOGGING
-						LOGERR("TOUCH_DRAG: %d,%d\n", x, y);
-#endif
-						if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
-							state = 1;
-						key_repeat = 0;
-						blankTimer.resetTimerAndUnblank();
-					}
-				}
-			}
-		}
-		else if (ev.type == EV_KEY)
-		{
-			// Handle key-press here
-#ifdef _EVENT_LOGGING
-			LOGERR("TOUCH_KEY: %d\n", ev.code);
-#endif
-			// Left mouse button
-			if(ev.code == BTN_LEFT)
-			{
-				if(ev.value == 1)
-				{
-					cursor->GetPos(x, y);
-
-					if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
-						state = 1;
-					drag = 1;
-					touch_and_hold = 1;
-					dontwait = 1;
-					key_repeat = 0;
-					gettimeofday(&touchStart, NULL);
-				}
-				else if(drag == 1)
-				{
-					if (state == 0)
-					{
-						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;
-						touch_repeat = 0;
-						if (!key_repeat)
-							dontwait = 0;
-					}
-					state = 0;
-					drag = 0;
-				}
-			}
-			// side mouse button, often used for "back" function
-			else if(ev.code == BTN_SIDE)
-			{
-				if(ev.value == 1)
-					kb->KeyDown(KEY_BACK);
-				else
-					kb->KeyUp(KEY_BACK);
-			} else if (ev.value != 0) {
-				// This is a key press
-				if (kb->KeyDown(ev.code)) {
-					// Key repeat is enabled for this key
-					key_repeat = 1;
-					touch_and_hold = 0;
-					touch_repeat = 0;
-					dontwait = 1;
-					gettimeofday(&touchStart, NULL);
-					blankTimer.resetTimerAndUnblank();
-				} else {
-					key_repeat = 0;
-					touch_and_hold = 0;
-					touch_repeat = 0;
-					dontwait = 0;
-					blankTimer.resetTimerAndUnblank();
-				}
-			} else {
-				// This is a key release
-				kb->KeyUp(ev.code);
-				key_repeat = 0;
-				touch_and_hold = 0;
-				touch_repeat = 0;
-				dontwait = 0;
-				blankTimer.resetTimerAndUnblank();
-			}
-		}
-		else if(ev.type == EV_REL)
-		{
-#ifdef _EVENT_LOGGING
-			LOGERR("EV_REL %d %d\n", ev.code, ev.value);
-#endif
-			if(ev.code == REL_X)
-				cursor->Move(ev.value, 0);
-			else if(ev.code == REL_Y)
-				cursor->Move(0, ev.value);
-
-			if(drag == 1) {
-				cursor->GetPos(x, y);
-#ifdef _EVENT_LOGGING
-				LOGERR("TOUCH_DRAG: %d, %d\n", x, y);
-#endif
-				if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
-					state = 1;
-				key_repeat = 0;
 			}
 		}
 	}
-	return NULL;
+	else if (ev.type == EV_KEY)
+	{
+		// Handle key-press here
+#ifdef _EVENT_LOGGING
+		LOGERR("TOUCH_KEY: %d\n", ev.code);
+#endif
+		// Left mouse button
+		if(ev.code == BTN_LEFT)
+		{
+			// Left mouse button is treated as a touch
+			if(ev.value == 1)
+			{
+				cursor->GetPos(x, y);
+#ifdef _EVENT_LOGGING
+				LOGERR("Mouse TOUCH_START: %d,%d\n", x, y);
+#endif
+				if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
+					state = AS_NO_ACTION;
+				else
+					state = AS_IN_ACTION_AREA;
+				touch_status = TS_TOUCH_AND_HOLD;
+				gettimeofday(&touchStart, NULL);
+			}
+			else if(touch_status)
+			{
+				// Left mouse button was previously pressed and now is
+				// being released so send a TOUCH_RELEASE
+				if (state == AS_IN_ACTION_AREA)
+				{
+					cursor->GetPos(x, y);
+
+#ifdef _EVENT_LOGGING
+					LOGERR("Mouse TOUCH_RELEASE: %d,%d\n", x, y);
+#endif
+					PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
+
+				}
+				touch_status = TS_NONE;
+			}
+		}
+		// side mouse button, often used for "back" function
+		else if(ev.code == BTN_SIDE)
+		{
+			if(ev.value == 1)
+				kb->KeyDown(KEY_BACK);
+			else
+				kb->KeyUp(KEY_BACK);
+		} else if (ev.value != 0) {
+			// This is a key press
+			if (kb->KeyDown(ev.code)) {
+				// Key repeat is enabled for this key
+				key_status = KS_KEY_PRESSED;
+				touch_status = TS_NONE;
+				gettimeofday(&touchStart, NULL);
+				blankTimer.resetTimerAndUnblank();
+			} else {
+				key_status = KS_NONE;
+				touch_status = TS_NONE;
+				blankTimer.resetTimerAndUnblank();
+			}
+		} else {
+			// This is a key release
+			kb->KeyUp(ev.code);
+			key_status = KS_NONE;
+			touch_status = TS_NONE;
+			blankTimer.resetTimerAndUnblank();
+		}
+	}
+	else if(ev.type == EV_REL)
+	{
+		// Mouse movement
+#ifdef _EVENT_LOGGING
+		LOGERR("EV_REL %d %d\n", ev.code, ev.value);
+#endif
+		if(ev.code == REL_X)
+			cursor->Move(ev.value, 0);
+		else if(ev.code == REL_Y)
+			cursor->Move(0, ev.value);
+
+		if(touch_status) {
+			cursor->GetPos(x, y);
+#ifdef _EVENT_LOGGING
+			LOGERR("Mouse TOUCH_DRAG: %d, %d\n", x, y);
+#endif
+			key_status = KS_NONE;
+		}
+	}
+	return;
 }
 
 static void setup_ors_command()
@@ -517,6 +537,7 @@
 
 	do
 	{
+		get_input(0); // get inputs but don't send drag notices
 		timespec curTime;
 		clock_gettime(CLOCK_MONOTONIC, &curTime);
 
@@ -526,12 +547,13 @@
 		if (diff.tv_sec || diff.tv_nsec > 33333333)
 		{
 			lastCall = curTime;
+			get_input(1); // send only drag notices if needed
 			return;
 		}
 
 		// We need to sleep some period time microseconds
-		unsigned int sleepTime = 33333 -(diff.tv_nsec / 1000);
-		usleep(sleepTime);
+		//unsigned int sleepTime = 33333 -(diff.tv_nsec / 1000);
+		//usleep(sleepTime); // removed so we can scan for input
 	} while (1);
 }
 
@@ -829,17 +851,14 @@
 	gGuiConsoleTerminate.set_value(1);
 
 	while (gGuiConsoleRunning.get_value())
-		loopTimer();
+		usleep(10000);
 
 	// Set the default package
 	PageManager::SelectPackage("TWRP");
 
-	if (!gGuiInputRunning)
+	if (!gGuiInputInit)
 	{
-		// Start by spinning off an input handler.
-		pthread_t t;
-		pthread_create(&t, NULL, input_thread, NULL);
-		gGuiInputRunning = 1;
+		input_init();
 	}
 #ifndef TW_OEM_BUILD
 	if (allow_commands)
diff --git a/gui/hardwarekeyboard.cpp b/gui/hardwarekeyboard.cpp
old mode 100644
new mode 100755
index d8cdfd4..1e3d7bc
--- a/gui/hardwarekeyboard.cpp
+++ b/gui/hardwarekeyboard.cpp
@@ -1,5 +1,5 @@
 // hardwarekeyboard.cpp - HardwareKeyboard object
-// Shell file used for most devices. A custom hardwarekeyboard.cpp is needed for devices with a hardware keyboard.
+// Custom hardware keyboard support for Asus Transformer devices
 
 #include <stdarg.h>
 #include <stdio.h>
@@ -19,65 +19,417 @@
 #include <string>
 
 extern "C" {
-#include "../twcommon.h"
+#include "../common.h"
 #include "../minuitwrp/minui.h"
+#include "../recovery_ui.h"
 }
 
 #include "rapidxml.hpp"
 #include "objects.hpp"
+#include "../data.hpp"
+#include <linux/input.h>

 
-HardwareKeyboard::HardwareKeyboard(void)
-{
-
+HardwareKeyboard::HardwareKeyboard(void) {
+	// Do Nothing
+	DataManager::SetValue("Lshift_down", 0);
+	DataManager::SetValue("Rshift_down", 0);
+	DataManager::SetValue("last_key", 0);
 }
 
-HardwareKeyboard::~HardwareKeyboard()
-{
-
+HardwareKeyboard::~HardwareKeyboard() {
+	// Do Nothing
 }
 
-int HardwareKeyboard::KeyDown(int key_code)
-{
-	mPressedKeys.insert(key_code);
-	PageManager::NotifyKey(key_code, true);
+int HardwareKeyboard::KeyDown(int key_code) {
+
+	int keyboard = -1;
+	int shiftkey, Lshift_down, Rshift_down;
+
+	DataManager::GetValue("Lshift_down", Lshift_down);
+	DataManager::GetValue("Rshift_down", Rshift_down);
+	if (Lshift_down || Rshift_down)
+		shiftkey = 1;
+	else
+		shiftkey = 0;
+
 #ifdef _EVENT_LOGGING
-	LOGERR("HardwareKeyboard::KeyDown %i\n", key_code);
+	LOGE("HardwareKeyboard::KeyDown %i\n", key_code);
 #endif
-	return 0; // 0 = no key repeat anything else turns on key repeat
+	switch (key_code) {
+		case KEY_LEFTSHIFT: // Left Shift
+			DataManager::SetValue("Lshift_down", 1);
+			return 0;
+			break;
+		case KEY_RIGHTSHIFT: // Right Shift
+			DataManager::SetValue("Rshift_down", 1);
+			return 0;
+			break;
+		case KEY_A:
+			if (shiftkey)
+				keyboard = 'A';
+			else
+				keyboard = 'a';
+			break;
+		case KEY_B:
+			if (shiftkey)
+				keyboard = 'B';
+			else
+				keyboard = 'b';
+			break;
+		case KEY_C:
+			if (shiftkey)
+				keyboard = 'C';
+			else
+				keyboard = 'c';
+			break;
+		case KEY_D:
+			if (shiftkey)
+				keyboard = 'D';
+			else
+				keyboard = 'd';
+			break;
+		case KEY_E:
+			if (shiftkey)
+				keyboard = 'E';
+			else
+				keyboard = 'e';
+			break;
+		case KEY_F:
+			if (shiftkey)
+				keyboard = 'F';
+			else
+				keyboard = 'f';
+			break;
+		case KEY_G:
+			if (shiftkey)
+				keyboard = 'G';
+			else
+				keyboard = 'g';
+			break;
+		case KEY_H:
+			if (shiftkey)
+				keyboard = 'H';
+			else
+				keyboard = 'h';
+			break;
+		case KEY_I:
+			if (shiftkey)
+				keyboard = 'I';
+			else
+				keyboard = 'i';
+			break;
+		case KEY_J:
+			if (shiftkey)
+				keyboard = 'J';
+			else
+				keyboard = 'j';
+			break;
+		case KEY_K:
+			if (shiftkey)
+				keyboard = 'K';
+			else
+				keyboard = 'k';
+			break;
+		case KEY_L:
+			if (shiftkey)
+				keyboard = 'L';
+			else
+				keyboard = 'l';
+			break;
+		case KEY_M:
+			if (shiftkey)
+				keyboard = 'M';
+			else
+				keyboard = 'm';
+			break;
+		case KEY_N:
+			if (shiftkey)
+				keyboard = 'N';
+			else
+				keyboard = 'n';
+			break;
+		case KEY_O:
+			if (shiftkey)
+				keyboard = 'O';
+			else
+				keyboard = 'o';
+			break;
+		case KEY_P:
+			if (shiftkey)
+				keyboard = 'P';
+			else
+				keyboard = 'p';
+			break;
+		case KEY_Q:
+			if (shiftkey)
+				keyboard = 'Q';
+			else
+				keyboard = 'q';
+			break;
+		case KEY_R:
+			if (shiftkey)
+				keyboard = 'R';
+			else
+				keyboard = 'r';
+			break;
+		case KEY_S:
+			if (shiftkey)
+				keyboard = 'S';
+			else
+				keyboard = 's';
+			break;
+		case KEY_T:
+			if (shiftkey)
+				keyboard = 'T';
+			else
+				keyboard = 't';
+			break;
+		case KEY_U:
+			if (shiftkey)
+				keyboard = 'U';
+			else
+				keyboard = 'u';
+			break;
+		case KEY_V:
+			if (shiftkey)
+				keyboard = 'V';
+			else
+				keyboard = 'v';
+			break;
+		case KEY_W:
+			if (shiftkey)
+				keyboard = 'W';
+			else
+				keyboard = 'w';
+			break;
+		case KEY_X:
+			if (shiftkey)
+				keyboard = 'X';
+			else
+				keyboard = 'x';
+			break;
+		case KEY_Y:
+			if (shiftkey)
+				keyboard = 'Y';
+			else
+				keyboard = 'y';
+			break;
+		case KEY_Z:
+			if (shiftkey)
+				keyboard = 'Z';
+			else
+				keyboard = 'z';
+			break;
+		case KEY_0:
+			if (shiftkey)
+				keyboard = ')';
+			else
+				keyboard = '0';
+			break;
+		case KEY_1:
+			if (shiftkey)
+				keyboard = '!';
+			else
+				keyboard = '1';
+			break;
+		case KEY_2:
+			if (shiftkey)
+				keyboard = '@';
+			else
+				keyboard = '2';
+			break;
+		case KEY_3:
+			if (shiftkey)
+				keyboard = '#';
+			else
+				keyboard = '3';
+			break;
+		case KEY_4:
+			if (shiftkey)
+				keyboard = '$';
+			else
+				keyboard = '4';
+			break;
+		case KEY_5:
+			if (shiftkey)
+				keyboard = '%';
+			else
+				keyboard = '5';
+			break;
+		case KEY_6:
+			if (shiftkey)
+				keyboard = '^';
+			else
+				keyboard = '6';
+			break;
+		case KEY_7:
+			if (shiftkey)
+				keyboard = '&';
+			else
+				keyboard = '7';
+			break;
+		case KEY_8:
+			if (shiftkey)
+				keyboard = '*';
+			else
+				keyboard = '8';
+			break;
+		case KEY_9:
+			if (shiftkey)
+				keyboard = '(';
+			else
+				keyboard = '9';
+			break;
+		case KEY_SPACE:
+			keyboard = ' ';
+			break;
+		case KEY_BACKSPACE:
+			keyboard = KEYBOARD_BACKSPACE;
+			break;
+		case KEY_ENTER:
+			keyboard = KEYBOARD_ACTION;
+			break;
+		case KEY_SLASH:
+			if (shiftkey)
+				keyboard = '?';
+			else
+				keyboard = '/';
+			break;
+		case KEY_DOT:
+			if (shiftkey)
+				keyboard = '>';
+			else
+				keyboard = '.';
+			break;
+		case KEY_COMMA:
+			if (shiftkey)
+				keyboard = '<';
+			else
+				keyboard = ',';
+			break;
+		case KEY_MINUS:
+			if (shiftkey)
+				keyboard = '_';
+			else
+				keyboard = '-';
+			break;
+		case KEY_GRAVE:
+			if (shiftkey)
+				keyboard = '~';
+			else
+				keyboard = '`';
+			break;
+		case KEY_EQUAL:
+			if (shiftkey)
+				keyboard = '+';
+			else
+				keyboard = '=';
+			break;
+		case KEY_LEFTBRACE:
+			if (shiftkey)
+				keyboard = '{';
+			else
+				keyboard = '[';
+			break;
+		case KEY_RIGHTBRACE:
+			if (shiftkey)
+				keyboard = '}';
+			else
+				keyboard = ']';
+			break;
+		case KEY_BACKSLASH:
+			if (shiftkey)
+				keyboard = '|';
+			else
+				keyboard = '\\';
+			break;
+		case KEY_SEMICOLON:
+			if (shiftkey)
+				keyboard = ':';
+			else
+				keyboard = ';';
+			break;
+		case KEY_APOSTROPHE:
+			if (shiftkey)
+				keyboard = '\"';
+			else
+				keyboard = '\'';
+			break;
+		case KEY_UP: // Up arrow
+			keyboard = KEYBOARD_ARROW_UP;
+			break;
+		case KEY_DOWN: // Down arrow
+			keyboard = KEYBOARD_ARROW_DOWN;
+			break;
+		case KEY_LEFT: // Left arrow
+			keyboard = KEYBOARD_ARROW_LEFT;
+			break;
+		case KEY_RIGHT: // Right arrow
+			keyboard = KEYBOARD_ARROW_RIGHT;
+			break;
+		case KEY_BACK: // back button on screen
+			mPressedKeys.insert(KEY_BACK);
+			PageManager::NotifyKey(KEY_BACK, true);
+			return 0;
+			break;
+		case KEY_HOMEPAGE: // keyboard home button
+		case KEY_HOME: // home button on screen
+			mPressedKeys.insert(KEY_HOME);
+			PageManager::NotifyKey(KEY_HOME, true);
+			return 0;
+			break;
+		case KEY_SLEEP: // keyboard lock button
+		case KEY_POWER: // tablet power button
+			mPressedKeys.insert(KEY_POWER);
+			PageManager::NotifyKey(KEY_POWER, true);
+			return 0;
+			break;
+#ifdef _EVENT_LOGGING
+		default:
+			LOGE("Unmapped keycode: %i\n", key_code);
+			break;
+#endif
+	}
+	if (keyboard != -1) {
+		DataManager::SetValue("last_key", keyboard);
+		mPressedKeys.insert(keyboard);
+		if (!PageManager::NotifyKeyboard(keyboard))
+			return 1;  // Return 1 to enable key repeat
+	} else {
+		DataManager::SetValue("last_key", 0);
+	}
+	return 0;
 }
 
-int HardwareKeyboard::KeyUp(int key_code)
-{
+int HardwareKeyboard::KeyUp(int key_code) {
 	std::set<int>::iterator itr = mPressedKeys.find(key_code);
-	if(itr != mPressedKeys.end())
-	{
+	if (itr != mPressedKeys.end()) {
 		mPressedKeys.erase(itr);
 		PageManager::NotifyKey(key_code, false);
 	}
 #ifdef _EVENT_LOGGING
-	LOGERR("HardwareKeyboard::KeyUp %i\n", key_code);
+	LOGE("HardwareKeyboard::KeyUp %i\n", key_code);
 #endif
+	if (key_code == KEY_LEFTSHIFT) { // Left Shift
+		DataManager::SetValue("Lshift_down", 0);
+	} else if (key_code == 31) { // Right Shift
+		DataManager::SetValue("Rshift_down", 0);
+	}
 	return 0;
 }
 
-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
-	 * }
-	 */
+int HardwareKeyboard::KeyRepeat(void) {
+	int last_key;
 
+	DataManager::GetValue("last_key", last_key);
 #ifdef _EVENT_LOGGING
-	LOGERR("HardwareKeyboard::KeyRepeat\n");
+	LOGE("HardwareKeyboard::KeyRepeat: %i\n", last_key);
 #endif
+	if (last_key)
+		PageManager::NotifyKeyboard(last_key);
 	return 0;
 }
 
-void HardwareKeyboard::ConsumeKeyRelease(int key)
-{
+void HardwareKeyboard::ConsumeKeyRelease(int key) {
 	mPressedKeys.erase(key);
 }
diff --git a/minuitwrp/events.c b/minuitwrp/events.c
index f02edd3..98b3a34 100644
--- a/minuitwrp/events.c
+++ b/minuitwrp/events.c
@@ -719,44 +719,40 @@
     return 0;
 }
 
-int ev_get(struct input_event *ev, unsigned dont_wait)
+int ev_get(struct input_event *ev)
 {
     int r;
     unsigned n;
     struct timeval curr;
 
-    do {
-        gettimeofday(&curr, NULL);
-        if(curr.tv_sec - lastInputStat.tv_sec >= 2)
+    gettimeofday(&curr, NULL);
+    if(curr.tv_sec - lastInputStat.tv_sec >= 2)
+    {
+        struct stat st;
+        stat("/dev/input", &st);
+        if (st.st_mtime > lastInputMTime)
         {
-            struct stat st;
-            stat("/dev/input", &st);
-            if (st.st_mtime > lastInputMTime)
-            {
-                LOGI("Reloading input devices\n");
-                ev_exit();
-                ev_init();
-                lastInputMTime = st.st_mtime;
-            }
-            lastInputStat = curr;
+            printf("Reloading input devices\n");
+            ev_exit();
+            ev_init();
+            lastInputMTime = st.st_mtime;
         }
+        lastInputStat = curr;
+    }
 
-        r = poll(ev_fds, ev_count, 0);
+    r = poll(ev_fds, ev_count, 0);
 
-        if(r > 0) {
-            for(n = 0; n < ev_count; n++) {
-                if(ev_fds[n].revents & POLLIN) {
-                    r = read(ev_fds[n].fd, ev, sizeof(*ev));
-                    if(r == sizeof(*ev)) {
-                        if (!vk_modify(&evs[n], ev))
-                            return 0;
-                    }
+    if(r > 0) {
+        for(n = 0; n < ev_count; n++) {
+            if(ev_fds[n].revents & POLLIN) {
+                r = read(ev_fds[n].fd, ev, sizeof(*ev));
+                if(r == sizeof(*ev)) {
+                    if (!vk_modify(&evs[n], ev))
+                        return 0;
                 }
             }
         }
-
-        usleep(1000);
-    } while(dont_wait == 0);
+    }
 
     return -1;
 }
diff --git a/minuitwrp/minui.h b/minuitwrp/minui.h
index cb9f8a3..abebc14 100644
--- a/minuitwrp/minui.h
+++ b/minuitwrp/minui.h
@@ -75,7 +75,7 @@
 
 int ev_init(void);
 void ev_exit(void);
-int ev_get(struct input_event *ev, unsigned dont_wait);
+int ev_get(struct input_event *ev);
 int ev_has_mouse(void);
 
 // Resources