Can anyone help me with the question below?  It's the only thing that's
keeping me from switching from StumpWM.  Specifically, how can I send ^t
(Ctrl-t) to the current client?

Ross

Ross Patterson <[email protected]> writes:

> 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