Prepare GUI for IME support

This commit is contained in:
yw05 2021-03-30 13:52:45 +02:00 committed by sfan5
parent d7127df9f8
commit 32004b9c5f
7 changed files with 122 additions and 56 deletions

@ -34,7 +34,11 @@ namespace irr
IrrlichtDevice::postEventFromUser. They take the same path as mouse events. */ IrrlichtDevice::postEventFromUser. They take the same path as mouse events. */
EET_KEY_INPUT_EVENT, EET_KEY_INPUT_EVENT,
//! A touch input event. //! A string input event.
/** This event is created when multiple characters are sent at a time (e.g. using an IME). */
EET_STRING_INPUT_EVENT,
//! A touch input event.
EET_TOUCH_INPUT_EVENT, EET_TOUCH_INPUT_EVENT,
//! A accelerometer event. //! A accelerometer event.
@ -413,7 +417,14 @@ struct SEvent
bool Control:1; bool Control:1;
}; };
//! Any kind of touch event. //! String input event.
struct SStringInput
{
//! The string that is entered
core::stringw *Str;
};
//! Any kind of touch event.
struct STouchInput struct STouchInput
{ {
// Touch ID. // Touch ID.
@ -581,6 +592,7 @@ struct SEvent
struct SGUIEvent GUIEvent; struct SGUIEvent GUIEvent;
struct SMouseInput MouseInput; struct SMouseInput MouseInput;
struct SKeyInput KeyInput; struct SKeyInput KeyInput;
struct SStringInput StringInput;
struct STouchInput TouchInput; struct STouchInput TouchInput;
struct SAccelerometerEvent AccelerometerEvent; struct SAccelerometerEvent AccelerometerEvent;
struct SGyroscopeEvent GyroscopeEvent; struct SGyroscopeEvent GyroscopeEvent;

@ -789,6 +789,13 @@ public:
} }
//! Returns whether the element takes input from the IME
virtual bool acceptsIME()
{
return false;
}
//! Writes attributes of the scene node. //! Writes attributes of the scene node.
/** Implement this to expose the attributes of your scene node for /** Implement this to expose the attributes of your scene node for
scripting languages, editors, debuggers or xml serialization purposes. */ scripting languages, editors, debuggers or xml serialization purposes. */

@ -252,6 +252,10 @@ bool CGUIEditBox::OnEvent(const SEvent& event)
if (processMouse(event)) if (processMouse(event))
return true; return true;
break; break;
case EET_STRING_INPUT_EVENT:
inputString(*event.StringInput.Str);
return true;
break;
default: default:
break; break;
} }
@ -1391,76 +1395,91 @@ s32 CGUIEditBox::getLineFromPos(s32 pos)
void CGUIEditBox::inputChar(wchar_t c) void CGUIEditBox::inputChar(wchar_t c)
{
if (c == 0)
return;
core::stringw s(&c, 1);
inputString(s);
}
void CGUIEditBox::inputString(const core::stringw &str)
{ {
if (!isEnabled()) if (!isEnabled())
return; return;
if (c != 0) core::stringw s;
u32 len = str.size();
if (MarkBegin != MarkEnd)
{ {
// replace marked text
const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
s = Text.subString(0, realmbgn);
s.append(str);
s.append( Text.subString(realmend, Text.size()-realmend) );
Text = s;
CursorPos = realmbgn+len;
}
else if ( OverwriteMode )
{
//check to see if we are at the end of the text
if ( (u32)CursorPos+len < Text.size())
{ {
core::stringw s; bool isEOL = false;
s32 EOLPos;
if (MarkBegin != MarkEnd) for (u32 i = CursorPos; i < CursorPos+len && i < Max; i++)
{ {
// replace marked text if (Text[i] == L'\n' || Text[i] == L'\r')
const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
s = Text.subString(0, realmbgn);
s.append(c);
s.append( Text.subString(realmend, Text.size()-realmend) );
Text = s;
CursorPos = realmbgn+1;
}
else if ( OverwriteMode )
{
//check to see if we are at the end of the text
if ( (u32)CursorPos != Text.size())
{ {
bool isEOL = (Text[CursorPos] == L'\n' ||Text[CursorPos] == L'\r' ); isEOL = true;
if (!isEOL || Text.size() < Max || Max == 0) EOLPos = i;
{ break;
s = Text.subString(0, CursorPos);
s.append(c);
if ( isEOL )
{
//just keep appending to the current line
//This follows the behavior of other gui libraries behaviors
s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
}
else
{
//replace the next character
s.append( Text.subString(CursorPos + 1,Text.size() - CursorPos + 1));
}
Text = s;
++CursorPos;
}
}
else if (Text.size() < Max || Max == 0)
{
// add new character because we are at the end of the string
s = Text.subString(0, CursorPos);
s.append(c);
s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
Text = s;
++CursorPos;
} }
} }
else if (Text.size() < Max || Max == 0) if (!isEOL || Text.size()+len <= Max || Max == 0)
{ {
// add new character
s = Text.subString(0, CursorPos); s = Text.subString(0, CursorPos);
s.append(c); s.append(str);
s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); if ( isEOL )
{
//just keep appending to the current line
//This follows the behavior of other gui libraries behaviors
s.append( Text.subString(EOLPos, Text.size()-EOLPos) );
}
else
{
//replace the next character
s.append( Text.subString(CursorPos + len,Text.size() - CursorPos - len));
}
Text = s; Text = s;
++CursorPos; CursorPos+=len;
} }
}
BlinkStartTime = os::Timer::getTime(); else if (Text.size()+len <= Max || Max == 0)
setTextMarkers(0, 0); {
// add new character because we are at the end of the string
s = Text.subString(0, CursorPos);
s.append(str);
s.append( Text.subString(CursorPos+len, Text.size()-CursorPos-len) );
Text = s;
CursorPos+=len;
} }
} }
else if (Text.size()+len <= Max || Max == 0)
{
// add new character
s = Text.subString(0, CursorPos);
s.append(str);
s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
Text = s;
CursorPos+=len;
}
BlinkStartTime = os::Timer::getTime();
setTextMarkers(0, 0);
breakText(); breakText();
calculateScrollPos(); calculateScrollPos();
sendGuiEvent(EGET_EDITBOX_CHANGED); sendGuiEvent(EGET_EDITBOX_CHANGED);
@ -1625,6 +1644,12 @@ void CGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
} }
} }
//! Returns whether the element takes input from the IME
bool CGUIEditBox::acceptsIME()
{
return isEnabled();
}
//! Writes attributes of the element. //! Writes attributes of the element.
void CGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const void CGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{ {

@ -139,6 +139,10 @@ namespace gui
//! Updates the absolute position, splits text if required //! Updates the absolute position, splits text if required
virtual void updateAbsolutePosition() _IRR_OVERRIDE_; virtual void updateAbsolutePosition() _IRR_OVERRIDE_;
//! Returns whether the element takes input from the IME
virtual bool acceptsIME() _IRR_OVERRIDE_;
//! Writes attributes of the element. //! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_;
@ -154,6 +158,8 @@ namespace gui
s32 getLineFromPos(s32 pos); s32 getLineFromPos(s32 pos);
//! adds a letter to the edit box //! adds a letter to the edit box
void inputChar(wchar_t c); void inputChar(wchar_t c);
//! adds a string to the edit box
void inputString(const core::stringw &str);
//! calculates the current scroll position //! calculates the current scroll position
void calculateScrollPos(); void calculateScrollPos();
//! calculated the FrameRect //! calculated the FrameRect

@ -656,6 +656,10 @@ bool CGUIEnvironment::postEventFromUser(const SEvent& event)
} }
} }
break; break;
case EET_STRING_INPUT_EVENT:
if (Focus && Focus->OnEvent(event))
return true;
break;
default: default:
break; break;
} // end switch } // end switch

@ -6,6 +6,7 @@
#include "ISceneManager.h" #include "ISceneManager.h"
#include "IEventReceiver.h" #include "IEventReceiver.h"
#include "IFileSystem.h" #include "IFileSystem.h"
#include "IGUIElement.h"
#include "IGUIEnvironment.h" #include "IGUIEnvironment.h"
#include "os.h" #include "os.h"
#include "IrrCompileConfig.h" #include "IrrCompileConfig.h"
@ -503,6 +504,14 @@ void CIrrDeviceStub::clearSystemMessages()
{ {
} }
//! Checks whether the input device should take input from the IME
bool CIrrDeviceStub::acceptsIME()
{
if (!GUIEnvironment)
return false;
gui::IGUIElement *elem = GUIEnvironment->getFocus();
return elem && elem->acceptsIME();
}
} // end namespace irr } // end namespace irr

@ -194,6 +194,9 @@ namespace irr
void calculateGammaRamp ( u16 *ramp, f32 gamma, f32 relativebrightness, f32 relativecontrast ); void calculateGammaRamp ( u16 *ramp, f32 gamma, f32 relativebrightness, f32 relativecontrast );
void calculateGammaFromRamp ( f32 &gamma, const u16 *ramp ); void calculateGammaFromRamp ( f32 &gamma, const u16 *ramp );
//! Checks whether the input device should take input from the IME
bool acceptsIME();
video::IVideoDriver* VideoDriver; video::IVideoDriver* VideoDriver;
gui::IGUIEnvironment* GUIEnvironment; gui::IGUIEnvironment* GUIEnvironment;
scene::ISceneManager* SceneManager; scene::ISceneManager* SceneManager;