hammerspoon icon indicating copy to clipboard operation
hammerspoon copied to clipboard

hs.hotkey.bind - Allow to use any key as a modifier

Open j-martin opened this issue 4 years ago • 7 comments

Similar to https://github.com/Hammerspoon/hammerspoon/issues/689 and https://github.com/Hammerspoon/hammerspoon/issues/1372 I'd like to be able to use any keycode as a modifier when defining hotkey bindings. I would re-open these issues, but I am not allowed to.

The idea is to use Karabiner to map Caps Lock to something like F19keycode (which no application uses) and then be able to set a ton of different hotkey bindings that won't interfere with other apps. In other words, a Hyper key. Currently, I use the combination of cmd, opt, ctrl and it works well enough. The idea is by using F19 (or any obscure keycode) I can combine my hyper key with other modifiers to get even more combinations of hotkeys.

j-martin avatar Mar 14 '20 04:03 j-martin

I think it is already possible with a keyboard handler...

keyboardEventListener = hs.eventtap.new({
		hs.eventtap.event.types.flagsChanged,
		hs.eventtap.event.types.keyUp,
		hs.eventtap.event.types.keyDown
	}, keyboardHandler)
keyboardEventListener:start()

Use this and define a keyboardHandler function where you can check for the characters and mark them internal in your Lua script as a modifier. It works fine. I use it with fn and other keys, but it should be possible with all others.

Here is an empty keyboard event handler i use:

local keyboardHandler = function(event)
	local flags = event:getFlags()
	local characters = event:getCharacters(true)
	-- local keyCode = event:getKeyCode()
	local rawData = event:getRawEventData()
	local nsEventData = rawData['NSEventData']
	local data1 = nsEventData['data1']
	local keyUp = ((data1>>8)&1) == 1
	-- local keyRepeat = (data1&1) == 1
	local systemKey = event:systemKey()
	local key = systemKey['key']
	...
end

Modify it as much as you need it ;)

dasmurphy avatar Mar 15 '20 20:03 dasmurphy

I was hoping for something a bit more elegant. Also, I am also using hotkey modals, so I would need to hack.

I guess my question to the maintainers is: Would making getMods less selective to work (or some other Lua code) or there needs to be some underlining ObjC change?

https://github.com/Hammerspoon/hammerspoon/blob/master/extensions/hotkey/init.lua#L127-L142

j-martin avatar Mar 17 '20 15:03 j-martin

I had the same idea and ran into the same issue @j-martin, by binding to modifier keys for a hyper you restrict yourself from doing other modifier key actions. Binding to some unused key would solve this.

Chandler avatar May 12 '21 07:05 Chandler

@j-martin I do something similar to this… I just trigger the enter/leave status for the modal manually: https://github.com/evantravers/Hyper.spoon/blob/master/init.lua#L28

evantravers avatar Apr 06 '22 15:04 evantravers

i would also like to have any key as modifier integrated as core function (or as a spoon) - so i don't need to do a complicated workaround with KeyUp/KeyDown (which i don't tried so far)

on my wishlist is this unused key on my keyboard: FN

PS: CAPS_LOCK is also an unused key

muescha avatar Aug 03 '22 15:08 muescha

any chance to get some solution or workaround for a "drop in" replacement of hs.hotkey.bind for fn?

muescha avatar Oct 04 '23 23:10 muescha

As a true modifier, not possible with the hotkey model -- it uses Carbon APIs which handle all of the detection so it's pretty rigidly limited to be as it is.

As a modal toggle, easily -- F19 is a recognized character in hs.keycodes.map, so something like the following would work:

modal = hs.hotkey.modal.new({}, "F19")
modal:bind({}, "a", function()
    doAThing...
    modal:exit() -- remove if this shouldn't clear the modal toggle
end)
modal:bind({}, "b", function()
    doBThing...
    modal:exit() -- remove if this shouldn't clear the modal toggle
end)
...etc...
modal:bind({}, "F19", function() -- second press leaves modal
    modal:exit()
end)

As to using FN, you could capture it by creating an hs.eventtap for flagsChanged and entering/exiting a modal hotkey not bound to a toggle key, but you might run into issues with certain keys (not sure, haven't tried recently) because arrows, pageUp, home, etc. internally automatically set the fn key flag.

As to using Caps_Lock, again the eventtap route with flagsChanged events would work, but caps lock is weird in that it's a toggle, not a true modifier key so it's more like the example above for F19 (see #3512 for more info). You might be able to use the hs.eventtap.event.type.systemDefined type for an eventtap, but I never got it work reliably, though that was a few years ago.

In this vein, there is a spoon I hope to land in the next week or so that uses a trick similar to the above example (i.e. a modal like approach) that lets you bind hotkeys to "only" the left or right modifiers... more details (and how to download it now before it lands) at https://github.com/Hammerspoon/hammerspoon/issues/1199#issuecomment-1593876369, though you may want to review the whole thread if this idea interests you.

asmagill avatar Oct 05 '23 02:10 asmagill