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);
             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;

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

@@ -87,10 +87,10 @@ EVENT(E_KEYUP, KeyUp)
     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_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
 {
     OBJECT(FreeTypeLibrary);
-    
+
 public:
     /// Construct.
     FreeTypeLibrary(Context* context) :
@@ -60,15 +60,15 @@ public:
         if (error)
             LOGERROR("Could not initialize FreeType library");
     }
-    
+
     /// Destruct.
     virtual ~FreeTypeLibrary()
     {
         FT_Done_FreeType(library_);
     }
-    
+
     FT_Library GetLibrary() const { return library_; }
-    
+
 private:
     /// FreeType library.
     FT_Library library_;
@@ -100,7 +100,7 @@ FontFace::~FontFace()
         FT_Done_Face((FT_Face)face_);
         face_ = 0;
     }
-    
+
     if (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();
         font_->SetMemoryUse(font_->GetMemoryUse() - totalTextureSize);
     }
-    
+
     for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
         delete *i;
     mutableGlyphs_.Clear();
@@ -132,7 +132,7 @@ const FontGlyph* FontFace::GetGlyph(unsigned c)
             mutableGlyphs_.PushFront(mutableGlyph);
             glyph.iterator_ = mutableGlyphs_.Begin();
         }
-        
+
         glyph.used_ = true;
         return &glyph;
     }
@@ -144,10 +144,10 @@ short FontFace::GetKerning(unsigned c, unsigned d) const
 {
     if (!hasKerning_)
         return 0;
-    
+
     if (c == '\n' || d == '\n')
         return 0;
-    
+
     unsigned leftIndex = 0;
     unsigned rightIndex = 0;
     HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
@@ -160,7 +160,7 @@ short FontFace::GetKerning(unsigned c, unsigned d) const
         rightIndex = rightIt->second_;
     else
         return 0;
-    
+
     HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
     if (kerningIt != glyphs_[leftIndex].kerning_.End())
         return kerningIt->second_;
@@ -181,9 +181,9 @@ bool FontFace::IsDataLost() const
 bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
 {
     assert(font_ && face_ && textures_.Empty());
-    
+
     allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
-    
+
     for (unsigned i = 0; i < glyphs_.Size(); ++i)
     {
         if (glyphs_[i].width_ && glyphs_[i].height_)
@@ -211,19 +211,19 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
             glyphs_[i].page_ = 0;
         }
     }
-    
+
     // Create image for rendering all the glyphs, clear to black
     SharedPtr<Image> image(new Image(font_->GetContext()));
     image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
     unsigned char* imageData = image->GetData();
     memset(imageData, 0, image->GetWidth() * image->GetHeight());
-    
+
     int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
 
     // Render glyphs
     for (unsigned i = 0; i < glyphs_.Size(); ++i)
         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
     SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
     if (!texture)
@@ -232,10 +232,10 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
             glyphs_[i].page_ = M_MAX_UNSIGNED;
         return false;
     }
-    
+
     textures_.Push(texture);
     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());
     return true;
 }
@@ -243,9 +243,9 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
 void FontFace::RenderGlyph(unsigned index)
 {
     assert(font_ && face_);
-    
+
     FontGlyph& glyph = glyphs_[index];
-    
+
     // If glyph is empty, just set the current page
     if (!glyph.width_ || !glyph.height_)
     {
@@ -254,7 +254,7 @@ void FontFace::RenderGlyph(unsigned index)
         glyph.page_ = textures_.Size() - 1;
         return;
     }
-    
+
     int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
 
     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
             allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
         }
-        
+
         glyph.x_ = x;
         glyph.y_ = y;
         glyph.page_ = textures_.Size() - 1;
-        
+
         if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
         {
             bitmapSize_ = glyph.width_ * glyph.height_;
             bitmap_ = new unsigned char[bitmapSize_];
         }
-        
+
         RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
         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.iterator_ = it;
         mutableGlyph->glyphIndex_ = index;
-        
+
         if (!bitmap_)
         {
             bitmapSize_ = cellWidth_ * cellHeight_;
             bitmap_ = new unsigned char[bitmapSize_];
         }
-        
+
         // Clear the cell bitmap before rendering to ensure padding
         memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
         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];
     if (!glyph.width_ || !glyph.height_)
         return;
-    
+
     FT_Face face = (FT_Face)face_;
     FT_GlyphSlot slot = face->glyph;
     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]);
     memset(emptyBitmap.Get(), 0, width * height);
     texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
-    
+
     textures_.Push(texture);
     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);
 }
 
 void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
 {
     assert(mutableGlyphs_.Empty());
-    
+
     SetupNextTexture(textureWidth, textureHeight);
-    
+
     cellWidth_ = maxWidth + 1;
     cellHeight_ = maxHeight + 1;
-    
+
     // Allocate as many mutable glyphs as possible
     int 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;
         mutableGlyphs_.Push(glyph);
     }
-    
+
     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)
 {
     PROFILE(LoadFont);
-    
+
     // In headless mode, do not actually load, just return success
     Graphics* graphics = GetSubsystem<Graphics>();
     if (!graphics)
         return true;
-    
+
     fontType_ = FONT_NONE;
     faces_.Clear();
-    
+
     fontDataSize_ = source.GetSize();
     if (fontDataSize_)
     {
@@ -440,9 +440,9 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
     FontFace* fontFace = GetFace(pointSize);
     if (!fontFace)
         return false;
-    
+
     PROFILE(FontSaveXML);
-    
+
     SharedPtr<FontFace> packedFontFace;
     if (usedGlyphs)
     {
@@ -453,7 +453,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
         else
             return false;
     }
-    
+
     SharedPtr<XMLFile> xml(new XMLFile(context_));
     XMLElement rootElem = xml->CreateRoot("font");
 
@@ -462,7 +462,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
     String fileName = GetFileName(GetName());
     childElem.SetAttribute("face", fileName);
     childElem.SetAttribute("size", String(pointSize));
-    
+
     // Common
     childElem = rootElem.CreateChild("common");
     childElem.SetInt("lineHeight", fontFace->rowHeight_);
@@ -487,11 +487,11 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
         pageElem.SetInt("id", i);
         String texFileName = fileName + "_" + String(i) + ".png";
         pageElem.SetAttribute("file", texFileName);
-        
+
         // Save the font face texture to image file
         SaveFaceTexture(fontFace->textures_[i], pathName + texFileName);
     }
-    
+
     // Chars and kernings
     XMLElement charsElem = rootElem.CreateChild("chars");
     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("xadvance", glyph.advanceX_);
         charElem.SetInt("page", glyph.page_);
-        
+
         // Kerning
         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
                 if (j->second_ == 0)
                     continue;
-                
+
                 XMLElement kerningElem = kerningsElem.CreateChild("kerning");
                 kerningElem.SetInt("first", i->first_);
                 kerningElem.SetInt("second", j->first_);
@@ -531,7 +531,7 @@ bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
             }
         }
     }
-    
+
     return xml->Save(dest);
 }
 
@@ -541,13 +541,13 @@ FontFace* Font::GetFace(int pointSize)
     Graphics* graphics = GetSubsystem<Graphics>();
     if (!graphics)
         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
     if (fontType_ == FONT_BITMAP)
         pointSize = 0;
     else
         pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
-    
+
     HashMap<int, SharedPtr<FontFace> >::Iterator i = faces_.Find(pointSize);
     if (i != faces_.End())
     {
@@ -559,9 +559,9 @@ FontFace* Font::GetFace(int pointSize)
             faces_.Erase(i);
         }
     }
-    
+
     PROFILE(GetFontFace);
-    
+
     switch (fontType_)
     {
     case FONT_FREETYPE:
@@ -569,7 +569,7 @@ FontFace* Font::GetFace(int pointSize)
 
     case FONT_BITMAP:
         return GetFaceBitmap(pointSize);
-    
+
     default:
         return 0;
     }
@@ -610,26 +610,26 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_));
     // Ensure the FreeType library is kept alive as long as TTF font resources exist
     freeType_ = freeType;
-    
+
     UI* ui = GetSubsystem<UI>();
     int maxTextureSize = ui->GetMaxFontTextureSize();
-    
+
     FT_Face face;
     FT_Error error;
     FT_Library library = freeType->GetLibrary();
-    
+
     if (pointSize <= 0)
     {
         LOGERROR("Zero or negative point size");
         return 0;
     }
-    
+
     if (!fontDataSize_)
     {
         LOGERROR("Could not create font face from zero size data");
         return 0;
     }
-    
+
     error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
     if (error)
     {
@@ -643,13 +643,13 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         LOGERROR("Could not set font point size " + String(pointSize));
         return 0;
     }
-    
+
     SharedPtr<FontFace> newFace(new FontFace(this));
     newFace->face_ = face;
-    
+
     FT_GlyphSlot slot = face->glyph;
     unsigned numGlyphs = 0;
-    
+
     // Build glyph mapping
     FT_UInt glyphIndex;
     FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
@@ -659,16 +659,16 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         newFace->glyphMapping_[charCode] = glyphIndex;
         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
     }
-    
+
     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
     int maxWidth = 0;
     int maxHeight = 0;
     int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
     int ascender = face->size->metrics.ascender >> 6;
     int descender = face->size->metrics.descender >> 6;
-    
+
     // 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);
     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->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
     newFace->pointSize_ = pointSize;
     newFace->rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
-    
+
     newFace->glyphs_.Reserve(numGlyphs);
-    
+
     for (unsigned i = 0; i < numGlyphs; ++i)
     {
         FontGlyph newGlyph;
-        
+
         error = FT_Load_Glyph(face, i, loadMode);
         if (!error)
         {
@@ -698,7 +698,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
             newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
             newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
             newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
-            
+
             maxWidth = Max(maxWidth, newGlyph.width_);
             maxHeight = Max(maxHeight, newGlyph.height_);
         }
@@ -710,10 +710,10 @@ FontFace* Font::GetFaceFreeType(int pointSize)
             newGlyph.offsetY_ = 0;
             newGlyph.advanceX_ = 0;
         }
-        
+
         newFace->glyphs_.Push(newGlyph);
     }
-    
+
     // Store kerning if face has kerning information
     if (FT_HAS_KERNING(face))
     {
@@ -756,9 +756,9 @@ FontFace* Font::GetFaceFreeType(int pointSize)
                 if (version == 0 && coverage == 1)
                 {
                     unsigned numKerningPairs = deserializer.ReadUShort();
-                    // Skip searchRange, entrySelector & rangeShift
+                    // Skip searchRange, entrySelector and rangeShift
                     deserializer.Seek(deserializer.GetPosition() + 3 * sizeof(unsigned short));
-                    
+
                     for (unsigned j = 0; j < numKerningPairs; ++j)
                     {
                         unsigned leftIndex = deserializer.ReadUShort();
@@ -780,7 +780,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         else
             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
     // glyphs are only created as necessary
     if (newFace->RenderAllGlyphs(maxTextureSize, maxTextureSize))
@@ -795,7 +795,7 @@ FontFace* Font::GetFaceFreeType(int pointSize)
         else
             newFace->SetupNextTexture(maxTextureSize, maxTextureSize);
     }
-    
+
     faces_[pointSize] = newFace;
     return newFace;
 }
@@ -809,7 +809,7 @@ FontFace* Font::GetFaceBitmap(int pointSize)
         LOGERROR("Could not load XML file");
         return 0;
     }
-    
+
     XMLElement root = xmlReader->GetRoot("font");
     if (root.IsNull())
     {
@@ -823,13 +823,13 @@ FontFace* Font::GetFaceBitmap(int pointSize)
         LOGERROR("Could not find Pages element");
         return 0;
     }
-    
+
     SharedPtr<FontFace> newFace(new FontFace(this));
-    
+
     XMLElement infoElem = root.GetChild("info");
     if (!infoElem.IsNull())
         newFace->pointSize_ = infoElem.GetInt("size");
-    
+
     XMLElement commonElem = root.GetChild("common");
     newFace->rowHeight_ = commonElem.GetInt("lineHeight");
     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
         String textureFile = fontPath + pageElem.GetAttribute("file");
-        
+
         // Load texture manually to allow controlling the alpha channel mode
         SharedPtr<File> fontFile = resourceCache->GetFile(textureFile);
         SharedPtr<Image> fontImage(new Image(context_));
@@ -864,15 +864,15 @@ FontFace* Font::GetFaceBitmap(int pointSize)
             return 0;
         newFace->textures_.Push(texture);
         totalTextureSize += fontImage->GetWidth() * fontImage->GetHeight() * fontImage->GetComponents();
-        
+
         pageElem = pageElem.GetNext("page");
     }
-    
+
     XMLElement charsElem = root.GetChild("chars");
     int count = charsElem.GetInt("count");
     newFace->glyphs_.Reserve(count);
     unsigned index = 0;
-    
+
     XMLElement charElem = charsElem.GetChild("char");
     while (!charElem.IsNull())
     {
@@ -888,10 +888,10 @@ FontFace* Font::GetFaceBitmap(int pointSize)
         glyph.page_ = charElem.GetInt("page");
         newFace->glyphs_.Push(glyph);
         newFace->glyphMapping_[id] = index++;
-        
+
         charElem = charElem.GetNext("char");
     }
-    
+
     XMLElement kerningsElem = root.GetChild("kernings");
     if (kerningsElem.IsNull())
         newFace->hasKerning_ = false;
@@ -906,15 +906,15 @@ FontFace* Font::GetFaceBitmap(int pointSize)
             {
                 int second = kerningElem.GetInt("second");
                 int amount = kerningElem.GetInt("amount");
-                
+
                 FontGlyph& glyph = newFace->glyphs_[i->second_];
                 glyph.kerning_[second] = amount;
             }
-            
+
             kerningElem = kerningElem.GetNext("kerning");
         }
     }
-    
+
     LOGDEBUGF("Bitmap font face %s has %d glyphs", GetFileName(GetName()).CString(), count);
 
     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
     SharedPtr<FontFace> packedFontFace(new FontFace((Font*)0));
-    
+
     int maxTextureSize = GetSubsystem<UI>()->GetMaxFontTextureSize();
-    
+
     // Clone properties
     packedFontFace->pointSize_ = fontFace->pointSize_;
     packedFontFace->rowHeight_ = fontFace->rowHeight_;
     packedFontFace->hasKerning_ = fontFace->hasKerning_;
-    
+
     // 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());
-    
+
     // Save the existing textures as image resources
     Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
     for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
         images[i] = SaveFaceTexture(fontFace->textures_[i]);
-    
+
     // Reallocate used glyphs to new texture(s)
     unsigned page = 0;
     unsigned index = 0;
@@ -982,18 +982,18 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
                 else
                     break;
             }
-            
+
             packedFontFace->glyphs_.Push(glyph);
             packedFontFace->glyphMapping_[i->first_] = index++;
         }
-        
+
         int texWidth = allocator.GetWidth();
         int texHeight = allocator.GetHeight();
-        
+
         // Create the image for rendering the fonts
         SharedPtr<Image> image(new Image(context_));
         image->SetSize(texWidth, texHeight, components);
-        
+
         // First clear the whole image
         unsigned char* imageData = image->GetData();
         for (int y = 0; y < texHeight; ++y)
@@ -1001,22 +1001,22 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
             unsigned char* dest = imageData + components * texWidth * y;
             memset(dest, 0, components * texWidth);
         }
-        
+
         // Then render the glyphs into new image
         for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
         {
             FontGlyph glyph = fontFace->glyphs_[j->second_];
             if (!glyph.used_)
                 continue;
-            
+
             if (!glyph.width_ || !glyph.height_)
             {
                 ++startIndex;
                 continue;
             }
-            
+
             FontGlyph packedGlyph = packedFontFace->glyphs_[startIndex++];
-            
+
             Image* image = images[glyph.page_];
             unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
             unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
@@ -1027,7 +1027,7 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
                 destination += components * texWidth;
             }
         }
-        
+
         // Finally load image into the texture
         SharedPtr<Texture2D> texture = LoadFaceTexture(image);
         if (!texture)
@@ -1038,7 +1038,7 @@ SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
         startIter = i;
         assert(index == startIndex);
     }
-    
+
     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 (GetSubsystem<UI>()->GetUseScreenKeyboard() && HasFocus())
                 SetFocus(false);
-            
+
             using namespace TextFinished;
 
             VariantMap& eventData = GetEventDataMap();
@@ -410,40 +410,37 @@ void LineEdit::OnKey(int key, int buttons, int qualifiers)
         UpdateCursor();
 }
 
-void LineEdit::OnChar(unsigned c, int buttons, int qualifiers)
+void LineEdit::OnTextInput(const String& text, int buttons, int qualifiers)
 {
     if (!editable_)
         return;
-    
+
     bool changed = false;
-    
+
     // If only CTRL is held down, do not edit
     if ((qualifiers & (QUAL_CTRL | QUAL_ALT)) == QUAL_CTRL)
         return;
-        
+
     // Send char as an event to allow changing it
     using namespace CharEntry;
-    
+
     VariantMap& eventData = GetEventDataMap();
     eventData[P_ELEMENT] = this;
-    eventData[P_CHAR] = c;
+    eventData[P_TEXT] = text;
     eventData[P_BUTTONS] = buttons;
     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 (cursorPosition_ == line_.LengthUTF8())
-                line_ += charStr;
+                line_ += newText;
             else
-                line_ = line_.SubstringUTF8(0, cursorPosition_) + charStr + line_.SubstringUTF8(cursorPosition_);
-            ++cursorPosition_;
+                line_ = line_.SubstringUTF8(0, cursorPosition_) + newText + line_.SubstringUTF8(cursorPosition_);
+            cursorPosition_ += newText.LengthUTF8();
         }
         else
         {
@@ -451,10 +448,10 @@ void LineEdit::OnChar(unsigned c, int buttons, int qualifiers)
             unsigned start = text_->GetSelectionStart();
             unsigned length = text_->GetSelectionLength();
             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
-                line_ = line_.SubstringUTF8(0, start) + charStr;
-            cursorPosition_ = start + 1;
+                line_ = line_.SubstringUTF8(0, start) + newText;
+            cursorPosition_ = start + newText.LengthUTF8();
         }
         changed = true;
     }
@@ -629,7 +626,7 @@ void LineEdit::HandleFocused(StringHash eventType, VariantMap& eventData)
         text_->SetSelection(0);
     }
     UpdateCursor();
-    
+
     if (GetSubsystem<UI>()->GetUseScreenKeyboard())
         GetSubsystem<Input>()->SetScreenKeyboardVisible(true);
 }
@@ -637,7 +634,7 @@ void LineEdit::HandleFocused(StringHash eventType, VariantMap& eventData)
 void LineEdit::HandleDefocused(StringHash eventType, VariantMap& eventData)
 {
     text_->ClearSelection();
-    
+
     if (GetSubsystem<UI>()->GetUseScreenKeyboard())
         GetSubsystem<Input>()->SetScreenKeyboardVisible(false);
 }

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

@@ -61,8 +61,8 @@ public:
     virtual bool OnDragDropFinish(UIElement* source);
     /// React to a key press.
     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.
     void SetText(const String& text);
@@ -80,7 +80,7 @@ public:
     void SetTextSelectable(bool enable);
     /// Set whether copy-paste operations are allowed, default true.
     void SetTextCopyable(bool enable);
-    
+
     /// Return text.
     const String& GetText() const { return line_; }
     /// Return cursor position.
@@ -101,7 +101,7 @@ public:
     Text* GetTextElement() const { return text_; }
     /// Return cursor element.
     BorderImage* GetCursor() const { return cursor_; }
-    
+
 protected:
     /// Filter implicit attributes in serialization process.
     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_TOUCHMOVE, HANDLER(UI, HandleTouchMove));
     SubscribeToEvent(E_KEYDOWN, HANDLER(UI, HandleKeyDown));
-    SubscribeToEvent(E_CHAR, HANDLER(UI, HandleChar));
+    SubscribeToEvent(E_TEXTINPUT, HANDLER(UI, HandleTextInput));
     SubscribeToEvent(E_DROPFILE, HANDLER(UI, HandleDropFile));
 
     // 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();
     qualifiers_ = eventData[P_QUALIFIERS].GetInt();
 
     UIElement* element = focusElement_;
     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)

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

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

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

@@ -115,7 +115,7 @@ class URHO3D_API UIElement : public Animatable
 {
     OBJECT(UIElement);
     BASEOBJECT(UIElement);
-    
+
 public:
     /// Construct.
     UIElement(Context* context);
@@ -167,8 +167,8 @@ public:
     virtual void OnWheel(int delta, int buttons, int qualifiers) {}
     /// React to a key press.
     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.
     virtual void OnResize() {}
     /// React to position change.

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

@@ -188,11 +188,11 @@ EVENT(E_MODALCHANGED, ModalChanged)
     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_CHAR, Char);                    // int
+    PARAM(P_TEXT, Text);                    // String
     PARAM(P_BUTTONS, Buttons);              // 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.
   3. This notice may not be removed or altered from any source distribution.
 */
+
+// Modified by Aster Jian for Urho3D
+
 #include "../../SDL_internal.h"
 
 #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) {
             IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
             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 (!videodata->ime_uiless)