Linux/SDL2 - IME support for composing Japanese, Chinese, etc. input. Tested with ibus/mozc giving over-the-top editing with candidate clause selection, Media pages in the internal web browser do not yet have accurate input placement
parent
d42936ee6f
commit
a5cb6dab38
|
|
@ -57,6 +57,12 @@
|
|||
// Imported globals
|
||||
//
|
||||
|
||||
// <FS:Zi> IME - International input compositing, i.e. for Japanese / Chinese text input
|
||||
#if LL_SDL2
|
||||
extern LLControlGroup gSavedSettings;
|
||||
#endif
|
||||
// </FS:Zi>
|
||||
|
||||
//
|
||||
// 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]);
|
||||
// <FS:Zi> IME - International input compositing, i.e. for Japanese / Chinese text input
|
||||
#if LL_SDL2
|
||||
static LLCachedControl<S32> sdl2_ime_default_vertical_offset(*LLControlGroup::getInstance("Global"), "SDL2IMEDefaultVerticalOffset");
|
||||
ime_pos.mY += sdl2_ime_default_vertical_offset;
|
||||
#endif
|
||||
// </FS:Zi>
|
||||
getWindow()->setLanguageTextInput( ime_pos );
|
||||
}
|
||||
}
|
||||
|
|
@ -2313,12 +2325,21 @@ void LLLineEditor::setFocus( BOOL new_state )
|
|||
|
||||
if (new_state)
|
||||
{
|
||||
// <FS:Zi> 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
|
||||
// </FS:Zi>
|
||||
// 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 // <FS:Zi>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2498,7 +2519,16 @@ void LLLineEditor::updateAllowingLanguageInput()
|
|||
// test app, no window available
|
||||
return;
|
||||
}
|
||||
// <FS:Zi> 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
|
||||
// </FS:Zi>
|
||||
if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL)
|
||||
#endif // <FS:Zi>
|
||||
{
|
||||
window->allowLanguageTextInput(this, TRUE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,12 @@
|
|||
|
||||
#include "fsregistrarutils.h"
|
||||
|
||||
// <FS:Zi> IME - International input compositing, i.e. for Japanese / Chinese text input
|
||||
#if LL_SDL2
|
||||
extern LLControlGroup gSavedSettings;
|
||||
#endif
|
||||
// </FS:Zi>
|
||||
|
||||
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]);
|
||||
// <FS:Zi> IME - International input compositing, i.e. for Japanese / Chinese text input
|
||||
#if LL_SDL2
|
||||
static LLCachedControl<S32> sdl2_ime_default_vertical_offset(*LLControlGroup::getInstance("Global"), "SDL2IMEDefaultVerticalOffset");
|
||||
ime_pos.mY += sdl2_ime_default_vertical_offset;
|
||||
#endif
|
||||
// </FS:Zi>
|
||||
getWindow()->setLanguageTextInput( ime_pos );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "llstring.h"
|
||||
#include "lldir.h"
|
||||
#include "llfindlocale.h"
|
||||
#include "llframetimer.h"
|
||||
|
||||
#ifdef LL_GLIB
|
||||
#include <glib.h>
|
||||
|
|
@ -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 );
|
||||
|
||||
// <FS:ND> 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)
|
|||
}
|
||||
// </FS:Zi>
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -26203,5 +26203,38 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SDL2IMEDefaultVerticalOffset</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Default vertical offset to apply to the international input method editor for Japanese, Chinese, etc.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>18</integer>
|
||||
</map>
|
||||
<key>SDL2IMEChatHistoryVerticalOffset</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Chat History: Vertical offset to apply to the international input method editor for Japanese, Chinese, etc.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>14</integer>
|
||||
</map>
|
||||
<key>SDL2IMEMediaVerticalOffset</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Media: Vertical offset to apply to the international input method editor for Japanese, Chinese, etc.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>-4</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
|
|
|||
|
|
@ -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<LLChatEntry*>(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<LLChatEntry*>(gFocusMgr.getKeyboardFocus());
|
||||
}
|
||||
}
|
||||
// we might not know which is our chat input line yet
|
||||
updateChatInputLine();
|
||||
|
||||
// do we know our chat input line now?
|
||||
if(mChatInputLine)
|
||||
|
|
|
|||
|
|
@ -96,8 +96,17 @@ class FSChatHistory : public LLTextEditor // <FS:Zi> 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&);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@
|
|||
#include "llviewermenu.h"
|
||||
#include "llviewermenufile.h" // LLFilePickerThread
|
||||
|
||||
// <FS:Zi> IME - International input compositing, i.e. for Japanese / Chinese text input
|
||||
#if LL_SDL2
|
||||
#include "llwindow.h"
|
||||
#endif
|
||||
// </FS:Zi>
|
||||
|
||||
// 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)
|
||||
{
|
||||
// <FS:Zi> 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
|
||||
// </FS:Zi>
|
||||
|
||||
if (b)
|
||||
{
|
||||
onFocusReceived();
|
||||
|
|
|
|||
Loading…
Reference in New Issue