Hammerspoon / hammerspoon

Staggeringly powerful macOS desktop automation with Lua
http://www.hammerspoon.org
MIT License
12.09k stars 582 forks source link

Listening on Modifier Keys #1025

Closed daGrevis closed 7 years ago

daGrevis commented 8 years ago

I'm looking for a way to listen to "right cmd" button being pressed. I want to remap it to "right alt", because I feel that real "right alt" button is too far away.

This is what I have so far:

rcmd_handler = function(evt)
  ...
end

rcmd_tap = hs.eventtap.new({hs.eventtap.event.types.keyDown}, rcmd_handler)
rcmd_tap:start()

Is there any event that fires when 'right cmd' is pressed? keyDown doesn't seem to work for that button.

Bonus question: how can I trigger 'right alt' key press?

latenitefilms commented 8 years ago

I'm certainly no expert - but maybe something like this would work?

rcmd_tap = hs.eventtap.new({ hs.eventtap.event.types.keyDown }, function(event)
    local whichFlags = event:getFlags()
    if whichFlags['cmd'] then
        hs.eventtap.keyStroke({"alt"}, "")
    end 
end)
xream commented 8 years ago

You should use {hs.eventtap.event.types.flagsChanged}.

daGrevis commented 8 years ago

Okay, I got everything working except for triggering the 'alt' event. Unfortunately hs.eventtap.keyStroke({"alt"}, "") doesn't fire the same key codes as pressing alt would.

Same behavior when I do: hs.eventtap.event.newKeyEvent({"alt"}, "", true):post().

xream commented 8 years ago

You can use AppleScript: hs.osascript.applescript('tell application "System Events" to key code 58'). This is left alt. The keycode of right alt is 61.

asmagill commented 8 years ago

@xream, Interesting... I wonder... I'll need to modify hs.eventtap.event.newKeyEvent to take a numeric value instead of just a character to see if we can replicate this... do you know if there is a list of the "modifier" keys and their keycodes somewhere? hs.keycodes.map only contains the "visible" characters, and I can confirm that 58 and 61 are not set in that table, so I suspect we can probably send these ourselves with a few tweaks.

xream commented 8 years ago

@asmagill You can print hs.eventtap.event:getKeyCode() to get the keycode. What you said will not work. Because we can only trigger keyDown and keyUp events with/without modifier keys, not flagsChanged which is pressing a modifier key .

asmagill commented 8 years ago

@daGrevis, I'd be curious if the following works for generating a "right alt keypress":

hs.eventtap.event.newKeyEvent({}, " ", true):setKeyCode(61):post()
hs.eventtap.event.newKeyEvent({}, " ", false):setKeyCode(61):post()

The second argument to newKeyEvent doesn't matter, as long as it's a valid key, since the second method should reset it to keycode 61, and since we're emulating a keypress, you'll need to do both lines in succession.

If this doesn't work, I'll look into adding the creation of arbitrary events to hs.eventtap.event this weekend and see if we can track down a combination that does work... calling out to AppleScript, while functional, is slow.

@xream, I was hoping for a list defining all of the known keycodes... and I think I found it in the Events.h header from the Carbon framework. The current constructors for hs.eventtap.event are limited to key, mouse, and scroll event types, but the CoreGraphics functions those constructors use do support creating other event types... I'm just trying to decide if it's worth the effort to add that to the Hammerspoon module or not.

xream commented 8 years ago

@asmagill Wow. Btw, will this work then?

xream commented 8 years ago

@asmagill When we press the 'opt' key, we get a flagsChanged event with keycode 61 and flag alt and a flagsChanged event with keycode 61 without any flag.

When we use newKeyEvent to generate the opt keypress, we get a keyDown event with keycode 61 no flag and a keyUp event with keycode 61 no flag.

asmagill commented 8 years ago

Ok, I was afraid of that... it was worth a shot. I have a couple of other ideas, but unfortunately they require additions to hs.eventtap.event, so it's going to have to wait until tomorrow or Saturday for me to make the additions.

asmagill commented 8 years ago

@daGrevis, if I may ask so I can test while tweaking hs.eventtap... what application are you trying to send a right alt to? I can always whip up an event watcher to detect it during my tests, but it's always more effective when I can test it against another application that more closely resembles real-world use. Thanks!

daGrevis commented 8 years ago

@asmagill

Sorry for the late response.

I'm testing in iTerm2, Terminal and Chrome. Pressing right command key should send the same keycodes as right option.

If you change your keyboard input source to "Latvian" and press e while holding right option, it should input the ē letter. Remapped right command + e should do the same - it should inputting the ē letter again.

asmagill commented 8 years ago

Sorry for the delay in getting back to this -- I am working on an addition to eventtap that allows creating raw events of any type, but it has proven to be a little more difficult than originally expected, since some event properties must be created and set through NSEvent rather than CGEvent (which is what the bulk of the module is based on)... I hope to have something for testing later this week/next week, but I did want to note that it's in progress.

KevinVillela commented 7 years ago

Hi, just wondering if there was any progress made here? I am interested in binding right-command to right-alt as well. Thanks!

franciscolourenco commented 7 years ago

Same here. I'm just interested in toggling modifiers in general, don't care which one specifically. If there is a way please let me know.

This is the purpose: https://github.com/Hammerspoon/hammerspoon/issues/1235#issuecomment-280957090

Thanks!

cmsj commented 7 years ago

I want to generally discourage using Hammerspoon for key remapping. karabiner is the tool to use for that, and it should be usable enough on Sierra to swap single keys, and I think it will be able to do more complex mappings pretty soon.

franciscolourenco commented 7 years ago

@cmsj we disagree on the "pretty soon" part :)

cmsj commented 7 years ago

@aristidesfl I've been watching its commits and I think tekezo is already putting in the required pieces for complex mappings :)

luckman212 commented 4 years ago

Sorry to dredge up an old issue, but because of stability problems with Karabiner, I'm looking for ways to do some simple modifier key remapping directly in Hammerspoon.

Would like to know if there's a reasonable way of event tapping, for example, just the right command key.

tigger04 commented 2 years ago

Sorry to dredge up an old issue, but because of stability problems with Karabiner, I'm looking for ways to do some simple modifier key remapping directly in Hammerspoon.

Would like to know if there's a reasonable way of event tapping, for example, just the right command key.

+1 on this, another Karabiner refugee here :(

asmagill commented 2 years ago

I've not used it to remap modifiers, so you'll need to test that part out, but I've used something similar to the following to detect right modifiers:

-- we have to watch for flag changes *and* keyDown/Up since a command key (e.g. Cmd-C) is
-- it's own event

e = hs.eventtap.new({
    hs.eventtap.event.types.flagsChanged,
    hs.eventtap.event.types.keyUp,
    hs.eventtap.event.types.keyDown}, function(ev) 
    -- synthesized events set 0x20000000 and we may or may not get the nonCoalesced bit,
    -- so filter them out
    local rawFlags = ev:getRawEventData().CGEventData.flags & 0xdffffeff
    local regularFlags = ev:getFlags()

    -- uncomment this out when troubleshooting -- apparently different modifiers use
    -- different flags indicating left vs right: e.g.
--     {
--       cmd = true
--     }    1048584
--     {}   0
--     {
--       cmd = true
--     }    1048592        // right
--     {}   0
--
--     {
--       shift = true
--     }    131076         // right
--     {}   0
--     {
--       shift = true
--     }    131074
--     {}   0
--
-- etc.
--     print(inspect(regularFlags), rawFlags)

    if rawFlags == 1048592 then
        -- do what the right cmd key is supposed to do
        -- may want to check ev:getType() to see if this was just the modifier (flagsChanged)
        -- or a command key sequence (keyDown/keyUp)
        print("righty!", ev:getType())
        return true, {} -- eat the event
        -- if you want to replace it with a different modifier, you'd do something like:
        -- local newEvent = hs.eventtap.event.newEvent(....)....
        -- return true, { newEvent }
    end
end):start()