Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eventtap for ctrl+shift+eject increments #2115

Closed
katernet opened this issue Jun 16, 2019 · 17 comments
Closed

eventtap for ctrl+shift+eject increments #2115

katernet opened this issue Jun 16, 2019 · 17 comments

Comments

@katernet
Copy link

katernet commented Jun 16, 2019

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.

#1220 (comment)
https://blog.theodo.com/2018/03/making-runtime-funtime-hammerspoon/ (last piece of code)

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.

@latenitefilms
Copy link
Contributor

latenitefilms commented Jun 16, 2019

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()

@katernet
Copy link
Author

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.

@latenitefilms
Copy link
Contributor

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?

@katernet
Copy link
Author

katernet commented Jun 16, 2019

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.

@latenitefilms
Copy link
Contributor

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()

@katernet
Copy link
Author

katernet commented Jun 16, 2019

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: {}

@asmagill
Copy link
Member

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:

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...

@katernet
Copy link
Author

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: {}

@katernet
Copy link
Author

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: {}

@latenitefilms
Copy link
Contributor

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()

@katernet
Copy link
Author

katernet commented Jun 16, 2019

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 !

@latenitefilms
Copy link
Contributor

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()

@katernet
Copy link
Author

init.lua:4: <name> expected near 'repeat'

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

@latenitefilms
Copy link
Contributor

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()

@katernet
Copy link
Author

Perfect! Pressing ctrl+shift and then eject:

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

@latenitefilms
Copy link
Contributor

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!

@katernet
Copy link
Author

katernet commented Jun 16, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants