Skip to content

feat(platform/macos): support CJK ime input#20

Merged
cloudwu merged 1 commit intocloudwu:masterfrom
yuchanns:feat/support-cjk-ime-macos
Oct 6, 2025
Merged

feat(platform/macos): support CJK ime input#20
cloudwu merged 1 commit intocloudwu:masterfrom
yuchanns:feat/support-cjk-ime-macos

Conversation

@yuchanns
Copy link
Contributor

@yuchanns yuchanns commented Oct 6, 2025

目前 soluna 并不支持在 macOS 下输入 CJK,输入中文只能拿到拼音结果。根本原因在于 sokol_app 不支持,也不太可能支持,参见 floooh/sokol#595

因此这个 PR 通过 hook 实现了在 macOS 上的 cjk 输入,如果有输入法的文字则构造 SAPP_EVENTTYPE_CHAR 事件,否则 fallback 为 sokol_app 的 builtin 处理。同时也添加了一个 lua api set_ime_rect 用来设置输入法候选框的位置,目前只支持 macOS, Linux 和 Windows 的我还没时间看。在 deepfuture 的效果如下图:

image

PS: 这个 PR 合并后,我还需要在 deepfuture 提交改动才能实现输入法位置的校准,Windows 的预计没那么快,同样暂时只支持 macOS。

@cloudwu cloudwu merged commit d345b0b into cloudwu:master Oct 6, 2025
5 checks passed
@cloudwu
Copy link
Owner

cloudwu commented Oct 6, 2025

前两天我尝试过在 windows 下调用 imm32 的 api 设置输入框位置,但失败了。没有找原因

我猜测应该是 https://learn.microsoft.com/en-us/windows/win32/api/imm/nf-imm-immsetcompositionwindow 这个 API ,但不知道为啥在我的系统上没有效果。

@yuchanns yuchanns deleted the feat/support-cjk-ime-macos branch October 7, 2025 01:50
@jiangbo
Copy link

jiangbo commented Dec 19, 2025

@cloudwu 大佬,打扰一下。
我也使用 sokol 遇到了中文输入的问题,不清楚我们遇到的是不是一样的问题。floooh/sokol#1398
现在注释掉问题中提到的代码,就可以了。zig 代码,和 C 语言差不多:

const sokol = @import("sokol");
const win32 = std.os.windows;

const COMPOSITIONFORM = extern struct {
    dwStyle: u32,
    ptCurrentPos: win32.POINT,
    rcArea: win32.RECT,
};
const HWND = std.os.windows.HWND;
pub const HIMC = *opaque {};
pub extern "Imm32" fn ImmGetContext(HWND) callconv(.winapi) ?HIMC;
pub extern "Imm32" fn ImmSetCompositionWindow(HIMC, *COMPOSITIONFORM) callconv(.winapi) win32.BOOL;
pub extern "Imm32" fn ImmReleaseContext(HWND, HIMC) callconv(.winapi) win32.BOOL;

pub fn frame(_: f32) void {
    // scene.update(delta);
    // scene.draw();

    const sokolHwnd = sokol.app.win32GetHwnd().?;
    const hwnd: HWND = @ptrCast(@constCast(sokolHwnd));
    const himc = ImmGetContext(hwnd).?;
    std.log.info("hwnd:{}, himc: {}", .{ hwnd, himc });

    var cf = std.mem.zeroes(COMPOSITIONFORM);
    cf.dwStyle = 0x0002; // CFS_POINT
    cf.ptCurrentPos.x = 200; // 你的文本光标位置(像素)
    cf.ptCurrentPos.y = 200;

    var hr = ImmSetCompositionWindow(himc, &cf);
    std.debug.assert(hr == win32.TRUE);

    // var cand = std.mem.zeroes(CANDIDATEFORM);
    // cand.dwIndex = 0;
    // cand.dwStyle = 0x0040; // CFS_CANDIDATEPOS;
    // cand.ptCurrentPos.x = 100;
    // cand.ptCurrentPos.y = 100 + 20;

    // hr = ImmSetCandidateWindow(himc, &cand);
    // std.debug.assert(hr == win32.TRUE);
    hr = ImmReleaseContext(hwnd, himc);
    std.debug.assert(hr == win32.TRUE);
}
QQ20251219-102923

不清楚 sokol 那个要怎么修改,我对 win32 了解不多。

@cloudwu
Copy link
Owner

cloudwu commented Dec 19, 2025

@yuchanns 前段写过应该比较有经验。我没有研究,但我认为仅仅只是调用 ImmSetCompositionWindow 这些 API 是不够的。肯定要在 windows 消息循环里处理一些消息。(WM_IME_STARTCOMPOSITION WM_IME_COMPOSITION 等)

See #22

@jiangbo
Copy link

jiangbo commented Dec 19, 2025

谢谢,有空我去学习一下。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants