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

same KeyEvent from within hotkey.bind #2081

Closed
agzam opened this issue Apr 25, 2019 · 5 comments
Closed

same KeyEvent from within hotkey.bind #2081

agzam opened this issue Apr 25, 2019 · 5 comments

Comments

@agzam
Copy link

agzam commented Apr 25, 2019

I need to bind a key and based on certain logic from within hs.hotkey.bind need to emulate the same sequence.

Let's say, for example I have a global bind: Control-C. Imagine in browser it would do something, but in Emacs it should do nothing, but also it should not shadow Emacs's default keybinding. So it needs to "throw the keys back" - replay Control-C sequence.

I've been trying to get this right using eventtap.event.newKeyEvent, hs.timer.doAfter - nothing works. Can someone help me to get this right? Thanks a lot!

@latenitefilms
Copy link
Contributor

I'm not entirely sure I understand your question, but I think what you're after is better achieved with hs.eventtap as opposed to hs.hotkey.

For example:

hs.eventtap.new({hs.eventtap.event.types.keyUp}, function(event)
    local flags = event:getFlags()
    local keyCode = event:getKeyCode()
    if flags:containExactly({"ctrl"}) and keyCode == hs.keycodes.map["c"] then
        print("CTRL+C has been pressed.")
        -- INSERT LOGIC HERE.
        local shouldTheEventBeDeleted = true --  true if the event should be deleted, false if it should propagate to any other applications watching for that event
        local tableOfEventsToPost = {} -- a table of events to post        
        return shouldTheEventBeDeleted, tableOfEventsToPost
    end
end):start()

@asmagill
Copy link
Member

If you're wanting the key combo to do something for most applications, but not for a few specific ones, you're better off using a window filter or application watcher and enabling/disabling the hotkey(s) when the active application changes.

Hotkey's as defined with hs.hotkey, when enabled, are always caught and can not be "passed through"... any attempt to create a synthetic version of the hot key combination with hs.eventtap.event will in turn be caught by hs.hotkey, thus creating an infinite loop... search the issues -- this has come up before.

Watching for a hotkey with hs.eventtap seems like it should be more flexible, but if your Mac gets busy, you may notice dropped keystrokes (and not just the ones you're trying to match on)... we've attempted rewriting hs.hotkey to use the eventtap infrastructure in the past and it just isn't fast enough to be enabled all of the time for key and flag events -- you have to catch them all then determine if its one you care about.

Search the issues and you should find some examples of watchers that should point you in the right direction... I'll try and post an example later but I'm not at my computer at the moment.

@latenitefilms
Copy link
Contributor

As usual, @asmagill makes a really good point.

Here's an example of how to use hs.window.filter:

#2029 (comment)

There's an example of using hs.application.watcher in the Getting Started guide:

http://www.hammerspoon.org/go/#appevents

@agzam
Copy link
Author

agzam commented Apr 25, 2019

Thank you everyone for you help. Closing this, since not a real issue

@agzam agzam closed this as completed Apr 25, 2019
@overvale
Copy link

overvale commented Aug 3, 2020

I was able to get this working by adapting some code from some dot files

local function keyCode(modifiers, key)
  return function() hs.eventtap.keyStroke(modifiers, key, 0) end
end

-- Create a modal hotkey object with an absurd triggering hotkey,
-- since it will never be triggered from the keyboard
hotkeys = hs.hotkey.modal.new({"cmd", "shift", "alt"}, "F19")
-- Bind all your normal hotkeys to the modal state object
hotkeys:bind({'ctrl'}, ',', keyCode({'alt'}, 'left'))
hotkeys:bind({'ctrl'}, '.', keyCode({'alt'}, 'down'))
hotkeys:bind({'ctrl'}, "'", keyCode({'alt'}, 'forwarddelete'))
hotkeys:bind({'ctrl'}, ';', keyCode({'alt'}, 'delete'))
hotkeys:bind({'ctrl'}, 'u', keyCode({'cmd'}, 'delete'))

-- Define a callback function to be called when application events happen
function applicationWatcherCallback(appName, eventType, appObject)
  if (appName == "Emacs") then
    if (eventType == hs.application.watcher.activated) then
      -- Emacs just got focus, disable our hotkeys
      hotkeys:exit()
    elseif (eventType == hs.application.watcher.deactivated) then
      -- Emacs just lost focus, enable our hotkeys
      hotkeys:enter()
    end
  end
end

-- Create and start the application event watcher
watcher = hs.application.watcher.new(applicationWatcherCallback)
watcher:start()

-- Activate the modal state
hotkeys:enter()

I have no idea if this is a smart way to do it, but it was the only way I could get it to work.

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

4 participants