I've got this working using the snippet below in rc.lua.  The one thing I
can't get to work is the bit to escape the prefix so that doing "Ctrl-t
t" will send "Ctrl-t" onto the client.  Can anyone help with this:

    keygrabber.stop()
    root.fake_input("key_press", keycodes["Control"])
    root.fake_input("key_press", keycodes["t"])
    root.fake_input("key_release", keycodes["t"])
    root.fake_input("key_release", keycodes["Control"])

I fired up `xev` and this is what I see when I'm using an rc.lua with
that code and I hit "Ctrl-t t" in the xev window::

    KeyPress event, serial 29, synthetic NO, window 0x3800001,
        root 0xae, subw 0x0, time 25151798, (117,90), root:(118,116),
        state 0x0, keycode 66 (keysym 0xffe3, Control_L), same_screen YES,
        XLookupString gives 0 bytes: 
        XmbLookupString gives 0 bytes: 
        XFilterEvent returns: False
    
    FocusOut event, serial 29, synthetic NO, window 0x3800001,
        mode NotifyGrab, detail NotifyAncestor
    
    FocusOut event, serial 29, synthetic NO, window 0x3800001,
        mode NotifyUngrab, detail NotifyPointer
    
    FocusIn event, serial 29, synthetic NO, window 0x3800001,
        mode NotifyUngrab, detail NotifyAncestor
    
    KeymapNotify event, serial 29, synthetic NO, window 0x0,
        keys:  4294967214 0   0   16  0   0   0   0   0   0   0   0   0   0   0 
  0   
               0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   
    
    MappingNotify event, serial 29, synthetic NO, window 0x0,
        request MappingKeyboard, first_keycode 8, count 248
    
    KeyPress event, serial 29, synthetic NO, window 0x3800001,
        root 0xae, subw 0x0, time 25154364, (117,90), root:(118,116),
        state 0x0, keycode 66 (keysym 0xffe3, Control_L), same_screen YES,
        XLookupString gives 0 bytes: 
        XmbLookupString gives 0 bytes: 
        XFilterEvent returns: False
    
    KeyRelease event, serial 29, synthetic NO, window 0x3800001,
        root 0xae, subw 0x0, time 25154365, (117,90), root:(118,116),
        state 0x4, keycode 28 (keysym 0x74, t), same_screen YES,
        XLookupString gives 1 bytes: (14) ""
        XFilterEvent returns: False
    
    KeyRelease event, serial 29, synthetic NO, window 0x3800001,
        root 0xae, subw 0x0, time 25154365, (117,90), root:(118,116),
        state 0x4, keycode 66 (keysym 0xffe3, Control_L), same_screen YES,
        XLookupString gives 0 bytes: 
        XFilterEvent returns: False
    
    MappingNotify event, serial 30, synthetic NO, window 0x0,
        request MappingKeyboard, first_keycode 8, count 248

It looks to me like `root.fake_input("key_press", keycodes["t"])` never
gets to the client but the release does.  Why might that be?

I ran into some bugs. It's really kind of stupid that the keygrabber
stuff returns string letter for the key that it grabbed, it should
really be passing in keycodes.  The keygrabber also doesn't pass
modifiers in the `mod` argument as documented, they are passed in
individually in the `key` argument.  Hence I have to collect them.  It
would also be nice if awesome provided access to keycodes in the LUA
API.

Here's the code.

    ...
    num_shift = { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" }
    keycodes = { ["t"] = 28,
                 ["Control"] = 66 }
    
    -- Bind all key numbers to tags.
    -- Be careful: we use keycodes to make it works on any keyboard layout.
    -- This should map on the top row of your keyboard, usually 1 to 9.
    for i = 1, keynumber do
        globalkeys = awful.util.table.join(globalkeys,
            awful.key({ modkey }, "#" .. i + 9,
                      function ()
                            local screen = mouse.screen
                            if tags[screen][i] then
                                awful.tag.viewonly(tags[screen][i])
                            end
                      end),
            awful.key({ modkey, "Control" }, "#" .. i + 9,
                      function ()
                          local screen = mouse.screen
                          if tags[screen][i] then
                              awful.tag.viewtoggle(tags[screen][i])
                          end
                      end),
            awful.key({ modkey, "Shift" }, "#" .. i + 9,
                      function ()
                          if client.focus and tags[client.focus.screen][i] then
                              
awful.client.movetotag(tags[client.focus.screen][i])
                          end
                      end),
            awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
                      function ()
                          if client.focus and tags[client.focus.screen][i] then
                              
awful.client.toggletag(tags[client.focus.screen][i])
                          end
                      end))
        keycodes[tostring(i)] = tonumber(i + 9)
        keycodes[num_shift[i]] = keycodes[tostring(i)]
    end
    
    clientbuttons = awful.util.table.join(
        awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
        awful.button({ modkey }, 1, awful.mouse.client.move),
        awful.button({ modkey }, 3, awful.mouse.client.resize))
    
    -- Make Ctrl-t prefix act like modkey
    mod_prefixes = {["Shift_"] = "Shift",
                    ["Control_"] = "Control",
                    ["Alt_"] = "Mod2" ,
                    ["Super_"] = modkey}
    globalkeys = awful.util.table.join(
       globalkeys,
       awful.key(
          { "Control" }, "t",
          function(c)
             -- compare the modifiers as if modkey was included
             mod_match = {modkey}
             keygrabber.run(
                function(mod, key, event)
                   if event == "release" then return true end
    
                   -- collect grabbed modifiers
                   for i, modifier in pairs(mod) do
                      if not awful.util.table.hasitem(mod_match, modifier) then
                         table.insert(mod_match, modifier)
                      end
                   end
    
                   if key == "t" and #mod_match == 1 then
                      -- escape to send a Ctrl-t to the client
                      keygrabber.stop()
                      root.fake_input("key_press", keycodes["Control"])
                      root.fake_input("key_press", keycodes["t"])
                      root.fake_input("key_release", keycodes["t"])
                      root.fake_input("key_release", keycodes["Control"])
                      return false
                   end
    
                   for mod_prefix, modifier in pairs(mod_prefixes) do
                      if string.sub(
                         key, 1, string.len(mod_prefix)) == mod_prefix then
                         -- Grabbed key was a modifier,
                         -- add to the list and keep grabbing
                         if not awful.util.table.hasitem(mod_match, modifier) 
then
                            table.insert(mod_match, modifier)
                         end
                         return true
                      end
                   end
    
                   -- Time to handle it so stop grabbing
                   keygrabber.stop()
    
                   -- Look for a matching key binding
                   -- TODO doesn't delegate to client bindings
                   found_globalkey = nil
                   for i, binding in pairs(globalkeys) do
                      if (awful.util.table.hasitem(binding.modifiers, modkey) 
and
                          (awful.key.match(binding, mod_match, key) or
                           (keycodes[key] ~= nil and 
                            awful.key.match(
                               binding, mod_match, "#" .. keycodes[key])))
                         ) then
                         found_binding = binding
                         break
                      end
                   end
    
                   if found_binding == nil then
                      -- Didn't match a global binding, raise an error
                      awesome.emit_signal(
                         "debug::error",
                         string.format("No keybinding for '%s-%s' found",
                                       table.concat(mod_match, "-"), key))
                      return false
                   end
    
                   -- Act as if the key press had been done with modkey
                   found_binding:emit_signal("press")
                   return false
                end)
          end))
    
    -- Set keys
    root.keys(globalkeys)
    -- }}}
    ...

I'd love any help with the Escape stuff,
Ross

On Wed, Oct 3, 2012 at 10:32 AM, Ignas Anikevicius <[email protected]> 
wrote:
> Hello,
>
> I was thinking about it a while back, when I wanted to make modular key
> bindings, and I my thinking was as follows (I didn't implement it
> because I was lazy-or-busy....
>
> So the idea I had was:
>     - Set globalkeys variable to several keys which let you enter
>       several modes.
>     - Those modes have different values for globalkeys and the variable
>       for globalkeys is set to a different value when switching to
>       some mode.
>     - Each globalkeys set has a keybinding to exit the mode and restore
>       the initial globalkeys value.
>
> Last step might not be necessary if one changes the bindings, so that
> the globalkeys are restored automatically. This could be more easily
> done by wrapping awful.key command in a helper function. For example (if
> I haven't made silly mistakes):
>
>     myhelperfunc = function (mod, key, press, release)
>         if release then
>             return awful.key(mod, key, press,
>                 function ()
>                     release
>                     globalkeys = globalkeys_init
>                 end)
>         else
>             return awful.key(mod, key,
>                 function ()
>                     press
>                     globalkeys = globalkeys_init
>                 end)
>         end
>     end
>
> In theory this should work, but there might be something, which I did
> not think about. If you would like an example of some code, maybe I
> would be able to provide some hack, on which you could build on.
>
> All the best,
>
> Ignas A.


-- 
To unsubscribe, send mail to [email protected].

Reply via email to