From 0388755df1e3d65aa6d17f90965bcf5037c204ab Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Sat, 26 Aug 2017 11:15:56 +1000
Subject: Add gwinTextEditSendKey() and gwinTextEditSendSpecialKey()

---
 src/gwin/gwin_textedit.c | 190 ++++++++++++++++++++++++++---------------------
 src/gwin/gwin_textedit.h |  26 +++++++
 2 files changed, 131 insertions(+), 85 deletions(-)

(limited to 'src/gwin')

diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c
index 8e639300..61c28c66 100644
--- a/src/gwin/gwin_textedit.c
+++ b/src/gwin/gwin_textedit.c
@@ -26,54 +26,54 @@
 #define gh2obj ((GTexteditObject *)gh)
 #define gw2obj ((GTexteditObject *)gw)
 
-static void TextEditRemoveChar(GWidgetObject* gw) {
+static void TextEditRemoveChar(GHandle gh) {
 	char		*p;
 	const char	*q;
 	unsigned	sz;
 	unsigned	pos;
 
-	sz = strlen(gw->text);
-	pos = gw2obj->cursorPos;
-	q = gw->text+pos;
+	sz = strlen(gh2obj->w.text);
+	pos = gh2obj->cursorPos;
+	q = gh2obj->w.text+pos;
 	
-	if (!(gw->g.flags & GWIN_FLG_ALLOCTXT)) {
+	if (!(gh->flags & GWIN_FLG_ALLOCTXT)) {
 		// Allocate and then copy
 		if (!(p = gfxAlloc(sz)))
 			return;
 		if (pos)
-			memcpy(p, gw->text, pos);
+			memcpy(p, gh2obj->w.text, pos);
 		memcpy(p+pos, q+1, sz-pos);
-		gw->g.flags |= GWIN_FLG_ALLOCTXT;
+		gh->flags |= GWIN_FLG_ALLOCTXT;
 	} else {
 		// Copy and then reallocate
 		memcpy((char *)q, q+1, sz-pos);
-		if (!(p = gfxRealloc((char *)gw->text, sz+1, sz)))		// This should never fail as we are making it smaller
+		if (!(p = gfxRealloc((char *)gh2obj->w.text, sz+1, sz)))		// This should never fail as we are making it smaller
 			return;
 	}
-	gw->text = p;
+	gh2obj->w.text = p;
 }
 
-static bool_t TextEditAddChars(GWidgetObject* gw, unsigned cnt) {
+static bool_t TextEditAddChars(GHandle gh, unsigned cnt) {
 	char		*p;
 	const char	*q;
 	unsigned	sz;
 	unsigned	pos;
 
 	// Get the size of the text buffer
-	sz = strlen(gw->text)+1;
-	pos = gw2obj->cursorPos;
+	sz = strlen(gh2obj->w.text)+1;
+	pos = gh2obj->cursorPos;
 
-	if (!(gw->g.flags & GWIN_FLG_ALLOCTXT)) {
+	if (!(gh->flags & GWIN_FLG_ALLOCTXT)) {
 		if (!(p = gfxAlloc(sz+cnt)))
 			return FALSE;
-		memcpy(p, gw->text, pos);
-		memcpy(p+pos+cnt, gw->text+pos, sz-pos);
-		gw->g.flags |= GWIN_FLG_ALLOCTXT;
-		gw->text = p;
+		memcpy(p, gh2obj->w.text, pos);
+		memcpy(p+pos+cnt, gh2obj->w.text+pos, sz-pos);
+		gh->flags |= GWIN_FLG_ALLOCTXT;
+		gh2obj->w.text = p;
 	} else {
-		if (!(p = gfxRealloc((char *)gw->text, sz, sz+cnt)))
+		if (!(p = gfxRealloc((char *)gh2obj->w.text, sz, sz+cnt)))
 			return FALSE;
-		gw->text = p;
+		gh2obj->w.text = p;
 		q = p+pos;
 		p += sz;
 		while(--p >= q)
@@ -117,76 +117,13 @@ static void TextEditMouseDown(GWidgetObject* gw, coord_t x, coord_t y) {
 
 		// Is it a special key?
 		if (pke->keystate & GKEYSTATE_SPECIAL) {
-
 			// Arrow keys to move the cursor
-			switch ((uint8_t)pke->c[0]) {
-			case GKEY_LEFT:
-				if (!gw2obj->cursorPos)
-					return;
-				gw2obj->cursorPos--;
-				break;
-			case GKEY_RIGHT:
-				if (!gw->text[gw2obj->cursorPos])
-					return;
-				gw2obj->cursorPos++;
-				break;
-			case GKEY_HOME:
-				if (!gw2obj->cursorPos)
-					return;
-				gw2obj->cursorPos = 0;
-				break;
-			case GKEY_END:
-				if (!gw->text[gw2obj->cursorPos])
-					return;
-				gw2obj->cursorPos = strlen(gw->text);
-				break;
-			default:
-				return;
-			}
-
-		} else {
+			gwinTextEditSendSpecialKey(&gw->g, (uint8_t)pke->c[0]);
+			return;
 
-			// Normal key press
-			switch((uint8_t)pke->c[0]) {
-			case GKEY_BACKSPACE:
-				// Backspace
-				if (!gw2obj->cursorPos)
-					return;
-				gw2obj->cursorPos--;
-				TextEditRemoveChar(gw);
-				break;
-			case GKEY_TAB:
-			case GKEY_LF:
-			case GKEY_CR:
-				// Move to the next field
-				_gwinMoveFocus();
-				return;
-			case GKEY_DEL:
-				// Delete
-				if (!gw->text[gw2obj->cursorPos])
-					return;
-				TextEditRemoveChar(gw);
-				break;
-			default:
-				// Ignore any other control characters
-				if ((uint8_t)pke->c[0] < GKEY_SPACE)
-					return;
-
-				// Keep the edit length to less than the maximum
-				if (gw2obj->maxSize && strlen(gw->text)+pke->bytecount > gw2obj->maxSize)
-					return;
-
-				// Make space
-				if (TextEditAddChars(gw, pke->bytecount)) {
-					// Insert the characters
-					memcpy((char *)gw->text+gw2obj->cursorPos, pke->c, pke->bytecount);
-					gw2obj->cursorPos += pke->bytecount;
-				}
-				break;
-			}
 		}
 
-		_gwinUpdate((GHandle)gw);
+		gwinTextEditSendKey(&gw->g, pke->c, pke->bytecount);
 	}
 #endif
 
@@ -246,6 +183,89 @@ GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit
 	return (GHandle)wt;
 }
 
+#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD
+	void gwinTextEditSendSpecialKey(GHandle gh, uint8_t key) {
+		// Is it a valid handle?
+		if (gh->vmt != (gwinVMT*)&texteditVMT)
+			return;
+
+		// Arrow keys to move the cursor
+		switch (key) {
+		case GKEY_LEFT:
+			if (!gh2obj->cursorPos)
+				return;
+			gh2obj->cursorPos--;
+			break;
+		case GKEY_RIGHT:
+			if (!gh2obj->w.text[gh2obj->cursorPos])
+				return;
+			gh2obj->cursorPos++;
+			break;
+		case GKEY_HOME:
+			if (!gh2obj->cursorPos)
+				return;
+			gh2obj->cursorPos = 0;
+			break;
+		case GKEY_END:
+			if (!gh2obj->w.text[gh2obj->cursorPos])
+				return;
+			gh2obj->cursorPos = strlen(gh2obj->w.text);
+			break;
+		default:
+			return;
+		}
+
+		_gwinUpdate(gh);
+	}
+
+	void gwinTextEditSendKey(GHandle gh, char *key, unsigned len) {
+		// Is it a valid handle?
+		if (gh->vmt != (gwinVMT*)&texteditVMT || !key || !len)
+			return;
+
+		// Normal key press
+		switch((uint8_t)key[0]) {
+		case GKEY_BACKSPACE:
+			// Backspace
+			if (!gh2obj->cursorPos)
+				return;
+			gh2obj->cursorPos--;
+			TextEditRemoveChar(gh);
+			break;
+		case GKEY_TAB:
+		case GKEY_LF:
+		case GKEY_CR:
+			// Move to the next field
+			_gwinMoveFocus();
+			return;
+		case GKEY_DEL:
+			// Delete
+			if (!gh2obj->w.text[gh2obj->cursorPos])
+				return;
+			TextEditRemoveChar(gh);
+			break;
+		default:
+			// Ignore any other control characters
+			if ((uint8_t)key[0] < GKEY_SPACE)
+				return;
+
+			// Keep the edit length to less than the maximum
+			if (gh2obj->maxSize && strlen(gh2obj->w.text)+len > gh2obj->maxSize)
+				return;
+
+			// Make space
+			if (TextEditAddChars(gh, len)) {
+				// Insert the characters
+				memcpy((char *)gh2obj->w.text+gh2obj->cursorPos, key, len);
+				gh2obj->cursorPos += len;
+			}
+			break;
+		}
+
+		_gwinUpdate(gh);
+	}
+#endif
+
 void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param)
 {
 	const char*			p;
diff --git a/src/gwin/gwin_textedit.h b/src/gwin/gwin_textedit.h
index ed2f634d..8cf6c03e 100644
--- a/src/gwin/gwin_textedit.h
+++ b/src/gwin/gwin_textedit.h
@@ -63,6 +63,32 @@ extern "C" {
 GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit, size_t maxSize);
 #define gwinTexteditCreate(wt, pInit, maxSize)			gwinGTexteditCreate(GDISP, wt, pInit, maxSize)
 
+/**
+ * @brief				Send a special key to the textedit such as GKEY_LEFT, GKEY_RIGHT, GKEY_HOME, GKEY_END
+ *
+ * @param[in] gh		The window handle (must be a textedit window)
+ * @param[in] key		The special key to send.
+ * @pre					Requires GINPUT_NEED_KEYBOARD or GWIN_NEED_KEYBOARD to be on
+ * @api
+ */
+void gwinTextEditSendSpecialKey(GHandle gh, uint8_t key);
+
+/**
+ * @brief				Send a normal utf8 character to the textedit
+ *
+ * @param[in] gh		The window handle (must be a textedit window)
+ * @param[in] pkey		The pointer to the utf8 character to send.
+ * @param[in] len		The length of the utf8 character in bytes.
+ * @note				This must ONLY be called with a single utf8 character at a time. Don't attempt to
+ *						send a string of characters in the one call.
+ * @note				Characters are interpreted as if they came directly from a keyboard ie a backspace
+ *						character will perform the backspace operation, a tab will send the focus to the next
+ *						control etc.
+ * @pre					Requires GINPUT_NEED_KEYBOARD or GWIN_NEED_KEYBOARD to be on
+ * @api
+ */
+void gwinTextEditSendKey(GHandle gh, char *pkey, unsigned len);
+
 /**
  * @defgroup Renderings_Textedit Renderings
  *
-- 
cgit v1.2.3