Skip to content

Commit

Permalink
Support IME composition strings of arbitrary length
Browse files Browse the repository at this point in the history
Previously, IME composition strings were limited to at most 32 bytes, e.g. 10 Hiragana characters. Now, `SDL_TextEditingExtEvent` (`SDL_TEXTEDITING_EXT`) is supported, which uses heap-allocated composition strings of arbitrary length.

On the other hand, the buffer for input event text was larger than necessary, as SDL text events only contain at most 32 bytes (`SDL_TEXTINPUTEVENT_TEXT_SIZE` is not used directly to avoid the include). With the hint for extended IME handling enabled, long composition text will be sent as multiple text events (without breaking UTF-8).
  • Loading branch information
Robyt3 committed Jul 27, 2024
1 parent 78cbb45 commit 8a3929d
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 43 deletions.
5 changes: 5 additions & 0 deletions src/engine/client/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4562,6 +4562,11 @@ int main(int argc, const char **argv)
SDL_SetHint("SDL_TOUCH_MOUSE_EVENTS", "0");
SDL_SetHint("SDL_MOUSE_TOUCH_EVENTS", "0");

// Support longer IME composition strings (enables SDL_TEXTEDITING_EXT).
#if SDL_VERSION_ATLEAST(2, 0, 22)
SDL_SetHint(SDL_HINT_IME_SUPPORT_EXTENDED_TEXT, "1");
#endif

#if defined(CONF_PLATFORM_MACOS)
// Hints will not be set if there is an existing override hint or environment variable that takes precedence.
// So this respects cli environment overrides.
Expand Down
56 changes: 30 additions & 26 deletions src/engine/client/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ CInput::CInput()

m_pClipboardText = nullptr;

m_CompositionLength = COMP_LENGTH_INACTIVE;
m_CompositionCursor = 0;
m_CandidateSelectedIndex = -1;

Expand Down Expand Up @@ -328,9 +327,8 @@ void CInput::StopTextInput()
SDL_StopTextInput();
// disable system messages for performance
SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
m_CompositionLength = COMP_LENGTH_INACTIVE;
m_CompositionString = "";
m_CompositionCursor = 0;
m_aComposition[0] = '\0';
m_vCandidates.clear();
}

Expand Down Expand Up @@ -574,6 +572,26 @@ void CInput::HandleTouchMotionEvent(const SDL_TouchFingerEvent &Event)
}
}

void CInput::HandleTextEditingEvent(const char *pText, int Start, int Length)
{
if(pText[0] != '\0')
{
m_CompositionString = pText;
m_CompositionCursor = 0;
for(int i = 0; i < Start; i++)
{
m_CompositionCursor = str_utf8_forward(m_CompositionString.c_str(), m_CompositionCursor);
}
// Length is currently unused on Windows and will always be 0, so we don't support selecting composition text
AddTextEvent("");
}
else
{
m_CompositionString = "";
m_CompositionCursor = 0;
}
}

void CInput::SetCompositionWindowPosition(float X, float Y, float H)
{
SDL_Rect Rect;
Expand Down Expand Up @@ -658,29 +676,18 @@ int CInput::Update()
break;

case SDL_TEXTEDITING:
{
m_CompositionLength = str_length(Event.edit.text);
if(m_CompositionLength)
{
str_copy(m_aComposition, Event.edit.text);
m_CompositionCursor = 0;
for(int i = 0; i < Event.edit.start; i++)
m_CompositionCursor = str_utf8_forward(m_aComposition, m_CompositionCursor);
// Event.edit.length is currently unused on Windows and will always be 0, so we don't support selecting composition text
AddTextEvent("");
}
else
{
m_aComposition[0] = '\0';
m_CompositionLength = 0;
m_CompositionCursor = 0;
}
HandleTextEditingEvent(Event.edit.text, Event.edit.start, Event.edit.length);
break;
}

#if SDL_VERSION_ATLEAST(2, 0, 22)
case SDL_TEXTEDITING_EXT:
HandleTextEditingEvent(Event.editExt.text, Event.editExt.start, Event.editExt.length);
SDL_free(Event.editExt.text);
break;
#endif

case SDL_TEXTINPUT:
m_aComposition[0] = '\0';
m_CompositionLength = COMP_LENGTH_INACTIVE;
m_CompositionString = "";
m_CompositionCursor = 0;
AddTextEvent(Event.text.text);
break;
Expand Down Expand Up @@ -861,9 +868,6 @@ int CInput::Update()
}
}

if(m_CompositionLength == 0)
m_CompositionLength = COMP_LENGTH_INACTIVE;

return 0;
}

Expand Down
10 changes: 5 additions & 5 deletions src/engine/client/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,8 @@ class CInput : public IEngineInput
#endif

// IME support
char m_aComposition[MAX_COMPOSITION_ARRAY_SIZE];
std::string m_CompositionString;
int m_CompositionCursor;
int m_CompositionLength;
std::vector<std::string> m_vCandidates;
int m_CandidateSelectedIndex;

Expand All @@ -113,6 +112,7 @@ class CInput : public IEngineInput
void HandleTouchDownEvent(const SDL_TouchFingerEvent &Event);
void HandleTouchUpEvent(const SDL_TouchFingerEvent &Event);
void HandleTouchMotionEvent(const SDL_TouchFingerEvent &Event);
void HandleTextEditingEvent(const char *pText, int Start, int Length);

char m_aDropFile[IO_MAX_PATH_LENGTH];

Expand Down Expand Up @@ -155,10 +155,10 @@ class CInput : public IEngineInput

void StartTextInput() override;
void StopTextInput() override;
const char *GetComposition() const override { return m_aComposition; }
bool HasComposition() const override { return m_CompositionLength != COMP_LENGTH_INACTIVE; }
const char *GetComposition() const override { return m_CompositionString.c_str(); }
bool HasComposition() const override { return !m_CompositionString.empty(); }
int GetCompositionCursor() const override { return m_CompositionCursor; }
int GetCompositionLength() const override { return m_CompositionLength; }
int GetCompositionLength() const override { return m_CompositionString.length(); }
const char *GetCandidate(int Index) const override { return m_vCandidates[Index].c_str(); }
int GetCandidateCount() const override { return m_vCandidates.size(); }
int GetCandidateSelectedIndex() const override { return m_CandidateSelectedIndex; }
Expand Down
13 changes: 1 addition & 12 deletions src/engine/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,13 @@ class IInput : public IInterface
{
MACRO_INTERFACE("input")
public:
enum
{
INPUT_TEXT_SIZE = 32 * UTF8_BYTE_LENGTH + 1,
};

class CEvent
{
public:
int m_Flags;
int m_Key;
uint32_t m_InputCount;
char m_aText[INPUT_TEXT_SIZE];
char m_aText[32]; // SDL_TEXTINPUTEVENT_TEXT_SIZE
};

enum
Expand All @@ -45,12 +40,6 @@ class IInput : public IInterface
CURSOR_MOUSE,
CURSOR_JOYSTICK,
};
enum
{
MAX_COMPOSITION_ARRAY_SIZE = 32, // SDL2 limitation

COMP_LENGTH_INACTIVE = -1,
};

// events
virtual void ConsumeEvents(std::function<void(const CEvent &Event)> Consumer) const = 0;
Expand Down

0 comments on commit 8a3929d

Please sign in to comment.