Skip to main content

ib_ime/
imm.rs

1use bitflags::bitflags;
2use windows_sys::Win32::{
3    Foundation::HWND,
4    UI::Input::{
5        Ime::{
6            ImmGetContext, ImmGetConversionStatus, ImmGetOpenStatus, ImmReleaseContext,
7            ImmSetConversionStatus, ImmSetOpenStatus,
8        },
9        KeyboardAndMouse::GetFocus,
10    },
11};
12
13/// `true` for on, `false` for off.
14pub type ImeState = bool;
15
16/// Get current IME state for a window.
17///
18/// Ref: https://github.com/dotnet/wpf/blob/aa997926b405d7ccea7a28f3b02ef8c1409ed4ca/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputMethod.cs#L538-L542
19pub fn get_window_ime_state(hwnd: HWND) -> ImeState {
20    let himc = unsafe { ImmGetContext(hwnd) };
21    if himc.is_null() {
22        return false;
23    }
24
25    let f_open = unsafe { ImmGetOpenStatus(himc) } != 0;
26    unsafe { ImmReleaseContext(hwnd, himc) };
27
28    f_open
29}
30
31/// Get current IME state for the window with focus.
32pub fn get_ime_state() -> ImeState {
33    let hwnd = unsafe { GetFocus() };
34    get_window_ime_state(hwnd)
35}
36
37/// Set current IME state for a window.
38///
39/// Ref: https://github.com/dotnet/wpf/blob/aa997926b405d7ccea7a28f3b02ef8c1409ed4ca/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputMethod.cs#L571-L586
40pub fn set_window_ime_state(hwnd: HWND, state: ImeState) {
41    let himc = unsafe { ImmGetContext(hwnd) };
42    if himc.is_null() {
43        return;
44    }
45
46    let fopen = unsafe { ImmGetOpenStatus(himc) } != 0;
47
48    // we don't have to call IMM unless the value is changed.
49    if fopen != state {
50        unsafe { ImmSetOpenStatus(himc, state as _) };
51    }
52
53    unsafe { ImmReleaseContext(hwnd, himc) };
54}
55
56/// Set current IME state for the window with focus.
57pub fn set_ime_state(state: ImeState) {
58    let hwnd = unsafe { GetFocus() };
59    set_window_ime_state(hwnd, state);
60}
61
62/// IME conversion mode bitflags.
63///
64/// Ref: [IME Conversion Mode Values - Win32 apps | Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/intl/ime-conversion-mode-values)
65#[derive(Clone, Copy, PartialEq, Eq, Debug)]
66pub struct ImeConversionMode(u32);
67
68bitflags! {
69    impl ImeConversionMode: u32 {
70        /// Alphanumeric input mode. This is the default, defined as 0x0000.
71        const ALPHANUMERIC = 0x0000;
72        /// Set to 1 if character code input mode; 0 if not.
73        const CHARCODE = 0x0001;
74        /// Set to 1 if EUDC conversion mode; 0 if not.
75        const EUDC = 0x0002;
76        /// Windows Me/98, Windows 2000, Windows XP: Set to 1 if fixed conversion mode; 0 if not.
77        const FIXED = 0x0004;
78        /// Set to 1 if full shape mode; 0 if half shape mode.
79        const FULLSHAPE = 0x0008;
80        /// Set to 1 if HANJA convert mode; 0 if not.
81        const HANJACONVERT = 0x0010;
82        /// Set to 1 if KATAKANA mode; 0 if HIRAGANA mode.
83        const KATAKANA = 0x0020;
84        /// Set to 1 if NATIVE mode; 0 if ALPHANUMERIC mode.
85        const NATIVE = 0x0040;
86        /// Set to 1 to prevent processing of conversions by IME; 0 if not.
87        const NOCONVERSION = 0x0080;
88        /// Set to 1 if ROMAN input mode; 0 if not.
89        const ROMAN = 0x0100;
90        /// Set to 1 if Soft Keyboard mode; 0 if not.
91        const SOFTKBD = 0x0200;
92        /// Set to 1 if SYMBOL conversion mode; 0 if not.
93        const SYMBOL = 0x0400;
94    }
95}
96
97/// Get current IME conversion mode for a window.
98///
99/// Ref: https://github.com/dotnet/wpf/blob/aa997926b405d7ccea7a28f3b02ef8c1409ed4ca/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputMethod.cs#L773-L775
100pub fn get_window_ime_conversion_mode(hwnd: HWND) -> ImeConversionMode {
101    let himc = unsafe { ImmGetContext(hwnd) };
102    if himc.is_null() {
103        return ImeConversionMode::empty();
104    }
105
106    let mut convmode = 0u32;
107    let mut sentence = 0u32;
108    unsafe { ImmGetConversionStatus(himc, &mut convmode, &mut sentence) };
109    unsafe { ImmReleaseContext(hwnd, himc) };
110
111    ImeConversionMode::from_bits_retain(convmode)
112}
113
114/// Get current IME conversion mode for the window with focus.
115pub fn get_ime_conversion_mode() -> ImeConversionMode {
116    let hwnd = unsafe { GetFocus() };
117    get_window_ime_conversion_mode(hwnd)
118}
119
120/// Set current IME conversion mode for a window.
121///
122/// Ref: https://github.com/dotnet/wpf/blob/aa997926b405d7ccea7a28f3b02ef8c1409ed4ca/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/InputMethod.cs#L911-L977
123pub fn set_window_ime_conversion_mode(hwnd: HWND, convmode: ImeConversionMode) {
124    let himc = unsafe { ImmGetContext(hwnd) };
125    if himc.is_null() {
126        return;
127    }
128
129    unsafe { ImmSetConversionStatus(himc, convmode.bits(), 0) };
130    unsafe { ImmReleaseContext(hwnd, himc) };
131}
132
133/// Set current IME conversion mode for the window with focus.
134pub fn set_ime_conversion_mode(convmode: ImeConversionMode) {
135    let hwnd = unsafe { GetFocus() };
136    set_window_ime_conversion_mode(hwnd, convmode);
137}