diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index b72d006608..27cb4acbf7 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -57,6 +57,12 @@
// Imported globals
//
+// IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+extern LLControlGroup gSavedSettings;
+#endif
+//
+
//
// Constants
//
@@ -2164,6 +2170,12 @@ void LLLineEditor::draw()
ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]);
ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]);
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+ static LLCachedControl sdl2_ime_default_vertical_offset(*LLControlGroup::getInstance("Global"), "SDL2IMEDefaultVerticalOffset");
+ ime_pos.mY += sdl2_ime_default_vertical_offset;
+#endif
+ //
getWindow()->setLanguageTextInput( ime_pos );
}
}
@@ -2313,12 +2325,21 @@ void LLLineEditor::setFocus( BOOL new_state )
if (new_state)
{
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+ // Linux/SDL2 doesn't currently allow to disable IME, so we remove the restrictions on
+ // password entry fields and prevalidated input fields. Otherwise those fields would
+ // be completely inaccessible.
+ getWindow()->allowLanguageTextInput(this, true);
+#else
+ //
// Allow Language Text Input only when this LineEditor has
// no prevalidate function attached. This criterion works
// fine on 1.15.0.2, since all prevalidate func reject any
// non-ASCII characters. I'm not sure on future versions,
// however.
getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL);
+#endif //
}
}
@@ -2498,7 +2519,16 @@ void LLLineEditor::updateAllowingLanguageInput()
// test app, no window available
return;
}
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+ // Linux/SDL2 doesn't currently allow to disable IME, so we remove the restrictions on
+ // password entry fields and prevalidated input fields. Otherwise those fields would
+ // be completely inaccessible.
+ if (hasFocus() && !mReadOnly)
+#else
+ //
if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL)
+#endif //
{
window->allowLanguageTextInput(this, TRUE);
}
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index d8bd718da5..7689b98765 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -50,6 +50,12 @@
#include "fsregistrarutils.h"
+// IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+extern LLControlGroup gSavedSettings;
+#endif
+//
+
const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds
const S32 CURSOR_THICKNESS = 2;
const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click.
@@ -645,6 +651,12 @@ void LLTextBase::drawCursor()
ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]);
ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]);
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+ static LLCachedControl sdl2_ime_default_vertical_offset(*LLControlGroup::getInstance("Global"), "SDL2IMEDefaultVerticalOffset");
+ ime_pos.mY += sdl2_ime_default_vertical_offset;
+#endif
+ //
getWindow()->setLanguageTextInput( ime_pos );
}
}
diff --git a/indra/llwindow/llwindowsdl2.cpp b/indra/llwindow/llwindowsdl2.cpp
index 02551fa176..17bf62d7b5 100644
--- a/indra/llwindow/llwindowsdl2.cpp
+++ b/indra/llwindow/llwindowsdl2.cpp
@@ -39,6 +39,7 @@
#include "llstring.h"
#include "lldir.h"
#include "llfindlocale.h"
+#include "llframetimer.h"
#ifdef LL_GLIB
#include
@@ -390,6 +391,10 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks,
mIsMinimized = -1;
mFSAASamples = fsaa_samples;
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+ // Preeditor means here the actual XUI input field currently in use
+ mPreeditor = nullptr;
+
#if LL_X11
mSDL_XWindowID = None;
mSDL_Display = NULL;
@@ -654,6 +659,10 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B
SDL_SetHint( SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0" );
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+ // Request the IME interface to show over-the-top compositing while typing
+ SDL_SetHint( SDL_HINT_IME_INTERNAL_EDITING, "1");
+
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO ) < 0 )
{
LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL;
@@ -1758,6 +1767,7 @@ void LLWindowSDL::gatherInput()
static int rightClick = 0;
static Uint32 lastLeftDown = 0;
static Uint32 lastRightDown = 0;
+ static U64 previousTextinputTime = 0;
SDL_Event event;
// Handle all outstanding SDL events
@@ -1796,9 +1806,10 @@ void LLWindowSDL::gatherInput()
else
handleUnicodeUTF16(key, mKeyModifiers);
}
+ previousTextinputTime = LLFrameTimer::getTotalTime();
break;
}
-
+
case SDL_KEYDOWN:
mKeyVirtualKey = event.key.keysym.sym;
mKeyModifiers = event.key.keysym.mod;
@@ -1810,6 +1821,19 @@ void LLWindowSDL::gatherInput()
mKeyVirtualKey = SDLK_RETURN;
}
+ if (mKeyVirtualKey == SDLK_RETURN)
+ {
+ // block spurious enter key events that break up IME entered lines in teh wrong places
+ U64 eventTimeDiff = LLFrameTimer::getTotalTime() - previousTextinputTime;
+ previousTextinputTime = 0;
+
+ if (eventTimeDiff < 20000)
+ {
+ LL_INFOS() << "SDL_KEYDOWN(SDLK_RETURN) event came too fast after SDL_TEXTINPUT, blocked - Time: " << eventTimeDiff << LL_ENDL;
+ break;
+ }
+ }
+
gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers );
// Slightly hacky :| To make the viewer honor enter (eg to accept form input) we've to not only send handleKeyDown but also send a
@@ -2646,4 +2670,51 @@ void LLWindowSDL::toggleVSync(bool enable_vsync)
}
//
+// IME - International input compositing, i.e. for Japanese / Chinese text input
+// Put the IME window at the right place (near current text input).
+// Point coordinates should be the top of the current text line.
+void LLWindowSDL::setLanguageTextInput(const LLCoordGL& position)
+{
+ LLCoordWindow win_pos;
+ convertCoords( position, &win_pos );
+
+ SDL_Rect r;
+ r.x = win_pos.mX;
+ r.y = win_pos.mY;
+ r.w = 500;
+ r.h = 16;
+
+ SDL_SetTextInputRect(&r);
+}
+
+// IME - International input compositing, i.e. for Japanese / Chinese text input
+void LLWindowSDL::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
+{
+ if (preeditor != mPreeditor && !b)
+ {
+ // This condition may occur with a call to
+ // setEnabled(BOOL) from LLTextEditor or LLLineEditor
+ // when the control is not focused.
+ // We need to silently ignore the case so that
+ // the language input status of the focused control
+ // is not disturbed.
+ return;
+ }
+
+ // Take care of old and new preeditors.
+ if (preeditor != mPreeditor || !b)
+ {
+ mPreeditor = (b ? preeditor : nullptr);
+ }
+
+ if (b)
+ {
+ SDL_StartTextInput();
+ }
+ else
+ {
+ SDL_StopTextInput();
+ }
+}
+
#endif // LL_SDL
diff --git a/indra/llwindow/llwindowsdl2.h b/indra/llwindow/llwindowsdl2.h
index 20adba802e..05530f8766 100644
--- a/indra/llwindow/llwindowsdl2.h
+++ b/indra/llwindow/llwindowsdl2.h
@@ -128,6 +128,9 @@ public:
/*virtual*/ void *getPlatformWindow();
/*virtual*/ void bringToFront();
+ /*virtual*/ void allowLanguageTextInput(LLPreeditor* preeditor, BOOL b);
+ /*virtual*/ void setLanguageTextInput(const LLCoordGL& pos);
+
/*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async);
/*virtual*/ void openFile(const std::string& file_name);
@@ -201,6 +204,7 @@ protected:
SDL_Surface* mSurface;
SDL_GLContext mContext;
SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT];
+ LLPreeditor* mPreeditor;
std::string mWindowTitle;
double mOriginalAspectRatio;
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a523ff5712..3d42817e33 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -26203,5 +26203,38 @@ Change of this parameter will affect the layout of buttons in notification toast
Value
0
+ SDL2IMEDefaultVerticalOffset
+
+ SDL2IMEChatHistoryVerticalOffset
+
+ SDL2IMEMediaVerticalOffset
+
diff --git a/indra/newview/fschathistory.cpp b/indra/newview/fschathistory.cpp
index d72947c4b3..5a0d60f385 100644
--- a/indra/newview/fschathistory.cpp
+++ b/indra/newview/fschathistory.cpp
@@ -68,6 +68,10 @@
#include "llviewermenu.h"
#include "llviewernetwork.h"
+#if LL_SDL2
+#include "llwindow.h"
+#endif
+
#include "fscommon.h"
#include "llchatentry.h"
#include "llfocusmgr.h"
@@ -1210,6 +1214,50 @@ FSChatHistory::~FSChatHistory()
this->clear();
}
+void FSChatHistory::updateChatInputLine()
+{
+ if(!mChatInputLine)
+ {
+ // get our focus root
+ LLUICtrl* focusRoot=findRootMostFocusRoot();
+ if(focusRoot)
+ {
+ // focus on the next item that is a text input control
+ focusRoot->focusNextItem(true);
+ // remember the control's pointer if it really is a LLLineEditor
+ mChatInputLine = dynamic_cast(gFocusMgr.getKeyboardFocus());
+ }
+ }
+}
+
+#if LL_SDL2
+void FSChatHistory::setFocus(BOOL b)
+{
+ LLTextEditor::setFocus(b);
+
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+ updateChatInputLine();
+
+ if (b && mChatInputLine)
+ {
+ // Make sure the IME is in the right place, on top of the input line
+ LLRect screen_pos = mChatInputLine->calcScreenRect();
+ LLCoordGL ime_pos(screen_pos.mLeft, screen_pos.mBottom + gSavedSettings.getS32("SDL2IMEChatHistoryVerticalOffset"));
+
+ // shift by a few pixels so the IME doesn't pop to the left side when the input
+ // field is very close to the left edge
+ ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]) + 5;
+ ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]);
+
+ getWindow()->setLanguageTextInput(ime_pos);
+ }
+
+ // this floater is not an LLPreeditor but we are only interested in the pointer anyway
+ // so hopefully we will get away with this
+ getWindow()->allowLanguageTextInput((LLPreeditor*) this, true);
+}
+#endif
+
void FSChatHistory::initFromParams(const FSChatHistory::Params& p)
{
// initialize the LLTextEditor base class first ... -Zi
@@ -1794,19 +1842,8 @@ BOOL FSChatHistory::handleUnicodeCharHere(llwchar uni_char)
return LLTextEditor::handleUnicodeCharHere(uni_char);
}
- // we don't know which is our chat input line yet
- if(!mChatInputLine)
- {
- // get our focus root
- LLUICtrl* focusRoot=findRootMostFocusRoot();
- if(focusRoot)
- {
- // focus on the next item that is a text input control
- focusRoot->focusNextItem(true);
- // remember the control's pointer if it really is a LLLineEditor
- mChatInputLine = dynamic_cast(gFocusMgr.getKeyboardFocus());
- }
- }
+ // we might not know which is our chat input line yet
+ updateChatInputLine();
// do we know our chat input line now?
if(mChatInputLine)
diff --git a/indra/newview/fschathistory.h b/indra/newview/fschathistory.h
index b98581d87e..9dd7236cac 100644
--- a/indra/newview/fschathistory.h
+++ b/indra/newview/fschathistory.h
@@ -96,8 +96,17 @@ class FSChatHistory : public LLTextEditor // FIRE-8600: TAB out of chat
*/
LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args);
+ // try to fill in mChatInputLine
+ void updateChatInputLine();
+
public:
~FSChatHistory();
+
+#if LL_SDL2
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+ /* virtual */ void setFocus(BOOL b);
+#endif
+
LLSD getValue() const;
void initFromParams(const Params&);
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 4626745cb5..5bba2f9e54 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -48,6 +48,12 @@
#include "llviewermenu.h"
#include "llviewermenufile.h" // LLFilePickerThread
+// IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+#include "llwindow.h"
+#endif
+//
+
// linden library includes
#include "llfocusmgr.h"
#include "llsdutil.h"
@@ -411,6 +417,34 @@ void LLMediaCtrl::onFocusLost()
// This might go away later.
void LLMediaCtrl::setFocus(BOOL b)
{
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+#if LL_SDL2
+ // IME - International input compositing, i.e. for Japanese / Chinese text input
+
+ // Caveat: we currently don't know the position of the input cursor inside the
+ // media control box, so the IME will pop up somewhere at the top instead,
+ // which is not ideal and needs more research
+
+ if (b)
+ {
+ // Make sure the IME is in the right place, on top of the input line
+ LLRect screen_pos = calcScreenRect();
+ LLCoordGL ime_pos(screen_pos.mLeft, screen_pos.mTop + gSavedSettings.getS32("SDL2IMEMediaVerticalOffset"));
+
+ // shift by a few pixels so the IME doesn't pop to the left side when the nedia
+ // control is very close to the left edge
+ ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]) + 5;
+ ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]);
+
+ getWindow()->setLanguageTextInput(ime_pos);
+ }
+
+ // this floater is not an LLPreeditor but we are only interested in the pointer anyway
+ // so hopefully we will get away with this
+ getWindow()->allowLanguageTextInput((LLPreeditor*) this, b);
+#endif
+ //
+
if (b)
{
onFocusReceived();