ililim / dual-key-remap

Remap any key to any other two keys on Windows 🔥. Remap CapsLock to both Ctrl and Escape! (It's like xcape for windows!)
GNU General Public License v2.0
512 stars 36 forks source link

`with_other` key don't get released when using Japanese IME #32

Closed escape0707 closed 3 years ago

escape0707 commented 3 years ago

Description

When a Japanese IME is activated, if you press remap_key and other key, the remap_key will be holding down after the other key is released. And the only way to "release" it is to press remap_key or with_other key again (sometimes one of them won't work). Of course, you can terminate dual-key-remap to release it, too. The holding down remap_key is carried even if I switch to another program.

Run dual-key-remap in privileged mode won't help, either.

How To Reproduce

  1. Open an application, e.g. use this browser currently viewing this page.
  2. Press remap_key h to display history panel.
  3. Type s.

What To Expect

s entered into history panel's search box.

What happened

The browser acts like Ctrl s is pressed and starts the webpage saving procedure.

The holding down Ctrl key is carried even if I switch to another program, and can be fixed by pressing Ctrl or remap_key again.

config.txt

Both of the configs below will be able to reproduce this problem.

remap_key=CAPSLOCK
when_alone=ESCAPE
with_other=CTRL

remap_key=ESCAPE
when_alone=CAPSLOCK
with_other=ESCAPE

or:

remap_key=CAPSLOCK
when_alone=ESCAPE
with_other=CTRL
ililim commented 3 years ago

Does this always happen when opening the vscode integrated terminal? I wonder if perhaps the process that receives the input there is somehow running with elevated (admin) privileges so that dual-key-remap never sees the other key stroke.

Also this config: remap_key=ESCAPE when_alone=CAPSLOCK with_other=ESCAPE

is that meant to trigger escape when it's held with another key but capslock when it's pressed alone?

escape0707 commented 3 years ago

Thank you for your quick reply!

Does this always happen when opening the vscode integrated terminal? I wonder if perhaps the process that receives the input there is somehow running with elevated (admin) privileges so that dual-key-remap never sees the other key stroke.

It happens everywhere in the VSCode process. I can do a Ctrl h then p and the p doesn't go in to the search box but Ctrl p "Go to file..." is invoked.

Also this config: remap_key=ESCAPE when_alone=CAPSLOCK with_other=ESCAPE

is that meant to trigger escape when it's held with another key but capslock when it's pressed alone?

Yes, but it's basically only used to gain the ability to toggle capslock.

Edit:

I removed the second part and restarted VSCode. Now the problem seems not happening at the moment. But it do came up multiple times recently. I think I will keep a closer eye on the condition to trigger this.

ililim commented 3 years ago

If you remove that second capslock config do you still get that problem? Perhaps the two configurations are somehow in conflict with each other.

escape0707 commented 3 years ago

I tried removing it, and it works. But then I add it back and restart, it's still working. Seems that something else is the condition.

When this problem appears, terminating and restarting dual-key-remap won't help. It seems that only restart VSCode helped.

I'll keep updating this issue when it appears again.

escape0707 commented 3 years ago

Okay, I got it.

It's because I'm using Japanese Input Method at some time. And both Microsoft IME and Google IME will cause this problem when selected, even if you use their English mode. This doesn't happen when English or Chinese Input Method is chosen. And it persists to happen when I'm using minimal config.txt.

remap_key=CAPSLOCK
when_alone=ESCAPE
with_other=CTRL

If you have some spare time, I suggest you download Google Japanese IME or enable Microsoft Japanese IME in settings app and see if the same problem could be reproduced on some other machine. I don't have another one to try out now...

BTW, which application is activated does not matter. I reproduced it on firefox and explorer.exe when using JP IME, too.


I've edited the issue's title and the description, too.

escape0707 commented 3 years ago

The worst part is that running dual-key-remap in privileged mode won't help.

ililim commented 3 years ago

Ah nice job finding the cause! Yeah I did not test this, curious to learn what the cause would be. I'll try to reproduce this sometime next week.

archiif commented 3 years ago

Any progress with this bug?

ililim commented 3 years ago

Sorry no! Haven't had a chance to test this yet.

ililim commented 3 years ago

If this is still an issue, could confirm if it occurs with the latest version? https://github.com/ililim/dual-key-remap/discussions/36

escape0707 commented 3 years ago

If this is still an issue, could confirm if it occurs with the latest version? https://github.com/ililim/dual-key-remap/discussions/36

Just confirmed, it's still happening.

ililim commented 3 years ago

OK so I tried to reproduce this error but was unsuccessful in doing so. Could you guide me in a minimal set of steps I can take to trigger this issue?

Also, could you run dual-key-remap with the setting debug=1 enabled and send me the output when you try to run a rebind of CAPSLOCK to ESC?

Steps taken:

escape0707 commented 3 years ago

Alright, so, the steps I took are exactly what you've described. I'll add debug output aside with my specific input here:

  1. Use en-US input and US keyboard layout as reference.

  2. Switch to Microsoft Edge which is what I'm editing this post with.

  3. Run dual-key-remap version 0.6 with only debug=1 prepended to config.txt:

    dual-key-remap.exe version: 0.4, author: ililim
  4. Press and hold Caps Lock, press and release S, release Caps Lock, press and release Caps Lock:

    (input) CAPSLOCK DOWN [scan:0x3a virt:0x14]
    (event) event_remapped_key_down
    (input) KEY_S DOWN [scan:0x1f virt:0x53]
    (send) CTRL DOWN
    (input) KEY_S UP   [scan:0x1f virt:0x53]
    (input) CAPSLOCK UP   [scan:0x3a virt:0x14]
    (event) event_remapped_key_up
    (send) CTRL UP
    (input) CAPSLOCK DOWN [scan:0x3a virt:0x14]
    (event) event_remapped_key_down
    (input) CAPSLOCK UP   [scan:0x3a virt:0x14]
    (event) event_remapped_key_up
    (send) ESCAPE DOWN
    (send) ESCAPE UP
    (input) KEY UP   [scan:0x00 virt:0x00]

    This describes how I pressed and what get send to system correctly.

  5. Switch to Microsoft Japanese IME, restart dual-key-remap.

  6. Press and hold Caps Lock, press and release S, release Caps Lock. The program gives one of the three below possible outputs (I tried several times and restarted the program in between each time):

    (input) KEY DOWN [scan:0x3a virt:0xf2]
    (input) KEY_S DOWN [scan:0x1f virt:0x53]
    (input) KEY_S UP   [scan:0x1f virt:0x53]

    or

    (input) KEY UP   [scan:0x3a virt:0xf0]
    (input) KEY DOWN [scan:0x3a virt:0xf2]
    (input) KEY_S DOWN [scan:0x1f virt:0x53]
    (input) KEY_S UP   [scan:0x1f virt:0x53]

    or

    (input) CAPSLOCK DOWN [scan:0x3a virt:0x14]
    (event) event_remapped_key_down
    (input) KEY_S DOWN [scan:0x1f virt:0x53]
    (send) CTRL DOWN
    (input) KEY_S UP   [scan:0x1f virt:0x53]
  7. Press and release Caps Lock:

    (input) KEY UP   [scan:0x3a virt:0xf0]
    (input) KEY DOWN [scan:0x3a virt:0xf2]
  8. Press the mouse on the Cancel button on the popup panel:

    (input) KEY UP   [scan:0x00 virt:0x00]

The program DID work for very few times but it's inconsistent and I don't know what's the cause.

ililim commented 3 years ago

Awesome this is exactly what I I needed. So what I'm seeing is that the Virtual Key Code for Caps switches every time you press it. My theory then is that Japanese IME mode changes how Caps works, and it instead sends 3 types of codes to switch between Latin uppercase and Japanese. So Japanese IME remaps Caps itself to three keys effectively.

The reason it sometimes works is because you're cycling between the three Caps "modes" so to speak. So the first is regular Caps, then you get the two "special" modes and if you press the button enough eventually you get the regular Caps again. However it looks like Windows never sends the "key-up" symbol in this mode so as far as dual-key-remap knows, you're holding caps down this entire time (which it has translated to holding Ctrl the entire time).

It looks like the keyboard scan-code is somewhat consistent... so perhaps I should use that to read the input? Scan-codes can change by device though and won't work 100%. Maybe what I should do is to lookup a code by virtual-code, and if that fails then look up by scan-code?

I'll have to give this a think. But at least we know what's wrong.

P.S. Seems that I forgot to update the version number in debug mode, will fix that next version :).

ililim commented 3 years ago

Looks like Windows documents the key behavior in this document: https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/keyboard-japan-ime

escape0707 commented 3 years ago

I think you get it. 🎉 One supporting fact I didn't think of mentioning in the first place is if you start dual-key-remap and happens to get the correct case, it will stay in the correct way thereafter. I forgot whether it holds true if you "switch to another IME or a window with another IME selected" then switch back.

Although I wonder whether this is reproducible on you side now or you are using a different keyboard layout so it can't happen? 🧐

ililim commented 3 years ago

OK I managed to reproduce the problem. The issue you're seeing is because when Windows Japanese IME is enabled, Windows will swallow capslock if you hold ctrl!

So with no keys remapped (just debug mode on) and Japanese IME on:

  1. Hold down capslock
  2. Hold down ctrl
  3. Raise capslock
  4. Raise ctrl

Outputs:

(input) CAPSLOCK DOWN [scan:0x3a virt:0x14]
(input) CTRL DOWN [scan:0x1d virt:0xa2]
(input) CTRL UP   [scan:0x1d virt:0xa2]

As you see, step 3 is ignored and no CAPSLOCK UP is sent! So as far as the system is concerned the user is still holding Capslock. This is not a problem in most cases as not many keys listen for Capslock being held down or not, but dual-key-remap does!

I can't think of a solution through dual-key-remap itself, but you could do the following using some additional tools:

Rebind Capslock -> Escape through the registry. You can use the tool https://github.com/randyrants/sharpkeys to do so through a UI. You will have to sign out for the rebind to take effect.

From now on Windows will treat your Capslock is an Escape key. Then in your remap use the following:

remap_key=ESCAPE
when_alone=ESCAPE
with_other=CTRL

Now you get the remapping as originally intended compatible with the Japanese IME.

escape0707 commented 3 years ago

Thanks for your investigation!

It seems that swapping the key for esc and capslock seems more straightforward / intuitive and could even minimize what dual-key-remap have to tinkle with.

I'll give a try and report back.

escape0707 commented 3 years ago

Oh, I forgot to report back here. The result is satisfying, and no problem is occurring with the suggested setup.

escape0707 commented 1 year ago

I wrote a simple script to automate the setup process for this use case, useful for anyone who wants to use vim with CapsLock under Windows: https://github.com/escape0707/scripts/blob/master/Setup-dual-key-remap.ps1

As it modifies registry to add startup entry for this program and modify Windows keymap to the result I get by using SharpKeys, the script needs to be run with administrator priviledge. Please read the script or use ChatGPT to make sure what it does, any modify it as you wish before execute.

Content preview:

$programVersionTag = "v0.7"
$githubReleaseUrl = "https://github.com/ililim/dual-key-remap/releases/download/$programVersionTag/dual-key-remap-$programVersionTag.zip"
$zipPath = [System.IO.Path]::Combine($env:TEMP, "dual-key-remap-$programVersionTag.zip")
Invoke-WebRequest -Uri $githubReleaseUrl -OutFile $zipPath

$extractDir = [System.IO.Path]::Combine($env:USERPROFILE, "my-programs", "dual-key-remap")
Expand-Archive -Path $zipPath -DestinationPath $extractDir
Remove-Item $zipPath

$programDir = [System.IO.Path]::Combine($extractDir, "dual-key-remap-$programVersionTag")
$programPath = [System.IO.Path]::Combine($programDir, "dual-key-remap.exe")
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" `
    -Name "dual-key-remap" `
    -Value $programPath

$configPath = [System.IO.Path]::Combine($programDir, "config.txt")
(Get-Content $configPath) -replace "CAPSLOCK", "ESCAPE" | Set-Content $configPath

$scanCodeMap = [byte[]]@(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00, `
    0x00,0x01,0x00,0x3a,0x00,0x3a,0x00,0x01,0x00,0x00,0x00,0x00,0x00)
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Keyboard Layout" `
    -Name "Scancode Map" `
    -Value $scanCodeMap