使用Wpf实现了调整输入法的候选框坐标,但是首次启动时无法唤出候选框

HoWe Yu 86 信誉分
2025-06-18T09:47:50.25+00:00

项目很简单,就一个主窗口。xaml代码:

<Window x:Class="输入法测试.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:输入法测试"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Background="LightBlue">
    </Grid>
</Window>

C#代码:

using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;

namespace 输入法测试
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }

        #region Win32

        [DllImport("imm32.dll")]
        public static extern IntPtr ImmGetContext(IntPtr hWnd);

        [DllImport("imm32.dll", CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool ImmSetCompositionFont(IntPtr hIMC, ref LOGFONT font);

        [DllImport("imm32.dll")]
        public static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref COMPOSITIONFORM lpCompForm);

        [DllImport("imm32.dll")]
        public static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left, top, right, bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct COMPOSITIONFORM
        {
            public int dwStyle;
            public POINT ptCurrentPos;
            public RECT rcArea;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        internal struct LOGFONT
        {
            public int lfHeight, lfWidth, lfEscapement, lfOrientation, lfWeight;

            public byte lfItalic,
                lfUnderline,
                lfStrikeOut,
                lfCharSet,
                lfOutPrecision,
                lfClipPrecision,
                lfQuality,
                lfPitchAndFamily;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string lfFaceName;
        }

        public const int CFS_POINT = 0x0002;

        public const int WM_IME_COMPOSITION = 0x010F;

        #endregion

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            InputMethod.SetIsInputMethodSuspended(this, true);
            // 获取窗口句柄源
            HwndSource hwndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
            // 监听窗口消息
            hwndSource.AddHook(WndProc);
        }

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case WM_IME_COMPOSITION:
                    // 字号,用于调整候选框垂直偏移
                    LOGFONT font = new LOGFONT();
                    font.lfHeight = 16;
                    // 坐标,调整候选框相对于客户区左上角的偏移
                    COMPOSITIONFORM point = new COMPOSITIONFORM
                    {
                        dwStyle = CFS_POINT,
                        ptCurrentPos = new POINT { x = 0, y = 0 }
                    };
                    // 获取输入法上下文
                    IntPtr context = ImmGetContext(hwnd);
                    // 设置字体
                    ImmSetCompositionFont(context, ref font);
                    // 设置候选框位置
                    ImmSetCompositionWindow(context, ref point);
                    // 释放输入法上下文
                    ImmReleaseContext(hwnd, context);
                    handled = true;
                    break;
            }
            return IntPtr.Zero;
        }
    }
}

编译并运行后,必需切换至其他应用(或点击桌面)再切回来,才可以在中文输入状态下唤出候选框:

000

C#
C#
一种面向对象的类型安全的编程语言,它起源于 C 语言系列,包括对面向组件的编程的支持。
225 个问题
0 个注释 无注释
{count} 票

你的答案

问题作者可以将答案标记为“接受的答案”,这有助于用户了解已解决作者问题的答案。