Hammerspoon: eventtap for ctrl+shift+eject increments

Created on 16 Jun 2019  Â·  17Comments  Â·  Source: Hammerspoon/hammerspoon

I am trying to make a module for mapping ctrl+shift+eject to sleep the display.

(Karabiner Elements ignores the eject key while launched, the display sleep shortcut works while Karabiner is closed.)

I've made the following with help from the following link. It works, however it seems to run the second eventtap incrementally i.e. once the first time, twice the second time etc.

https://github.com/Hammerspoon/hammerspoon/issues/1220#issuecomment-276941617
https://blog.theodo.com/2018/03/making-runtime-funtime-hammerspoon/ (last piece of code)

```lua
hs.eventtap.new({ hs.eventtap.event.types.flagsChanged }, function(eventCS)
local flagsCS = eventCS:getFlags()
if flagsCS.ctrl and flagsCS.shift then

    hs.eventtap.new({ hs.eventtap.event.types.NSSystemDefined }, function(eventE)
        local flagsE = eventE:systemKey()
        if flagsE.key == 'EJECT' and flagsE.down then
            print('test')
            os.execute("pmset displaysleepnow")
        end
    end):start()

end

end):start()
```

Console:
2019-06-16 15:53:03: test 2019-06-16 15:53:11: test 2019-06-16 15:53:11: test 2019-06-16 15:53:19: test 2019-06-16 15:53:19: test 2019-06-16 15:53:19: test

Any ideas? Thanks.

All 17 comments

If you just want CONTROL+SHIFT+EJECT to sleep the display, you just need one hs.eventtap:

myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
    local flags = event:getFlags()
    local systemKey = event:systemKey()   
    if flags.ctrl and flags.shift and systemKey.key == "EJECT" and systemKey.down then
        print("test")
        os.execute("pmset displaysleepnow")                 
   end
end):start()

Awesome thanks @latenitefilms I suspected this could be it, but I couldn't work out how to use only one hs.eventtap

However this doesn't seem to work, "test" not printing in console and display not turning off.

Ummm, it worked fine here on my MacBook Pro with an external keyboard.

Try pasting it in the Hammerspoon Console, and see if it works there?

Do you see any error messages?

I have an Apple USB keyboard.

I disabled my current init.lua and made a new one containing your code (I commented out os.execute for testing)

Console when reloading config:
```
2019-06-16 16:49:59: Welcome to the Hammerspoon Console!
You can run any Lua code in here.

2019-06-16 16:50:01: -- Lazy extension loading enabled
2019-06-16 16:50:01: -- Loading ~/.hammerspoon/init.lua
2019-06-16 16:50:01: -- Loading extension: eventtap
2019-06-16 16:50:01: -- Done.
```

Still not working unfortunately - 'test' not printing.

Console when pasting in your lua code:
```

myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
local flags = event:getFlags()
local systemKey = event:systemKey()
if flags.ctrl and flags.shift and systemKey.key == "EJECT" and systemKey.down then
print("test")
os.execute("pmset displaysleepnow")
end
end):start()
```

No errors.

Strange, well, it's working fine here. You can try adding in some debugging code:

myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
    local flags = event:getFlags()
    local systemKey = event:systemKey()   
    if flags.ctrl and flags.shift and systemKey.key == "EJECT" then
        print("CONTROL+SHIFT+EJECT Pressed!")
        return true
    else
        print(string.format("flags: %s", hs.inspect(flags)))
        print(string.format("systemKey: %s", hs.inspect(systemKey)))
   end
end):start()

Debug output.

Held rightctrl+rightshift and then pressed eject and then quickly released all three keys. It seems "CONTROL+SHIFT+EJECT Pressed!" wasn't printed.

I've also tried left ctrl and left shift.

2019-06-16 17:26:26: flags: { ctrl = true } 2019-06-16 17:26:26: systemKey: {} 2019-06-16 17:26:26: flags: { ctrl = true, shift = true } 2019-06-16 17:26:26: systemKey: {} 2019-06-16 17:26:26: flags: {} 2019-06-16 17:26:26: systemKey: {} 2019-06-16 17:26:26: flags: {} 2019-06-16 17:26:26: systemKey: { down = true, key = "EJECT", keyCode = 14, repeat = false } 2019-06-16 17:26:26: flags: {} 2019-06-16 17:26:26: systemKey: { down = false, key = "EJECT", keyCode = 14, repeat = false } 2019-06-16 17:26:26: flags: { ctrl = true } 2019-06-16 17:26:26: systemKey: {} 2019-06-16 17:26:26: flags: {} 2019-06-16 17:26:26: systemKey: {}

Looks like, at least on your keyboard, when the EJECT key is pressed, it ignores the modifier flags in the event it generates (notice that flags is empty for both the EJECT down and EJECT up events in the log).

I wonder if it's clearing them globally or just for the event itself... try this:

~lua
myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
local flags = event:getFlags()
local systemKey = event:systemKey()
if flags.ctrl and flags.shift and systemKey.key == "EJECT" then
print("CONTROL+SHIFT+EJECT Pressed!")
return true
else
print(string.format("flags: %s", hs.inspect(flags)))
print(string.format("flags from instant check: %s", hs.inspect(hs.eventtap.checkKeyboardModifiers())))
print(string.format("systemKey: %s", hs.inspect(systemKey)))
end
end):start()
~

I've added a line in the debugging output which uses hs.eventtap.checkKeyboardModifiers() to take a snapshot of the current flags without actually querying an event to get them...

Thanks @asmagill very much appreciated.

Debug output

2019-06-16 17:50:17: flags: { ctrl = true } 2019-06-16 17:50:17: flags from instant check: {} 2019-06-16 17:50:17: systemKey: {} 2019-06-16 17:50:17: flags: { ctrl = true, shift = true } 2019-06-16 17:50:17: flags from instant check: { ctrl = true, ["⌃"] = true } 2019-06-16 17:50:17: systemKey: {} 2019-06-16 17:50:18: flags: {} 2019-06-16 17:50:18: flags from instant check: { ctrl = true, shift = true, ["⇧"] = true, ["⌃"] = true } 2019-06-16 17:50:18: systemKey: {} 2019-06-16 17:50:18: flags: {} 2019-06-16 17:50:18: flags from instant check: { ctrl = true, shift = true, ["⇧"] = true, ["⌃"] = true } 2019-06-16 17:50:18: systemKey: { down = true, key = "EJECT", keyCode = 14, repeat = false } 2019-06-16 17:50:18: flags: {} 2019-06-16 17:50:18: flags from instant check: { ctrl = true, shift = true, ["⇧"] = true, ["⌃"] = true } 2019-06-16 17:50:18: systemKey: { down = false, key = "EJECT", keyCode = 14, repeat = false } 2019-06-16 17:50:18: flags: { ctrl = true } 2019-06-16 17:50:18: flags from instant check: { ctrl = true, shift = true, ["⇧"] = true, ["⌃"] = true } 2019-06-16 17:50:18: systemKey: {} 2019-06-16 17:50:18: flags: {} 2019-06-16 17:50:18: flags from instant check: { ctrl = true, ["⌃"] = true } 2019-06-16 17:50:18: systemKey: {}

With Karabiner quit it works. God damn it Karabiner 😂

Debug output

2019-06-16 18:46:07: flags: {
  shift = true
}
2019-06-16 18:46:07: flags from instant check: {}
2019-06-16 18:46:07: systemKey: {}
2019-06-16 18:46:07: flags: {
  ctrl = true,
  shift = true
}
2019-06-16 18:46:07: flags from instant check: {
  shift = true,
  ["⇧"] = true
}
2019-06-16 18:46:07: systemKey: {}
2019-06-16 18:46:07: flags: {
  ctrl = true,
  shift = true
}
2019-06-16 18:46:07: flags from instant check: {
  ctrl = true,
  shift = true,
  ["⇧"] = true,
  ["⌃"] = true
}
2019-06-16 18:46:07: systemKey: {}
2019-06-16 18:46:07: CONTROL+SHIFT+EJECT Pressed!
2019-06-16 18:46:07: CONTROL+SHIFT+EJECT Pressed!
2019-06-16 18:46:07: flags: {
  shift = true
}
2019-06-16 18:46:07: flags from instant check: {
  ctrl = true,
  shift = true,
  ["⇧"] = true,
  ["⌃"] = true
}
2019-06-16 18:46:07: systemKey: {}
2019-06-16 18:46:07: flags: {}
2019-06-16 18:46:07: flags from instant check: {
  ctrl = true,
  shift = true,
  ["⇧"] = true,
  ["⌃"] = true
}
2019-06-16 18:46:07: systemKey: {}

Try this:

myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
    local flags = hs.eventtap.checkKeyboardModifiers()
    local systemKey = event:systemKey()   
    if flags.ctrl and flags.shift and systemKey.key == "EJECT" then
        print("CONTROL+SHIFT+EJECT Pressed!")
        return true
   end
end):start()

Awesome this works

This is when I am press ctrl+shift+eject all at the same time

2019-06-16 19:17:13: CONTROL+SHIFT+EJECT Pressed!

This is when I press ctrl+shift and then press eject (what I have been used to after years of using macOS)

2019-06-16 19:17:26: CONTROL+SHIFT+EJECT Pressed!
2019-06-16 19:17:26: CONTROL+SHIFT+EJECT Pressed!

I'll take it! Thanks @latenitefilms @asmagill !

You could try:

myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
    local flags = hs.eventtap.checkKeyboardModifiers()
    local systemKey = event:systemKey()   
    if flags.ctrl and flags.shift and systemKey.key == "EJECT" and systemKey.down and not systemKey.repeat then
        print("CONTROL+SHIFT+EJECT Pressed!")
        return true
   end
end):start()
init.lua:4: <name> expected near 'repeat'

I guess it's expecting something else for and not systemKey.repeat

Ummm, try:

myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
    local flags = hs.eventtap.checkKeyboardModifiers()
    local systemKey = event:systemKey()   
    if flags.ctrl and flags.shift and systemKey.key == "EJECT" and systemKey.down and not systemKey["repeat"] then
        print("CONTROL+SHIFT+EJECT Pressed!")
        return true
   end
end):start()

Perfect! Pressing ctrl+shift and then eject:

2019-06-16 19:40:47: CONTROL+SHIFT+EJECT Pressed!

Woohoo! Got there in the end.

Please close this issue if you're all good. Feel free to re-open later down the line if needed.

Happy coding!

Thanks a lot @latenitefilms I really appreciate it.

Final script with sleep and shutdown added.

myEventtap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.NSSystemDefined }, function(event)
local flags = hs.eventtap.checkKeyboardModifiers()
local systemKey = event:systemKey()
    if flags.ctrl and flags.shift and systemKey.key == "EJECT" and systemKey.down and not systemKey["repeat"] then
        os.execute("pmset displaysleepnow")
        return true
    end
    if flags.alt and flags.cmd and systemKey.key == "EJECT" and systemKey.down and not systemKey["repeat"] then
        os.execute("pmset sleepnow")
        return true
    end
    if flags.ctrl and flags.cmd and systemKey.key == "EJECT" and systemKey.down and not systemKey["repeat"] then
        hs.osascript.applescript([[
                tell app "System Events" to shut down
        ]])
        return true
    end
end):start()

note: I have root access to /usr/bin/pmset in sudoers

Was this page helpful?
0 / 5 - 0 ratings

Related issues

agzam picture agzam  Â·  3Comments

dasmurphy picture dasmurphy  Â·  4Comments

jiahut picture jiahut  Â·  3Comments

asmagill picture asmagill  Â·  4Comments

tomrbowden picture tomrbowden  Â·  3Comments