summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2010-04-07 21:04:37 +0200
committerhut <hut@lavabit.com>2010-04-07 21:04:37 +0200
commit0b306138950baef339164481d93aaabb882027bc (patch)
tree8795e7fdfca985bb4826b6d2b15b4b086fc6e992
parentbe7c282c2d73472254946f5043bf835f6bbb038a (diff)
downloadranger-0b306138950baef339164481d93aaabb882027bc.tar.gz
added KeyManager
-rw-r--r--ranger/__main__.py1
-rw-r--r--ranger/container/__init__.py2
-rw-r--r--ranger/container/keymap.py33
-rw-r--r--ranger/core/environment.py7
-rw-r--r--ranger/defaults/keys.py557
-rw-r--r--ranger/defaults/oldkeys.py555
-rw-r--r--ranger/gui/ui.py12
-rw-r--r--ranger/gui/widgets/console.py3
-rw-r--r--ranger/gui/widgets/pager.py5
-rw-r--r--ranger/gui/widgets/taskview.py1
-rw-r--r--ranger/shared/settings.py12
-rw-r--r--test/tc_newkeys.py39
-rw-r--r--test/tc_ui.py2
13 files changed, 689 insertions, 540 deletions
diff --git a/ranger/__main__.py b/ranger/__main__.py
index 674ad8f6..863eadd5 100644
--- a/ranger/__main__.py
+++ b/ranger/__main__.py
@@ -112,6 +112,7 @@ def main():
 		path = '.'
 
 	Environment(path)
+	SettingsAware._setup_keys()
 
 	try:
 		my_ui = UI()
diff --git a/ranger/container/__init__.py b/ranger/container/__init__.py
index 4c8f08ba..c1bb8194 100644
--- a/ranger/container/__init__.py
+++ b/ranger/container/__init__.py
@@ -17,5 +17,5 @@
 used to manage stored data
 """
 from ranger.container.history import History
-from .keymap import KeyMap, KeyBuffer
+from .keymap import KeyMap, KeyBuffer, KeyManager
 from .bookmarks import Bookmarks
diff --git a/ranger/container/keymap.py b/ranger/container/keymap.py
index 1e634f1d..62cf0e7a 100644
--- a/ranger/container/keymap.py
+++ b/ranger/container/keymap.py
@@ -61,11 +61,11 @@ class KeyMap(Tree):
 	"""Contains a tree with all the keybindings"""
 	def map(self, *args, **keywords):
 		if keywords:
-			return self.add_binding(*args, **keywords)
+			return self._add_binding(*args, **keywords)
 		firstarg = args[-1]
 		if isfunction(firstarg):
 			keywords[FUNC] = firstarg
-			return self.add_binding(*args[:-1], **keywords)
+			return self._add_binding(*args[:-1], **keywords)
 		def decorator_function(func):
 			keywords = {FUNC:func}
 			self.map(*args, **keywords)
@@ -74,7 +74,7 @@ class KeyMap(Tree):
 
 	__call__ = map
 
-	def add_binding(self, *keys, **actions):
+	def _add_binding(self, *keys, **actions):
 		assert keys
 		bind = Binding(keys, actions)
 		for key in keys:
@@ -83,6 +83,33 @@ class KeyMap(Tree):
 	def __getitem__(self, key):
 		return self.traverse(translate_keys(key))
 
+
+class KeyManager(object):
+	def __init__(self, keybuffer, contexts):
+		self._keybuffer = keybuffer
+		self._contexts = {
+			'any': KeyMap(),
+			'directions': KeyMap(),
+		}
+		for context in contexts:
+			self._contexts[context] = KeyMap()
+
+	def map(self, context, *args, **keywords):
+		self.get_context(context).map(*args, **keywords)
+
+	def get_context(self, context):
+		assert isinstance(context, str)
+		assert context in self._contexts, "no such context!"
+		return self._contexts[context]
+	__getitem__ = get_context
+
+	def use_context(self, context, directions='directions'):
+		context = self.get_context(context)
+		if self._keybuffer.keymap is not context:
+			directions = self.get_context(directions)
+			self._keybuffer.assign(context, directions)
+			self._keybuffer.clear()
+
 class Binding(object):
 	"""The keybinding object"""
 	def __init__(self, keys, actions):
diff --git a/ranger/core/environment.py b/ranger/core/environment.py
index 0b38c475..d83003b1 100644
--- a/ranger/core/environment.py
+++ b/ranger/core/environment.py
@@ -20,10 +20,13 @@ import socket
 from os.path import abspath, normpath, join, expanduser, isdir
 
 from ranger.fsobject.directory import Directory, NoDirectoryGiven
-from ranger.container import KeyBuffer, History
+from ranger.container import KeyBuffer, KeyManager, History
 from ranger.ext.signal_dispatcher import SignalDispatcher
 from ranger.shared import SettingsAware
 
+ALLOWED_CONTEXTS = ('general', 'pager', 'embedded_pager', 'taskview',
+		'console')
+
 class Environment(SettingsAware, SignalDispatcher):
 	"""A collection of data which is relevant for more than
 	one class.
@@ -40,6 +43,7 @@ class Environment(SettingsAware, SignalDispatcher):
 	pathway = None
 	path = None
 	keybuffer = None
+	keymanager = None
 
 	def __init__(self, path):
 		SignalDispatcher.__init__(self)
@@ -48,6 +52,7 @@ class Environment(SettingsAware, SignalDispatcher):
 		self.pathway = ()
 		self.directories = {}
 		self.keybuffer = KeyBuffer(None, None)
+		self.keymanager = KeyManager(self.keybuffer, ALLOWED_CONTEXTS)
 		self.copy = set()
 		self.history = History(self.settings.max_history_size)
 
diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py
index 467d26e6..72558a23 100644
--- a/ranger/defaults/keys.py
+++ b/ranger/defaults/keys.py
@@ -39,517 +39,48 @@ Check ranger.keyapi for more information
 
 from ranger.api.keys import *
 
-def _vimlike_aliases(map):
-	alias = map.alias
 
-	# the key 'k' will always do the same as KEY_UP, etc.
-	alias(KEY_UP, 'k')
-	alias(KEY_DOWN, 'j')
-	alias(KEY_LEFT, 'h')
-	alias(KEY_RIGHT, 'l')
-
-	alias(KEY_NPAGE, ctrl('f'))
-	alias(KEY_PPAGE, ctrl('b'))
-	alias(KEY_HOME, 'gg')
-	alias(KEY_END, 'G')
-
-
-def _emacs_aliases(map):
-	alias = map.alias
-	alias(KEY_LEFT, ctrl('b'))
-	alias(KEY_RIGHT, ctrl('f'))
-	alias(KEY_HOME, ctrl('a'))
-	alias(KEY_END, ctrl('e'))
-	alias(KEY_DC, ctrl('d'))
-	alias(DEL, ctrl('h'))
-
-
-def initialize_commands(map):
-	"""Initialize the commands for the main user interface"""
-
-	# -------------------------------------------------------- movement
-	_vimlike_aliases(map)
-	_basic_movement(map)
-
-	map.alias(KEY_LEFT, KEY_BACKSPACE, DEL)
-	map.alias(KEY_RIGHT, KEY_ENTER, ctrl('j'))
-
-	map('%', fm.move(to=50, percentage=True))
-	map(KEY_NPAGE, ctrl('f'), fm.move(down=1, pages=True))
-	map(KEY_PPAGE, ctrl('b'), fm.move(up=1, pages=True))
-	map(ctrl('d'), 'J', fm.move(down=0.5, pages=True))
-	map(ctrl('u'), 'K', fm.move(up=0.5, pages=True))
-
-	map(']', fm.traverse())
-	map('[', fm.history_go(-1))
-
-	# --------------------------------------------------------- history
-	map('H', fm.history_go(-1))
-	map('L', fm.history_go(1))
-
-	# ----------------------------------------------- tagging / marking
-	map('t', fm.tag_toggle())
-	map('T', fm.tag_remove())
-
-	map(' ', fm.mark(toggle=True))
-	map('v', fm.mark(all=True, toggle=True))
-	map('V', fm.mark(all=True, val=False))
-
-	# ------------------------------------------ file system operations
-	map('yy', fm.copy())
-	map('dd', fm.cut())
-	map('pp', fm.paste())
-	map('po', fm.paste(overwrite=True))
-	map('pl', fm.paste_symlink())
-	map('p', hint='press //p// once again to confirm pasting' \
-			', or //l// to create symlinks')
-
-	# ---------------------------------------------------- run programs
-	map('s', fm.execute_command(os.environ['SHELL']))
-	map('E', fm.edit_file())
-	map(',term', fm.execute_command('x-terminal-emulator', flags='d'))
-	map('du', fm.execute_command('du --max-depth=1 -h | less'))
-
-	# -------------------------------------------------- toggle options
-	map('b', fm.notify('Warning: settings are now changed with z!', bad=True))
-	map('z', hint="show_//h//idden //p//review_files //d//irectories_first " \
-		"//c//ollapse_preview flush//i//nput ca//s//e_insensitive")
-	map('zh', fm.toggle_boolean_option('show_hidden'))
-	map('zp', fm.toggle_boolean_option('preview_files'))
-	map('zP', fm.toggle_boolean_option('preview_directories'))
-	map('zi', fm.toggle_boolean_option('flushinput'))
-	map('zd', fm.toggle_boolean_option('sort_directories_first'))
-	map('zc', fm.toggle_boolean_option('collapse_preview'))
-	map('zs', fm.toggle_boolean_option('sort_case_insensitive'))
-
-	# ------------------------------------------------------------ sort
-	map('o', 'O', hint="//s//ize //b//ase//n//ame //m//time //t//ype //r//everse")
-	sort_dict = {
-		's': 'size',
-		'b': 'basename',
-		'n': 'basename',
-		'm': 'mtime',
-		't': 'type',
-	}
-
-	for key, val in sort_dict.items():
-		for key, is_capital in ((key, False), (key.upper(), True)):
-			# reverse if any of the two letters is capital
-			map('o' + key, fm.sort(func=val, reverse=is_capital))
-			map('O' + key, fm.sort(func=val, reverse=True))
-
-	map('or', 'Or', 'oR', 'OR', lambda arg: \
-			arg.fm.sort(reverse=not arg.fm.settings.sort_reverse))
-
-	# ----------------------------------------------- console shortcuts
-	@map("A")
-	def append_to_filename(arg):
-		command = 'rename ' + arg.fm.env.cf.basename
-		arg.fm.open_console(cmode.COMMAND, command)
-
-	map('cw', fm.open_console(cmode.COMMAND, 'rename '))
-	map('cd', fm.open_console(cmode.COMMAND, 'cd '))
-	map('f', fm.open_console(cmode.COMMAND_QUICK, 'find '))
-	map('tf', fm.open_console(cmode.COMMAND, 'filter '))
-	map('d', hint='d//u// (disk usage) d//d// (cut)')
-	map('@', fm.open_console(cmode.OPEN, '@'))
-	map('#', fm.open_console(cmode.OPEN, 'p!'))
-
-	# --------------------------------------------- jump to directories
-	map('gh', fm.cd('~'))
-	map('ge', fm.cd('/etc'))
-	map('gu', fm.cd('/usr'))
-	map('gd', fm.cd('/dev'))
-	map('gl', fm.cd('/lib'))
-	map('go', fm.cd('/opt'))
-	map('gv', fm.cd('/var'))
-	map('gr', 'g/', fm.cd('/'))
-	map('gm', fm.cd('/media'))
-	map('gn', fm.cd('/mnt'))
-	map('gt', fm.cd('/tmp'))
-	map('gs', fm.cd('/srv'))
-	map('gR', fm.cd(RANGERDIR))
-
-	# ------------------------------------------------------------ tabs
-	map('gc', ctrl('W'), fm.tab_close())
-	map('gt', TAB, fm.tab_move(1))
-	map('gT', KEY_BTAB, fm.tab_move(-1))
-	map('gn', ctrl('N'), fm.tab_new())
-	for n in range(10):
-		map('g' + str(n), fm.tab_open(n))
-
-	# ------------------------------------------------------- searching
-	map('/', fm.open_console(cmode.SEARCH))
-
-	map('n', fm.search())
-	map('N', fm.search(forward=False))
-
-	map('ct', fm.search(order='tag'))
-	map('cc', fm.search(order='ctime'))
-	map('cm', fm.search(order='mimetype'))
-	map('cs', fm.search(order='size'))
-	map('c', hint='//c//time //m//imetype //s//ize //t//agged')
-
-	# ------------------------------------------------------- bookmarks
-	for key in ALLOWED_BOOKMARK_KEYS:
-		map("`" + key, "'" + key, fm.enter_bookmark(key))
-		map("m" + key, fm.set_bookmark(key))
-		map("um" + key, fm.unset_bookmark(key))
-	map("`", "'", "m", "um", draw_bookmarks=True)
-
-	# ---------------------------------------------------- change views
-	map('i', fm.display_file())
-	map(ctrl('p'), fm.display_log())
-	map('?', KEY_F1, fm.display_help())
-	map('w', lambda arg: arg.fm.ui.open_taskview())
-
-	# ---------------------------------------------------------- custom
-	# This is useful to track watched episode of a series.
-	@bind(']')
-	def tag_next_and_run(arg):
-		fm = arg.fm
-		fm.tag_remove()
-		fm.tag_remove(movedown=False)
-		fm.tag_toggle()
-		fm.move_pointer(relative=-2)
-		fm.move_right()
-		fm.move_pointer(relative=1)
-
-	# "enter" = shortcut for "1l"
-	bind(KEY_ENTER, ctrl('j'), fm.move_right(mode=1))
-
-	# ------------------------------------------------ system functions
-	_system_functions(map)
-	map('ZZ', 'ZQ', fm.exit())
-	map(ctrl('R'), fm.reset())
-	map('R', fm.reload_cwd())
-	@map(ctrl('C'))
-	def ctrl_c(arg):
-		try:
-			item = arg.fm.loader.queue[0]
-		except:
-			arg.fm.notify("Type Q or :quit<Enter> to exit Ranger")
-		else:
-			arg.fm.notify("Aborting: " + item.get_description())
-			arg.fm.loader.remove(index=0)
-
-	map(':', ';', fm.open_console(cmode.COMMAND))
-	map('>', fm.open_console(cmode.COMMAND_QUICK))
-	map('!', fm.open_console(cmode.OPEN))
-	map('r', fm.open_console(cmode.OPEN_QUICK))
-
-	map.rebuild_paths()
-
-
-def initialize_console_commands(map):
-	"""Initialize the commands for the console widget only"""
-
-	_basic_movement(map)
-	_emacs_aliases(map)
-
-	# -------------------------------------------------------- movement
-	map(KEY_UP, wdg.history_move(-1))
-	map(KEY_DOWN, wdg.history_move(1))
-	map(KEY_HOME, wdg.move(right=0, absolute=True))
-	map(KEY_END, wdg.move(right=-1, absolute=True))
-
-	# ----------------------------------------- deleting / pasting text
-	map(KEY_DC, wdg.delete(0))
-	map(KEY_BACKSPACE, DEL, wdg.delete(-1))
-	map(ctrl('w'), wdg.delete_word())
-	map(ctrl('k'), wdg.delete_rest(1))
-	map(ctrl('u'), wdg.delete_rest(-1))
-	map(ctrl('y'), wdg.paste())
-
-	# ------------------------------------------------ system functions
-	map(KEY_F1, lambda arg: arg.fm.display_command_help(arg.wdg))
-	map(ctrl('c'), ESC, wdg.close())
-	map(ctrl('j'), KEY_ENTER, wdg.execute())
-	map(TAB, wdg.tab())
-	map(KEY_BTAB, wdg.tab(-1))
-
-	map.rebuild_paths()
-
-
-def initialize_taskview_commands(map):
-	"""Initialize the commands for the TaskView widget"""
-	_basic_movement(map)
-	_vimlike_aliases(map)
-	_system_functions(map)
-
-	# -------------------------------------------------- (re)move tasks
-	map('K', wdg.task_move(0))
-	map('J', wdg.task_move(-1))
-	map('dd', wdg.task_remove())
-
-	# ------------------------------------------------ system functions
-	map('?', fm.display_help())
-	map('w', 'q', ESC, ctrl('d'), ctrl('c'),
-			lambda arg: arg.fm.ui.close_taskview())
-
-	map.rebuild_paths()
-
-
-def initialize_pager_commands(map):
-	_base_pager_commands(map)
-	map('q', 'i', ESC, KEY_F1, lambda arg: arg.fm.ui.close_pager())
-	map.rebuild_paths()
-
-
-def initialize_embedded_pager_commands(map):
-	_base_pager_commands(map)
-	map('q', 'i', ESC, lambda arg: arg.fm.ui.close_embedded_pager())
-	map.rebuild_paths()
-
-
-def _base_pager_commands(map):
-	_basic_movement(map)
-	_vimlike_aliases(map)
-	_system_functions(map)
-
-	# -------------------------------------------------------- movement
-	map(KEY_LEFT, wdg.move(left=4))
-	map(KEY_RIGHT, wdg.move(right=4))
-	map(KEY_NPAGE, ctrl('f'), wdg.move(down=1, pages=True))
-	map(KEY_PPAGE, ctrl('b'), wdg.move(up=1, pages=True))
-	map(ctrl('d'), wdg.move(down=0.5, pages=True))
-	map(ctrl('u'), wdg.move(up=0.5, pages=True))
-	map(' ', wdg.move(down=0.8, pages=True))
-
-	# ---------------------------------------------------------- others
-	map('E', fm.edit_file())
-	map('?', fm.display_help())
-
-	# --------------------------------------------- less-like shortcuts
-	map.alias(KEY_NPAGE, 'f')
-	map.alias(KEY_PPAGE, 'b')
-	map.alias(ctrl('d'), 'd')
-	map.alias(ctrl('u'), 'u')
-
-
-def _system_functions(map):
-	map('Q', fm.exit())
-	map(ctrl('L'), fm.redraw_window())
-
-
-def _basic_movement(map):
-	map(KEY_DOWN, wdg.move(down=1))
-	map(KEY_UP, wdg.move(up=1))
-	map(KEY_RIGHT, wdg.move(right=1))
-	map(KEY_LEFT, wdg.move(left=1))
-	map(KEY_HOME, wdg.move(to=0))
-	map(KEY_END, wdg.move(to=-1))
-
-
-
-# ------ newkey:
-
-
-def base_directions():
-	# Direction Keys
-	map = KeyMap()
-	map('<down>', dir=Direction(down=1))
-	map('<up>', dir=Direction(down=-1))
-	map('<left>', dir=Direction(right=-1))
-	map('<right>', dir=Direction(right=1))
-	map('<home>', dir=Direction(down=0, absolute=True))
-	map('<end>', dir=Direction(down=-1, absolute=True))
-	map('<pagedown>', dir=Direction(down=1, pages=True))
-	map('<pageup>', dir=Direction(down=-1, pages=True))
-	map('%<any>', dir=Direction(down=1, percentage=True, absolute=True))
-	map('<space>', dir=Direction(down=1, pages=True))
-	map('<CR>', dir=Direction(down=1))
-
-	return map
-
-def vim():
-	# Direction Keys
-	map = KeyMap()
-	map.merge(base_directions())
-	map('j', alias='<down>')
-	map('k', alias='<up>')
-	map('h', alias='<left>')
-	map('l', alias='<right>')
-	map('gg', alias='<home>')
-	map('G', alias='<end>')
-	map('J', dir=Direction(down=20))
-	map('K', dir=Direction(down=-20))
-
-	return map
-
-def system_keys():
-	map = KeyMap()
-	map('Q', fm.exit())
-	map('<mouse>', fm.handle_mouse())
-	map('<C-L>', fm.redraw_window())
-	map('<resize>', fm.resize())
-
-	return map
-
-def browser_keys():
-	map = KeyMap()
-	map.merge(system_keys())
-
-	@map('<dir>')
-	def move(arg):
-		arg.fm.move(narg=arg.n, **arg.direction)
-	map('gg', fm.move(to=0))
-	map(fm.exit(), 'Q')
-
-	map('<cr>', fm.move(dir=Direction(right=1)))
-
-	# --------------------------------------------------------- history
-	map('H', fm.history_go(-1))
-	map('L', fm.history_go(1))
-
-	# ----------------------------------------------- tagging / marking
-	map('t', fm.tag_toggle())
-	map('T', fm.tag_remove())
-
-	map(' ', fm.mark(toggle=True))
-	map('v', fm.mark(all=True, toggle=True))
-	map('V', fm.mark(all=True, val=False))
-
-	# ------------------------------------------ file system operations
-	map('yy', fm.copy())
-	map('dd', fm.cut())
-	map('pp', fm.paste())
-	map('po', fm.paste(overwrite=True))
-	map('pl', fm.paste_symlink())
-	map('p<bg>', fm.hint('press //p// once again to confirm pasting' \
-			', or //l// to create symlinks'))
-
-	# ---------------------------------------------------- run programs
-	map('s', fm.execute_command(os.environ['SHELL']))
-	map('E', fm.edit_file())
-	map('.term', fm.execute_command('x-terminal-emulator', flags='d'))
-	map('du', fm.execute_command('du --max-depth=1 -h | less'))
-
-	# -------------------------------------------------- toggle options
-	map('b<bg>', fm.hint("bind_//h//idden //p//review_files" \
-		"//d//irectories_first //c//ollapse_preview flush//i//nput"))
-	map('bh', fm.toggle_boolean_option('show_hidden'))
-	map('bp', fm.toggle_boolean_option('preview_files'))
-	map('bi', fm.toggle_boolean_option('flushinput'))
-	map('bd', fm.toggle_boolean_option('directories_first'))
-	map('bc', fm.toggle_boolean_option('collapse_preview'))
-
-	# ------------------------------------------------------------ sort
-	map('o<bg>', 'O<bg>', fm.hint("//s//ize //b//ase//n//ame //m//time" \
-		" //t//ype //r//everse"))
-	sort_dict = {
-		's': 'size',
-		'b': 'basename',
-		'n': 'basename',
-		'm': 'mtime',
-		't': 'type',
-	}
-
-	for key, val in sort_dict.items():
-		for key, is_capital in ((key, False), (key.upper(), True)):
-			# reverse if any of the two letters is capital
-			map('o' + key, fm.sort(func=val, reverse=is_capital))
-			map('O' + key, fm.sort(func=val, reverse=True))
-
-	map('or', 'Or', 'oR', 'OR', lambda arg: \
-			arg.fm.sort(reverse=not arg.fm.settings.reverse))
-
-	# ----------------------------------------------- console shortcuts
-	@map("A")
-	def append_to_filename(arg):
-		command = 'rename ' + arg.fm.env.cf.basename
-		arg.fm.open_console(cmode.COMMAND, command)
-
-	map('cw', fm.open_console(cmode.COMMAND, 'rename '))
-	map('cd', fm.open_console(cmode.COMMAND, 'cd '))
-	map('f', fm.open_console(cmode.COMMAND_QUICK, 'find '))
-	map('bf', fm.open_console(cmode.COMMAND, 'filter '))
-	map('d<bg>', fm.hint('d//u// (disk usage) d//d// (cut)'))
-
-
-	# --------------------------------------------- jump to directories
-	map('gh', fm.cd('~'))
-	map('ge', fm.cd('/etc'))
-	map('gu', fm.cd('/usr'))
-	map('gd', fm.cd('/dev'))
-	map('gl', fm.cd('/lib'))
-	map('go', fm.cd('/opt'))
-	map('gv', fm.cd('/var'))
-	map('gr', 'g/', fm.cd('/'))
-	map('gm', fm.cd('/media'))
-	map('gn', fm.cd('/mnt'))
-	map('gs', fm.cd('/srv'))
-	map('gR', fm.cd(RANGERDIR))
-
-	# ------------------------------------------------------------ tabs
-	map('gc', ctrl('W'), fm.tab_close())
-	map('gt', TAB, fm.tab_move(1))
-	map('gT', KEY_BTAB, fm.tab_move(-1))
-	map('gn', ctrl('N'), fm.tab_new())
-	for n in range(10):
-		map('g' + str(n), fm.tab_open(n))
-		map('<A-' + str(n) + '>', fm.tab_open(n))
-
-	# ------------------------------------------------------- searching
-	map('/', fm.open_console(cmode.SEARCH))
-
-	map('n', fm.search())
-	map('N', fm.search(forward=False))
-
-	map('ct', fm.search(order='tag'))
-	map('cc', fm.search(order='ctime'))
-	map('cm', fm.search(order='mimetype'))
-	map('cs', fm.search(order='size'))
-	map('c<bg>', fm.hint('//c//time //m//imetype //s//ize'))
-
-	# ------------------------------------------------------- bookmarks
-	for key in ALLOWED_BOOKMARK_KEYS:
-		map("`" + key, "'" + key, fm.enter_bookmark(key))
-		map("m" + key, fm.set_bookmark(key))
-		map("um" + key, fm.unset_bookmark(key))
-	map("`<bg>", "'<bg>", "m<bg>", fm.draw_bookmarks())
-
-
-	map(':', ';', fm.open_console(cmode.COMMAND))
-
-	# ---------------------------------------------------- change views
-	map('i', fm.display_file())
-	map(ctrl('p'), fm.display_log())
-	map('?', KEY_F1, fm.display_help())
-	map('w', lambda arg: arg.fm.ui.open_taskview())
-
-	# ------------------------------------------------ system functions
-	map('ZZ', fm.exit())
-	map(ctrl('R'), fm.reset())
-	map('R', fm.reload_cwd())
-	map(ctrl('C'), fm.exit())
-
-	map(':', ';', fm.open_console(cmode.COMMAND))
-	map('>', fm.open_console(cmode.COMMAND_QUICK))
-	map('!', fm.open_console(cmode.OPEN))
-	map('r', fm.open_console(cmode.OPEN_QUICK))
-
-	return map
-
-def console_keys():
-	map = KeyMap()
-	map.merge(system_keys())
-
-	@map('<any>')
-	def type_key(arg):
-		arg.wdg.type_key(arg.match)
-
-	map('<up>', wdg.history_move(-1))
-	map('<down>', wdg.history_move(1))
-	map('<tab>', wdg.tab())
-
-#from pprint import pprint
-#pprint(browser_keys()._tree[106].__dict__)
-#raise SystemExit()
-
-ui_keys = browser_keys()
-taskview_keys = ui_keys
-pager_keys = ui_keys
-embedded_pager_keys = ui_keys
-console_keys = console_keys()
-directions = vim()
+# ---------------------------------------------------------
+# Define keys for everywhere:
+map = keymanager['general']
+@map('<dir>')
+def move(arg):
+	arg.wdg.move(narg=arg.n, **arg.direction)
+
+map('Q', fm.exit())
+map('<C-L>', fm.redraw_window())
+
+# ---------------------------------------------------------
+# Define keys in "general" context:
+map = keymanager['general']
+
+
+map('j', fm.move(down=1))
+map('Q', fm.exit())
+
+# --------------------------------------------------------- history
+map('H', fm.history_go(-1))
+map('L', fm.history_go(1))
+
+# ----------------------------------------------- tagging / marking
+map('t', fm.tag_toggle())
+map('T', fm.tag_remove())
+
+map(' ', fm.mark(toggle=True))
+map('v', fm.mark(all=True, toggle=True))
+map('V', fm.mark(all=True, val=False))
+
+# ---------------------------------------------------------
+# Define direction keys
+map = keymanager.get_context('directions')
+map('<down>', dir=Direction(down=1))
+map('<up>', dir=Direction(down=-1))
+map('<left>', dir=Direction(right=-1))
+map('<right>', dir=Direction(right=1))
+map('<home>', dir=Direction(down=0, absolute=True))
+map('<end>', dir=Direction(down=-1, absolute=True))
+map('<pagedown>', dir=Direction(down=1, pages=True))
+map('<pageup>', dir=Direction(down=-1, pages=True))
+map('%<any>', dir=Direction(down=1, percentage=True, absolute=True))
+map('<space>', dir=Direction(down=1, pages=True))
+map('<CR>', dir=Direction(down=1))
diff --git a/ranger/defaults/oldkeys.py b/ranger/defaults/oldkeys.py
new file mode 100644
index 00000000..467d26e6
--- /dev/null
+++ b/ranger/defaults/oldkeys.py
@@ -0,0 +1,555 @@
+# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+This is the default key configuration file of ranger.
+Syntax for binding keys: map(*keys, fnc)
+
+keys are one or more key-combinations which are either:
+* a string
+* an integer which represents an ascii code
+* a tuple of integers
+
+fnc is a function which is called with the CommandArgument object.
+
+The CommandArgument object has these attributes:
+arg.fm: the file manager instance
+arg.wdg: the widget or ui instance
+arg.n: the number typed before the key combination (if allowed)
+arg.keys: the string representation of the used key combination
+arg.keybuffer: the keybuffer instance
+
+Check ranger.keyapi for more information
+"""
+
+# NOTE: The "map" object used below is a callable CommandList
+# object and NOT the builtin python map function!
+
+from ranger.api.keys import *
+
+def _vimlike_aliases(map):
+	alias = map.alias
+
+	# the key 'k' will always do the same as KEY_UP, etc.
+	alias(KEY_UP, 'k')
+	alias(KEY_DOWN, 'j')
+	alias(KEY_LEFT, 'h')
+	alias(KEY_RIGHT, 'l')
+
+	alias(KEY_NPAGE, ctrl('f'))
+	alias(KEY_PPAGE, ctrl('b'))
+	alias(KEY_HOME, 'gg')
+	alias(KEY_END, 'G')
+
+
+def _emacs_aliases(map):
+	alias = map.alias
+	alias(KEY_LEFT, ctrl('b'))
+	alias(KEY_RIGHT, ctrl('f'))
+	alias(KEY_HOME, ctrl('a'))
+	alias(KEY_END, ctrl('e'))
+	alias(KEY_DC, ctrl('d'))
+	alias(DEL, ctrl('h'))
+
+
+def initialize_commands(map):
+	"""Initialize the commands for the main user interface"""
+
+	# -------------------------------------------------------- movement
+	_vimlike_aliases(map)
+	_basic_movement(map)
+
+	map.alias(KEY_LEFT, KEY_BACKSPACE, DEL)
+	map.alias(KEY_RIGHT, KEY_ENTER, ctrl('j'))
+
+	map('%', fm.move(to=50, percentage=True))
+	map(KEY_NPAGE, ctrl('f'), fm.move(down=1, pages=True))
+	map(KEY_PPAGE, ctrl('b'), fm.move(up=1, pages=True))
+	map(ctrl('d'), 'J', fm.move(down=0.5, pages=True))
+	map(ctrl('u'), 'K', fm.move(up=0.5, pages=True))
+
+	map(']', fm.traverse())
+	map('[', fm.history_go(-1))
+
+	# --------------------------------------------------------- history
+	map('H', fm.history_go(-1))
+	map('L', fm.history_go(1))
+
+	# ----------------------------------------------- tagging / marking
+	map('t', fm.tag_toggle())
+	map('T', fm.tag_remove())
+
+	map(' ', fm.mark(toggle=True))
+	map('v', fm.mark(all=True, toggle=True))
+	map('V', fm.mark(all=True, val=False))
+
+	# ------------------------------------------ file system operations
+	map('yy', fm.copy())
+	map('dd', fm.cut())
+	map('pp', fm.paste())
+	map('po', fm.paste(overwrite=True))
+	map('pl', fm.paste_symlink())
+	map('p', hint='press //p// once again to confirm pasting' \
+			', or //l// to create symlinks')
+
+	# ---------------------------------------------------- run programs
+	map('s', fm.execute_command(os.environ['SHELL']))
+	map('E', fm.edit_file())
+	map(',term', fm.execute_command('x-terminal-emulator', flags='d'))
+	map('du', fm.execute_command('du --max-depth=1 -h | less'))
+
+	# -------------------------------------------------- toggle options
+	map('b', fm.notify('Warning: settings are now changed with z!', bad=True))
+	map('z', hint="show_//h//idden //p//review_files //d//irectories_first " \
+		"//c//ollapse_preview flush//i//nput ca//s//e_insensitive")
+	map('zh', fm.toggle_boolean_option('show_hidden'))
+	map('zp', fm.toggle_boolean_option('preview_files'))
+	map('zP', fm.toggle_boolean_option('preview_directories'))
+	map('zi', fm.toggle_boolean_option('flushinput'))
+	map('zd', fm.toggle_boolean_option('sort_directories_first'))
+	map('zc', fm.toggle_boolean_option('collapse_preview'))
+	map('zs', fm.toggle_boolean_option('sort_case_insensitive'))
+
+	# ------------------------------------------------------------ sort
+	map('o', 'O', hint="//s//ize //b//ase//n//ame //m//time //t//ype //r//everse")
+	sort_dict = {
+		's': 'size',
+		'b': 'basename',
+		'n': 'basename',
+		'm': 'mtime',
+		't': 'type',
+	}
+
+	for key, val in sort_dict.items():
+		for key, is_capital in ((key, False), (key.upper(), True)):
+			# reverse if any of the two letters is capital
+			map('o' + key, fm.sort(func=val, reverse=is_capital))
+			map('O' + key, fm.sort(func=val, reverse=True))
+
+	map('or', 'Or', 'oR', 'OR', lambda arg: \
+			arg.fm.sort(reverse=not arg.fm.settings.sort_reverse))
+
+	# ----------------------------------------------- console shortcuts
+	@map("A")
+	def append_to_filename(arg):
+		command = 'rename ' + arg.fm.env.cf.basename
+		arg.fm.open_console(cmode.COMMAND, command)
+
+	map('cw', fm.open_console(cmode.COMMAND, 'rename '))
+	map('cd', fm.open_console(cmode.COMMAND, 'cd '))
+	map('f', fm.open_console(cmode.COMMAND_QUICK, 'find '))
+	map('tf', fm.open_console(cmode.COMMAND, 'filter '))
+	map('d', hint='d//u// (disk usage) d//d// (cut)')
+	map('@', fm.open_console(cmode.OPEN, '@'))
+	map('#', fm.open_console(cmode.OPEN, 'p!'))
+
+	# --------------------------------------------- jump to directories
+	map('gh', fm.cd('~'))
+	map('ge', fm.cd('/etc'))
+	map('gu', fm.cd('/usr'))
+	map('gd', fm.cd('/dev'))
+	map('gl', fm.cd('/lib'))
+	map('go', fm.cd('/opt'))
+	map('gv', fm.cd('/var'))
+	map('gr', 'g/', fm.cd('/'))
+	map('gm', fm.cd('/media'))
+	map('gn', fm.cd('/mnt'))
+	map('gt', fm.cd('/tmp'))
+	map('gs', fm.cd('/srv'))
+	map('gR', fm.cd(RANGERDIR))
+
+	# ------------------------------------------------------------ tabs
+	map('gc', ctrl('W'), fm.tab_close())
+	map('gt', TAB, fm.tab_move(1))
+	map('gT', KEY_BTAB, fm.tab_move(-1))
+	map('gn', ctrl('N'), fm.tab_new())
+	for n in range(10):
+		map('g' + str(n), fm.tab_open(n))
+
+	# ------------------------------------------------------- searching
+	map('/', fm.open_console(cmode.SEARCH))
+
+	map('n', fm.search())
+	map('N', fm.search(forward=False))
+
+	map('ct', fm.search(order='tag'))
+	map('cc', fm.search(order='ctime'))
+	map('cm', fm.search(order='mimetype'))
+	map('cs', fm.search(order='size'))
+	map('c', hint='//c//time //m//imetype //s//ize //t//agged')
+
+	# ------------------------------------------------------- bookmarks
+	for key in ALLOWED_BOOKMARK_KEYS:
+		map("`" + key, "'" + key, fm.enter_bookmark(key))
+		map("m" + key, fm.set_bookmark(key))
+		map("um" + key, fm.unset_bookmark(key))
+	map("`", "'", "m", "um", draw_bookmarks=True)
+
+	# ---------------------------------------------------- change views
+	map('i', fm.display_file())
+	map(ctrl('p'), fm.display_log())
+	map('?', KEY_F1, fm.display_help())
+	map('w', lambda arg: arg.fm.ui.open_taskview())
+
+	# ---------------------------------------------------------- custom
+	# This is useful to track watched episode of a series.
+	@bind(']')
+	def tag_next_and_run(arg):
+		fm = arg.fm
+		fm.tag_remove()
+		fm.tag_remove(movedown=False)
+		fm.tag_toggle()
+		fm.move_pointer(relative=-2)
+		fm.move_right()
+		fm.move_pointer(relative=1)
+
+	# "enter" = shortcut for "1l"
+	bind(KEY_ENTER, ctrl('j'), fm.move_right(mode=1))
+
+	# ------------------------------------------------ system functions
+	_system_functions(map)
+	map('ZZ', 'ZQ', fm.exit())
+	map(ctrl('R'), fm.reset())
+	map('R', fm.reload_cwd())
+	@map(ctrl('C'))
+	def ctrl_c(arg):
+		try:
+			item = arg.fm.loader.queue[0]
+		except:
+			arg.fm.notify("Type Q or :quit<Enter> to exit Ranger")
+		else:
+			arg.fm.notify("Aborting: " + item.get_description())
+			arg.fm.loader.remove(index=0)
+
+	map(':', ';', fm.open_console(cmode.COMMAND))
+	map('>', fm.open_console(cmode.COMMAND_QUICK))
+	map('!', fm.open_console(cmode.OPEN))
+	map('r', fm.open_console(cmode.OPEN_QUICK))
+
+	map.rebuild_paths()
+
+
+def initialize_console_commands(map):
+	"""Initialize the commands for the console widget only"""
+
+	_basic_movement(map)
+	_emacs_aliases(map)
+
+	# -------------------------------------------------------- movement
+	map(KEY_UP, wdg.history_move(-1))
+	map(KEY_DOWN, wdg.history_move(1))
+	map(KEY_HOME, wdg.move(right=0, absolute=True))
+	map(KEY_END, wdg.move(right=-1, absolute=True))
+
+	# ----------------------------------------- deleting / pasting text
+	map(KEY_DC, wdg.delete(0))
+	map(KEY_BACKSPACE, DEL, wdg.delete(-1))
+	map(ctrl('w'), wdg.delete_word())
+	map(ctrl('k'), wdg.delete_rest(1))
+	map(ctrl('u'), wdg.delete_rest(-1))
+	map(ctrl('y'), wdg.paste())
+
+	# ------------------------------------------------ system functions
+	map(KEY_F1, lambda arg: arg.fm.display_command_help(arg.wdg))
+	map(ctrl('c'), ESC, wdg.close())
+	map(ctrl('j'), KEY_ENTER, wdg.execute())
+	map(TAB, wdg.tab())
+	map(KEY_BTAB, wdg.tab(-1))
+
+	map.rebuild_paths()
+
+
+def initialize_taskview_commands(map):
+	"""Initialize the commands for the TaskView widget"""
+	_basic_movement(map)
+	_vimlike_aliases(map)
+	_system_functions(map)
+
+	# -------------------------------------------------- (re)move tasks
+	map('K', wdg.task_move(0))
+	map('J', wdg.task_move(-1))
+	map('dd', wdg.task_remove())
+
+	# ------------------------------------------------ system functions
+	map('?', fm.display_help())
+	map('w', 'q', ESC, ctrl('d'), ctrl('c'),
+			lambda arg: arg.fm.ui.close_taskview())
+
+	map.rebuild_paths()
+
+
+def initialize_pager_commands(map):
+	_base_pager_commands(map)
+	map('q', 'i', ESC, KEY_F1, lambda arg: arg.fm.ui.close_pager())
+	map.rebuild_paths()
+
+
+def initialize_embedded_pager_commands(map):
+	_base_pager_commands(map)
+	map('q', 'i', ESC, lambda arg: arg.fm.ui.close_embedded_pager())
+	map.rebuild_paths()
+
+
+def _base_pager_commands(map):
+	_basic_movement(map)
+	_vimlike_aliases(map)
+	_system_functions(map)
+
+	# -------------------------------------------------------- movement
+	map(KEY_LEFT, wdg.move(left=4))
+	map(KEY_RIGHT, wdg.move(right=4))
+	map(KEY_NPAGE, ctrl('f'), wdg.move(down=1, pages=True))
+	map(KEY_PPAGE, ctrl('b'), wdg.move(up=1, pages=True))
+	map(ctrl('d'), wdg.move(down=0.5, pages=True))
+	map(ctrl('u'), wdg.move(up=0.5, pages=True))
+	map(' ', wdg.move(down=0.8, pages=True))
+
+	# ---------------------------------------------------------- others
+	map('E', fm.edit_file())
+	map('?', fm.display_help())
+
+	# --------------------------------------------- less-like shortcuts
+	map.alias(KEY_NPAGE, 'f')
+	map.alias(KEY_PPAGE, 'b')
+	map.alias(ctrl('d'), 'd')
+	map.alias(ctrl('u'), 'u')
+
+
+def _system_functions(map):
+	map('Q', fm.exit())
+	map(ctrl('L'), fm.redraw_window())
+
+
+def _basic_movement(map):
+	map(KEY_DOWN, wdg.move(down=1))
+	map(KEY_UP, wdg.move(up=1))
+	map(KEY_RIGHT, wdg.move(right=1))
+	map(KEY_LEFT, wdg.move(left=1))
+	map(KEY_HOME, wdg.move(to=0))
+	map(KEY_END, wdg.move(to=-1))
+
+
+
+# ------ newkey:
+
+
+def base_directions():
+	# Direction Keys
+	map = KeyMap()
+	map('<down>', dir=Direction(down=1))
+	map('<up>', dir=Direction(down=-1))
+	map('<left>', dir=Direction(right=-1))
+	map('<right>', dir=Direction(right=1))
+	map('<home>', dir=Direction(down=0, absolute=True))
+	map('<end>', dir=Direction(down=-1, absolute=True))
+	map('<pagedown>', dir=Direction(down=1, pages=True))
+	map('<pageup>', dir=Direction(down=-1, pages=True))
+	map('%<any>', dir=Direction(down=1, percentage=True, absolute=True))
+	map('<space>', dir=Direction(down=1, pages=True))
+	map('<CR>', dir=Direction(down=1))
+
+	return map
+
+def vim():
+	# Direction Keys
+	map = KeyMap()
+	map.merge(base_directions())
+	map('j', alias='<down>')
+	map('k', alias='<up>')
+	map('h', alias='<left>')
+	map('l', alias='<right>')
+	map('gg', alias='<home>')
+	map('G', alias='<end>')
+	map('J', dir=Direction(down=20))
+	map('K', dir=Direction(down=-20))
+
+	return map
+
+def system_keys():
+	map = KeyMap()
+	map('Q', fm.exit())
+	map('<mouse>', fm.handle_mouse())
+	map('<C-L>', fm.redraw_window())
+	map('<resize>', fm.resize())
+
+	return map
+
+def browser_keys():
+	map = KeyMap()
+	map.merge(system_keys())
+
+	@map('<dir>')
+	def move(arg):
+		arg.fm.move(narg=arg.n, **arg.direction)
+	map('gg', fm.move(to=0))
+	map(fm.exit(), 'Q')
+
+	map('<cr>', fm.move(dir=Direction(right=1)))
+
+	# --------------------------------------------------------- history
+	map('H', fm.history_go(-1))
+	map('L', fm.history_go(1))
+
+	# ----------------------------------------------- tagging / marking
+	map('t', fm.tag_toggle())
+	map('T', fm.tag_remove())
+
+	map(' ', fm.mark(toggle=True))
+	map('v', fm.mark(all=True, toggle=True))
+	map('V', fm.mark(all=True, val=False))
+
+	# ------------------------------------------ file system operations
+	map('yy', fm.copy())
+	map('dd', fm.cut())
+	map('pp', fm.paste())
+	map('po', fm.paste(overwrite=True))
+	map('pl', fm.paste_symlink())
+	map('p<bg>', fm.hint('press //p// once again to confirm pasting' \
+			', or //l// to create symlinks'))
+
+	# ---------------------------------------------------- run programs
+	map('s', fm.execute_command(os.environ['SHELL']))
+	map('E', fm.edit_file())
+	map('.term', fm.execute_command('x-terminal-emulator', flags='d'))
+	map('du', fm.execute_command('du --max-depth=1 -h | less'))
+
+	# -------------------------------------------------- toggle options
+	map('b<bg>', fm.hint("bind_//h//idden //p//review_files" \
+		"//d//irectories_first //c//ollapse_preview flush//i//nput"))
+	map('bh', fm.toggle_boolean_option('show_hidden'))
+	map('bp', fm.toggle_boolean_option('preview_files'))
+	map('bi', fm.toggle_boolean_option('flushinput'))
+	map('bd', fm.toggle_boolean_option('directories_first'))
+	map('bc', fm.toggle_boolean_option('collapse_preview'))
+
+	# ------------------------------------------------------------ sort
+	map('o<bg>', 'O<bg>', fm.hint("//s//ize //b//ase//n//ame //m//time" \
+		" //t//ype //r//everse"))
+	sort_dict = {
+		's': 'size',
+		'b': 'basename',
+		'n': 'basename',
+		'm': 'mtime',
+		't': 'type',
+	}
+
+	for key, val in sort_dict.items():
+		for key, is_capital in ((key, False), (key.upper(), True)):
+			# reverse if any of the two letters is capital
+			map('o' + key, fm.sort(func=val, reverse=is_capital))
+			map('O' + key, fm.sort(func=val, reverse=True))
+
+	map('or', 'Or', 'oR', 'OR', lambda arg: \
+			arg.fm.sort(reverse=not arg.fm.settings.reverse))
+
+	# ----------------------------------------------- console shortcuts
+	@map("A")
+	def append_to_filename(arg):
+		command = 'rename ' + arg.fm.env.cf.basename
+		arg.fm.open_console(cmode.COMMAND, command)
+
+	map('cw', fm.open_console(cmode.COMMAND, 'rename '))
+	map('cd', fm.open_console(cmode.COMMAND, 'cd '))
+	map('f', fm.open_console(cmode.COMMAND_QUICK, 'find '))
+	map('bf', fm.open_console(cmode.COMMAND, 'filter '))
+	map('d<bg>', fm.hint('d//u// (disk usage) d//d// (cut)'))
+
+
+	# --------------------------------------------- jump to directories
+	map('gh', fm.cd('~'))
+	map('ge', fm.cd('/etc'))
+	map('gu', fm.cd('/usr'))
+	map('gd', fm.cd('/dev'))
+	map('gl', fm.cd('/lib'))
+	map('go', fm.cd('/opt'))
+	map('gv', fm.cd('/var'))
+	map('gr', 'g/', fm.cd('/'))
+	map('gm', fm.cd('/media'))
+	map('gn', fm.cd('/mnt'))
+	map('gs', fm.cd('/srv'))
+	map('gR', fm.cd(RANGERDIR))
+
+	# ------------------------------------------------------------ tabs
+	map('gc', ctrl('W'), fm.tab_close())
+	map('gt', TAB, fm.tab_move(1))
+	map('gT', KEY_BTAB, fm.tab_move(-1))
+	map('gn', ctrl('N'), fm.tab_new())
+	for n in range(10):
+		map('g' + str(n), fm.tab_open(n))
+		map('<A-' + str(n) + '>', fm.tab_open(n))
+
+	# ------------------------------------------------------- searching
+	map('/', fm.open_console(cmode.SEARCH))
+
+	map('n', fm.search())
+	map('N', fm.search(forward=False))
+
+	map('ct', fm.search(order='tag'))
+	map('cc', fm.search(order='ctime'))
+	map('cm', fm.search(order='mimetype'))
+	map('cs', fm.search(order='size'))
+	map('c<bg>', fm.hint('//c//time //m//imetype //s//ize'))
+
+	# ------------------------------------------------------- bookmarks
+	for key in ALLOWED_BOOKMARK_KEYS:
+		map("`" + key, "'" + key, fm.enter_bookmark(key))
+		map("m" + key, fm.set_bookmark(key))
+		map("um" + key, fm.unset_bookmark(key))
+	map("`<bg>", "'<bg>", "m<bg>", fm.draw_bookmarks())
+
+
+	map(':', ';', fm.open_console(cmode.COMMAND))
+
+	# ---------------------------------------------------- change views
+	map('i', fm.display_file())
+	map(ctrl('p'), fm.display_log())
+	map('?', KEY_F1, fm.display_help())
+	map('w', lambda arg: arg.fm.ui.open_taskview())
+
+	# ------------------------------------------------ system functions
+	map('ZZ', fm.exit())
+	map(ctrl('R'), fm.reset())
+	map('R', fm.reload_cwd())
+	map(ctrl('C'), fm.exit())
+
+	map(':', ';', fm.open_console(cmode.COMMAND))
+	map('>', fm.open_console(cmode.COMMAND_QUICK))
+	map('!', fm.open_console(cmode.OPEN))
+	map('r', fm.open_console(cmode.OPEN_QUICK))
+
+	return map
+
+def console_keys():
+	map = KeyMap()
+	map.merge(system_keys())
+
+	@map('<any>')
+	def type_key(arg):
+		arg.wdg.type_key(arg.match)
+
+	map('<up>', wdg.history_move(-1))
+	map('<down>', wdg.history_move(1))
+	map('<tab>', wdg.tab())
+
+#from pprint import pprint
+#pprint(browser_keys()._tree[106].__dict__)
+#raise SystemExit()
+
+ui_keys = browser_keys()
+taskview_keys = ui_keys
+pager_keys = ui_keys
+embedded_pager_keys = ui_keys
+console_keys = console_keys()
+directions = vim()
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index 8d355665..f81f1c5d 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -31,7 +31,7 @@ class UI(DisplayableContainer):
 	is_set_up = False
 	mousemask = curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION
 	load_mode = False
-	def __init__(self, keymap=None, env=None, fm=None):
+	def __init__(self, env=None, fm=None):
 		self._draw_title = os.environ["TERM"] in TERMINALS_WITH_TITLE
 		os.environ['ESCDELAY'] = '25'   # don't know a cleaner way
 
@@ -40,12 +40,8 @@ class UI(DisplayableContainer):
 		if fm is not None:
 			self.fm = fm
 
-		if keymap is None:
-			self.keymap = self.settings.keys.browser_keys()
-		else:
-			self.keymap = keymap
 		self.win = curses.initscr()
-		self.env.keybuffer.assign(self.keymap, self.settings.keys.directions)
+		self.env.keymanager.use_context('general')
 		self.env.keybuffer.clear()
 
 		DisplayableContainer.__init__(self, None)
@@ -131,11 +127,11 @@ class UI(DisplayableContainer):
 			self.env.keybuffer.clear()
 			return
 
-		self.env.key_append(key)
-
 		if DisplayableContainer.press(self, key):
 			return
 
+		self.env.keymanager.use_context('general')
+		self.env.key_append(key)
 		kbuf = self.env.keybuffer
 		cmd = kbuf.command
 
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index aaa85d8e..67bd7893 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -59,7 +59,6 @@ class Console(Widget):
 	def __init__(self, win):
 		from ranger.container import History
 		Widget.__init__(self, win)
-		self.keymap = self.settings.keys.console_keys
 		self.clear()
 		self.histories = []
 		# load histories from files
@@ -154,8 +153,6 @@ class Console(Widget):
 		self.line = ''
 
 	def press(self, key):
-		from curses.ascii import ctrl, ESC
-
 		keytuple = self.env.keybuffer.tuple_with_numbers()
 		try:
 			cmd = self.commandlist[keytuple]
diff --git a/ranger/gui/widgets/pager.py b/ranger/gui/widgets/pager.py
index e915f790..b99bf5db 100644
--- a/ranger/gui/widgets/pager.py
+++ b/ranger/gui/widgets/pager.py
@@ -40,11 +40,6 @@ class Pager(Widget):
 		self.markup = None
 		self.lines = []
 
-		if embedded:
-			self.keymap = self.settings.keys.embedded_pager_keys
-		else:
-			self.keymap = self.settings.keys.pager_keys
-
 	def move_horizontal(self, *a, **k):
 		"""For compatibility"""
 		self.fm.notify("Your keys.py is out of date. Can't scroll!", bad=True)
diff --git a/ranger/gui/widgets/taskview.py b/ranger/gui/widgets/taskview.py
index f7937e11..fe31646d 100644
--- a/ranger/gui/widgets/taskview.py
+++ b/ranger/gui/widgets/taskview.py
@@ -30,7 +30,6 @@ class TaskView(Widget, Accumulator):
 		Widget.__init__(self, win)
 		Accumulator.__init__(self)
 		self.scroll_begin = 0
-		self.keymap = self.settings.keys.taskview_keys
 
 	def draw(self):
 		base_clr = deque()
diff --git a/ranger/shared/settings.py b/ranger/shared/settings.py
index a4a58e6e..e4a58f33 100644
--- a/ranger/shared/settings.py
+++ b/ranger/shared/settings.py
@@ -154,10 +154,16 @@ class SettingsAware(object):
 		except ImportError:
 			from ranger.defaults import apps
 		settings._raw_set('apps', apps)
+
+		SettingsAware.settings = settings
+
+	@staticmethod
+	def _setup_keys():  # ugly! but works.
+		import ranger.api.keys
+		import ranger.shared
+		env = ranger.shared.EnvironmentAware.env
+		ranger.api.keys.keymanager = env.keymanager
 		try:
 			import keys
 		except ImportError:
 			from ranger.defaults import keys
-		settings._raw_set('keys', keys)
-
-		SettingsAware.settings = settings
diff --git a/test/tc_newkeys.py b/test/tc_newkeys.py
index c953e88b..b1cb42fb 100644
--- a/test/tc_newkeys.py
+++ b/test/tc_newkeys.py
@@ -24,7 +24,7 @@ import sys
 
 class PressTestCase(TestCase):
 	"""Some useful methods for the actual test"""
-	def _mkpress(self, keybuffer, keymap):
+	def _mkpress(self, keybuffer, _=0):
 		def press(keys):
 			keybuffer.clear()
 			match = keybuffer.simulate_press(keys)
@@ -492,5 +492,42 @@ class Test(PressTestCase):
 		s.replace('Y')
 		self.assertNotEqual(t._tree, u._tree)
 
+	def test_keymap_with_context(self):
+		def func(arg):
+			return 5
+		def getdown(arg):
+			return arg.direction.down()
+
+		buffer = KeyBuffer(None, None)
+		press = self._mkpress(buffer)
+		kmc = KeyManager(buffer, ['foo', 'bar'])
+
+		map = kmc.get_context('foo')
+		map('a', func)
+		map('b', func)
+		map = kmc.get_context('bar')
+		map('c', func)
+		map('<dir>', getdown)
+
+		kmc.map('directions', 'j', dir=Direction(down=1))
+
+		kmc.use_context('foo')
+		self.assertEqual(5, press('a'))
+		self.assertEqual(5, press('b'))
+		self.assertPressFails(buffer, 'c')
+
+		kmc.use_context('bar')
+		self.assertPressFails(buffer, 'a')
+		self.assertPressFails(buffer, 'b')
+		self.assertEqual(5, press('c'))
+		self.assertEqual(1, press('j'))
+		kmc.use_context('foo')
+		kmc.use_context('foo')
+		kmc.use_context('foo')
+		kmc.use_context('bar')
+		kmc.use_context('foo')
+		kmc.use_context('bar')
+		kmc.use_context('bar')
+		self.assertEqual(1, press('j'))
 
 if __name__ == '__main__': main()
diff --git a/test/tc_ui.py b/test/tc_ui.py
index 98ddff93..3c659459 100644
--- a/test/tc_ui.py
+++ b/test/tc_ui.py
@@ -28,7 +28,7 @@ class Test(unittest.TestCase):
 	def setUp(self):
 
 		self.fm = Fake()
-		self.ui = ui.UI(env=Fake(), fm=self.fm, keymap=Fake())
+		self.ui = ui.UI(env=Fake(), fm=self.fm)
 
 		def fakesetup():
 			self.ui.widget = Fake()