moses-palmer / pynput

Sends virtual input commands
GNU Lesser General Public License v3.0
1.73k stars 243 forks source link

Need to sync keyboard lock keys #594

Open jzhvymetal opened 3 months ago

jzhvymetal commented 3 months ago

I'm doing a some development that the CapLock, NumLock, and ScrollLock need to be in sync. Request to add the following to get status of each:

import platform

def get_lock_state():
    system = platform.system()
    if system == "Windows":
        import ctypes
        return {
            'LED_CAPS_LOCK': ctypes.windll.user32.GetKeyState(0x14) & 0xffff != 0,
            'LED_SCROLL_LOCK': ctypes.windll.user32.GetKeyState(0x91) & 0xffff != 0,
            'LED_NUM_LOCK': ctypes.windll.user32.GetKeyState(0x90) & 0xffff != 0
        }
    elif system == "Linux":
        import subprocess
        xset_output = subprocess.check_output(["xset", "-q"]).decode("utf-8")
        return {
            'LED_CAPS_LOCK': "Caps Lock: on" in xset_output,
            'LED_SCROLL_LOCK': "Scroll Lock: on" in xset_output,
            'LED_NUM_LOCK': "Num Lock: on" in xset_output
        }
    elif system == "Darwin":
        from Quartz import CGEventCreateKeyboardEvent, kCGEventFlagMaskAlphaShift, kCGEventFlagMaskNumericPad
        def get_mac_lock_state(virtual_keycode):
            event = CGEventCreateKeyboardEvent(None, virtual_keycode, True)
            return bool(event.getFlags() & kCGEventFlagMaskAlphaShift)
        return {
            'LED_CAPS_LOCK': get_mac_lock_state(0x39),
            'LED_SCROLL_LOCK': get_mac_lock_state(0x6C),
            'LED_NUM_LOCK': get_mac_lock_state(0x47) or get_mac_lock_state(kCGEventFlagMaskNumericPad)
        }
    else:
        raise NotImplementedError("Unsupported platform")

Here is an example how I sync the CapLock status

class KEYS:
    KEY_CAPS_LOCK = keyboard.Key.caps_lock
    KEY_SCROLL_LOCK = keyboard.Key.scroll_lock
    KEY_NUM_LOCK = keyboard.Key.num_lock

class KeyModifiersMask:
    SHIFT = 0x0001
    CTRL = 0x0002
    ALT = 0x0004
    META = 0x0008
    GUI = 0x0010
    altGr = 0x0020
    level5Lock = 0x0040
    reserved = 0x0080
    LED_CAPS_LOCK = 0x1000
    LED_NUM_LOCK = 0x2000
    LED_SCROLL_LOCK = 0x4000

        lock_states = get_lock_state()
        #SYNC CAPS_LOCK
        if(KeyId!=KEYS.KEY_CAPS_LOCK and  ((KeyModifiersMask.LED_CAPS_LOCK & KeyModifiers)>0) != lock_states['LED_CAPS_LOCK']):
            keyboard_act.tap(KEYS.KEY_CAPS_LOCK)
            keyboard_act.tap(KEYS.KEY_CAPS_LOCK)