summaryrefslogtreecommitdiff
path: root/src/uqm/getchar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/getchar.c')
-rw-r--r--src/uqm/getchar.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/src/uqm/getchar.c b/src/uqm/getchar.c
new file mode 100644
index 0000000..3f1f6ed
--- /dev/null
+++ b/src/uqm/getchar.c
@@ -0,0 +1,442 @@
+//Copyright Paul Reiche, Fred Ford. 1992-2002
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "port.h"
+#include "controls.h"
+#include "libs/inplib.h"
+#include "libs/memlib.h"
+#include "libs/log.h"
+#include "globdata.h"
+#include "sounds.h"
+#include "settings.h"
+#include "resinst.h"
+#include "nameref.h"
+
+
+// TODO: This may be better done with UniChar at the cost of a tiny bit
+// of overhead to convert UniChar back to UTF8 string. This overhead
+// will probably be offset by removal of looped string-compare overhead ;)
+struct joy_char
+{
+ unsigned char len;
+ char enc[7];
+ // 1+7 is a nice round number
+};
+
+static int
+ReadOneChar (joy_char_t *ch, const UNICODE *str)
+{
+ UNICODE *next = skipUTF8Chars (str, 1);
+ int len = next - str;
+ ch->len = len;
+ memcpy (ch->enc, str, len);
+ ch->enc[len] = '\0'; // string term
+
+ return len;
+}
+
+static joy_char_t *
+LoadJoystickAlpha (STRING String, int *count)
+{
+ UNICODE *str;
+ int c;
+ int i;
+ joy_char_t *chars;
+ UNICODE *cur;
+
+ *count = 0;
+ str = GetStringAddress (String);
+ if (!str)
+ return 0;
+
+ c = utf8StringCount (str);
+ chars = HMalloc (c * sizeof (*chars));
+ if (!chars)
+ return 0;
+
+ for (i = 0, cur = str; i < c; ++i)
+ {
+ int len = ReadOneChar (chars + i, cur);
+ cur += len;
+ }
+
+ *count = c;
+ return chars;
+}
+
+static int
+JoyCharFindIn (const joy_char_t *ch, const joy_char_t *set,
+ int setsize)
+{
+ int i;
+
+ for (i = 0; i < setsize && strcmp (set[i].enc, ch->enc) != 0; ++i)
+ ;
+
+ return (i < setsize) ? i : -1;
+}
+
+static int
+JoyCharIsLower (const joy_char_t *ch, TEXTENTRY_STATE *pTES)
+{
+ return 0 <= JoyCharFindIn (ch, pTES->JoyLower, pTES->JoyRegLength);
+}
+
+static void
+JoyCharSwitchReg (joy_char_t *ch, const joy_char_t *from,
+ const joy_char_t *to, int regsize)
+{
+ int i = JoyCharFindIn (ch, from, regsize);
+ if (i >= 0)
+ *ch = to[i];
+}
+
+static void
+JoyCharToUpper (joy_char_t *outch, const joy_char_t *ch,
+ TEXTENTRY_STATE *pTES)
+{
+ *outch = *ch;
+ JoyCharSwitchReg (outch, pTES->JoyLower, pTES->JoyUpper,
+ pTES->JoyRegLength);
+}
+
+static void
+JoyCharToLower (joy_char_t *outch, const joy_char_t *ch,
+ TEXTENTRY_STATE *pTES)
+{
+ *outch = *ch;
+ JoyCharSwitchReg (outch, pTES->JoyUpper, pTES->JoyLower,
+ pTES->JoyRegLength);
+}
+
+BOOLEAN
+DoTextEntry (TEXTENTRY_STATE *pTES)
+{
+ UniChar ch;
+ UNICODE *pStr;
+ UNICODE *CacheInsPt;
+ int CacheCursorPos;
+ int len;
+ BOOLEAN changed = FALSE;
+
+ if (GLOBAL (CurrentActivity) & CHECK_ABORT)
+ return (FALSE);
+
+ if (!pTES->Initialized)
+ { // init basic vars
+ int lwlen;
+
+ pTES->InputFunc = DoTextEntry;
+ pTES->Success = FALSE;
+ pTES->Initialized = TRUE;
+ pTES->JoystickMode = FALSE;
+ pTES->UpperRegister = TRUE;
+
+ // init insertion point
+ if ((size_t)pTES->CursorPos > utf8StringCount (pTES->BaseStr))
+ pTES->CursorPos = utf8StringCount (pTES->BaseStr);
+ pTES->InsPt = skipUTF8Chars (pTES->BaseStr, pTES->CursorPos);
+
+ // load joystick alphabet
+ pTES->JoyAlphaString = CaptureStringTable (
+ LoadStringTable (JOYSTICK_ALPHA_STRTAB));
+ pTES->JoyAlpha = LoadJoystickAlpha (
+ SetAbsStringTableIndex (pTES->JoyAlphaString, 0),
+ &pTES->JoyAlphaLength);
+ pTES->JoyUpper = LoadJoystickAlpha (
+ SetAbsStringTableIndex (pTES->JoyAlphaString, 1),
+ &pTES->JoyRegLength);
+ pTES->JoyLower = LoadJoystickAlpha (
+ SetAbsStringTableIndex (pTES->JoyAlphaString, 2),
+ &lwlen);
+ if (lwlen != pTES->JoyRegLength)
+ {
+ if (lwlen < pTES->JoyRegLength)
+ pTES->JoyRegLength = lwlen;
+ log_add (log_Warning, "Warning: Joystick upper-lower registers"
+ " size mismatch; using the smallest subset (%d)",
+ pTES->JoyRegLength);
+ }
+
+ pTES->CacheStr = HMalloc (pTES->MaxSize * sizeof (*pTES->CacheStr));
+
+ EnterCharacterMode ();
+ DoInput (pTES, TRUE);
+ ExitCharacterMode ();
+
+ if (pTES->CacheStr)
+ HFree (pTES->CacheStr);
+ if (pTES->JoyLower)
+ HFree (pTES->JoyLower);
+ if (pTES->JoyUpper)
+ HFree (pTES->JoyUpper);
+ if (pTES->JoyAlpha)
+ HFree (pTES->JoyAlpha);
+ DestroyStringTable ( ReleaseStringTable (pTES->JoyAlphaString));
+
+ return pTES->Success;
+ }
+
+ pStr = pTES->InsPt;
+ len = strlen (pStr);
+ // save a copy of string
+ CacheInsPt = pTES->InsPt;
+ CacheCursorPos = pTES->CursorPos;
+ memcpy (pTES->CacheStr, pTES->BaseStr, pTES->MaxSize);
+
+ // process the pending character buffer
+ ch = GetNextCharacter ();
+ if (!ch && PulsedInputState.menu[KEY_MENU_ANY])
+ { // keyboard repeat, but only when buffer empty
+ ch = GetLastCharacter ();
+ }
+ while (ch)
+ {
+ UNICODE chbuf[8];
+ int chsize;
+
+ pTES->JoystickMode = FALSE;
+
+ chsize = getStringFromChar (chbuf, sizeof (chbuf), ch);
+ if (UniChar_isPrint (ch) && chsize > 0)
+ {
+ if (pStr + len - pTES->BaseStr + chsize < pTES->MaxSize)
+ { // insert character, when fits
+ memmove (pStr + chsize, pStr, len + 1);
+ memcpy (pStr, chbuf, chsize);
+ pStr += chsize;
+ ++pTES->CursorPos;
+ changed = TRUE;
+ }
+ else
+ { // does not fit
+ PlayMenuSound (MENU_SOUND_FAILURE);
+ }
+ }
+ ch = GetNextCharacter ();
+ }
+
+ if (PulsedInputState.menu[KEY_MENU_DELETE])
+ {
+ if (len)
+ {
+ joy_char_t ch;
+
+ ReadOneChar (&ch, pStr);
+ memmove (pStr, pStr + ch.len, len - ch.len + 1);
+ len -= ch.len;
+ changed = TRUE;
+ }
+ }
+ else if (PulsedInputState.menu[KEY_MENU_BACKSPACE])
+ {
+ if (pStr > pTES->BaseStr)
+ {
+ UNICODE *prev = skipUTF8Chars (pTES->BaseStr,
+ pTES->CursorPos - 1);
+
+ memmove (prev, pStr, len + 1);
+ pStr = prev;
+ --pTES->CursorPos;
+ changed = TRUE;
+ }
+ }
+ else if (PulsedInputState.menu[KEY_MENU_LEFT])
+ {
+ if (pStr > pTES->BaseStr)
+ {
+ UNICODE *prev = skipUTF8Chars (pTES->BaseStr,
+ pTES->CursorPos - 1);
+
+ pStr = prev;
+ len += (prev - pStr);
+ --pTES->CursorPos;
+ changed = TRUE;
+ }
+ }
+ else if (PulsedInputState.menu[KEY_MENU_RIGHT])
+ {
+ if (len > 0)
+ {
+ joy_char_t ch;
+
+ ReadOneChar (&ch, pStr);
+ pStr += ch.len;
+ len -= ch.len;
+ ++pTES->CursorPos;
+ changed = TRUE;
+ }
+ }
+ else if (PulsedInputState.menu[KEY_MENU_HOME])
+ {
+ if (pStr > pTES->BaseStr)
+ {
+ pStr = pTES->BaseStr;
+ len = strlen (pStr);
+ pTES->CursorPos = 0;
+ changed = TRUE;
+ }
+ }
+ else if (PulsedInputState.menu[KEY_MENU_END])
+ {
+ if (len > 0)
+ {
+ pTES->CursorPos += utf8StringCount (pStr);
+ pStr += len;
+ len = 0;
+ changed = TRUE;
+ }
+ }
+
+ if (pTES->JoyAlpha && (
+ PulsedInputState.menu[KEY_MENU_UP] ||
+ PulsedInputState.menu[KEY_MENU_DOWN] ||
+ PulsedInputState.menu[KEY_MENU_PAGE_UP] ||
+ PulsedInputState.menu[KEY_MENU_PAGE_DOWN]) )
+ { // do joystick text
+ joy_char_t ch;
+ joy_char_t newch;
+ joy_char_t cmpch;
+ int i;
+ BOOLEAN curCharUpper;
+
+ pTES->JoystickMode = TRUE;
+
+ if (len)
+ { // changing an existing character
+ ReadOneChar (&ch, pStr);
+ curCharUpper = !JoyCharIsLower (&ch, pTES);
+ }
+ else
+ { // adding a new character
+ ch = pTES->JoyAlpha[0];
+ // new characters will have case determined by the
+ // currently selected register
+ curCharUpper = pTES->UpperRegister;
+ }
+
+ newch = ch;
+ JoyCharToUpper (&cmpch, &ch, pTES);
+
+ // find current char in the alphabet
+ i = JoyCharFindIn (&cmpch, pTES->JoyAlpha, pTES->JoyAlphaLength);
+
+ if (PulsedInputState.menu[KEY_MENU_UP])
+ {
+ --i;
+ if (i < 0)
+ i = pTES->JoyAlphaLength - 1;
+ newch = pTES->JoyAlpha[i];
+ }
+ else if (PulsedInputState.menu[KEY_MENU_DOWN])
+ {
+ ++i;
+ if (i >= pTES->JoyAlphaLength)
+ i = 0;
+ newch = pTES->JoyAlpha[i];
+ }
+
+ if (PulsedInputState.menu[KEY_MENU_PAGE_UP] ||
+ PulsedInputState.menu[KEY_MENU_PAGE_DOWN])
+ {
+ if (len)
+ { // single char change
+ if (!curCharUpper)
+ JoyCharToUpper (&newch, &newch, pTES);
+ else
+ JoyCharToLower (&newch, &newch, pTES);
+ }
+ else
+ { // register change
+ pTES->UpperRegister = !pTES->UpperRegister;
+ }
+ }
+ else
+ { // check register
+ if (curCharUpper)
+ JoyCharToUpper (&newch, &newch, pTES);
+ else
+ JoyCharToLower (&newch, &newch, pTES);
+ }
+
+ if (strcmp (newch.enc, ch.enc) != 0)
+ { // new char is different, put it in
+ if (len)
+ { // change current -- this is messy with utf8
+ int l = len - ch.len;
+ if (pStr + l - pTES->BaseStr + newch.len < pTES->MaxSize)
+ {
+ // adjust other chars if necessary
+ if (newch.len != ch.len)
+ memmove (pStr + newch.len, pStr + ch.len, l + 1);
+
+ memcpy (pStr, newch.enc, newch.len);
+ len = l + newch.len;
+ changed = TRUE;
+ }
+ }
+ else
+ { // append
+ if (pStr + len - pTES->BaseStr + newch.len < pTES->MaxSize)
+ {
+ memcpy (pStr, newch.enc, newch.len);
+ pStr[newch.len] = '\0';
+ len += newch.len;
+ changed = TRUE;
+ }
+ else
+ { // does not fit
+ PlayMenuSound (MENU_SOUND_FAILURE);
+ }
+ }
+ }
+ }
+
+ if (PulsedInputState.menu[KEY_MENU_SELECT])
+ { // done entering
+ pTES->Success = TRUE;
+ return FALSE;
+ }
+ else if (PulsedInputState.menu[KEY_MENU_EDIT_CANCEL])
+ { // canceled entering
+ pTES->Success = FALSE;
+ return FALSE;
+ }
+
+ pTES->InsPt = pStr;
+
+ if (changed && pTES->ChangeCallback)
+ {
+ if (!pTES->ChangeCallback (pTES))
+ { // changes not accepted - revert
+ memcpy (pTES->BaseStr, pTES->CacheStr, pTES->MaxSize);
+ pTES->InsPt = CacheInsPt;
+ pTES->CursorPos = CacheCursorPos;
+
+ PlayMenuSound (MENU_SOUND_FAILURE);
+ }
+ }
+
+ if (pTES->FrameCallback)
+ return pTES->FrameCallback (pTES);
+ else
+ SleepThread (ONE_SECOND / 30);
+
+ return TRUE;
+}
+