Universal text input, phase 3: UCS/Unicode text input

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2157 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2006-01-10 07:28:54 +00:00
parent 6fc558d48a
commit 52efe15562
6 changed files with 240 additions and 67 deletions
+9 -2
View File
@@ -106,6 +106,8 @@ BATTLE_INPUT_STATE p2_combat_summary (void);
extern volatile BOOLEAN GamePaused, ExitRequested; extern volatile BOOLEAN GamePaused, ExitRequested;
typedef struct joy_char joy_char_t;
typedef struct textentry_state typedef struct textentry_state
{ {
// standard state required by DoInput // standard state required by DoInput
@@ -119,10 +121,15 @@ typedef struct textentry_state
STRING JoyAlphaString; // joystick alphabet definition STRING JoyAlphaString; // joystick alphabet definition
BOOLEAN JoystickMode; // TRUE when doing joystick input BOOLEAN JoystickMode; // TRUE when doing joystick input
BOOLEAN UpperRegister; // TRUE when entering Caps BOOLEAN UpperRegister; // TRUE when entering Caps
UNICODE *JoyAlphaStr; // joystick alphabet joy_char_t *JoyAlpha; // joystick alphabet
int JoyAlphaLength;
joy_char_t *JoyUpper; // joystick upper register
joy_char_t *JoyLower; // joystick lower register
int JoyRegLength;
UNICODE *InsPt; // set to current pos of insertion point
// these are public and must be set before calling DoTextEntry // these are public and must be set before calling DoTextEntry
UNICODE *BaseStr; // set to string to edit UNICODE *BaseStr; // set to string to edit
UNICODE *InsPt; // set to curremt pos of insertion point int CursorPos; // set to current cursor pos in chars
int MaxSize; // set to max size of edited string int MaxSize; // set to max size of edited string
BOOLEAN (*ChangeCallback) (struct textentry_state *pTES); BOOLEAN (*ChangeCallback) (struct textentry_state *pTES);
+2 -1
View File
@@ -355,7 +355,7 @@ OnNameChange (PTEXTENTRY_STATE pTES)
PMENU_STATE pMS = (PMENU_STATE) pTES->CbParam; PMENU_STATE pMS = (PMENU_STATE) pTES->CbParam;
COUNT hl = DDSHS_EDIT; COUNT hl = DDSHS_EDIT;
pMS->first_item.x = pTES->InsPt - pTES->BaseStr; pMS->first_item.x = pTES->CursorPos;
if (pTES->JoystickMode) if (pTES->JoystickMode)
hl |= DDSHS_BLOCKCUR; hl |= DDSHS_BLOCKCUR;
@@ -405,6 +405,7 @@ DoNaming (PMENU_STATE pMS)
tes.Initialized = FALSE; tes.Initialized = FALSE;
tes.MenuRepeatDelay = 0; tes.MenuRepeatDelay = 0;
tes.BaseStr = buf; tes.BaseStr = buf;
tes.CursorPos = 0;
tes.CbParam = pMS; tes.CbParam = pMS;
tes.ChangeCallback = OnNameChange; tes.ChangeCallback = OnNameChange;
+218 -54
View File
@@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include <ctype.h> #include "port.h"
#include "controls.h" #include "controls.h"
#include "libs/inplib.h" #include "libs/inplib.h"
#include "libs/misc.h" #include "libs/misc.h"
@@ -26,13 +26,112 @@
#include "resinst.h" #include "resinst.h"
#include "nameref.h" #include "nameref.h"
struct joy_char
{
unsigned char len;
unsigned 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 inline int
IsPrintableChar (wchar_t ch)
{
return iswgraph (ch) || (ch == ' ');
}
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, PTEXTENTRY_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,
PTEXTENTRY_STATE pTES)
{
*outch = *ch;
JoyCharSwitchReg (outch, pTES->JoyLower, pTES->JoyUpper,
pTES->JoyRegLength);
}
static void
JoyCharToLower (joy_char_t *outch, const joy_char_t *ch,
PTEXTENTRY_STATE pTES)
{
*outch = *ch;
JoyCharSwitchReg (outch, pTES->JoyUpper, pTES->JoyLower,
pTES->JoyRegLength);
}
BOOLEAN BOOLEAN
DoTextEntry (PTEXTENTRY_STATE pTES) DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
UNICODE ch; wchar_t ch;
UNICODE *pStr; UNICODE *pStr;
UNICODE *CacheInsPt; UNICODE *CacheInsPt;
int CacheCursorPos;
int len; int len;
BOOLEAN changed = FALSE; BOOLEAN changed = FALSE;
@@ -41,33 +140,63 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
if (!pTES->Initialized) if (!pTES->Initialized)
{ // init basic vars { // init basic vars
int lwlen;
pTES->InputFunc = DoTextEntry; pTES->InputFunc = DoTextEntry;
pTES->InsPt = pTES->BaseStr;
pTES->CacheStr = HMalloc (pTES->MaxSize);
pTES->Success = FALSE; pTES->Success = FALSE;
pTES->Initialized = TRUE; pTES->Initialized = TRUE;
pTES->JoystickMode = FALSE; pTES->JoystickMode = FALSE;
pTES->UpperRegister = TRUE; 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 ( pTES->JoyAlphaString = CaptureStringTable (
LoadStringTable (JOYSTICK_ALPHA_STRTAB)); LoadStringTable (JOYSTICK_ALPHA_STRTAB));
pTES->JoyAlphaStr = GetStringAddress ( pTES->JoyAlpha = LoadJoystickAlpha (
SetAbsStringTableIndex (pTES->JoyAlphaString, 0)); 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;
fprintf (stderr, "Warning: Joystick upper-lower registers size "
"mismatch; using the smallest subset (%d)\n",
pTES->JoyRegLength);
}
pTES->CacheStr = HMalloc (pTES->MaxSize * sizeof (*pTES->CacheStr));
DoInput (pTES, TRUE); DoInput (pTES, TRUE);
if (pTES->CacheStr) if (pTES->CacheStr)
HFree (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)); DestroyStringTable ( ReleaseStringTable (pTES->JoyAlphaString));
return pTES->Success; return pTES->Success;
} }
pStr = pTES->InsPt; pStr = pTES->InsPt;
len = wstrlen (pStr); len = strlen (pStr);
// save a copy of string // save a copy of string
CacheInsPt = pTES->InsPt; CacheInsPt = pTES->InsPt;
wstrncpy (pTES->CacheStr, pTES->BaseStr, pTES->MaxSize - 1); CacheCursorPos = pTES->CursorPos;
pTES->CacheStr[pTES->MaxSize - 1] = '\0'; memcpy (pTES->CacheStr, pTES->BaseStr, pTES->MaxSize);
// process the pending character buffer // process the pending character buffer
ch = GetNextCharacter (); ch = GetNextCharacter ();
@@ -77,14 +206,19 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
} }
while (ch) while (ch)
{ {
UNICODE chbuf[8];
int chsize;
pTES->JoystickMode = FALSE; pTES->JoystickMode = FALSE;
if (isprint (ch) && (pStr + len - pTES->BaseStr + 1 < pTES->MaxSize)) chsize = getStringFromChar (chbuf, sizeof (chbuf), ch);
{ if (IsPrintableChar (ch) && chsize > 0
memmove (pStr + 1, pStr, (len + 1) * sizeof (*pStr)); && (pStr + len - pTES->BaseStr + chsize < pTES->MaxSize))
*pStr = ch; { // insert character
++pStr; memmove (pStr + chsize, pStr, len + 1);
++len; memcpy (pStr, chbuf, chsize);
pStr += chsize;
++pTES->CursorPos;
changed = TRUE; changed = TRUE;
} }
ch = GetNextCharacter (); ch = GetNextCharacter ();
@@ -94,8 +228,11 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
if (len) if (len)
{ {
memmove (pStr, pStr + 1, len * sizeof (*pStr)); joy_char_t ch;
--len;
ReadOneChar (&ch, pStr);
memmove (pStr, pStr + ch.len, len - ch.len + 1);
len -= ch.len;
changed = TRUE; changed = TRUE;
} }
} }
@@ -103,9 +240,12 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
if (pStr > pTES->BaseStr) if (pStr > pTES->BaseStr)
{ {
memmove (pStr - 1, pStr, (len + 1) * sizeof (*pStr)); UNICODE *prev = skipUTF8Chars (pTES->BaseStr,
--pStr; pTES->CursorPos - 1);
--len;
memmove (prev, pStr, len + 1);
pStr = prev;
--pTES->CursorPos;
changed = TRUE; changed = TRUE;
} }
} }
@@ -113,7 +253,12 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
if (pStr > pTES->BaseStr) if (pStr > pTES->BaseStr)
{ {
--pStr; UNICODE *prev = skipUTF8Chars (pTES->BaseStr,
pTES->CursorPos - 1);
pStr = prev;
len += (prev - pStr);
--pTES->CursorPos;
changed = TRUE; changed = TRUE;
} }
} }
@@ -121,7 +266,12 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
if (len > 0) if (len > 0)
{ {
++pStr; joy_char_t ch;
ReadOneChar (&ch, pStr);
pStr += ch.len;
len -= ch.len;
++pTES->CursorPos;
changed = TRUE; changed = TRUE;
} }
} }
@@ -130,6 +280,8 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
if (pStr > pTES->BaseStr) if (pStr > pTES->BaseStr)
{ {
pStr = pTES->BaseStr; pStr = pTES->BaseStr;
len = strlen (pStr);
pTES->CursorPos = 0;
changed = TRUE; changed = TRUE;
} }
} }
@@ -137,50 +289,50 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
if (len > 0) if (len > 0)
{ {
pTES->CursorPos += utf8StringCount (pStr);
pStr += len; pStr += len;
len = 0;
changed = TRUE; changed = TRUE;
} }
} }
if (pTES->JoyAlphaStr && ( if (pTES->JoyAlpha && (
PulsedInputState.key[KEY_MENU_UP] || PulsedInputState.key[KEY_MENU_UP] ||
PulsedInputState.key[KEY_MENU_DOWN] || PulsedInputState.key[KEY_MENU_DOWN] ||
PulsedInputState.key[KEY_MENU_PAGE_UP] || PulsedInputState.key[KEY_MENU_PAGE_UP] ||
PulsedInputState.key[KEY_MENU_PAGE_DOWN]) ) PulsedInputState.key[KEY_MENU_PAGE_DOWN]) )
{ // do joystick text { // do joystick text
UNICODE newch; joy_char_t ch;
UNICODE cmpch; joy_char_t newch;
joy_char_t cmpch;
int i; int i;
pTES->JoystickMode = TRUE; pTES->JoystickMode = TRUE;
if (len) if (len)
ch = *pStr; ReadOneChar (&ch, pStr);
else else
ch = pTES->JoyAlphaStr[0]; ch = pTES->JoyAlpha[0];
newch = ch; newch = ch;
cmpch = toupper (ch); JoyCharToUpper (&cmpch, &ch, pTES);
// find current char in the alphabet // find current char in the alphabet
for (i = 0; pTES->JoyAlphaStr[i] != cmpch i = JoyCharFindIn (&cmpch, pTES->JoyAlpha, pTES->JoyAlphaLength);
&& pTES->JoyAlphaStr[i] != '\0'; ++i)
;
if (PulsedInputState.key[KEY_MENU_UP]) if (PulsedInputState.key[KEY_MENU_UP])
{ {
--i; --i;
if (i < 0) if (i < 0)
i = wstrlen (pTES->JoyAlphaStr) - 1; i = pTES->JoyAlphaLength - 1;
newch = pTES->JoyAlphaStr[i]; newch = pTES->JoyAlpha[i];
} }
else if (PulsedInputState.key[KEY_MENU_DOWN]) else if (PulsedInputState.key[KEY_MENU_DOWN])
{ {
++i; ++i;
if (i >= (int)wstrlen(pTES->JoyAlphaStr)) if (i >= pTES->JoyAlphaLength)
newch = pTES->JoyAlphaStr[0]; i = 0;
else newch = pTES->JoyAlpha[i];
newch = pTES->JoyAlphaStr[i];
} }
if (PulsedInputState.key[KEY_MENU_PAGE_UP] || if (PulsedInputState.key[KEY_MENU_PAGE_UP] ||
@@ -188,10 +340,10 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
if (len) if (len)
{ // single char change { // single char change
if (islower (newch)) if (JoyCharIsLower (&newch, pTES))
newch = toupper (newch); JoyCharToUpper (&newch, &newch, pTES);
else else
newch = tolower (newch); JoyCharToLower (&newch, &newch, pTES);
} }
else else
{ // register change { // register change
@@ -201,24 +353,36 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
else else
{ // check register { // check register
if (pTES->UpperRegister) if (pTES->UpperRegister)
newch = toupper (newch); JoyCharToUpper (&newch, &newch, pTES);
else else
newch = tolower (newch); JoyCharToLower (&newch, &newch, pTES);
} }
if (newch != ch) if (strcmp (newch.enc, ch.enc) != 0)
{ { // new char is different, put it in
if (len) if (len)
{ // change current { // change current -- this is messy with utf8
pStr[0] = newch; int l = len - ch.len;
changed = TRUE; 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 if (pStr + len - pTES->BaseStr + 1 < pTES->MaxSize) else
{ // append { // append
pStr[0] = newch; if (pStr + len - pTES->BaseStr + newch.len < pTES->MaxSize)
pStr[1] = '\0'; {
++len; memcpy (pStr, newch.enc, newch.len);
changed = TRUE; pStr[newch.len] = '\0';
len += newch.len;
changed = TRUE;
}
} }
} }
} }
@@ -240,9 +404,9 @@ DoTextEntry (PTEXTENTRY_STATE pTES)
{ {
if (!pTES->ChangeCallback (pTES)) if (!pTES->ChangeCallback (pTES))
{ // changes not accepted - revert { // changes not accepted - revert
wstrncpy (pTES->BaseStr, pTES->CacheStr, pTES->MaxSize - 1); memcpy (pTES->BaseStr, pTES->CacheStr, pTES->MaxSize);
pTES->BaseStr[pTES->MaxSize - 1] = '\0';
pTES->InsPt = CacheInsPt; pTES->InsPt = CacheInsPt;
pTES->CursorPos = CacheCursorPos;
PlaySoundEffect (SetAbsSoundIndex (MenuSounds, 2), PlaySoundEffect (SetAbsSoundIndex (MenuSounds, 2),
0, NotPositional (), NULL, 0); 0, NotPositional (), NULL, 0);
+3 -2
View File
@@ -20,6 +20,7 @@
#define _INPLIB_H #define _INPLIB_H
#include "memlib.h" #include "memlib.h"
#include <stddef.h>
typedef DWORD INPUT_STATE; typedef DWORD INPUT_STATE;
@@ -42,8 +43,8 @@ extern volatile int MouseButtonDown;
void EnableCharacterMode (void); void EnableCharacterMode (void);
void DisableCharacterMode (void); void DisableCharacterMode (void);
UNICODE GetNextCharacter (void); wchar_t GetNextCharacter (void);
UNICODE GetLastCharacter (void); wchar_t GetLastCharacter (void);
#endif /* _INPLIB_H */ #endif /* _INPLIB_H */
+6 -7
View File
@@ -30,12 +30,11 @@
#define KBDBUFSIZE (1 << 8) #define KBDBUFSIZE (1 << 8)
static int kbdhead=0, kbdtail=0; static int kbdhead=0, kbdtail=0;
static UNICODE kbdbuf[KBDBUFSIZE]; static wchar_t kbdbuf[KBDBUFSIZE];
static UNICODE lastchar; static wchar_t lastchar;
static int kbdstate[SDLK_LAST]; static int kbdstate[SDLK_LAST];
static BOOLEAN InputInitialized = FALSE; static BOOLEAN InputInitialized = FALSE;
UWORD UNICODEToKBD (UNICODE which_key);
static BOOLEAN _in_character_mode = FALSE; static BOOLEAN _in_character_mode = FALSE;
@@ -238,10 +237,10 @@ DisableCharacterMode (void)
lastchar = 0; lastchar = 0;
} }
UNICODE wchar_t
GetNextCharacter (void) GetNextCharacter (void)
{ {
UNICODE result; wchar_t result;
if (kbdhead == kbdtail) if (kbdhead == kbdtail)
return 0; return 0;
result = kbdbuf[kbdhead]; result = kbdbuf[kbdhead];
@@ -249,7 +248,7 @@ GetNextCharacter (void)
return result; return result;
} }
UNICODE wchar_t
GetLastCharacter (void) GetLastCharacter (void)
{ {
return lastchar; return lastchar;
@@ -285,7 +284,7 @@ ProcessInputEvent (const SDL_Event *Event)
{ // process character input event, if any { // process character input event, if any
SDLKey k = Event->key.keysym.sym; SDLKey k = Event->key.keysym.sym;
UNICODE map_key = (UNICODE) Event->key.keysym.unicode; wchar_t map_key = Event->key.keysym.unicode;
if (Event->type == SDL_KEYDOWN) if (Event->type == SDL_KEYDOWN)
{ {
+2 -1
View File
@@ -1158,7 +1158,7 @@ OnTeamNameChange (PTEXTENTRY_STATE pTES)
BOOLEAN ret; BOOLEAN ret;
COUNT hl = DTSHS_EDIT; COUNT hl = DTSHS_EDIT;
pMS->CurIndex = pTES->InsPt - pTES->BaseStr; pMS->CurIndex = pTES->CursorPos;
if (pTES->JoystickMode) if (pTES->JoystickMode)
hl |= DTSHS_BLOCKCUR; hl |= DTSHS_BLOCKCUR;
@@ -1236,6 +1236,7 @@ DoEdit (PMELEE_STATE pMS)
tes.Initialized = FALSE; tes.Initialized = FALSE;
tes.MenuRepeatDelay = 0; tes.MenuRepeatDelay = 0;
tes.BaseStr = pMS->TeamImage[pMS->side].TeamName; tes.BaseStr = pMS->TeamImage[pMS->side].TeamName;
tes.CursorPos = 0;
tes.MaxSize = MAX_TEAM_CHARS + 1; tes.MaxSize = MAX_TEAM_CHARS + 1;
tes.CbParam = pMS; tes.CbParam = pMS;
tes.ChangeCallback = OnTeamNameChange; tes.ChangeCallback = OnTeamNameChange;