diff --git a/game/engines/default/data/keybinds/actions.lua b/game/engines/default/data/keybinds/actions.lua
index d6e64838e6175c3460530715d319bc84b7b970f7..4b6f879f13715963dd4c8953b8a83fd9038cfc60 100644
--- a/game/engines/default/data/keybinds/actions.lua
+++ b/game/engines/default/data/keybinds/actions.lua
@@ -18,34 +18,34 @@
 -- darkgod@te4.org
 
 defineAction{
-	default = { "uni:<", "uni:>" },
+	default = { "sym:=<:false:false:false:false", "sym:=>:false:false:false:false" },
 	type = "CHANGE_LEVEL",
 	group = "actions",
 	name = "Go to next/previous level",
 }
 
 defineAction{
-	default = { "uni:G" },
+	default = { "sym:=g:false:true:false:false" },
 	type = "LEVELUP",
 	group = "actions",
 	name = "Levelup window",
 }
 defineAction{
-	default = { "uni:m" },
+	default = { "sym:=m:false:false:false:false" },
 	type = "USE_TALENTS",
 	group = "actions",
 	name = "Use talents",
 }
 
 defineAction{
-	default = { "uni:j", "sym:_q:true:false:false:false" },
+	default = { "sym:=j:false:false:false:false", "sym:_q:true:false:false:false" },
 	type = "SHOW_QUESTS",
 	group = "actions",
 	name = "Show quests",
 }
 
 defineAction{
-	default = { "uni:r", "uni:R" },
+	default = { "sym:=r:false:false:false:false", "sym:=r:false:true:false:false" },
 	type = "REST",
 	group = "actions",
 	name = "Rest for a while",
@@ -73,7 +73,7 @@ defineAction{
 }
 
 defineAction{
-	default = { "uni:l" },
+	default = { "sym:=l:false:false:false:false" },
 	type = "LOOK_AROUND",
 	group = "actions",
 	name = "Look around",
@@ -87,14 +87,14 @@ defineAction{
 }
 
 defineAction{
-	default = { "sym:_t:true:false:false:false" },
+	default = { "sym:=t:true:false:false:false" },
 	type = "SHOW_TIME",
 	group = "actions",
 	name = "Show game calendar",
 }
 
 defineAction{
-	default = { "uni:c", "uni:C" },
+	default = { "sym:=c", "sym:=c:false:true:false:false" },
 	type = "SHOW_CHARACTER_SHEET",
 	group = "actions",
 	name = "Show character sheet",
@@ -107,13 +107,6 @@ defineAction{
 	name = "Switch graphical modes",
 }
 
-defineAction{
-	default = { "uni:?" },
-	type = "HELP",
-	group = "actions",
-	name = "Help",
-}
-
 defineAction{
 	default = { "sym:_RETURN:false:false:false:false", "sym:_KP_ENTER:false:false:false:false" },
 	type = "ACCEPT",
diff --git a/game/engines/default/data/keybinds/interface.lua b/game/engines/default/data/keybinds/interface.lua
index 655bdb02054bc4bfaebb34e0026f86b80c43c3a2..7bb381e8bdd96b2a1d1478d5733747b90b959986 100644
--- a/game/engines/default/data/keybinds/interface.lua
+++ b/game/engines/default/data/keybinds/interface.lua
@@ -25,7 +25,7 @@ defineAction{
 }
 
 defineAction{
-	default = { "sym:_m:true:false:false:false" },
+	default = { "sym:=m:true:false:false:false" },
 	type = "SHOW_MESSAGE_LOG",
 	group = "actions",
 	name = "Show message log",
diff --git a/game/engines/default/data/keybinds/inventory.lua b/game/engines/default/data/keybinds/inventory.lua
index 26b5ec066d7b9688a37cf6162f6f0eb798889a05..f8501c3a83197b86f43f404b4da35d005d78ee5a 100644
--- a/game/engines/default/data/keybinds/inventory.lua
+++ b/game/engines/default/data/keybinds/inventory.lua
@@ -18,53 +18,53 @@
 -- darkgod@te4.org
 
 defineAction{
-	default = { "uni:i", },
+	default = { "sym:=i:false:false:false:false", },
 	type = "SHOW_INVENTORY",
 	group = "inventory",
 	name = "Show inventory",
 }
 defineAction{
-	default = { "uni:e", },
+	default = { "sym:=e:false:false:false:false", },
 	type = "SHOW_EQUIPMENT",
 	group = "inventory",
 	name = "Show equipment",
 }
 
 defineAction{
-	default = { "uni:g" },
+	default = { "sym:=g:false:false:false:false" },
 	type = "PICKUP_FLOOR",
 	group = "actions",
 	name = "Pickup items",
 }
 defineAction{
-	default = { "uni:d" },
+	default = { "sym:=d:false:false:false:false" },
 	type = "DROP_FLOOR",
 	group = "actions",
 	name = "Drop items",
 }
 
 defineAction{
-	default = { "uni:w", },
+	default = { "sym:=w:false:false:false:false", },
 	type = "WEAR_ITEM",
 	group = "inventory",
 	name = "Wield/wear items",
 }
 defineAction{
-	default = { "uni:t", },
+	default = { "sym:=t:false:false:false:false", },
 	type = "TAKEOFF_ITEM",
 	group = "inventory",
 	name = "Takeoff items",
 }
 
 defineAction{
-	default = { "uni:u", },
+	default = { "sym:=u:false:false:false:false", },
 	type = "USE_ITEM",
 	group = "inventory",
 	name = "Use items",
 }
 
 defineAction{
-	default = { "uni:x", },
+	default = { "sym:=x:false:false:false:false", },
 	type = "QUICK_SWITCH_WEAPON",
 	group = "inventory",
 	name = "Quick switch weapons set",
diff --git a/game/engines/default/data/keybinds/move.lua b/game/engines/default/data/keybinds/move.lua
index efb06861bc08aee800e1ba15b08d4bf088146b73..184bd117d832ea9324fb02de09b0cb97d78a08b5 100644
--- a/game/engines/default/data/keybinds/move.lua
+++ b/game/engines/default/data/keybinds/move.lua
@@ -76,7 +76,7 @@ defineAction{
 
 -- Running
 defineAction{
-	default = { "uni:." },
+	default = { "sym:=.:false:false:false:false" },
 	type = "RUN",
 	group = "movement",
 	name = "Run",
diff --git a/game/engines/default/engine/Birther.lua b/game/engines/default/engine/Birther.lua
index c2d8ae0ba517f64d9fe60b27c923997269898931..b0fd3b519eeb0d7af3a227d42e3580bd7e03847c 100644
--- a/game/engines/default/engine/Birther.lua
+++ b/game/engines/default/engine/Birther.lua
@@ -139,6 +139,8 @@ function _M:on_register()
 	self:next()
 	self:select(self.list[self.c_list.sel])
 
+	self.key:unicodeInput(true)
+
 	if __module_extra_info.no_quickbirth then return end
 	if self.quickbirth then
 		if __module_extra_info.auto_quickbirth then
diff --git a/game/engines/default/engine/DebugConsole.lua b/game/engines/default/engine/DebugConsole.lua
index d4d6bf76a422f377119b85804095608590f5589c..4cd67c84bc57e52fc8b4a89aa506e724822bec5c 100644
--- a/game/engines/default/engine/DebugConsole.lua
+++ b/game/engines/default/engine/DebugConsole.lua
@@ -31,6 +31,7 @@ commands = {}
 
 function _M:init()
 	engine.Dialog.init(self, "Lua Console", core.display.size())
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
 	self:keyCommands{
 		_RETURN = function()
 			table.insert(self.commands, self.line)
diff --git a/game/engines/default/engine/KeyBind.lua b/game/engines/default/engine/KeyBind.lua
index d1f374145665292cbd819c2bf615323cd0281af2..09b3acc6b5429047e3b66ceb30b317eeabfb38d6 100644
--- a/game/engines/default/engine/KeyBind.lua
+++ b/game/engines/default/engine/KeyBind.lua
@@ -117,6 +117,7 @@ end
 function _M:init()
 	engine.KeyCommand.init(self)
 	self.virtuals = {}
+	self.use_unicode = false
 
 	self:bindKeys()
 end
@@ -141,8 +142,8 @@ function _M:findBoundKeys(virtual)
 	return unpack(bs)
 end
 
-function _M:makeKeyString(sym, ctrl, shift, alt, meta, unicode)
-	return ("sym:%s:%s:%s:%s:%s"):format(tostring(self.sym_to_name[sym] or sym), tostring(ctrl), tostring(shift), tostring(alt), tostring(meta)), unicode and "uni:"..unicode
+function _M:makeKeyString(sym, ctrl, shift, alt, meta, unicode, key)
+	return ("sym:%s:%s:%s:%s:%s"):format(tostring(self.sym_to_name[sym] or sym), tostring(ctrl), tostring(shift), tostring(alt), tostring(meta)), key and ("sym:=%s:%s:%s:%s:%s"):format(key, tostring(ctrl), tostring(shift), tostring(alt), tostring(meta)), unicode and "uni:"..unicode
 end
 
 function _M:makeGestureString(gesture)
@@ -166,12 +167,14 @@ function _M:formatKeyString(ks)
 		shift = shift == "true" and true or false
 		alt = alt == "true" and true or false
 		meta = meta == "true" and true or false
-		if tonumber(sym) then
-			sym = tonumber(sym)
+		if sym:sub(1, 1) == "=" then
+			sym = sym:sub(2)
 		else
-			sym = _M[sym]
+			if tonumber(sym) then sym = tonumber(sym)
+			else sym = _M[sym]
+			end
+			sym = core.key.symName(sym)
 		end
-		sym = core.key.symName(sym)
 
 		if ctrl then sym = "[C]+"..sym end
 		if shift then sym = "[S]+"..sym end
@@ -203,24 +206,32 @@ function _M:formatKeyString(ks)
 end
 
 function _M:receiveKey(sym, ctrl, shift, alt, meta, unicode, isup, key, ismouse)
+	if unicode and not self.use_unicode then return end
+
 	self:handleStatus(sym, ctrl, shift, alt, meta, unicode, isup)
 
 	if self.any_key then self.any_key(sym, ctrl, shift, alt, meta, unicode, isup, key) end
 
 	local ks, us
-	if not ismouse then ks, us = self:makeKeyString(sym, ctrl, shift, alt, meta, unicode)
+	if not ismouse then ks, kks, us = self:makeKeyString(sym, ctrl, shift, alt, meta, unicode, key)
 	else ks = self:makeMouseString(sym, ctrl, shift, alt, meta) end
---	print("[BIND]", sym, ctrl, shift, alt, meta, unicode, " :=: ", ks, us, " ?=? ", self.binds[ks], us and self.binds[us])
+--	print("[BIND]", sym, ctrl, shift, alt, meta, unicode, " :=: ", ks, kks, us, " ?=? ", self.binds[ks], kks and self.binds[kks], us and self.binds[us])
 	if self.binds[ks] then
 		for virt, _ in pairs(self.binds[ks]) do if self.virtuals[virt] then
 			if isup and not _M.binds_def[virt].updown then return end
-			self.virtuals[virt](sym, ctrl, shift, alt, meta, unicode, isup)
+			self.virtuals[virt](sym, ctrl, shift, alt, meta, unicode, isup, key)
+			return true
+		end end
+	elseif kks and self.binds[kks] then
+		for virt, _ in pairs(self.binds[kks]) do if self.virtuals[virt] then
+			if isup and not _M.binds_def[virt].updown then return end
+			self.virtuals[virt](sym, ctrl, shift, alt, meta, unicode, isup, key)
 			return true
 		end end
 	elseif us and self.binds[us] then
 		for virt, _ in pairs(self.binds[us]) do if self.virtuals[virt] then
 --			if isup and not _M.binds_def[virt].updown then return end
-			self.virtuals[virt](sym, ctrl, shift, alt, meta, unicode, isup)
+			self.virtuals[virt](sym, ctrl, shift, alt, meta, unicode, isup, key)
 			return true
 		end end
 	end
@@ -228,6 +239,11 @@ function _M:receiveKey(sym, ctrl, shift, alt, meta, unicode, isup, key, ismouse)
 	return engine.KeyCommand.receiveKey(self, sym, ctrl, shift, alt, meta, unicode, isup, key)
 end
 
+--- Allow receiving unicode events
+function _M:unicodeInput(v)
+	self.use_unicode = v
+end
+
 --- Reset all binds
 function _M:reset()
 	self.virtuals = {}
diff --git a/game/engines/default/engine/dialogs/Chat.lua b/game/engines/default/engine/dialogs/Chat.lua
index 8ace9104d4b801faab5754b69ea0dd9caa914952..86e2ad1a9dae5b87267bd8c29bf911dac0715a7b 100644
--- a/game/engines/default/engine/dialogs/Chat.lua
+++ b/game/engines/default/engine/dialogs/Chat.lua
@@ -57,6 +57,10 @@ function _M:init(chat, id)
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:select(item)
 	local a = self.chat:get(self.cur_id).answers[item.answer]
 	if not a then return end
diff --git a/game/engines/default/engine/dialogs/ShowEquipInven.lua b/game/engines/default/engine/dialogs/ShowEquipInven.lua
index aad90445aa1bcf631b0e29c4bbfbf58d55428fd8..74e08a2fc92efc29fd9d9028781741f19e3aa7d7 100644
--- a/game/engines/default/engine/dialogs/ShowEquipInven.lua
+++ b/game/engines/default/engine/dialogs/ShowEquipInven.lua
@@ -135,6 +135,10 @@ function _M:init(title, actor, filter, action, on_select)
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:defineHotkey(id)
 	if not self.actor or not self.actor.hotkey then return end
 
diff --git a/game/engines/default/engine/dialogs/ShowEquipment.lua b/game/engines/default/engine/dialogs/ShowEquipment.lua
index 1db6713e3258524f4738872c30348e2d3e3157a4..ac773a2e456c54eaf92140f4c19a69c33469bd3e 100644
--- a/game/engines/default/engine/dialogs/ShowEquipment.lua
+++ b/game/engines/default/engine/dialogs/ShowEquipment.lua
@@ -67,6 +67,10 @@ function _M:init(title, actor, filter, action)
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:select(item)
 	if item and self.uis[2] then
 		self.c_desc:switchItem(item, item.desc)
diff --git a/game/engines/default/engine/dialogs/ShowInventory.lua b/game/engines/default/engine/dialogs/ShowInventory.lua
index 06c677c92c6fc542e537116bc5b6fcd51b496830..f7c3185ae49ffce98bf644bc2ba7384930d2f4ed 100644
--- a/game/engines/default/engine/dialogs/ShowInventory.lua
+++ b/game/engines/default/engine/dialogs/ShowInventory.lua
@@ -65,6 +65,10 @@ function _M:init(title, inven, filter, action, actor)
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:select(item)
 	if item then
 		self.c_desc:switchItem(item, item.desc)
diff --git a/game/engines/default/engine/dialogs/ShowPickupFloor.lua b/game/engines/default/engine/dialogs/ShowPickupFloor.lua
index e86b22f669b7aa245bf70dcb891bec35cdba5e2f..5ec7a5e974befa511413e041d0cf615898e76c69 100644
--- a/game/engines/default/engine/dialogs/ShowPickupFloor.lua
+++ b/game/engines/default/engine/dialogs/ShowPickupFloor.lua
@@ -73,6 +73,10 @@ function _M:init(title, x, y, filter, action, takeall, actor)
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:used()
 	if self.taking_all then return end
 	self:generateList()
diff --git a/game/engines/default/engine/dialogs/ShowStore.lua b/game/engines/default/engine/dialogs/ShowStore.lua
index 62785e259988d8a896e31ef1fffe0ffd4de9bdb8..721fb63925220e82a831b9154e97e1aea42fe920 100644
--- a/game/engines/default/engine/dialogs/ShowStore.lua
+++ b/game/engines/default/engine/dialogs/ShowStore.lua
@@ -80,6 +80,10 @@ function _M:init(title, store_inven, actor_inven, store_filter, actor_filter, ac
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:updateStore()
 	self:generateList()
 end
diff --git a/game/engines/default/engine/dialogs/UseTalents.lua b/game/engines/default/engine/dialogs/UseTalents.lua
index 3f606e3b0c06b65ee9c08c06737a10dfe9a5d8ea..e8c72d0e697f226e5a350ae314319decd075eb3e 100644
--- a/game/engines/default/engine/dialogs/UseTalents.lua
+++ b/game/engines/default/engine/dialogs/UseTalents.lua
@@ -114,6 +114,10 @@ Check out the keybinding screen in the game menu to bind hotkeys to a key (defau
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:defineHotkey(id)
 	if not self.actor.hotkey then return end
 	local item = self.list[self.c_list.sel]
diff --git a/game/engines/default/engine/interface/ActorInventory.lua b/game/engines/default/engine/interface/ActorInventory.lua
index 066bf099bfa7526eb3272ec1031f124da4170fcc..8c60c39532aefafcf3d8015c498f7970b9065a27 100644
--- a/game/engines/default/engine/interface/ActorInventory.lua
+++ b/game/engines/default/engine/interface/ActorInventory.lua
@@ -77,6 +77,17 @@ function _M:getInven(id)
 	end
 end
 
+--- Tells if an inventory still has room left
+function _M:canAddToInven(id)
+	if type(id) == "number" then
+		return #self.inven[id] < self.inven[id].max
+	elseif type(id) == "string" then
+		return #self.inven[self["INVEN_"..id]] < self.inven[self["INVEN_"..id]].max
+	else
+		return id
+	end
+end
+
 --- Adds an object to an inventory
 -- @return false if the object could not be added otherwise true and the inventory index where it is now
 function _M:addObject(inven_id, o)
diff --git a/game/engines/default/engine/interface/PlayerHotkeys.lua b/game/engines/default/engine/interface/PlayerHotkeys.lua
index 11003eb6222309ce006a262c6dba7df0e9e44ded..25422ca9729f733639b74aca111707d4385107ed 100644
--- a/game/engines/default/engine/interface/PlayerHotkeys.lua
+++ b/game/engines/default/engine/interface/PlayerHotkeys.lua
@@ -87,12 +87,12 @@ end
 
 --- Switch to previous hotkey page
 function _M:prevHotkeyPage()
-	self.hotkey_page = util.boundWrap(self.hotkey_page - 1, 1, 3)
+	self.hotkey_page = util.boundWrap(self.hotkey_page - 1, 1, 4)
 	self.changed = true
 end
 --- Switch to next hotkey page
 function _M:nextHotkeyPage()
-	self.hotkey_page = util.boundWrap(self.hotkey_page + 1, 1, 3)
+	self.hotkey_page = util.boundWrap(self.hotkey_page + 1, 1, 4)
 	self.changed = true
 end
 --- Switch to hotkey page
diff --git a/game/engines/default/engine/ui/Focusable.lua b/game/engines/default/engine/ui/Focusable.lua
index 704b13eac732a1d1e710163682901eef43493572..1b502c88c2d0e50d275bfc42f30fad83df2b0805 100644
--- a/game/engines/default/engine/ui/Focusable.lua
+++ b/game/engines/default/engine/ui/Focusable.lua
@@ -31,4 +31,5 @@ function _M:setFocus(v)
 	if not v then
 		self.focus_decay = self.focus_decay_max
 	end
+	if self.on_focus then self:on_focus(v) end
 end
diff --git a/game/engines/default/engine/ui/Numberbox.lua b/game/engines/default/engine/ui/Numberbox.lua
index 9a879f9f19e8ede59ad039114476cf01edbfaa96..31c57bfd252225119cfc47cf92b4a4c8d1f5119e 100644
--- a/game/engines/default/engine/ui/Numberbox.lua
+++ b/game/engines/default/engine/ui/Numberbox.lua
@@ -43,6 +43,10 @@ function _M:init(t)
 	Base.init(self, t)
 end
 
+function _M:on_focus(v)
+	game:onTickEnd(function() self.key:unicodeInput(v) end)
+end
+
 function _M:generate()
 	self.mouse:reset()
 	self.key:reset()
diff --git a/game/engines/default/engine/ui/Textbox.lua b/game/engines/default/engine/ui/Textbox.lua
index 828e6746dd043a182e75928dbf2aca33d9e7ff37..8bb644b939a2aab40527f3bbb22d66f615ce8841 100644
--- a/game/engines/default/engine/ui/Textbox.lua
+++ b/game/engines/default/engine/ui/Textbox.lua
@@ -44,6 +44,10 @@ function _M:init(t)
 	Base.init(self, t)
 end
 
+function _M:on_focus(v)
+	game:onTickEnd(function() self.key:unicodeInput(v) end)
+end
+
 function _M:generate()
 	self.mouse:reset()
 	self.key:reset()
diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua
index 95560b979fec6d727cca2ce046f0d2e199ea46d3..6b23ef0f8d0a39e5e70079536aaf921eec0fba19 100644
--- a/game/engines/default/engine/utils.lua
+++ b/game/engines/default/engine/utils.lua
@@ -130,6 +130,12 @@ function table.listify(t)
 	return tt
 end
 
+function table.keys_to_values(t)
+	local tt = {}
+	for k, e in pairs(t) do tt[e] = k end
+	return tt
+end
+
 function table.keys(t)
 	local tt = {}
 	for k, e in pairs(t) do tt[#tt+1] = k end
diff --git a/game/modules/tome/dialogs/CharacterSheet.lua b/game/modules/tome/dialogs/CharacterSheet.lua
index 58b4e34850b1caf36cebe8e0bcd9b9bf3598a931..b901f920b526e98369693c6fe8601e18bac35486 100644
--- a/game/modules/tome/dialogs/CharacterSheet.lua
+++ b/game/modules/tome/dialogs/CharacterSheet.lua
@@ -109,6 +109,10 @@ function _M:switchTo(kind)
 	self:updateKeys()
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:updateKeys()
 	self.key:addCommands{
 	_TAB = function() self:tabTabs() end,
diff --git a/game/modules/tome/dialogs/LevelupDialog.lua b/game/modules/tome/dialogs/LevelupDialog.lua
index 8aed9a45d1a98e3f0a8e09f44f36b0da93e10048..8f7352e5408c8affd79d485acd0848f10b4653de 100644
--- a/game/modules/tome/dialogs/LevelupDialog.lua
+++ b/game/modules/tome/dialogs/LevelupDialog.lua
@@ -230,6 +230,8 @@ end
 
 function _M:updateKeys(kind)
 	self.key:reset()
+	self.key:unicodeInput(true)
+
 	if kind == "Stats" then
 		self.key:addCommands{
 			_TAB = function() self:tabTabs() end,
diff --git a/game/modules/tome/dialogs/PartyOrder.lua b/game/modules/tome/dialogs/PartyOrder.lua
index 391763ad308527c122595d8dda009447b4a451e3..299c0be8d19abb9ac5b284e7bea13bd3d0d6258c 100644
--- a/game/modules/tome/dialogs/PartyOrder.lua
+++ b/game/modules/tome/dialogs/PartyOrder.lua
@@ -50,6 +50,10 @@ function _M:init(actor, def)
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/PartySelect.lua b/game/modules/tome/dialogs/PartySelect.lua
index b6476019b31317552a4ba7290797528d2c5da8a8..16930a84b6f387e2d3a5a93e2f049e3bcb73b0a3 100644
--- a/game/modules/tome/dialogs/PartySelect.lua
+++ b/game/modules/tome/dialogs/PartySelect.lua
@@ -39,6 +39,10 @@ function _M:init()
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/UseTalents.lua b/game/modules/tome/dialogs/UseTalents.lua
index 8b0157b2648ec67a67b312c600680e4df1630f7a..e0e54a34556bdb584eb0e2874951476b0e0611a7 100644
--- a/game/modules/tome/dialogs/UseTalents.lua
+++ b/game/modules/tome/dialogs/UseTalents.lua
@@ -125,6 +125,10 @@ Right click or press '*' to configure.
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:defineHotkey(id)
 	if not self.actor.hotkey then return end
 	local item = self.cur_item
diff --git a/game/modules/tome/dialogs/debug/AlterFaction.lua b/game/modules/tome/dialogs/debug/AlterFaction.lua
index 87680dae84a03517265a776aa8d7d2a0ff70d6c8..884567155baa4c804bf72afe9b3aa5def104b18d 100644
--- a/game/modules/tome/dialogs/debug/AlterFaction.lua
+++ b/game/modules/tome/dialogs/debug/AlterFaction.lua
@@ -49,6 +49,10 @@ function _M:init()
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/debug/ChangeZone.lua b/game/modules/tome/dialogs/debug/ChangeZone.lua
index 0ffe8200b04854fbc1b523b5eade2c5fd2cbc561..6c083e01d69236c559b35e9b624712d993052343 100644
--- a/game/modules/tome/dialogs/debug/ChangeZone.lua
+++ b/game/modules/tome/dialogs/debug/ChangeZone.lua
@@ -48,6 +48,10 @@ function _M:init()
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/debug/CreateItem.lua b/game/modules/tome/dialogs/debug/CreateItem.lua
index 0fa7ad036b72b9093208c129f24dc9688cbaadd1..dc4de16fd7f67b28d808e3c788f40a7d5c172439 100644
--- a/game/modules/tome/dialogs/debug/CreateItem.lua
+++ b/game/modules/tome/dialogs/debug/CreateItem.lua
@@ -48,6 +48,10 @@ function _M:init()
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/debug/DebugMain.lua b/game/modules/tome/dialogs/debug/DebugMain.lua
index c9af7d7fc2785959d8d19cb83e08319560c68804..4c5c012bd7cddb3f7334ce431c87dad2b48d1531 100644
--- a/game/modules/tome/dialogs/debug/DebugMain.lua
+++ b/game/modules/tome/dialogs/debug/DebugMain.lua
@@ -39,6 +39,10 @@ function _M:init()
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/debug/GrantQuest.lua b/game/modules/tome/dialogs/debug/GrantQuest.lua
index b54de23077803d49c6a61707dc0c66327f4b0147..e88af1b087cd20dc01a24472f1a0f19993fa74aa 100644
--- a/game/modules/tome/dialogs/debug/GrantQuest.lua
+++ b/game/modules/tome/dialogs/debug/GrantQuest.lua
@@ -48,6 +48,10 @@ function _M:init()
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/debug/SummonCreature.lua b/game/modules/tome/dialogs/debug/SummonCreature.lua
index 06a5f163f3f7b381c1ce61262439c0105ab30856..72edd95b42c72c5ab4ff7907ee15f8c523dbb2b2 100644
--- a/game/modules/tome/dialogs/debug/SummonCreature.lua
+++ b/game/modules/tome/dialogs/debug/SummonCreature.lua
@@ -48,6 +48,10 @@ function _M:init()
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/orders/Behavior.lua b/game/modules/tome/dialogs/orders/Behavior.lua
index 5f8532f09855723be0eb23bc79241930463ed0e5..8225e8f13e7b88b04f8a5c71b6af06477a245bea 100644
--- a/game/modules/tome/dialogs/orders/Behavior.lua
+++ b/game/modules/tome/dialogs/orders/Behavior.lua
@@ -40,6 +40,10 @@ function _M:init(actor, def)
 	self.key:addBinds{ EXIT = function() game:unregisterDialog(self) end, }
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 	game:unregisterDialog(self)
diff --git a/game/modules/tome/dialogs/orders/Talents.lua b/game/modules/tome/dialogs/orders/Talents.lua
index 4334bbf45fa26ee59e779fe25b2f85312ee588d3..65177950e27467c4135332b6cb37090b85f41e1c 100644
--- a/game/modules/tome/dialogs/orders/Talents.lua
+++ b/game/modules/tome/dialogs/orders/Talents.lua
@@ -75,6 +75,10 @@ Word travels fast in Maj'Eyal, and if %s is a summon all future summons of the s
 	}
 end
 
+function _M:on_register()
+	game:onTickEnd(function() self.key:unicodeInput(true) end)
+end
+
 function _M:use(item)
 	if not item then return end
 
diff --git a/src/core_lua.c b/src/core_lua.c
index e146c53eeea2e5f7377d680cb9c49728c05956a6..038043de918cf4d70c8d939c45dcf214dc4140e1 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -204,12 +204,20 @@ static int lua_flush_key_events(lua_State *L)
 	return 0;
 }
 
+static int lua_key_unicode(lua_State *L)
+{
+	if (lua_isboolean(L, 1)) SDL_StartTextInput();
+	else SDL_StopTextInput();
+	return 0;
+}
+
 static const struct luaL_reg keylib[] =
 {
 	{"set_current_handler", lua_set_current_keyhandler},
 	{"modState", lua_get_mod_state},
 	{"symName", lua_get_scancode_name},
 	{"flush", lua_flush_key_events},
+	{"unicodeInput", lua_key_unicode},
 	{NULL, NULL},
 };
 
diff --git a/src/main.c b/src/main.c
index 9e66f89c46906a91e3245e4e474269ccb4671ce5..63a7106a5126842abb266afb3c5bb0c8b7dfde43 100644
--- a/src/main.c
+++ b/src/main.c
@@ -237,12 +237,29 @@ extern SDL_Cursor *mouse_cursor;
 extern SDL_Cursor *mouse_cursor_down;
 void on_event(SDL_Event *event)
 {
-	static char *last_unicode = NULL;
-
 	switch (event->type) {
 	case SDL_TEXTINPUT:
-		if (last_unicode) free(last_unicode);
-		last_unicode = strdup(event->text.text);
+		if (current_keyhandler != LUA_NOREF)
+		{
+			lua_rawgeti(L, LUA_REGISTRYINDEX, current_keyhandler);
+			lua_pushstring(L, "receiveKey");
+			lua_gettable(L, -2);
+			lua_remove(L, -2);
+			lua_rawgeti(L, LUA_REGISTRYINDEX, current_keyhandler);
+			lua_pushnumber(L, 0);
+
+			SDL_Keymod _pKeyState = SDL_GetModState();
+			lua_pushboolean(L, (_pKeyState & KMOD_CTRL) ? TRUE : FALSE);
+			lua_pushboolean(L, (_pKeyState & KMOD_SHIFT) ? TRUE : FALSE);
+			lua_pushboolean(L, (_pKeyState & KMOD_ALT) ? TRUE : FALSE);
+			lua_pushboolean(L, (_pKeyState & KMOD_GUI) ? TRUE : FALSE);
+
+			lua_pushstring(L, event->text.text);
+			lua_pushboolean(L, FALSE);
+			lua_pushnil(L);
+
+			docall(L, 9, 0);
+		}
 		break;
 	case SDL_KEYDOWN:
 	case SDL_KEYUP:
@@ -261,14 +278,7 @@ void on_event(SDL_Event *event)
 			lua_pushboolean(L, (_pKeyState & KMOD_ALT) ? TRUE : FALSE);
 			lua_pushboolean(L, (_pKeyState & KMOD_GUI) ? TRUE : FALSE);
 
-			if (last_unicode)
-			{
-				lua_pushstring(L, last_unicode);
-				free(last_unicode);
-				last_unicode = NULL;
-			}
-			else
-				lua_pushnil(L);
+			lua_pushnil(L);
 			lua_pushboolean(L, (event->type == SDL_KEYUP) ? TRUE : FALSE);
 
 			/* Convert unicode UCS-2 to UTF8 string */
@@ -983,10 +993,9 @@ int main(int argc, char *argv[])
 	/* Sets up OpenGL double buffering */
 	resizeWindow(WIDTH, HEIGHT);
 
-	// Allow getting unicode events
-	SDL_StartTextInput();
 	// Allow screensaver to work
 	SDL_EnableScreenSaver();
+	SDL_StartTextInput();
 
 	// Get OpenGL capabilities
 	multitexture_active = GLEW_ARB_multitexture;
diff --git a/src/map.c b/src/map.c
index 95c03f2c3a92a0cadc7a0829c394916e291c31df..595531ffe6784d95a8a9753aebc7b8ff43cd2e8f 100644
--- a/src/map.c
+++ b/src/map.c
@@ -55,8 +55,6 @@ static int map_object_new(lua_State *L)
 
 	obj->move_max = 0;
 
-	obj->closed = FALSE;
-
 	obj->cb_ref = LUA_NOREF;
 
 	obj->mm_r = -1;
@@ -88,8 +86,6 @@ static int map_object_free(lua_State *L)
 	map_object *obj = (map_object*)auxiliar_checkclass(L, "core{mapobj}", 1);
 	int i;
 
-	obj->closed = TRUE;
-
 	for (i = 0; i < obj->nb_textures; i++)
 		if (obj->textures_ref[i] != LUA_NOREF)
 			luaL_unref(L, LUA_REGISTRYINDEX, obj->textures_ref[i]);
@@ -1089,8 +1085,6 @@ void display_map_quad(GLuint *cur_tex, int *vert_idx, int *col_idx, map_type *ma
 	GLfloat *colors = map->colors;
 	GLfloat *texcoords = map->texcoords;
 
-	if (m->closed) exit(2);
-
 	/********************************************************
 	 ** Select the color to use
 	 ********************************************************/
@@ -1213,7 +1207,6 @@ void display_map_quad(GLuint *cur_tex, int *vert_idx, int *col_idx, map_type *ma
 	dm = m;
 	while (dm)
 	{
-		if (dm->closed) exit(3);
 		tglBindTexture(GL_TEXTURE_2D, dm->textures[0]);
 		DO_QUAD(dm, dx + (dm->dx + animdx) * map->tile_w, dy + (dm->dy + animdy) * map->tile_h, dm->dw, dm->dh, dm->scale, r, g, b, a, m->next);
 		dm->animdx = animdx;
diff --git a/src/map.h b/src/map.h
index 4aba6b225192f68d90ba8cc5f93484986191ff8b..6b1c18ff153bcb9ac1bbdca232ac022b60639d66 100644
--- a/src/map.h
+++ b/src/map.h
@@ -52,8 +52,6 @@ struct s_map_object {
 
 	int cb_ref;
 
-	bool closed;
-
 	struct s_map_object *next;
 	int next_ref;
 };