key-bindings


XMonad: Is there a way to bind a simultaneously triggered keychord?


Is there a way to make simultaneous key presses into a keybinding, e.g. for the keys w, e, f, when pressed within 0.05 seconds of each other, to trigger a command?
To be more specific:
If w, e, f are pressed within 0.05 seconds of each other, then upon the pressing of the last one, XMonad should trigger said command. XMonad should also have intercepted the three keys so that they are not superfluously sent to the focused window.
Otherwise (if at least one of them are not pressed within the 0.05 second time period) XMonad should send the keys to the focused window as usual.
My goal in this is to use w, e, f to "Escape" into a vim-like "Normal Mode", a XMonad.Actions.Submap (submap).
Update with a failed method, in case anyone can see a way to fix it:
I attempted to implement this using submaps, so that, for example, if you pressed w you would end up in chord_mode_w, if you pressed e from there you would end up in chord_mode_we, and if you pressed f from there you would finally end up in normal_mode, for instance. The implementation was very messy: I included, in my main keybindings, something like:
("w", spawn "xdotool key <chord_mode_w_keybinding> ; sleep 0.05 ; xdotool key <abort_keybinding>")
(chord_mode_w_keybinding, chord_mode_w)
for detecting w (the rest would be similar), along with (incomplete) submaps such as:
chord_mode_w = submap . mkKeymap c $
[
("e", chord_mode_we )
, ("f", chord_mode_wf )
, (abort_keybinding, pasteString "w")
-- in order for the submap to not eat all other letters,
-- would need to include all mappings like:
, ("a", pasteString "wa")
, ("b", pasteString "wb")
...
]
chord_mode_we = submap . mkKeymap c $
[
("f", normal_mode )
, (abort_keybinding, pasteString "we")
-- in order for the submap to not eat all other letters,
-- would need to include all mappings like:
, ("a", pasteString "wea")
, ("b", pasteString "web")
...
]
chord_mode_wf = submap . mkKeymap c $
[
("e", normal_mode )
, (abort_keybinding, pasteString "wf")
-- in order for the submap to not eat all other letters,
-- would need to include all mappings like:
, ("a", pasteString "wfa")
, ("b", pasteString "wfb")
...
]
A complete implementation would evidently have been very messy, but in theory should have sent me to normal_mode if I pressed "wef" within 0.05 seconds of each other, aborting and typing out the characters otherwise. There were two problems, however:
pasteString (as well as the other paste functions in XMonad.Util.Paste) is too slow for normal typing
I would end up in normal_mode only a small fraction of the time even if I set the abort delay much higher. Not sure of the reason behind this.
(The reason I used pasteString when aborting instead of spawning another xdotool was that output of xdotool would re-trigger one of the chord_mode_w_keybinding, chord_mode_e_keybinding, chord_mode_f_keybinding, back in the main keybindings, sending me back to the chord modes indefinitely.)
http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Actions-Submap.html
Submap really does do almost what you want (it gets you most of the way there) ... and I will suggest that you may want to change what you are trying to do, ever so slightly, and then Submaps handle it perfectly.
You can configure Submap to capture a w key event, and start waiting for an e which then waits for an f. I even tried this out, and confirmed that it works:
, ((0, xK_w), submap . M.fromList $
[ ((0, xK_e), submap . M.fromList $
[ ((0, xK_f), spawn "notify-send \"wef combo detected!\"" ) ])
])
However, the above is almost certainly not something you'd actually want to do... since it is now impossible to send a w keypress to a window (I had to disable that config before typing this answer, which required sending several w keypress events to the active window)
The behavior I saw just now when playing with this is: if I press w, xmonad traps that event (does not send it to the active window) and is now in a state where it is waiting for either e or something else ... if I press something else, xmonad is no longer in that state, but it does not "replay" those trapped events. So if I press w and then some other key which isn't e, the result is only that xmonad is back out of the state listening for keys in the submap. It does not ever allow a w through to the active window... which I found inconvenient.
Your options as I see it are:
1) settle for the initial keybinding having a modifier, so your multi-key command would be Mod4-w e f
2) find a way to hack the delay logic you described into the action in the submap
I started using a config like this, where I nest conceptually similar actions that are infrequently needed under a tree of nested submaps, analogous to what I pasted above. The root of that tree, however, always has a modifier, so it doesn't steal keypresses which I want to forward to the active window. I use Mod3-semicolon as the root of that tree, and then there are many unmodified keypresses which are just letters (they are mnemonics for the actions).
To me, this seems like a better solution, rather than waiting for a few hundred milliseconds, and then forwarding the events unless they matched. I feel like I would find that annoying, since it would delay any w keypress event...
YMMV, hope it helps someone

Related Links

home\ end keys in xterm not behaving correctly
Exporting ALL visual studio key actions (keyactions) for keybindings
How to setup a custom keybinding to run a script or execute a command in Atom editor?
Bind key prefix + ; to open command-prompt in tmux
keybinding to interchange keyboard language
Is there a move cursor to nearest '=' code navigation in IntelliJ?
Disabling Mousewheel Bind
Fish shell ESC/META keybinding with iterm2 on os x yosemite
XMonad: Is there a way to bind a simultaneously triggered keychord?
Simple key binding issue
unable to get C-PGUP or C-PGDOWN key codes in tmux
How do I override a default keybinding in LightTable?
Is it possible to change key bindings in Sublime Text dynamically from a plugin?
Ace Editor - Change CTRL+H keybinding
KeyBindings in Java stop working after component is remade
Tmux Scroll Up/Down Page using Ctrl-b and Ctrl-f

Categories

HOME
domain-driven-design
ldap
python-requests
highmaps
sms
xss
mediarecorder
aggregate-functions
opacity
sequence
normals
osclass
mongodb-replica-set
chef-recipe
saucelabs
k-means
cucumberjs
connection-pooling
wai-aria
rollupjs
jopendocument
visual-studio-community
overflow
boost-log
snapkit
angularjs-resource
ponylang
repeat
sdl-2
lighting
outlook-2010
strategy-pattern
anypoint-studio
area
jquery-inputmask
blueimp
julia-jump
fisheye
delphi-xe
java-5
compiler-warnings
test-kitchen
amazon-rds-aurora
taleo
hdpi
jsfl
import.io
denodo
flask-socketio
dcom
serialversionuid
skype-bots
extjs3
runtime-permissions
openpgp.js
richtext
node.js-client
suitesparse
vertex-shader
lattice
gevent
android-tabs
glade
mavlink
change-password
sprockets
gdi
skbio
containstable
opendolphin
app-data
android-contentresolver
magnet-uri
persian
exchange-server-2007
transparentproxy
grails-3.0.9
jeet-grid
genero
bungeecord
jad
backtrace
xcode5
drools-guvnor
information-hiding
mind-manager
redmine-plugins
pidgin
nativequery
randomaccessfile
ie-developer-tools
kendo-window
static-class
kademlia
asp.net-4.0
removeall
motordriver
hypertable
ios6-maps
sup
vectorwise
soapexception
qvariant
service-layer
xcdatamodel
miniport
xslt-grouping
helios
hp-trim
calendarextender
rpxnow

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App