mooz / xkeysnail

Yet another keyboard remapping tool for X environment
890 stars 112 forks source link

Feature: Ability to use Numlock status to limit numpad key remapping #132

Closed RedBearAK closed 1 year ago

RedBearAK commented 3 years ago

I needed to remap the base numeric keypad navigation/cursor key functions, but found that xkeysnail doesn't have the ability to use the on/off status of Numlock to avoid also remapping the number functions. So remapping the base numeric keypad keys without any modifiers makes the keypad useless as a number pad.

If Numlock is "on" and the keypad is producing numbers, I don't want to remap the keypad keys in that state. But if Numlock is "off" I want to remap the keypad-specific PgUp/PgDn/Home/End and arrow key codes to their non-keypad counterparts. This is currently not possible, since xkeysnail doesn't appear to register the state of Numlock.

There needs to be a way to incorporate Numlock status into the key mapping function.

A new modifier keyword could be added, like "NP_On"/"NP_Off" (Numpad on, numpad off).

Or, alternately, the existing numeric keypad key definitions could have separate "Numlock off" counterparts, using the same key code but different names, that force xkeysnail to check that Numlock status is "off" before remapping the key.

These keypad keys are already defined in key.py:

    KPASTERISK = 55

    KP7 = 71
    KP8 = 72
    KP9 = 73
    KPMINUS = 74
    KP4 = 75
    KP5 = 76
    KP6 = 77
    KPPLUS = 78
    KP1 = 79
    KP2 = 80
    KP3 = 81
    KP0 = 82
    KPDOT = 83

    KPJPCOMMA = 95
    KPENTER = 96

    KPSLASH = 98

    KPEQUAL = 117
    KPPLUSMINUS = 118

    KPCOMMA = 121

    KPLEFTPAREN = 179
    KPRIGHTPAREN = 180

Something like the lines below could be added to key.py, in addition to the lines above. Same order, same keys, but named with their "Numlock off" functions, with "_NLOFF" added to symbol keys (and 5 key, which has no common alternate function) just to distinguish them from the corresponding numeric Numlock "on" function of the same key. In this way, with an appropriate function added to xkeysnail, all of the numeric keypad keys could be remapped when Numlock is off without interfering with the ability to use the numpad as an actual numeric keypad when Numlock is on.

    KPASTERISK_NLOFF = 55

    KP7_HOME = 71
    KP8_UP = 72
    KP9_PAGE_UP = 73
    KPMINUS_NLOFF = 74
    KP4_LEFT = 75
    KP5_NLOFF = 76 
    KP6_RIGHT = 77
    KPPLUS_NLOFF = 78
    KP1_END = 79
    KP2_DOWN = 80
    KP3_PAGE_DOWN = 81
    KP0_INSERT = 82
    KPDOT_NLOFF = 83

    KPJPCOMMA_NLOFF = 95
    KPENTER_NLOFF = 96

    KPSLASH_NLOFF = 98

    KPEQUAL_NLOFF = 117
    KPPLUSMINUS_NLOFF = 118

    KPCOMMA_NLOFF = 121

    KPLEFTPAREN_NLOFF = 179
    KPRIGHTPAREN_NLOFF = 180

Alternate naming possibility, a prefix of "NLO_" for "Numlock off", and no alternate function names added:

    NLO_KPASTERISK = 55

    NLO_KP7 = 71
    NLO_KP8 = 72
    NLO_KP9 = 73
    NLO_KPMINUS = 74
    NLO_KP4 = 75
    NLO_KP5 = 76 
    NLO_KP6 = 77
    NLO_KPPLUS = 78
    NLO_KP1 = 79
    NLO_KP2 = 80
    NLO_KP3 = 81
    NLO_KP0 = 82
    NLO_KPDOT = 83

    NLO_KPJPCOMMA = 95
    NLO_KPENTER = 96

    NLO_KPSLASH = 98

    NLO_KPEQUAL = 117
    NLO_KPPLUSMINUS = 118

    NLO_KPCOMMA = 121

    NLO_KPLEFTPAREN = 179
    NLO_KPRIGHTPAREN = 180
joshgoebel commented 2 years ago

@RedBearAK What does hitting numlock do in evtest... does it generate keyboard events?

RedBearAK commented 2 years ago

@joshgoebel

Pretty sure when I was testing with xbindkeys -mk the NumLock key generated its own events. I don't think it's like the Fn key where it usually doesn't generate an event the OS is aware of.

I'm on a Windows machine at the moment and haven't used evtest before, so I'll have to get back to you on that part.

The OS has the ability to show an OSD with the NumLock status as you turn it on and off. So there would have to be an event of some kind.

joshgoebel commented 2 years ago

You should really test at lowest-level with evtest. (That's most useful)

https://stackoverflow.com/questions/13129804/python-how-to-get-current-keylock-status

Seems highly relevant... so it's easy-ish to query the device stats via evdev... but we can have multiple devices (numlock might be on on some while off on others - or not even present - my keyboard has no numlock)... so if we were going to expose that to the config (where you could use it in a conditional) the question would be how?

joshgoebel commented 2 years ago

If you wanted to just play with that's possible you could add a function to input.py to export the currently advice devices - then you could import input into your config and have access to those devices to use for conditional logic...

RedBearAK commented 2 years ago

@joshgoebel

but we can have multiple devices

You referring to having multiple keyboards (or numpads or other input devices) attached at the same time? I didn't really think about that.

If you hold the Shift key or toggle CapsLock on one keyboard, does that not change the output from other keyboards? I think I've tried that in the past and it was basically a system-wide state change that was not isolated to one input device.

With an independent device like a dedicated Numpad, the user certainly might want that state change to be isolated to that device. But that sounds like it would make things more complicated internally.

joshgoebel commented 2 years ago

I think I've tried that in the past and it was basically a system-wide state change that was not isolated to one input device.

I would not expect that behavior at all... and I'd guess it could very well be OS dependent also. Each keyboard is an independent device, it's entirely possible they could have their own independent input states (they have individual LEDs, etc)... I would certainly expect caps lock to be per device as well.

I can't help here since I don't have any keyboards with num lock, much less two. I have a number pad, but no number lock.

RedBearAK commented 2 years ago

@joshgoebel

This appears to be the relevant bit, after toggling NumLock, um... off and then on, I believe. There's the "LED" event the second time (even though there is no physical LED for any of the keyboard lock functions on my Acer laptop, which is really irritating at times).

Looks like the actual NumLock key status goes 1->0 every time you press it, but when the "state" changes to NumLock "on", there's the LED "on" event. So there's no LED "off" event, maybe? Just have to check the value of LED_NUML and try to keep track of it, I guess?

Won't be able to get back to this for a while.

Event: time 1654464686.427722, -------------- SYN_REPORT ------------
Event: time 1654464689.032521, type 4 (EV_MSC), code 4 (MSC_SCAN), value 45
Event: time 1654464689.032521, type 1 (EV_KEY), code 69 (KEY_NUMLOCK), value 1
Event: time 1654464689.032521, -------------- SYN_REPORT ------------
Event: time 1654464689.145025, type 4 (EV_MSC), code 4 (MSC_SCAN), value 45
Event: time 1654464689.145025, type 1 (EV_KEY), code 69 (KEY_NUMLOCK), value 0
Event: time 1654464689.145025, -------------- SYN_REPORT ------------
Event: time 1654464692.330456, type 4 (EV_MSC), code 4 (MSC_SCAN), value 45
Event: time 1654464692.330456, type 1 (EV_KEY), code 69 (KEY_NUMLOCK), value 1
Event: time 1654464692.330456, -------------- SYN_REPORT ------------
Event: time 1654464692.330993, type 17 (EV_LED), code 0 (LED_NUML), value 1
Event: time 1654464692.330993, -------------- SYN_REPORT ------------
Event: time 1654464692.424642, type 4 (EV_MSC), code 4 (MSC_SCAN), value 45
Event: time 1654464692.424642, type 1 (EV_KEY), code 69 (KEY_NUMLOCK), value 0
joshgoebel commented 2 years ago

Just have to check the value of LED_NUML and try to keep track of it, I guess?

Why should it be hard to keep track of? I assume it would be fast to check (state maintained in RAM in the device table or something)... I'd just query it each time you needed it.

RedBearAK commented 2 years ago

@joshgoebel

Why should it be hard to keep track of? I assume it would be fast to check (state maintained in RAM in the device table or something)... I'd just query it each time you needed it.

By "each time you needed it" do you mean every time the user presses a Numpad key? I'm never sure in programming exactly what kind of thing is "no big deal" to perform thousands of times and what kind of thing should be done more efficiently, like just watching for a state change event.

joshgoebel commented 2 years ago

do you mean every time the user presses a Numpad key?

Yes.

I'm never sure in programming exactly what kind of thing is "no big deal" to perform thousands of times and what kind of thing should be done more efficiently, like just watching for a state change event.

Well the secret often is there is no secret - you need to benchmark. I'm using years of experience to guess here, but I could be always be mistaken. I'd certainly start with testing that much simpler approach and see if it's fast before trying to track the state manually.

RedBearAK commented 1 year ago

This feature has been implemented in a fork of xkeysnail called keyszer. It now has both capslock_on and numlock_on as available context properties.

https://github.com/joshgoebel/keyszer/pull/76