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].
