diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index b72d006608..63482df996 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -2164,6 +2164,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 LLUICachedControl sdl2_ime_default_vertical_offset("SDL2IMEDefaultVerticalOffset"); + ime_pos.mY += sdl2_ime_default_vertical_offset; +#endif + // getWindow()->setLanguageTextInput( ime_pos ); } } @@ -2313,12 +2319,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 +2513,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 01b7fb0d38..0e8f9f2c5e 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -645,6 +645,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 LLUICachedControl sdl2_ime_default_vertical_offset("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 75cfbe8be8..2c7bfcee06 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -26214,5 +26214,38 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + SDL2IMEDefaultVerticalOffset + + Comment + Default vertical offset to apply to the international input method editor for Japanese, Chinese, etc. + Persist + 1 + Type + S32 + Value + 18 + + SDL2IMEChatHistoryVerticalOffset + + Comment + Chat History: Vertical offset to apply to the international input method editor for Japanese, Chinese, etc. + Persist + 1 + Type + S32 + Value + 14 + + SDL2IMEMediaVerticalOffset + + Comment + Media: Vertical offset to apply to the international input method editor for Japanese, Chinese, etc. + Persist + 1 + Type + S32 + Value + -4 + diff --git a/indra/newview/fschathistory.cpp b/indra/newview/fschathistory.cpp index baade64b0f..1ca779bd0b 100644 --- a/indra/newview/fschathistory.cpp +++ b/indra/newview/fschathistory.cpp @@ -69,6 +69,10 @@ #include "llviewermenu.h" #include "llviewernetwork.h" +#if LL_SDL2 +#include "llwindow.h" +#endif + #include "fscommon.h" #include "llchatentry.h" #include "llfocusmgr.h" @@ -1267,6 +1271,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 @@ -1851,19 +1899,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(); diff --git a/indra/newview/skins/default/xui/da/menu_profile_overflow.xml b/indra/newview/skins/default/xui/da/menu_profile_overflow.xml deleted file mode 100644 index 6745007c99..0000000000 --- a/indra/newview/skins/default/xui/da/menu_profile_overflow.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/indra/newview/skins/default/xui/da/panel_edit_classified.xml b/indra/newview/skins/default/xui/da/panel_edit_classified.xml deleted file mode 100644 index fc4780a34e..0000000000 --- a/indra/newview/skins/default/xui/da/panel_edit_classified.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - (vil blive opdateret efter gemning) - - - Publicér - - - Gem - - - Rediger annonce - - - - - - - - Titel: - - - Beskrivelse: - - - Lokation: - - - henter... - -