Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative to im-select.exe on Windows #20

Open
kls1991 opened this issue Dec 13, 2023 · 3 comments
Open

Alternative to im-select.exe on Windows #20

kls1991 opened this issue Dec 13, 2023 · 3 comments

Comments

@kls1991
Copy link

kls1991 commented Dec 13, 2023

I find that we can use luajit ffi to call win32api to control keyboard layout and ime state on Windows, without the burden of a extra binary and another language pack.
I'm not a pro coder yet, so I'm not confident enough to make a good pull request.
Below code is my personal config which doesn't support switching between keyboard-layouts, I think it's doable by similar method.
If a pull request is needed, I can try to read im-select.nvim's source code and make a configurable pull request.
Feel free to use below code with ❤️

-- Reference:
-- https://www.cnblogs.com/yf-zhao/p/16018481.html
-- https://zhuanlan.zhihu.com/p/425951648

local ffi = require "ffi"

ffi.cdef [[
    typedef unsigned int UINT, HWND, WPARAM;
    typedef unsigned long LPARAM, LRESULT;
    LRESULT SendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
    HWND ImmGetDefaultIMEWnd(HWND unnamedParam1);
    HWND GetForegroundWindow();
]]

local user32 = ffi.load "user32.dll"
local imm32 = ffi.load "imm32.dll"

local ime_hwnd
local ime_group = vim.api.nvim_create_augroup("ime_toggle", { clear = true })

-- Get ime control's hwnd after InsertEnter or CmdlineEnter
-- to ensure getting correct foregroundwindow
vim.api.nvim_create_autocmd({ "InsertEnter", "CmdlineEnter" }, {
    group = ime_group,
    once = true,
    desc = "Get ime control hwnd attached to nvim window",
    callback = function()
        ime_hwnd = imm32.ImmGetDefaultIMEWnd(user32.GetForegroundWindow())
    end,
})

local WM_IME_CONTROL = 0x283
local IMC_GETCONVERSIONMODE = 0x001
local IMC_SETCONVERSIONMODE = 0x002 -- It's said this value differs on different ime, I'm not sure
local ime_mode_ch = 1025
local ime_mode_en = 0

local function set_ime_mode(mode)
    return user32.SendMessageA(ime_hwnd, WM_IME_CONTROL, IMC_SETCONVERSIONMODE, mode)
end

local function get_ime_mode()
    return user32.SendMessageA(ime_hwnd, WM_IME_CONTROL, IMC_GETCONVERSIONMODE, 0)
end

vim.api.nvim_create_autocmd({ "InsertLeave", "CmdlineLeave" }, {
    group = ime_group,
    desc = "Toggle ime to English mode on normal mode",
    callback = function()
        if ime_mode_ch == get_ime_mode() then
            set_ime_mode(ime_mode_en)
        end
    end,
})
@keaising
Copy link
Owner

Good idea!

I will try it ASAP. If it works as expect, I will merge it.

@keaising
Copy link
Owner

keaising commented Mar 4, 2024

I don't abonden this issue, but in the last few months my PC has been far away from me, so I can't do the migration.

I will continue this work in May 2024.

@keaising
Copy link
Owner

Sorry for delay, but my computer is still on the way _(:з」∠)_

I will test this solution as soon as possible when I receive my computer.

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

No branches or pull requests

2 participants