diff --git a/Dalamud/Interface/Internal/DalamudIme.cs b/Dalamud/Interface/Internal/DalamudIme.cs
index f44c885ce..f8d7fb690 100644
--- a/Dalamud/Interface/Internal/DalamudIme.cs
+++ b/Dalamud/Interface/Internal/DalamudIme.cs
@@ -5,8 +5,10 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
+using System.Text.Unicode;
using Dalamud.Game.Text;
+using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Utility;
using Dalamud.Logging.Internal;
@@ -26,6 +28,26 @@ internal sealed unsafe class DalamudIme : IDisposable, IServiceType
{
private static readonly ModuleLog Log = new("IME");
+ private static readonly UnicodeRange[] HanRange =
+ {
+ UnicodeRanges.CjkRadicalsSupplement,
+ UnicodeRanges.CjkSymbolsandPunctuation,
+ UnicodeRanges.CjkUnifiedIdeographsExtensionA,
+ UnicodeRanges.CjkUnifiedIdeographs,
+ UnicodeRanges.CjkCompatibilityIdeographs,
+ UnicodeRanges.CjkCompatibilityForms,
+ // No more; Extension B~ are outside BMP range
+ };
+
+ private static readonly UnicodeRange[] HangulRange =
+ {
+ UnicodeRanges.HangulJamo,
+ UnicodeRanges.HangulSyllables,
+ UnicodeRanges.HangulCompatibilityJamo,
+ UnicodeRanges.HangulJamoExtendedA,
+ UnicodeRanges.HangulJamoExtendedB,
+ };
+
private readonly ImGuiSetPlatformImeDataDelegate setPlatformImeDataDelegate;
[ServiceManager.ServiceConstructor]
@@ -38,6 +60,16 @@ internal sealed unsafe class DalamudIme : IDisposable, IServiceType
private delegate void ImGuiSetPlatformImeDataDelegate(ImGuiViewportPtr viewport, ImGuiPlatformImeDataPtr data);
+ ///
+ /// Gets a value indicating whether Han(Chinese) input has been detected.
+ ///
+ public bool EncounteredHan { get; private set; }
+
+ ///
+ /// Gets a value indicating whether Hangul(Korean) input has been detected.
+ ///
+ public bool EncounteredHangul { get; private set; }
+
///
/// Gets a value indicating whether to display the cursor in input text. This also deals with blinking.
///
@@ -116,6 +148,39 @@ internal sealed unsafe class DalamudIme : IDisposable, IServiceType
GC.SuppressFinalize(this);
}
+ ///
+ /// Looks for the characters inside and enables fonts accordingly.
+ ///
+ /// The string.
+ public void ReflectCharacterEncounters(string str)
+ {
+ foreach (var chr in str)
+ {
+ if (HanRange.Any(x => x.FirstCodePoint <= chr && chr < x.FirstCodePoint + x.Length))
+ {
+ if (Service.Get()
+ .GetFdtReader(GameFontFamilyAndSize.Axis12)
+ ?.FindGlyph(chr) is null)
+ {
+ if (!this.EncounteredHan)
+ {
+ this.EncounteredHan = true;
+ Service.Get().RebuildFonts();
+ }
+ }
+ }
+
+ if (HangulRange.Any(x => x.FirstCodePoint <= chr && chr < x.FirstCodePoint + x.Length))
+ {
+ if (!this.EncounteredHangul)
+ {
+ this.EncounteredHangul = true;
+ Service.Get().RebuildFonts();
+ }
+ }
+ }
+ }
+
///
/// Processes window messages.
///
@@ -308,6 +373,8 @@ internal sealed unsafe class DalamudIme : IDisposable, IServiceType
? ImmGetCompositionString(hImc, GCS.GCS_RESULTSTR)
: ImmGetCompositionString(hImc, GCS.GCS_COMPSTR);
+ this.ReflectCharacterEncounters(newString);
+
if (s != e)
textState.DeleteChars(s, e - s);
textState.InsertChars(s, newString);
@@ -402,6 +469,7 @@ internal sealed unsafe class DalamudIme : IDisposable, IServiceType
(int)Math.Min(candlist.dwCount - candlist.dwPageStart, candlist.dwPageSize)))
{
this.ImmCand.Add(new((char*)(pStorage + candlist.dwOffset[i])));
+ this.ReflectCharacterEncounters(this.ImmCand[^1]);
}
}
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index d7ab5ba9d..49dfdb248 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
+using System.Text.Unicode;
using System.Threading;
using Dalamud.Configuration.Internal;
@@ -786,10 +787,22 @@ internal class InterfaceManager : IDisposable, IServiceType
var fontPathKr = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "NotoSansCJKkr-Regular.otf");
if (!File.Exists(fontPathKr))
fontPathKr = Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "NotoSansKR-Regular.otf");
+ if (!File.Exists(fontPathKr))
+ fontPathKr = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts", "malgun.ttf");
if (!File.Exists(fontPathKr))
fontPathKr = null;
Log.Verbose("[FONT] fontPathKr = {0}", fontPathKr);
+ var fontPathChs = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts", "msyh.ttc");
+ if (!File.Exists(fontPathChs))
+ fontPathChs = null;
+ Log.Verbose("[FONT] fontPathChs = {0}", fontPathChs);
+
+ var fontPathCht = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts", "msjh.ttc");
+ if (!File.Exists(fontPathCht))
+ fontPathCht = null;
+ Log.Verbose("[FONT] fontPathChs = {0}", fontPathCht);
+
// Default font
Log.Verbose("[FONT] SetupFonts - Default font");
var fontInfo = new TargetFontModification(
@@ -817,7 +830,8 @@ internal class InterfaceManager : IDisposable, IServiceType
this.loadedFontInfo[DefaultFont] = fontInfo;
}
- if (fontPathKr != null && Service.Get().EffectiveLanguage == "ko")
+ if (fontPathKr != null
+ && (Service.Get().EffectiveLanguage == "ko" || this.dalamudIme.EncounteredHangul))
{
fontConfig.MergeMode = true;
fontConfig.GlyphRanges = ioFonts.GetGlyphRangesKorean();
@@ -826,6 +840,46 @@ internal class InterfaceManager : IDisposable, IServiceType
fontConfig.MergeMode = false;
}
+ if (fontPathCht != null && Service.Get().EffectiveLanguage == "tw")
+ {
+ fontConfig.MergeMode = true;
+ var rangeHandle = GCHandle.Alloc(new ushort[]
+ {
+ (ushort)UnicodeRanges.CjkUnifiedIdeographs.FirstCodePoint,
+ (ushort)(UnicodeRanges.CjkUnifiedIdeographs.FirstCodePoint +
+ (UnicodeRanges.CjkUnifiedIdeographs.Length - 1)),
+ (ushort)UnicodeRanges.CjkUnifiedIdeographsExtensionA.FirstCodePoint,
+ (ushort)(UnicodeRanges.CjkUnifiedIdeographsExtensionA.FirstCodePoint +
+ (UnicodeRanges.CjkUnifiedIdeographsExtensionA.Length - 1)),
+ 0,
+ }, GCHandleType.Pinned);
+ garbageList.Add(rangeHandle);
+ fontConfig.GlyphRanges = rangeHandle.AddrOfPinnedObject();
+ fontConfig.PixelSnapH = true;
+ ioFonts.AddFontFromFileTTF(fontPathCht, fontConfig.SizePixels, fontConfig);
+ fontConfig.MergeMode = false;
+ }
+ else if (fontPathChs != null && (Service.Get().EffectiveLanguage == "zh"
+ || this.dalamudIme.EncounteredHan))
+ {
+ fontConfig.MergeMode = true;
+ var rangeHandle = GCHandle.Alloc(new ushort[]
+ {
+ (ushort)UnicodeRanges.CjkUnifiedIdeographs.FirstCodePoint,
+ (ushort)(UnicodeRanges.CjkUnifiedIdeographs.FirstCodePoint +
+ (UnicodeRanges.CjkUnifiedIdeographs.Length - 1)),
+ (ushort)UnicodeRanges.CjkUnifiedIdeographsExtensionA.FirstCodePoint,
+ (ushort)(UnicodeRanges.CjkUnifiedIdeographsExtensionA.FirstCodePoint +
+ (UnicodeRanges.CjkUnifiedIdeographsExtensionA.Length - 1)),
+ 0,
+ }, GCHandleType.Pinned);
+ garbageList.Add(rangeHandle);
+ fontConfig.GlyphRanges = rangeHandle.AddrOfPinnedObject();
+ fontConfig.PixelSnapH = true;
+ ioFonts.AddFontFromFileTTF(fontPathChs, fontConfig.SizePixels, fontConfig);
+ fontConfig.MergeMode = false;
+ }
+
// FontAwesome icon font
Log.Verbose("[FONT] SetupFonts - FontAwesome icon font");
{