Browse Source

Replace Char event with TextInput event for CJK IME support.

aster 11 years ago
parent
commit
e0737e6c46

+ 6 - 6
Source/Engine/Input/Input.cpp

@@ -949,14 +949,14 @@ void Input::HandleSDLEvent(void* sdlEvent)
             unsigned unicode = textInput_.AtUTF8(0);
             unsigned unicode = textInput_.AtUTF8(0);
             if (unicode)
             if (unicode)
             {
             {
-                using namespace Char;
+                using namespace TextInput;
 
 
-                VariantMap keyEventData;
+                VariantMap textInputEventData;
 
 
-                keyEventData[P_CHAR] = unicode;
-                keyEventData[P_BUTTONS] = mouseButtonDown_;
-                keyEventData[P_QUALIFIERS] = GetQualifiers();
-                SendEvent(E_CHAR, keyEventData);
+                textInputEventData[P_TEXT] = textInput_;
+                textInputEventData[P_BUTTONS] = mouseButtonDown_;
+                textInputEventData[P_QUALIFIERS] = GetQualifiers();
+                SendEvent(E_TEXTINPUT, textInputEventData);
             }
             }
         }
         }
         break;
         break;

+ 3 - 3
Source/Engine/Input/InputEvents.h

@@ -87,10 +87,10 @@ EVENT(E_KEYUP, KeyUp)
     PARAM(P_QUALIFIERS, Qualifiers);        // int
     PARAM(P_QUALIFIERS, Qualifiers);        // int
 }
 }
 
 
-/// Character typed on the keyboard.
-EVENT(E_CHAR, Char)
+/// Text input event.
+EVENT(E_TEXTINPUT, TextInput)
 {
 {
-    PARAM(P_CHAR, Char);                    // int
+    PARAM(P_TEXT, Text);                    // String
     PARAM(P_BUTTONS, Buttons);              // int
     PARAM(P_BUTTONS, Buttons);              // int
     PARAM(P_QUALIFIERS, Qualifiers);        // int
     PARAM(P_QUALIFIERS, Qualifiers);        // int
 }
 }

+ 99 - 99
Source/Engine/UI/Font.cpp

@@ -50,7 +50,7 @@ static const int MAX_POINT_SIZE = 96;
 class FreeTypeLibrary : public Object
 class FreeTypeLibrary : public Object
 {
 {
     OBJECT(FreeTypeLibrary);
     OBJECT(FreeTypeLibrary);
-    
+
 public:
 public:
     /// Construct.
     /// Construct.
     FreeTypeLibrary(Context* context) :
     FreeTypeLibrary(Context* context) :
@@ -60,15 +60,15 @@ public:
         if (error)
         if (error)
             LOGERROR("Could not initialize FreeType library");
             LOGERROR("Could not initialize FreeType library");
     }
     }
-    
+
     /// Destruct.
     /// Destruct.
     virtual ~FreeTypeLibrary()
     virtual ~FreeTypeLibrary()
     {
     {
         FT_Done_FreeType(library_);
         FT_Done_FreeType(library_);
     }
     }
-    
+
     FT_Library GetLibrary() const { return library_; }
     FT_Library GetLibrary() const { return library_; }
-    
+
 private:
 private:
     /// FreeType library.
     /// FreeType library.
     FT_Library library_;
     FT_Library library_;
@@ -100,7 +100,7 @@ FontFace::~FontFace()
         FT_Done_Face((FT_Face)face_);
         FT_Done_Face((FT_Face)face_);
         face_ = 0;
         face_ = 0;
     }
     }
-    
+
     if (font_)
     if (font_)
     {
     {
         // When a face is unloaded, deduct the used texture data size from the parent font
         // When a face is unloaded, deduct the used texture data size from the parent font
@@ -109,7 +109,7 @@ FontFace::~FontFace()
             totalTextureSize += textures_[i]->GetWidth() * textures_[i]->GetHeight();
             totalTextureSize += textures_[i]->GetWidth() * textures_[i]->GetHeight();
         font_->SetMemoryUse(font_->GetMemoryUse() - totalTextureSize);
         font_->SetMemoryUse(font_->GetMemoryUse() - totalTextureSize);
     }
     }
-    
+
     for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
     for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
         delete *i;
         delete *i;
     mutableGlyphs_.Clear();
     mutableGlyphs_.Clear();
@@ -132,7 +132,7 @@ const FontGlyph* FontFace::GetGlyph(unsigned c)
             mutableGlyphs_.PushFront(mutableGlyph);
             mutableGlyphs_.PushFront(mutableGlyph);
             glyph.iterator_ = mutableGlyphs_.Begin();
             glyph.iterator_ = mutableGlyphs_.Begin();
         }
         }
-        
+
         glyph.used_ = true;
         glyph.used_ = true;
         return &glyph;
         return &glyph;
     }
     }
@@ -144,10 +144,10 @@ short FontFace::GetKerning(unsigned c, unsigned d) const
 {
 {
     if (!hasKerning_)
     if (!hasKerning_)
         return 0;
         return 0;
-    
+
     if (c == '\n' || d == '\n')
     if (c == '\n' || d == '\n')
         return 0;
         return 0;
-    
+
     unsigned leftIndex = 0;
     unsigned leftIndex = 0;
     unsigned rightIndex = 0;
     unsigned rightIndex = 0;
     HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
     HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
@@ -160,7 +160,7 @@ short FontFace::GetKerning(unsigned c, unsigned d) const
         rightIndex = rightIt->second_;
         rightIndex = rightIt->second_;
     else
     else
         return 0;
         return 0;
-    
+
     HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
     HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
     if (kerningIt != glyphs_[leftIndex].kerning_.End())
     if (kerningIt != glyphs_[leftIndex].kerning_.End())
         return kerningIt->second_;
         return kerningIt->second_;
@@ -181,9 +181,9 @@ bool FontFace::IsDataLost() const
 bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
 bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
 {
 {
     assert(font_ && face_ && textures_.Empty());
     assert(font_ && face_ && textures_.Empty());
-    
+
     allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
     allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
-    
+
     for (unsigned i = 0; i < glyphs_.Size(); ++i)
     for (unsigned i = 0; i < glyphs_.Size(); ++i)
     {
     {
         if (glyphs_[i].width_ && glyphs_[i].height_)
         if (glyphs_[i].width_ && glyphs_[i].height_)
@@ -211,19 +211,19 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
             glyphs_[i].page_ = 0;
             glyphs_[i].page_ = 0;
         }
         }
     }
     }
-    
+
     // Create image for rendering all the glyphs, clear to black
     // Create image for rendering all the glyphs, clear to black
     SharedPtr<Image> image(new Image(font_->GetContext()));
     SharedPtr<Image> image(new Image(font_->GetContext()));
     image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
     image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
     unsigned char* imageData = image->GetData();
     unsigned char* imageData = image->GetData();
     memset(imageData, 0, image->GetWidth() * image->GetHeight());
     memset(imageData, 0, image->GetWidth() * image->GetHeight());
-    
+
     int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
     int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
 
 
     // Render glyphs
     // Render glyphs
     for (unsigned i = 0; i < glyphs_.Size(); ++i)
     for (unsigned i = 0; i < glyphs_.Size(); ++i)
         RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth(), loadMode);
         RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth(), loadMode);
-    
+
     // Load image into a texture, increment memory usage of the parent font
     // Load image into a texture, increment memory usage of the parent font
     SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
     SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
     if (!texture)
     if (!texture)
@@ -232,10 +232,10 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
             glyphs_[i].page_ = M_MAX_UNSIGNED;
             glyphs_[i].page_ = M_MAX_UNSIGNED;
         return false;
         return false;
     }
     }
-    
+
     textures_.Push(texture);
     textures_.Push(texture);
     font_->SetMemoryUse(font_->GetMemoryUse() + image->GetWidth() * image->GetHeight());
     font_->SetMemoryUse(font_->GetMemoryUse() + image->GetWidth() * image->GetHeight());
-    
+
     LOGDEBUGF("Font face %s (%dpt) uses a static page texture of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, texture->GetWidth(), texture->GetHeight());
     LOGDEBUGF("Font face %s (%dpt) uses a static page texture of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, texture->GetWidth(), texture->GetHeight());
     return true;
     return true;
 }
 }
@@ -243,9 +243,9 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
 void FontFace::RenderGlyph(unsigned index)
 void FontFace::RenderGlyph(unsigned index)
 {
 {
     assert(font_ && face_);
     assert(font_ && face_);
-    
+
     FontGlyph& glyph = glyphs_[index];
     FontGlyph& glyph = glyphs_[index];
-    
+
     // If glyph is empty, just set the current page
     // If glyph is empty, just set the current page
     if (!glyph.width_ || !glyph.height_)
     if (!glyph.width_ || !glyph.height_)
     {
     {
@@ -254,7 +254,7 @@ void FontFace::RenderGlyph(unsigned index)
         glyph.page_ = textures_.Size() - 1;
         glyph.page_ = textures_.Size() - 1;
         return;
         return;
     }
     }
-    
+
     int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
     int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
 
 
     if (!mutableGlyphs_.Size())
     if (!mutableGlyphs_.Size())
@@ -267,17 +267,17 @@ void FontFace::RenderGlyph(unsigned index)
             // This always succeeds, as it is the first allocation of an empty page
             // This always succeeds, as it is the first allocation of an empty page
             allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
             allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
         }
         }
-        
+
         glyph.x_ = x;
         glyph.x_ = x;
         glyph.y_ = y;
         glyph.y_ = y;
         glyph.page_ = textures_.Size() - 1;
         glyph.page_ = textures_.Size() - 1;
-        
+
         if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
         if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
         {
         {
             bitmapSize_ = glyph.width_ * glyph.height_;
             bitmapSize_ = glyph.width_ * glyph.height_;
             bitmap_ = new unsigned char[bitmapSize_];
             bitmap_ = new unsigned char[bitmapSize_];
         }
         }
-        
+
         RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
         RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
         textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
         textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
     }
     }
@@ -293,13 +293,13 @@ void FontFace::RenderGlyph(unsigned index)
         glyph.page_ = 0;
         glyph.page_ = 0;
         glyph.iterator_ = it;
         glyph.iterator_ = it;
         mutableGlyph->glyphIndex_ = index;
         mutableGlyph->glyphIndex_ = index;
-        
+
         if (!bitmap_)
         if (!bitmap_)
         {
         {
             bitmapSize_ = cellWidth_ * cellHeight_;
             bitmapSize_ = cellWidth_ * cellHeight_;
             bitmap_ = new unsigned char[bitmapSize_];
             bitmap_ = new unsigned char[bitmapSize_];
         }
         }
-        
+
         // Clear the cell bitmap before rendering to ensure padding
         // Clear the cell bitmap before rendering to ensure padding
         memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
         memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
         RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
         RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
@@ -312,7 +312,7 @@ void FontFace::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned p
     const FontGlyph& glyph = glyphs_[index];
     const FontGlyph& glyph = glyphs_[index];
     if (!glyph.width_ || !glyph.height_)
     if (!glyph.width_ || !glyph.height_)
         return;
         return;
-    
+
     FT_Face face = (FT_Face)face_;
     FT_Face face = (FT_Face)face_;
     FT_GlyphSlot slot = face->glyph;
     FT_GlyphSlot slot = face->glyph;
     FT_Load_Glyph(face, index, loadMode);
     FT_Load_Glyph(face, index, loadMode);
@@ -352,22 +352,22 @@ void FontFace::SetupNextTexture(int width, int height)
     SharedArrayPtr<unsigned char> emptyBitmap(new unsigned char[width * height]);
     SharedArrayPtr<unsigned char> emptyBitmap(new unsigned char[width * height]);
     memset(emptyBitmap.Get(), 0, width * height);
     memset(emptyBitmap.Get(), 0, width * height);
     texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
     texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
-    
+
     textures_.Push(texture);
     textures_.Push(texture);
     font_->SetMemoryUse(font_->GetMemoryUse() + width * height);
     font_->SetMemoryUse(font_->GetMemoryUse() + width * height);
-    
+
     LOGDEBUGF("Font face %s (%dpt) is using %d dynamic page textures of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, textures_.Size(), width, height);
     LOGDEBUGF("Font face %s (%dpt) is using %d dynamic page textures of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, textures_.Size(), width, height);
 }
 }
 
 
 void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
 void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
 {
 {
     assert(mutableGlyphs_.Empty());
     assert(mutableGlyphs_.Empty());
-    
+
     SetupNextTexture(textureWidth, textureHeight);
     SetupNextTexture(textureWidth, textureHeight);
-    
+
     cellWidth_ = maxWidth + 1;
     cellWidth_ = maxWidth + 1;
     cellHeight_ = maxHeight + 1;
     cellHeight_ = maxHeight + 1;
-    
+
     // Allocate as many mutable glyphs as possible
     // Allocate as many mutable glyphs as possible
     int x, y;
     int x, y;
     while (allocator_.Allocate(cellWidth_, cellHeight_, x, y))
     while (allocator_.Allocate(cellWidth_, cellHeight_, x, y))
@@ -377,7 +377,7 @@ void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWi
         glyph->y_ = y;
         glyph->y_ = y;
         mutableGlyphs_.Push(glyph);
         mutableGlyphs_.Push(glyph);
     }
     }
-    
+
     LOGDEBUGF("Font face %s (%dpt) is using %d mutable glyphs", GetFileName(font_->GetName()).CString(), pointSize_, mutableGlyphs_.Size());
     LOGDEBUGF("Font face %s (%dpt) is using %d mutable glyphs", GetFileName(font_->GetName()).CString(), pointSize_, mutableGlyphs_.Size());
 }
 }
 
 
@@ -403,15 +403,15 @@ void Font::RegisterObject(Context* context)
 bool Font::Load(Deserializer& source)
 bool Font::Load(Deserializer& source)
 {
 {
     PROFILE(LoadFont);
     PROFILE(LoadFont);
-    
+
     // In headless mode, do not actually load, just return success
     // In headless mode, do not actually load, just return success
     Graphics* graphics = GetSubsystem<Graphics>();
     Graphics* graphics = GetSubsystem<Graphics>();
     if (!graphics)
     if (!graphics)
         return true;
         return true;
-    
+
     fontType_ = FONT_NONE;
     fontType_ = FONT_NONE;
     faces_.Clear();
     faces_.Clear();
-    
+
     fontDataSize_ = source.GetSize();
     fontDataSize_ = source.GetSize();
     if (fontDataSize_)
     if (fontDataSize_)
     {
     {
@@ -440,9 +440,9 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
     FontFace* fontFace = GetFace(pointSize);
     FontFace* fontFace = GetFace(pointSize);
     if (!fontFace)
     if (!fontFace)
         return false;
         return false;
-    
+
     PROFILE(FontSaveXML);
     PROFILE(FontSaveXML);
-    
+
     SharedPtr<FontFace> packedFontFace;
     SharedPtr<FontFace> packedFontFace;
     if (usedGlyphs)
     if (usedGlyphs)
     {
     {
@@ -453,7 +453,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
         else
         else
             return false;
             return false;
     }
     }
-    
+
     SharedPtr<XMLFile> xml(new XMLFile(context_));
     SharedPtr<XMLFile> xml(new XMLFile(context_));
     XMLElement rootElem = xml->CreateRoot("font");
     XMLElement rootElem = xml->CreateRoot("font");
 
 
@@ -462,7 +462,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
     String fileName = GetFileName(GetName());
     String fileName = GetFileName(GetName());
     childElem.SetAttribute("face", fileName);
     childElem.SetAttribute("face", fileName);
     childElem.SetAttribute("size", String(pointSize));
     childElem.SetAttribute("size", String(pointSize));
-    
+
     // Common
     // Common
     childElem = rootElem.CreateChild("common");
     childElem = rootElem.CreateChild("common");
     childElem.SetInt("lineHeight", fontFace->rowHeight_);
     childElem.SetInt("lineHeight", fontFace->rowHeight_);
@@ -487,11 +487,11 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
         pageElem.SetInt("id", i);
         pageElem.SetInt("id", i);
         String texFileName = fileName + "_" + String(i) + ".png";
         String texFileName = fileName + "_" + String(i) + ".png";
         pageElem.SetAttribute("file", texFileName);
         pageElem.SetAttribute("file", texFileName);
-        
+
         // Save the font face texture to image file
         // Save the font face texture to image file
         SaveFaceTexture(fontFace->textures_[i], pathName + texFileName);
         SaveFaceTexture(fontFace->textures_[i], pathName + texFileName);
     }
     }
-    
+
     // Chars and kernings
     // Chars and kernings
     XMLElement charsElem = rootElem.CreateChild("chars");
     XMLElement charsElem = rootElem.CreateChild("chars");
     unsigned numGlyphs = fontFace->glyphs_.Size();
     unsigned numGlyphs = fontFace->glyphs_.Size();
@@ -514,7 +514,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
         charElem.SetInt("yoffset", glyph.offsetY_);
         charElem.SetInt("yoffset", glyph.offsetY_);
         charElem.SetInt("xadvance", glyph.advanceX_);
         charElem.SetInt("xadvance", glyph.advanceX_);
         charElem.SetInt("page", glyph.page_);
         charElem.SetInt("page", glyph.page_);
-        
+
         // Kerning
         // Kerning
         if (hasKerning)
         if (hasKerning)
         {
         {
@@ -523,7 +523,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
                 // To conserve space, only write when amount is non zero
                 // To conserve space, only write when amount is non zero
                 if (j->second_ == 0)
                 if (j->second_ == 0)
                     continue;
                     continue;
-                
+
                 XMLElement kerningElem = kerningsElem.CreateChild("kerning");
                 XMLElement kerningElem = kerningsElem.CreateChild("kerning");
                 kerningElem.SetInt("first", i->first_);
                 kerningElem.SetInt("first", i->first_);
                 kerningElem.SetInt("second", j->first_);
                 kerningElem.SetInt("second", j->first_);
@@ -531,7 +531,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
             }
             }
         }
         }
     }
     }
-    
+
     return xml->Save(dest);
     return xml->Save(dest);
 }
 }
 
 
@@ -541,13 +541,13 @@ FontFace* Font::GetFace(int pointSize)
     Graphics* graphics = GetSubsystem<Graphics>();
     Graphics* graphics = GetSubsystem<Graphics>();
     if (!graphics)
     if (!graphics)
         return 0;
         return 0;
-    
+
     // For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size
     // For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size
     if (fontType_ == FONT_BITMAP)
     if (fontType_ == FONT_BITMAP)
         pointSize = 0;
         pointSize = 0;
     else
     else
         pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
         pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
-    
+
     HashMap<int, SharedPtr<FontFace> >::Iterator i = faces_.Find(pointSize);
     HashMap<int, SharedPtr<FontFace> >::Iterator i = faces_.Find(pointSize);
     if (i != faces_.End())
     if (i != faces_.End())
     {
     {
@@ -559,9 +559,9 @@ FontFace* Font::GetFace(int pointSize)
             faces_.Erase(i);
             faces_.Erase(i);
         }
         }
     }
     }
-    
+
     PROFILE(GetFontFace);
     PROFILE(GetFontFace);
-    
+
     switch (fontType_)
     switch (fontType_)
     {
     {
     case FONT_FREETYPE:
     case FONT_FREETYPE:
@@ -569,7 +569,7 @@ FontFace* Font::GetFace(int pointSize)
 
 
     case FONT_BITMAP:
     case FONT_BITMAP:
         return GetFaceBitmap(pointSize);
         return GetFaceBitmap(pointSize);
-    
+
     default:
     default:
         return 0;
         return 0;
     }
     }
@@ -610,26 +610,26 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_));
         context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_));
     // Ensure the FreeType library is kept alive as long as TTF font resources exist
     // Ensure the FreeType library is kept alive as long as TTF font resources exist
     freeType_ = freeType;
     freeType_ = freeType;
-    
+
     UI* ui = GetSubsystem<UI>();
     UI* ui = GetSubsystem<UI>();
     int maxTextureSize = ui->GetMaxFontTextureSize();
     int maxTextureSize = ui->GetMaxFontTextureSize();
-    
+
     FT_Face face;
     FT_Face face;
     FT_Error error;
     FT_Error error;
     FT_Library library = freeType->GetLibrary();
     FT_Library library = freeType->GetLibrary();
-    
+
     if (pointSize <= 0)
     if (pointSize <= 0)
     {
     {
         LOGERROR("Zero or negative point size");
         LOGERROR("Zero or negative point size");
         return 0;
         return 0;
     }
     }
-    
+
     if (!fontDataSize_)
     if (!fontDataSize_)
     {
     {
         LOGERROR("Could not create font face from zero size data");
         LOGERROR("Could not create font face from zero size data");
         return 0;
         return 0;
     }
     }
-    
+
     error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
     error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
     if (error)
     if (error)
     {
     {
@@ -643,13 +643,13 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         LOGERROR("Could not set font point size " + String(pointSize));
         LOGERROR("Could not set font point size " + String(pointSize));
         return 0;
         return 0;
     }
     }
-    
+
     SharedPtr<FontFace> newFace(new FontFace(this));
     SharedPtr<FontFace> newFace(new FontFace(this));
     newFace->face_ = face;
     newFace->face_ = face;
-    
+
     FT_GlyphSlot slot = face->glyph;
     FT_GlyphSlot slot = face->glyph;
     unsigned numGlyphs = 0;
     unsigned numGlyphs = 0;
-    
+
     // Build glyph mapping
     // Build glyph mapping
     FT_UInt glyphIndex;
     FT_UInt glyphIndex;
     FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
     FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
@@ -659,16 +659,16 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         newFace->glyphMapping_[charCode] = glyphIndex;
         newFace->glyphMapping_[charCode] = glyphIndex;
         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
     }
     }
-    
+
     LOGDEBUGF("Font face %s (%dpt) has %d glyphs", GetFileName(GetName()).CString(), pointSize, numGlyphs);
     LOGDEBUGF("Font face %s (%dpt) has %d glyphs", GetFileName(GetName()).CString(), pointSize, numGlyphs);
-    
+
     // Load each of the glyphs to see the sizes & store other information
     // Load each of the glyphs to see the sizes & store other information
     int maxWidth = 0;
     int maxWidth = 0;
     int maxHeight = 0;
     int maxHeight = 0;
     int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
     int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
     int ascender = face->size->metrics.ascender >> 6;
     int ascender = face->size->metrics.ascender >> 6;
     int descender = face->size->metrics.descender >> 6;
     int descender = face->size->metrics.descender >> 6;
-    
+
     // Check if the font's OS/2 info gives different (larger) values for ascender & descender
     // Check if the font's OS/2 info gives different (larger) values for ascender & descender
     TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
     TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
     if (os2Info)
     if (os2Info)
@@ -678,17 +678,17 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
         descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
         descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
         descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
     }
     }
-    
+
     // Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
     // Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
     newFace->pointSize_ = pointSize;
     newFace->pointSize_ = pointSize;
     newFace->rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
     newFace->rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
-    
+
     newFace->glyphs_.Reserve(numGlyphs);
     newFace->glyphs_.Reserve(numGlyphs);
-    
+
     for (unsigned i = 0; i < numGlyphs; ++i)
     for (unsigned i = 0; i < numGlyphs; ++i)
     {
     {
         FontGlyph newGlyph;
         FontGlyph newGlyph;
-        
+
         error = FT_Load_Glyph(face, i, loadMode);
         error = FT_Load_Glyph(face, i, loadMode);
         if (!error)
         if (!error)
         {
         {
@@ -698,7 +698,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
             newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
             newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
             newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
             newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
             newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
             newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
-            
+
             maxWidth = Max(maxWidth, newGlyph.width_);
             maxWidth = Max(maxWidth, newGlyph.width_);
             maxHeight = Max(maxHeight, newGlyph.height_);
             maxHeight = Max(maxHeight, newGlyph.height_);
         }
         }
@@ -710,10 +710,10 @@ FontFace* Font::GetFaceFreeType(int pointSize)
             newGlyph.offsetY_ = 0;
             newGlyph.offsetY_ = 0;
             newGlyph.advanceX_ = 0;
             newGlyph.advanceX_ = 0;
         }
         }
-        
+
         newFace->glyphs_.Push(newGlyph);
         newFace->glyphs_.Push(newGlyph);
     }
     }
-    
+
     // Store kerning if face has kerning information
     // Store kerning if face has kerning information
     if (FT_HAS_KERNING(face))
     if (FT_HAS_KERNING(face))
     {
     {
@@ -756,9 +756,9 @@ FontFace* Font::GetFaceFreeType(int pointSize)
                 if (version == 0 && coverage == 1)
                 if (version == 0 && coverage == 1)
                 {
                 {
                     unsigned numKerningPairs = deserializer.ReadUShort();
                     unsigned numKerningPairs = deserializer.ReadUShort();
-                    // Skip searchRange, entrySelector & rangeShift
+                    // Skip searchRange, entrySelector and rangeShift
                     deserializer.Seek(deserializer.GetPosition() + 3 * sizeof(unsigned short));
                     deserializer.Seek(deserializer.GetPosition() + 3 * sizeof(unsigned short));
-                    
+
                     for (unsigned j = 0; j < numKerningPairs; ++j)
                     for (unsigned j = 0; j < numKerningPairs; ++j)
                     {
                     {
                         unsigned leftIndex = deserializer.ReadUShort();
                         unsigned leftIndex = deserializer.ReadUShort();
@@ -780,7 +780,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         else
         else
             LOGWARNING("Can not read kerning information: not version 0");
             LOGWARNING("Can not read kerning information: not version 0");
     }
     }
-    
+
     // Now try to pack into the smallest possible texture. If face does not fit into one texture, enable dynamic mode where
     // Now try to pack into the smallest possible texture. If face does not fit into one texture, enable dynamic mode where
     // glyphs are only created as necessary
     // glyphs are only created as necessary
     if (newFace->RenderAllGlyphs(maxTextureSize, maxTextureSize))
     if (newFace->RenderAllGlyphs(maxTextureSize, maxTextureSize))
@@ -795,7 +795,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         else
         else
             newFace->SetupNextTexture(maxTextureSize, maxTextureSize);
             newFace->SetupNextTexture(maxTextureSize, maxTextureSize);
     }
     }
-    
+
     faces_[pointSize] = newFace;
     faces_[pointSize] = newFace;
     return newFace;
     return newFace;
 }
 }
@@ -809,7 +809,7 @@ FontFace* Font::GetFaceBitmap(int pointSize)
         LOGERROR("Could not load XML file");
         LOGERROR("Could not load XML file");
         return 0;
         return 0;
     }
     }
-    
+
     XMLElement root = xmlReader->GetRoot("font");
     XMLElement root = xmlReader->GetRoot("font");
     if (root.IsNull())
     if (root.IsNull())
     {
     {
@@ -823,13 +823,13 @@ FontFace* Font::GetFaceBitmap(int pointSize)
         LOGERROR("Could not find Pages element");
         LOGERROR("Could not find Pages element");
         return 0;
         return 0;
     }
     }
-    
+
     SharedPtr<FontFace> newFace(new FontFace(this));
     SharedPtr<FontFace> newFace(new FontFace(this));
-    
+
     XMLElement infoElem = root.GetChild("info");
     XMLElement infoElem = root.GetChild("info");
     if (!infoElem.IsNull())
     if (!infoElem.IsNull())
         newFace->pointSize_ = infoElem.GetInt("size");
         newFace->pointSize_ = infoElem.GetInt("size");
-    
+
     XMLElement commonElem = root.GetChild("common");
     XMLElement commonElem = root.GetChild("common");
     newFace->rowHeight_ = commonElem.GetInt("lineHeight");
     newFace->rowHeight_ = commonElem.GetInt("lineHeight");
     unsigned pages = commonElem.GetInt("pages");
     unsigned pages = commonElem.GetInt("pages");
@@ -850,7 +850,7 @@ FontFace* Font::GetFaceBitmap(int pointSize)
 
 
         // Assume the font image is in the same directory as the font description file
         // Assume the font image is in the same directory as the font description file
         String textureFile = fontPath + pageElem.GetAttribute("file");
         String textureFile = fontPath + pageElem.GetAttribute("file");
-        
+
         // Load texture manually to allow controlling the alpha channel mode
         // Load texture manually to allow controlling the alpha channel mode
         SharedPtr<File> fontFile = resourceCache->GetFile(textureFile);
         SharedPtr<File> fontFile = resourceCache->GetFile(textureFile);
         SharedPtr<Image> fontImage(new Image(context_));
         SharedPtr<Image> fontImage(new Image(context_));
@@ -864,15 +864,15 @@ FontFace* Font::GetFaceBitmap(int pointSize)
             return 0;
             return 0;
         newFace->textures_.Push(texture);
         newFace->textures_.Push(texture);
         totalTextureSize += fontImage->GetWidth() * fontImage->GetHeight() * fontImage->GetComponents();
         totalTextureSize += fontImage->GetWidth() * fontImage->GetHeight() * fontImage->GetComponents();
-        
+
         pageElem = pageElem.GetNext("page");
         pageElem = pageElem.GetNext("page");
     }
     }
-    
+
     XMLElement charsElem = root.GetChild("chars");
     XMLElement charsElem = root.GetChild("chars");
     int count = charsElem.GetInt("count");
     int count = charsElem.GetInt("count");
     newFace->glyphs_.Reserve(count);
     newFace->glyphs_.Reserve(count);
     unsigned index = 0;
     unsigned index = 0;
-    
+
     XMLElement charElem = charsElem.GetChild("char");
     XMLElement charElem = charsElem.GetChild("char");
     while (!charElem.IsNull())
     while (!charElem.IsNull())
     {
     {
@@ -888,10 +888,10 @@ FontFace* Font::GetFaceBitmap(int pointSize)
         glyph.page_ = charElem.GetInt("page");
         glyph.page_ = charElem.GetInt("page");
         newFace->glyphs_.Push(glyph);
         newFace->glyphs_.Push(glyph);
         newFace->glyphMapping_[id] = index++;
         newFace->glyphMapping_[id] = index++;
-        
+
         charElem = charElem.GetNext("char");
         charElem = charElem.GetNext("char");
     }
     }
-    
+
     XMLElement kerningsElem = root.GetChild("kernings");
     XMLElement kerningsElem = root.GetChild("kernings");
     if (kerningsElem.IsNull())
     if (kerningsElem.IsNull())
         newFace->hasKerning_ = false;
         newFace->hasKerning_ = false;
@@ -906,15 +906,15 @@ FontFace* Font::GetFaceBitmap(int pointSize)
             {
             {
                 int second = kerningElem.GetInt("second");
                 int second = kerningElem.GetInt("second");
                 int amount = kerningElem.GetInt("amount");
                 int amount = kerningElem.GetInt("amount");
-                
+
                 FontGlyph& glyph = newFace->glyphs_[i->second_];
                 FontGlyph& glyph = newFace->glyphs_[i->second_];
                 glyph.kerning_[second] = amount;
                 glyph.kerning_[second] = amount;
             }
             }
-            
+
             kerningElem = kerningElem.GetNext("kerning");
             kerningElem = kerningElem.GetNext("kerning");
         }
         }
     }
     }
-    
+
     LOGDEBUGF("Bitmap font face %s has %d glyphs", GetFileName(GetName()).CString(), count);
     LOGDEBUGF("Bitmap font face %s has %d glyphs", GetFileName(GetName()).CString(), count);
 
 
     SetMemoryUse(GetMemoryUse() + totalTextureSize);
     SetMemoryUse(GetMemoryUse() + totalTextureSize);
@@ -938,22 +938,22 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
 {
 {
     // Set parent font as null for the packed face so that it does not attempt to manage the font's total memory use
     // Set parent font as null for the packed face so that it does not attempt to manage the font's total memory use
     SharedPtr<FontFace> packedFontFace(new FontFace((Font*)0));
     SharedPtr<FontFace> packedFontFace(new FontFace((Font*)0));
-    
+
     int maxTextureSize = GetSubsystem<UI>()->GetMaxFontTextureSize();
     int maxTextureSize = GetSubsystem<UI>()->GetMaxFontTextureSize();
-    
+
     // Clone properties
     // Clone properties
     packedFontFace->pointSize_ = fontFace->pointSize_;
     packedFontFace->pointSize_ = fontFace->pointSize_;
     packedFontFace->rowHeight_ = fontFace->rowHeight_;
     packedFontFace->rowHeight_ = fontFace->rowHeight_;
     packedFontFace->hasKerning_ = fontFace->hasKerning_;
     packedFontFace->hasKerning_ = fontFace->hasKerning_;
-    
+
     // Assume that format is the same for all textures and that bitmap font type may have more than one component
     // Assume that format is the same for all textures and that bitmap font type may have more than one component
     unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
     unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
-    
+
     // Save the existing textures as image resources
     // Save the existing textures as image resources
     Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
     Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
     for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
     for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
         images[i] = SaveFaceTexture(fontFace->textures_[i]);
         images[i] = SaveFaceTexture(fontFace->textures_[i]);
-    
+
     // Reallocate used glyphs to new texture(s)
     // Reallocate used glyphs to new texture(s)
     unsigned page = 0;
     unsigned page = 0;
     unsigned index = 0;
     unsigned index = 0;
@@ -982,18 +982,18 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
                 else
                 else
                     break;
                     break;
             }
             }
-            
+
             packedFontFace->glyphs_.Push(glyph);
             packedFontFace->glyphs_.Push(glyph);
             packedFontFace->glyphMapping_[i->first_] = index++;
             packedFontFace->glyphMapping_[i->first_] = index++;
         }
         }
-        
+
         int texWidth = allocator.GetWidth();
         int texWidth = allocator.GetWidth();
         int texHeight = allocator.GetHeight();
         int texHeight = allocator.GetHeight();
-        
+
         // Create the image for rendering the fonts
         // Create the image for rendering the fonts
         SharedPtr<Image> image(new Image(context_));
         SharedPtr<Image> image(new Image(context_));
         image->SetSize(texWidth, texHeight, components);
         image->SetSize(texWidth, texHeight, components);
-        
+
         // First clear the whole image
         // First clear the whole image
         unsigned char* imageData = image->GetData();
         unsigned char* imageData = image->GetData();
         for (int y = 0; y < texHeight; ++y)
         for (int y = 0; y < texHeight; ++y)
@@ -1001,22 +1001,22 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
             unsigned char* dest = imageData + components * texWidth * y;
             unsigned char* dest = imageData + components * texWidth * y;
             memset(dest, 0, components * texWidth);
             memset(dest, 0, components * texWidth);
         }
         }
-        
+
         // Then render the glyphs into new image
         // Then render the glyphs into new image
         for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
         for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
         {
         {
             FontGlyph glyph = fontFace->glyphs_[j->second_];
             FontGlyph glyph = fontFace->glyphs_[j->second_];
             if (!glyph.used_)
             if (!glyph.used_)
                 continue;
                 continue;
-            
+
             if (!glyph.width_ || !glyph.height_)
             if (!glyph.width_ || !glyph.height_)
             {
             {
                 ++startIndex;
                 ++startIndex;
                 continue;
                 continue;
             }
             }
-            
+
             FontGlyph packedGlyph = packedFontFace->glyphs_[startIndex++];
             FontGlyph packedGlyph = packedFontFace->glyphs_[startIndex++];
-            
+
             Image* image = images[glyph.page_];
             Image* image = images[glyph.page_];
             unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
             unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
             unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
             unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
@@ -1027,7 +1027,7 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
                 destination += components * texWidth;
                 destination += components * texWidth;
             }
             }
         }
         }
-        
+
         // Finally load image into the texture
         // Finally load image into the texture
         SharedPtr<Texture2D> texture = LoadFaceTexture(image);
         SharedPtr<Texture2D> texture = LoadFaceTexture(image);
         if (!texture)
         if (!texture)
@@ -1038,7 +1038,7 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
         startIter = i;
         startIter = i;
         assert(index == startIndex);
         assert(index == startIndex);
     }
     }
-    
+
     return packedFontFace;
     return packedFontFace;
 }
 }
 
 

+ 19 - 22
Source/Engine/UI/LineEdit.cpp

@@ -389,7 +389,7 @@ void LineEdit::OnKey(int key, int buttons, int qualifiers)
             // If using the on-screen keyboard, defocus this element to hide it now
             // If using the on-screen keyboard, defocus this element to hide it now
             if (GetSubsystem<UI>()->GetUseScreenKeyboard() && HasFocus())
             if (GetSubsystem<UI>()->GetUseScreenKeyboard() && HasFocus())
                 SetFocus(false);
                 SetFocus(false);
-            
+
             using namespace TextFinished;
             using namespace TextFinished;
 
 
             VariantMap& eventData = GetEventDataMap();
             VariantMap& eventData = GetEventDataMap();
@@ -410,40 +410,37 @@ void LineEdit::OnKey(int key, int buttons, int qualifiers)
         UpdateCursor();
         UpdateCursor();
 }
 }
 
 
-void LineEdit::OnChar(unsigned c, int buttons, int qualifiers)
+void LineEdit::OnTextInput(const String& text, int buttons, int qualifiers)
 {
 {
     if (!editable_)
     if (!editable_)
         return;
         return;
-    
+
     bool changed = false;
     bool changed = false;
-    
+
     // If only CTRL is held down, do not edit
     // If only CTRL is held down, do not edit
     if ((qualifiers & (QUAL_CTRL | QUAL_ALT)) == QUAL_CTRL)
     if ((qualifiers & (QUAL_CTRL | QUAL_ALT)) == QUAL_CTRL)
         return;
         return;
-        
+
     // Send char as an event to allow changing it
     // Send char as an event to allow changing it
     using namespace CharEntry;
     using namespace CharEntry;
-    
+
     VariantMap& eventData = GetEventDataMap();
     VariantMap& eventData = GetEventDataMap();
     eventData[P_ELEMENT] = this;
     eventData[P_ELEMENT] = this;
-    eventData[P_CHAR] = c;
+    eventData[P_TEXT] = text;
     eventData[P_BUTTONS] = buttons;
     eventData[P_BUTTONS] = buttons;
     eventData[P_QUALIFIERS] = qualifiers;
     eventData[P_QUALIFIERS] = qualifiers;
-    SendEvent(E_CHARENTRY, eventData);
-    c = eventData[P_CHAR].GetUInt();
-    
-    if (c >= 0x20 && (!maxLength_ || line_.LengthUTF8() < maxLength_))
-    {
-        String charStr;
-        charStr.AppendUTF8(c);
+    SendEvent(E_TEXTENTRY, eventData);
 
 
+    const String newText = eventData[P_TEXT].GetString().SubstringUTF8(0);
+    if (!newText.Empty() && (!maxLength_ || line_.LengthUTF8() + newText.LengthUTF8() <= maxLength_))
+    {
         if (!text_->GetSelectionLength())
         if (!text_->GetSelectionLength())
         {
         {
             if (cursorPosition_ == line_.LengthUTF8())
             if (cursorPosition_ == line_.LengthUTF8())
-                line_ += charStr;
+                line_ += newText;
             else
             else
-                line_ = line_.SubstringUTF8(0, cursorPosition_) + charStr + line_.SubstringUTF8(cursorPosition_);
-            ++cursorPosition_;
+                line_ = line_.SubstringUTF8(0, cursorPosition_) + newText + line_.SubstringUTF8(cursorPosition_);
+            cursorPosition_ += newText.LengthUTF8();
         }
         }
         else
         else
         {
         {
@@ -451,10 +448,10 @@ void LineEdit::OnChar(unsigned c, int buttons, int qualifiers)
             unsigned start = text_->GetSelectionStart();
             unsigned start = text_->GetSelectionStart();
             unsigned length = text_->GetSelectionLength();
             unsigned length = text_->GetSelectionLength();
             if (start + length < line_.LengthUTF8())
             if (start + length < line_.LengthUTF8())
-                line_ = line_.SubstringUTF8(0, start) + charStr + line_.SubstringUTF8(start + length);
+                line_ = line_.SubstringUTF8(0, start) + newText + line_.SubstringUTF8(start + length);
             else
             else
-                line_ = line_.SubstringUTF8(0, start) + charStr;
-            cursorPosition_ = start + 1;
+                line_ = line_.SubstringUTF8(0, start) + newText;
+            cursorPosition_ = start + newText.LengthUTF8();
         }
         }
         changed = true;
         changed = true;
     }
     }
@@ -629,7 +626,7 @@ void LineEdit::HandleFocused(StringHash eventType, VariantMap& eventData)
         text_->SetSelection(0);
         text_->SetSelection(0);
     }
     }
     UpdateCursor();
     UpdateCursor();
-    
+
     if (GetSubsystem<UI>()->GetUseScreenKeyboard())
     if (GetSubsystem<UI>()->GetUseScreenKeyboard())
         GetSubsystem<Input>()->SetScreenKeyboardVisible(true);
         GetSubsystem<Input>()->SetScreenKeyboardVisible(true);
 }
 }
@@ -637,7 +634,7 @@ void LineEdit::HandleFocused(StringHash eventType, VariantMap& eventData)
 void LineEdit::HandleDefocused(StringHash eventType, VariantMap& eventData)
 void LineEdit::HandleDefocused(StringHash eventType, VariantMap& eventData)
 {
 {
     text_->ClearSelection();
     text_->ClearSelection();
-    
+
     if (GetSubsystem<UI>()->GetUseScreenKeyboard())
     if (GetSubsystem<UI>()->GetUseScreenKeyboard())
         GetSubsystem<Input>()->SetScreenKeyboardVisible(false);
         GetSubsystem<Input>()->SetScreenKeyboardVisible(false);
 }
 }

+ 4 - 4
Source/Engine/UI/LineEdit.h

@@ -61,8 +61,8 @@ public:
     virtual bool OnDragDropFinish(UIElement* source);
     virtual bool OnDragDropFinish(UIElement* source);
     /// React to a key press.
     /// React to a key press.
     virtual void OnKey(int key, int buttons, int qualifiers);
     virtual void OnKey(int key, int buttons, int qualifiers);
-    /// React to a key press translated to a character.
-    virtual void OnChar(unsigned c, int buttons, int qualifiers);
+    /// React to text input event.
+    virtual void OnTextInput(const String& text, int buttons, int qualifiers);
 
 
     /// Set text.
     /// Set text.
     void SetText(const String& text);
     void SetText(const String& text);
@@ -80,7 +80,7 @@ public:
     void SetTextSelectable(bool enable);
     void SetTextSelectable(bool enable);
     /// Set whether copy-paste operations are allowed, default true.
     /// Set whether copy-paste operations are allowed, default true.
     void SetTextCopyable(bool enable);
     void SetTextCopyable(bool enable);
-    
+
     /// Return text.
     /// Return text.
     const String& GetText() const { return line_; }
     const String& GetText() const { return line_; }
     /// Return cursor position.
     /// Return cursor position.
@@ -101,7 +101,7 @@ public:
     Text* GetTextElement() const { return text_; }
     Text* GetTextElement() const { return text_; }
     /// Return cursor element.
     /// Return cursor element.
     BorderImage* GetCursor() const { return cursor_; }
     BorderImage* GetCursor() const { return cursor_; }
-    
+
 protected:
 protected:
     /// Filter implicit attributes in serialization process.
     /// Filter implicit attributes in serialization process.
     virtual bool FilterImplicitAttributes(XMLElement& dest) const;
     virtual bool FilterImplicitAttributes(XMLElement& dest) const;

+ 4 - 4
Source/Engine/UI/UI.cpp

@@ -120,7 +120,7 @@ UI::UI(Context* context) :
     SubscribeToEvent(E_TOUCHEND, HANDLER(UI, HandleTouchEnd));
     SubscribeToEvent(E_TOUCHEND, HANDLER(UI, HandleTouchEnd));
     SubscribeToEvent(E_TOUCHMOVE, HANDLER(UI, HandleTouchMove));
     SubscribeToEvent(E_TOUCHMOVE, HANDLER(UI, HandleTouchMove));
     SubscribeToEvent(E_KEYDOWN, HANDLER(UI, HandleKeyDown));
     SubscribeToEvent(E_KEYDOWN, HANDLER(UI, HandleKeyDown));
-    SubscribeToEvent(E_CHAR, HANDLER(UI, HandleChar));
+    SubscribeToEvent(E_TEXTINPUT, HANDLER(UI, HandleTextInput));
     SubscribeToEvent(E_DROPFILE, HANDLER(UI, HandleDropFile));
     SubscribeToEvent(E_DROPFILE, HANDLER(UI, HandleDropFile));
 
 
     // Try to initialize right now, but skip if screen mode is not yet set
     // Try to initialize right now, but skip if screen mode is not yet set
@@ -1393,16 +1393,16 @@ void UI::HandleKeyDown(StringHash eventType, VariantMap& eventData)
     }
     }
 }
 }
 
 
-void UI::HandleChar(StringHash eventType, VariantMap& eventData)
+void UI::HandleTextInput(StringHash eventType, VariantMap& eventData)
 {
 {
-    using namespace Char;
+    using namespace TextInput;
 
 
     mouseButtons_ = eventData[P_BUTTONS].GetInt();
     mouseButtons_ = eventData[P_BUTTONS].GetInt();
     qualifiers_ = eventData[P_QUALIFIERS].GetInt();
     qualifiers_ = eventData[P_QUALIFIERS].GetInt();
 
 
     UIElement* element = focusElement_;
     UIElement* element = focusElement_;
     if (element)
     if (element)
-        element->OnChar(eventData[P_CHAR].GetInt(), mouseButtons_, qualifiers_);
+        element->OnTextInput(eventData[P_TEXT].GetString(), mouseButtons_, qualifiers_);
 }
 }
 
 
 void UI::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
 void UI::HandleBeginFrame(StringHash eventType, VariantMap& eventData)

+ 3 - 3
Source/Engine/UI/UI.h

@@ -95,7 +95,7 @@ public:
     void SetUseMutableGlyphs(bool enable);
     void SetUseMutableGlyphs(bool enable);
     /// Set whether to force font autohinting instead of using FreeType's TTF bytecode interpreter.
     /// Set whether to force font autohinting instead of using FreeType's TTF bytecode interpreter.
     void SetForceAutoHint(bool enable);
     void SetForceAutoHint(bool enable);
-    
+
     /// Return root UI element.
     /// Return root UI element.
     UIElement* GetRoot() const { return rootElement_; }
     UIElement* GetRoot() const { return rootElement_; }
     /// Return root modal element.
     /// Return root modal element.
@@ -190,8 +190,8 @@ private:
     void HandleTouchMove(StringHash eventType, VariantMap& eventData);
     void HandleTouchMove(StringHash eventType, VariantMap& eventData);
     /// Handle keypress event.
     /// Handle keypress event.
     void HandleKeyDown(StringHash eventType, VariantMap& eventData);
     void HandleKeyDown(StringHash eventType, VariantMap& eventData);
-    /// Handle character event.
-    void HandleChar(StringHash eventType, VariantMap& eventData);
+    /// Handle text input event.
+    void HandleTextInput(StringHash eventType, VariantMap& eventData);
     /// Handle frame begin event.
     /// Handle frame begin event.
     void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
     void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
     /// Handle logic post-update event.
     /// Handle logic post-update event.

+ 3 - 3
Source/Engine/UI/UIElement.h

@@ -115,7 +115,7 @@ class URHO3D_API UIElement : public Animatable
 {
 {
     OBJECT(UIElement);
     OBJECT(UIElement);
     BASEOBJECT(UIElement);
     BASEOBJECT(UIElement);
-    
+
 public:
 public:
     /// Construct.
     /// Construct.
     UIElement(Context* context);
     UIElement(Context* context);
@@ -167,8 +167,8 @@ public:
     virtual void OnWheel(int delta, int buttons, int qualifiers) {}
     virtual void OnWheel(int delta, int buttons, int qualifiers) {}
     /// React to a key press.
     /// React to a key press.
     virtual void OnKey(int key, int buttons, int qualifiers) {}
     virtual void OnKey(int key, int buttons, int qualifiers) {}
-    /// React to a key press translated to a character.
-    virtual void OnChar(unsigned c, int buttons, int qualifiers) {}
+    /// React to text input event.
+    virtual void OnTextInput(const String& text, int buttons, int qualifiers) {}
     /// React to resize.
     /// React to resize.
     virtual void OnResize() {}
     virtual void OnResize() {}
     /// React to position change.
     /// React to position change.

+ 3 - 3
Source/Engine/UI/UIEvents.h

@@ -188,11 +188,11 @@ EVENT(E_MODALCHANGED, ModalChanged)
     PARAM(P_MODAL, Modal);                  // bool
     PARAM(P_MODAL, Modal);                  // bool
 }
 }
 
 
-/// Char entry into a LineEdit. The char can be modified in the event data.
-EVENT(E_CHARENTRY, CharEntry)
+/// Text entry into a LineEdit. The char can be modified in the event data.
+EVENT(E_TEXTENTRY, CharEntry)
 {
 {
     PARAM(P_ELEMENT, Element);              // UIElement pointer
     PARAM(P_ELEMENT, Element);              // UIElement pointer
-    PARAM(P_CHAR, Char);                    // int
+    PARAM(P_TEXT, Text);                    // String
     PARAM(P_BUTTONS, Buttons);              // int
     PARAM(P_BUTTONS, Buttons);              // int
     PARAM(P_QUALIFIERS, Qualifiers);        // int
     PARAM(P_QUALIFIERS, Qualifiers);        // int
 }
 }

+ 6 - 0
Source/ThirdParty/SDL/src/video/windows/SDL_windowskeyboard.c

@@ -18,6 +18,9 @@
      misrepresented as being the original software.
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
   3. This notice may not be removed or altered from any source distribution.
 */
 */
+
+// Modified by Aster Jian for Urho3D
+
 #include "../../SDL_internal.h"
 #include "../../SDL_internal.h"
 
 
 #if SDL_VIDEO_DRIVER_WINDOWS
 #if SDL_VIDEO_DRIVER_WINDOWS
@@ -835,6 +838,9 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD
         if (*lParam & GCS_RESULTSTR) {
         if (*lParam & GCS_RESULTSTR) {
             IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
             IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
             IME_SendInputEvent(videodata);
             IME_SendInputEvent(videodata);
+            // Urho3D: When text inputed, it is need to clear the text in composition
+            ImmAssociateContext(videodata->ime_hwnd_main, (HIMC)0);
+            ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
         }
         }
         if (*lParam & GCS_COMPSTR) {
         if (*lParam & GCS_COMPSTR) {
             if (!videodata->ime_uiless)
             if (!videodata->ime_uiless)