Fixed files: - SkiaImageButton.cs: Added SVG support with multi-path search - SkiaNavigationPage.cs: Added LinuxApplication.IsGtkMode check - SkiaRefreshView.cs: Added ICommand support (Command, CommandParameter) - SkiaTemplatedView.cs: Added missing using statements Extracted embedded types to separate files (matching decompiled pattern): - From SkiaMenuBar.cs: MenuBarItem, MenuItem, SkiaMenuFlyout, MenuItemClickedEventArgs - From SkiaNavigationPage.cs: NavigationEventArgs - From SkiaTabbedPage.cs: TabItem - From SkiaVisualStateManager.cs: SkiaVisualStateGroupList, SkiaVisualStateGroup, SkiaVisualState, SkiaVisualStateSetter - From SkiaSwipeView.cs: SwipeItem, SwipeStartedEventArgs, SwipeEndedEventArgs - From SkiaFlyoutPage.cs: FlyoutLayoutBehavior (already separate) - From SkiaIndicatorView.cs: IndicatorShape (already separate) - From SkiaBorder.cs: SkiaFrame - From SkiaCarouselView.cs: PositionChangedEventArgs - From SkiaCollectionView.cs: SkiaSelectionMode, ItemsLayoutOrientation - From SkiaContentPresenter.cs: LayoutAlignment Verified matching decompiled: - SkiaContextMenu.cs, SkiaFlexLayout.cs, SkiaGraphicsView.cs Build: 0 errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
183 lines
5.2 KiB
C#
183 lines
5.2 KiB
C#
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Microsoft.Maui.Platform.Linux.Services;
|
|
|
|
/// <summary>
|
|
/// Factory for creating the appropriate Input Method service.
|
|
/// Automatically selects IBus or XIM based on availability.
|
|
/// </summary>
|
|
public static class InputMethodServiceFactory
|
|
{
|
|
private static IInputMethodService? _instance;
|
|
private static readonly object _lock = new();
|
|
|
|
/// <summary>
|
|
/// Gets the singleton input method service instance.
|
|
/// </summary>
|
|
public static IInputMethodService Instance
|
|
{
|
|
get
|
|
{
|
|
if (_instance == null)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_instance ??= CreateService();
|
|
}
|
|
}
|
|
return _instance;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the most appropriate input method service for the current environment.
|
|
/// </summary>
|
|
public static IInputMethodService CreateService()
|
|
{
|
|
// Check environment variable for user preference
|
|
var imePreference = Environment.GetEnvironmentVariable("MAUI_INPUT_METHOD");
|
|
|
|
if (!string.IsNullOrEmpty(imePreference))
|
|
{
|
|
return imePreference.ToLowerInvariant() switch
|
|
{
|
|
"ibus" => CreateIBusService(),
|
|
"fcitx" or "fcitx5" => CreateFcitx5Service(),
|
|
"xim" => CreateXIMService(),
|
|
"none" => new NullInputMethodService(),
|
|
_ => CreateAutoService()
|
|
};
|
|
}
|
|
|
|
return CreateAutoService();
|
|
}
|
|
|
|
private static IInputMethodService CreateAutoService()
|
|
{
|
|
// Check GTK_IM_MODULE for hint
|
|
var imModule = Environment.GetEnvironmentVariable("GTK_IM_MODULE")?.ToLowerInvariant();
|
|
|
|
// Try Fcitx5 first if it's the configured IM
|
|
if (imModule?.Contains("fcitx") == true && Fcitx5InputMethodService.IsAvailable())
|
|
{
|
|
Console.WriteLine("InputMethodServiceFactory: Using Fcitx5");
|
|
return CreateFcitx5Service();
|
|
}
|
|
|
|
// Try IBus (most common on modern Linux)
|
|
if (IsIBusAvailable())
|
|
{
|
|
Console.WriteLine("InputMethodServiceFactory: Using IBus");
|
|
return CreateIBusService();
|
|
}
|
|
|
|
// Try Fcitx5 as fallback
|
|
if (Fcitx5InputMethodService.IsAvailable())
|
|
{
|
|
Console.WriteLine("InputMethodServiceFactory: Using Fcitx5");
|
|
return CreateFcitx5Service();
|
|
}
|
|
|
|
// Fall back to XIM
|
|
if (IsXIMAvailable())
|
|
{
|
|
Console.WriteLine("InputMethodServiceFactory: Using XIM");
|
|
return CreateXIMService();
|
|
}
|
|
|
|
// No IME available
|
|
Console.WriteLine("InputMethodServiceFactory: No IME available, using null service");
|
|
return new NullInputMethodService();
|
|
}
|
|
|
|
private static IInputMethodService CreateIBusService()
|
|
{
|
|
try
|
|
{
|
|
return new IBusInputMethodService();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"InputMethodServiceFactory: Failed to create IBus service - {ex.Message}");
|
|
return new NullInputMethodService();
|
|
}
|
|
}
|
|
|
|
private static IInputMethodService CreateFcitx5Service()
|
|
{
|
|
try
|
|
{
|
|
return new Fcitx5InputMethodService();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"InputMethodServiceFactory: Failed to create Fcitx5 service - {ex.Message}");
|
|
return new NullInputMethodService();
|
|
}
|
|
}
|
|
|
|
private static IInputMethodService CreateXIMService()
|
|
{
|
|
try
|
|
{
|
|
return new X11InputMethodService();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"InputMethodServiceFactory: Failed to create XIM service - {ex.Message}");
|
|
return new NullInputMethodService();
|
|
}
|
|
}
|
|
|
|
private static bool IsIBusAvailable()
|
|
{
|
|
// Check if IBus daemon is running
|
|
var ibusAddress = Environment.GetEnvironmentVariable("IBUS_ADDRESS");
|
|
if (!string.IsNullOrEmpty(ibusAddress))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Try to load IBus library
|
|
try
|
|
{
|
|
var handle = NativeLibrary.Load("libibus-1.0.so.5");
|
|
NativeLibrary.Free(handle);
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool IsXIMAvailable()
|
|
{
|
|
// Check XMODIFIERS environment variable
|
|
var xmodifiers = Environment.GetEnvironmentVariable("XMODIFIERS");
|
|
if (!string.IsNullOrEmpty(xmodifiers) && xmodifiers.Contains("@im="))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Check if running under X11
|
|
var display = Environment.GetEnvironmentVariable("DISPLAY");
|
|
return !string.IsNullOrEmpty(display);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the singleton instance (useful for testing).
|
|
/// </summary>
|
|
public static void Reset()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_instance?.Shutdown();
|
|
_instance = null;
|
|
}
|
|
}
|
|
}
|