talonvoice / beta

Issue tracker for the private Talon Beta
10 stars 0 forks source link

Windows media keys #67

Closed mrob95 closed 4 years ago

mrob95 commented 4 years ago

Meant to make an issue but totally forgot about this. Inserting media keys on Windows currently just inserts keys from the lowercase alphabet. For reference my talon file looks like this:

volume up <user.n20>: key("volup:{n20}")
volume down <user.n20>: key("voldown:{n20}")
music next <user.n20>: key("next:{n20}")
music previous <user.n20>: key("prev:{n20}")
music play: key(play)

And the keys dragonfly passes to sendinput are:

    # Multimedia keys
    VOLUME_UP = win32con.VK_VOLUME_UP
    VOLUME_DOWN = win32con.VK_VOLUME_DOWN
    VOLUME_MUTE = win32con.VK_VOLUME_MUTE
    MEDIA_NEXT_TRACK = win32con.VK_MEDIA_NEXT_TRACK
    MEDIA_PREV_TRACK = win32con.VK_MEDIA_PREV_TRACK
    MEDIA_PLAY_PAUSE = win32con.VK_MEDIA_PLAY_PAUSE
    BROWSER_BACK = win32con.VK_BROWSER_BACK
    BROWSER_FORWARD = win32con.VK_BROWSER_FORWARD
mrob95 commented 4 years ago

Done some digging on this. For the play/pause key printing the KEYBDINPUT structure which is passed to SendInput produces:

wVk wScan dwFlags time dwExtraInfo
179 34    0       0    <ctypes.wintypes.LP_c_ulong object at 0x000000000B58C8C8>
179 34    2       0    <ctypes.wintypes.LP_c_ulong object at 0x000000000B58C648>

wVk is equal to win32con.VK_MEDIA_PLAY_PAUSE

wScan is equal to windll.user32.MapVirtualKeyW(win32con.VK_MEDIA_PLAY_PAUSE, 0, layout) where layout is produced by the following:

def get_current_layout(cls):
        # Get the current window's keyboard layout.
        thread_id = win32process.GetWindowThreadProcessId(
            win32gui.GetForegroundWindow()
        )[0]
        return win32api.GetKeyboardLayout(thread_id)

dwExtraInfo is a null pointer

I think that is more or less everything that is going on, but happy to look into it further if necessary.

lunixbochs commented 4 years ago

Ok, so dragonfly decides to not send KEYEVENTF_SCANCODE in dwFlags, do you know what makes them decide to send or not send that? My wVk / wScan already match that I think.

mrob95 commented 4 years ago

Uhhh

flags = 0
        if virtual_keycode == 0:
            flags |= 4  # KEYEVENTF_UNICODE
        else:
            if virtual_keycode not in self.soft_keys:
                flags |= 8  # KEYEVENTF_SCANCODE
            if virtual_keycode in self.extended_keys:
                flags |= win32con.KEYEVENTF_EXTENDEDKEY
        if not down:
            flags |= win32con.KEYEVENTF_KEYUP
# These virtual keys don't have corresponding scancodes.
# The list was found experimentally and is open to improvement.
SOFT_KEYS = [x for x in range(0xc1, 0xdb)]
SOFT_KEYS += [x for x in range(0x15, 0x1b)]
SOFT_KEYS += [x for x in range(0x1c, 0x20)]
SOFT_KEYS += [x for x in range(0x3a, 0x41)]
SOFT_KEYS += [x for x in range(0x88, 0x90)]
SOFT_KEYS += [x for x in range(0xa6, 0xba)]
SOFT_KEYS += [
    0xe0, 0xe5, 0xe7, 0xe8, 0xfc, 0x01, 0x02, 0x4, 0x5, 0x6, 0x7, 0x0a, 0x0b,
    0x0e, 0x0f, 0x5d, 0x5e, 0x5f
]
lunixbochs commented 4 years ago

should be fixed in 1439