Skip to content
This repository has been archived by the owner on May 13, 2024. It is now read-only.

Add support for IMEs on Linux #23

Merged
merged 2 commits into from
Apr 2, 2021
Merged

Add support for IMEs on Linux #23

merged 2 commits into from
Apr 2, 2021

Conversation

y5nw
Copy link
Contributor

@y5nw y5nw commented Mar 30, 2021

This PR uses XSetLocaleModifiers to add support for IMEs.

To-Do

This pull request is ready for review.

  • IME support only appears to work with certain locales (e.g. zh_CN) (this was tested with an older version of MT)
  • TODO: Properly implement buffers for entering multiple characters at a time
  • Fix: the position of the IME hint appears to be constantly at the bottom of the screen
  • Fix: the IME is used in places where this behavior is not desired

Breaking changes

  • There is now a EET_STRING_INPUT_EVENT event:
    • The corresponding event field is event.StringInput
    • event.StringInput.Str contains a reference to the core::stringw that contains the entered string
  • IGUIElement now has a bool acceptsIME() method that returns whether the element accepts input from the IME:
    • true: keyboard input events are filtered by the IME before being passed to the element
    • false (default): keyboard input events are not filtered by the IME

References

@sfan5 sfan5 added the enhancement New feature or request label Mar 30, 2021
@y5nw y5nw mentioned this pull request Mar 31, 2021
5 tasks
@sfan5 sfan5 force-pushed the master branch 2 times, most recently from 4de18ef to d7127df Compare March 31, 2021 15:11
@y5nw y5nw marked this pull request as ready for review April 2, 2021 10:42
@y5nw
Copy link
Contributor Author

y5nw commented Apr 2, 2021

I also made the corresponding changes to Minetest. Should I post them now or should I wait for this PR to be merged?

@sfan5
Copy link
Member

sfan5 commented Apr 2, 2021

Posting them early is useful so they can be looked at or tested.

@sfan5 sfan5 changed the title Add support for IMEs Add support for IMEs on Linux Apr 2, 2021
@y5nw
Copy link
Contributor Author

y5nw commented Apr 2, 2021

diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp
index a4e91fe78..dc688395b 100644
--- a/src/gui/guiChatConsole.cpp
+++ b/src/gui/guiChatConsole.cpp
@@ -619,6 +619,11 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
 			m_chat_backend->scroll(rows);
 		}
 	}
+	else if(event.EventType == EET_STRING_INPUT_EVENT)
+	{
+		prompt.input(std::wstring(event.StringInput.Str->c_str()));
+		return true;
+	}
 
 	return Parent ? Parent->OnEvent(event) : false;
 }
diff --git a/src/gui/guiChatConsole.h b/src/gui/guiChatConsole.h
index 896342ab0..1152f2b2d 100644
--- a/src/gui/guiChatConsole.h
+++ b/src/gui/guiChatConsole.h
@@ -72,6 +72,8 @@ class GUIChatConsole : public gui::IGUIElement
 
 	virtual void setVisible(bool visible);
 
+	virtual bool acceptsIME() { return true; }
+
 private:
 	void reformatConsole();
 	void recalculateConsolePosition();
diff --git a/src/gui/guiEditBox.cpp b/src/gui/guiEditBox.cpp
index cd5a0868d..86cd2001e 100644
--- a/src/gui/guiEditBox.cpp
+++ b/src/gui/guiEditBox.cpp
@@ -216,6 +216,10 @@ bool GUIEditBox::OnEvent(const SEvent &event)
 			if (processMouse(event))
 				return true;
 			break;
+		case EET_STRING_INPUT_EVENT:
+			inputString(event.StringInput.Str);
+			return true;
+			break;
 		default:
 			break;
 		}
@@ -708,6 +712,46 @@ void GUIEditBox::inputChar(wchar_t c)
 	calculateScrollPos();
 }
 
+void GUIEditBox::inputString(core::stringw *str)
+{
+	if (!isEnabled() || !m_writable)
+		return;
+
+	if (str) {
+		u32 len = str->size();
+		if (Text.size()+len <= m_max || m_max == 0) {
+			core::stringw s;
+			if (m_mark_begin != m_mark_end) {
+				// clang-format off
+				// replace marked test
+				s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+				s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+				s = Text.subString(0, real_begin);
+				s.append(*str);
+				s.append(Text.subString(real_end, Text.size() - real_end));
+				Text = s;
+				m_cursor_pos = real_begin + len;
+				// clang-format on
+			} else {
+				// append string
+				s = Text.subString(0, m_cursor_pos);
+				s.append(*str);
+				s.append(Text.subString(m_cursor_pos,
+						Text.size() - m_cursor_pos));
+				Text = s;
+				m_cursor_pos += len;
+			}
+
+			m_blink_start_time = porting::getTimeMs();
+			setTextMarkers(0, 0);
+		}
+	}
+	breakText();
+	sendGuiEvent(EGET_EDITBOX_CHANGED);
+	calculateScrollPos();
+}
+
 bool GUIEditBox::processMouse(const SEvent &event)
 {
 	switch (event.MouseInput.Event) {
diff --git a/src/gui/guiEditBox.h b/src/gui/guiEditBox.h
index c616d75d1..da5628b6b 100644
--- a/src/gui/guiEditBox.h
+++ b/src/gui/guiEditBox.h
@@ -138,6 +138,8 @@ class GUIEditBox : public IGUIEditBox
 	virtual void deserializeAttributes(
 			io::IAttributes *in, io::SAttributeReadWriteOptions *options);
 
+	virtual bool acceptsIME() { return isEnabled() && m_writable; };
+
 protected:
 	virtual void breakText() = 0;
 
@@ -156,6 +158,7 @@ class GUIEditBox : public IGUIEditBox
 	virtual s32 getCursorPos(s32 x, s32 y) = 0;
 
 	bool processKey(const SEvent &event);
+	virtual void inputString(core::stringw *str);
 	virtual void inputChar(wchar_t c);
 
 	//! returns the line number that the cursor is on

source/Irrlicht/CGUIEditBox.cpp Outdated Show resolved Hide resolved
source/Irrlicht/CGUIEditBox.cpp Outdated Show resolved Hide resolved
source/Irrlicht/CGUIEditBox.cpp Outdated Show resolved Hide resolved
source/Irrlicht/CIrrDeviceLinux.cpp Show resolved Hide resolved
source/Irrlicht/CIrrDeviceLinux.cpp Outdated Show resolved Hide resolved
source/Irrlicht/CIrrDeviceLinux.cpp Show resolved Hide resolved
source/Irrlicht/CIrrDeviceLinux.cpp Outdated Show resolved Hide resolved
source/Irrlicht/CIrrDeviceLinux.cpp Outdated Show resolved Hide resolved
@sfan5
Copy link
Member

sfan5 commented Apr 2, 2021

Works great aside from the code comments, good job 👍.

@y5nw
Copy link
Contributor Author

y5nw commented Apr 2, 2021

Here is the fixup patch to keep GUIEditBox::inputString consistent with CGUIEditBox in Irrlicht:

diff --git a/src/gui/guiEditBox.cpp b/src/gui/guiEditBox.cpp
index 86cd2001e..260589f02 100644
--- a/src/gui/guiEditBox.cpp
+++ b/src/gui/guiEditBox.cpp
@@ -217,7 +217,7 @@ bool GUIEditBox::OnEvent(const SEvent &event)
 				return true;
 			break;
 		case EET_STRING_INPUT_EVENT:
-			inputString(event.StringInput.Str);
+			inputString(*event.StringInput.Str);
 			return true;
 			break;
 		default:
@@ -674,79 +674,44 @@ bool GUIEditBox::onKeyDelete(const SEvent &event, s32 &mark_begin, s32 &mark_end
 
 void GUIEditBox::inputChar(wchar_t c)
 {
-	if (!isEnabled() || !m_writable)
-		return;
-
-	if (c != 0) {
-		if (Text.size() < m_max || m_max == 0) {
-			core::stringw s;
-
-			if (m_mark_begin != m_mark_end) {
-				// clang-format off
-				// replace marked text
-				s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
-				s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
-
-				s = Text.subString(0, real_begin);
-				s.append(c);
-				s.append(Text.subString(real_end, Text.size() - real_end));
-				Text = s;
-				m_cursor_pos = real_begin + 1;
-				// clang-format on
-			} else {
-				// add new character
-				s = Text.subString(0, m_cursor_pos);
-				s.append(c);
-				s.append(Text.subString(m_cursor_pos,
-						Text.size() - m_cursor_pos));
-				Text = s;
-				++m_cursor_pos;
-			}
-
-			m_blink_start_time = porting::getTimeMs();
-			setTextMarkers(0, 0);
-		}
-	}
-	breakText();
-	sendGuiEvent(EGET_EDITBOX_CHANGED);
-	calculateScrollPos();
+	core::stringw s(&c, 1);
+	inputString(s);
 }
 
-void GUIEditBox::inputString(core::stringw *str)
+void GUIEditBox::inputString(const core::stringw &str)
 {
 	if (!isEnabled() || !m_writable)
 		return;
 
-	if (str) {
-		u32 len = str->size();
-		if (Text.size()+len <= m_max || m_max == 0) {
-			core::stringw s;
-			if (m_mark_begin != m_mark_end) {
-				// clang-format off
-				// replace marked test
-				s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
-				s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
-
-				s = Text.subString(0, real_begin);
-				s.append(*str);
-				s.append(Text.subString(real_end, Text.size() - real_end));
-				Text = s;
-				m_cursor_pos = real_begin + len;
-				// clang-format on
-			} else {
-				// append string
-				s = Text.subString(0, m_cursor_pos);
-				s.append(*str);
-				s.append(Text.subString(m_cursor_pos,
-						Text.size() - m_cursor_pos));
-				Text = s;
-				m_cursor_pos += len;
-			}
-
-			m_blink_start_time = porting::getTimeMs();
-			setTextMarkers(0, 0);
+	u32 len = str.size();
+	if (Text.size()+len <= m_max || m_max == 0) {
+		core::stringw s;
+		if (m_mark_begin != m_mark_end) {
+			// clang-format off
+			// replace marked test
+			s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+			s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+			s = Text.subString(0, real_begin);
+			s.append(str);
+			s.append(Text.subString(real_end, Text.size() - real_end));
+			Text = s;
+			m_cursor_pos = real_begin + len;
+			// clang-format on
+		} else {
+			// append string
+			s = Text.subString(0, m_cursor_pos);
+			s.append(str);
+			s.append(Text.subString(m_cursor_pos,
+					Text.size() - m_cursor_pos));
+			Text = s;
+			m_cursor_pos += len;
 		}
+
+		m_blink_start_time = porting::getTimeMs();
+		setTextMarkers(0, 0);
 	}
+
 	breakText();
 	sendGuiEvent(EGET_EDITBOX_CHANGED);
 	calculateScrollPos();
diff --git a/src/gui/guiEditBox.h b/src/gui/guiEditBox.h
index da5628b6b..2a5c911bc 100644
--- a/src/gui/guiEditBox.h
+++ b/src/gui/guiEditBox.h
@@ -158,7 +158,7 @@ class GUIEditBox : public IGUIEditBox
 	virtual s32 getCursorPos(s32 x, s32 y) = 0;
 
 	bool processKey(const SEvent &event);
-	virtual void inputString(core::stringw *str);
+	virtual void inputString(const core::stringw &str);
 	virtual void inputChar(wchar_t c);
 
 	//! returns the line number that the cursor is on

source/Irrlicht/CGUIEditBox.h Outdated Show resolved Hide resolved
source/Irrlicht/CIrrDeviceLinux.cpp Outdated Show resolved Hide resolved
source/Irrlicht/CGUIEditBox.cpp Show resolved Hide resolved
@sfan5 sfan5 merged commit 3ef5902 into minetest:master Apr 2, 2021
@sfan5
Copy link
Member

sfan5 commented Apr 2, 2021

Thanks, I've squashed your commits and merged them.
You'll want to open a PR with the other changes on Minetest's repo.

SmallJoker pushed a commit to minetest/minetest that referenced this pull request Apr 5, 2021
Make edit boxes respond to string input events (introduced in minetest/irrlicht#23) that are usually triggered by entering text with an IME.
@y5nw y5nw mentioned this pull request Oct 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants