Hammerspoon: Switch to specific layout on command left key press only?

Created on 11 Oct 2016  ·  4Comments  ·  Source: Hammerspoon/hammerspoon

Since Karabiner is down in Siera a lot of us stuck with switching between keyboard layouts using ugly ctlr+space.

Is it possible in hammerspoon to do the following:

  1. On left command key press switch to “en” keyboard layout
  2. On right command key press switch to another, e. g. “ru” keyboard layout.

I’ve tried to do the following:

hs.hotkey.bind(nil, 58, function()
    hs.keycodes.setLayout("Russian - Ilya Birman Typography")
end)


hs.hotkey.bind(nil, 61, function()
    hs.keycodes.setLayout("English - Ilya Birman Typography")
end)

… but it’s not working. 58 and 61 are codes for left and right alts (since I don’t know the correct codes for left and right command). And the layout names are correct of what layouts are installed on my mac.

Most helpful comment

Skipped timer alltogether by adding couple of variables. Changes language on command KeyUp event, but only if nothing happened after command KeyDown (e. g. another key press, mouse click, scroll, etc.)

No previous Lua or Hammerspoon experience whatsoever, so may contain bugs or be not very optimised.

local module = {}
module.showPopUp = false
module.leftCmdLayout = "English - Ilya Birman Typography"
module.rightCmdLayout = "Russian - Ilya Birman Typography"


module.eventwatcher1 = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, function(e)

    local flags = e:getFlags()

    if flags.cmd
       and not (flags.alt or flags.shift or flags.ctrl or flags.fn)
    then
        module.cmdWasPressed = true
        module.cmdShouldBeIgnored = false
        return false;
    end

    if flags.cmd
       and (flags.alt or flags.shift or flags.ctrl or flags.fn)
       and module.cmdWasPressed
    then
        module.cmdShouldBeIgnored = true
        return false;
    end

    if not flags.cmd
    then
        if module.cmdWasPressed
       and not module.cmdShouldBeIgnored
        then
            local keyCode = e:getKeyCode()

            if keyCode == 0x37 then
                hs.keycodes.setLayout(module.leftCmdLayout)

        if module.showPopUp then
            hs.alert.show("English", 0.2)
        end

        elseif keyCode == 0x36 then
        hs.keycodes.setLayout(module.rightCmdLayout)

        if module.showPopUp then
            hs.alert.show("Russian", 0.2)
        end
        end
    end

    module.cmdWasPressed = false
    module.cmdShouldBeIgnored = false
    end

    return false;
end):start()


module.eventwatcher2 = hs.eventtap.new({"all", hs.eventtap.event.types.flagsChanged}, function(e)

    local flags = e:getFlags()

    if flags.cmd and module.cmdWasPressed then
    module.cmdShouldBeIgnored = true
    end

    return false;
end):start()

All 4 comments

You can't bind just a modifier as a hotkey, but you can use the eventtap module... something like this would probably work:

layoutWatcher = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, function(e)
    local flags = e:getFlags()
    if flags.cmd and not (flags.alt or flags.shift or flags.ctrl or flags.fn) then
        local keyCode = e:getKeyCode()
        if keyCode == 0x37 then
            print("~~ left cmd key")
        elseif keyCode == 0x36 then
            print("~~ right cmd key")
        end
    end    
end):start()

Thinking about it, though, you'll probably want to set up a timer and make sure that no key press or flag changes occur within a specific timeout to make sure that the cmd key is _just_ the command key and not part of a key-sequence (like cmd-Q, etc.)

I do something like that in this file here which checks to see if a command key is pressed and held to display a cheatsheet like display: https://github.com/asmagill/hammerspoon-config/blob/master/utils/_keys/cheatsheet.lua#L253

Skipped timer alltogether by adding couple of variables. Changes language on command KeyUp event, but only if nothing happened after command KeyDown (e. g. another key press, mouse click, scroll, etc.)

No previous Lua or Hammerspoon experience whatsoever, so may contain bugs or be not very optimised.

local module = {}
module.showPopUp = false
module.leftCmdLayout = "English - Ilya Birman Typography"
module.rightCmdLayout = "Russian - Ilya Birman Typography"


module.eventwatcher1 = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, function(e)

    local flags = e:getFlags()

    if flags.cmd
       and not (flags.alt or flags.shift or flags.ctrl or flags.fn)
    then
        module.cmdWasPressed = true
        module.cmdShouldBeIgnored = false
        return false;
    end

    if flags.cmd
       and (flags.alt or flags.shift or flags.ctrl or flags.fn)
       and module.cmdWasPressed
    then
        module.cmdShouldBeIgnored = true
        return false;
    end

    if not flags.cmd
    then
        if module.cmdWasPressed
       and not module.cmdShouldBeIgnored
        then
            local keyCode = e:getKeyCode()

            if keyCode == 0x37 then
                hs.keycodes.setLayout(module.leftCmdLayout)

        if module.showPopUp then
            hs.alert.show("English", 0.2)
        end

        elseif keyCode == 0x36 then
        hs.keycodes.setLayout(module.rightCmdLayout)

        if module.showPopUp then
            hs.alert.show("Russian", 0.2)
        end
        end
    end

    module.cmdWasPressed = false
    module.cmdShouldBeIgnored = false
    end

    return false;
end):start()


module.eventwatcher2 = hs.eventtap.new({"all", hs.eventtap.event.types.flagsChanged}, function(e)

    local flags = e:getFlags()

    if flags.cmd and module.cmdWasPressed then
    module.cmdShouldBeIgnored = true
    end

    return false;
end):start()

https://gist.github.com/stepango/3b7dda91c8ab82ec88a14a3ef89a296a

ctrlPressed = false
keyPressed = false

layoutWatcher = hs.eventtap.new({hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.keyUp}, function(e)
    local flags = e:getFlags()
    local keyCode = e:getKeyCode()
    if flags.cmd and keyCode == 0x36 and not (flags.alt or flags.shift or flags.ctrl or flags.fn) then
        ctrlPressed = true
        keyPressed = false
    elseif ctrlPressed and not (flags.cmd or flags.alt or flags.shift or flags.ctrl or flags.fn) and not keyPressed then
        ctrlPressed = false
        if keyCode == 0x36 then
            local lay = hs.keycodes.currentLayout()
            if lay == "U.S." then
              hs.keycodes.setLayout("Russian")
            else
              hs.keycodes.setLayout("U.S.")
            end
        end
    else
        keyPressed = true
    end
end):start()
Was this page helpful?
0 / 5 - 0 ratings

Related issues

BigSully picture BigSully  ·  3Comments

Pancia picture Pancia  ·  4Comments

aaronjensen picture aaronjensen  ·  3Comments

franzwr picture franzwr  ·  3Comments

latenitefilms picture latenitefilms  ·  4Comments