diff --git a/modules/client/client.lua b/modules/client/client.lua
index 7a8485bc..bbfb1e2a 100644
--- a/modules/client/client.lua
+++ b/modules/client/client.lua
@@ -37,6 +37,11 @@ function Client.init()
   g_window.setIcon(resolvepath('clienticon.png'))
   g_keyboard.bindKeyDown('Ctrl+Shift+R', Client.reloadScripts)
 
+  local clientVersion = g_settings.getInteger('client-version')
+  if clientVersion ~= 0 then
+    g_game.setClientVersion(clientVersion)
+  end
+
   connect(g_app, { onRun =
     function()
       -- Play startup music (The Silver Tree, by Mattias Westlund)
diff --git a/modules/client_entergame/entergame.otui b/modules/client_entergame/entergame.otui
index 2d2e0844..ddb76c9b 100644
--- a/modules/client_entergame/entergame.otui
+++ b/modules/client_entergame/entergame.otui
@@ -5,7 +5,6 @@ EnterGameWindow
   !text: tr('Enter Game')
   size: 236 274
   @onEnter: EnterGame.doLogin()
-  @onEscape: EnterGame.hide()
 
   MenuLabel
     !text: tr('Account name')
@@ -107,14 +106,6 @@ EnterGameWindow
   Button
     !text: tr('Ok')
     width: 64
-    anchors.right: next.left
-    anchors.bottom: parent.bottom
-    margin-right: 10
-    @onClick: EnterGame.doLogin()
-
-  Button
-    !text: tr('Cancel')
-    width: 64
     anchors.right: parent.right
     anchors.bottom: parent.bottom
-    @onClick: EnterGame.hide()
+    @onClick: EnterGame.doLogin()
diff --git a/modules/client_skins/skins/default/cursors/text.png b/modules/client_skins/skins/default/cursors/text.png
new file mode 100644
index 00000000..2a69d564
Binary files /dev/null and b/modules/client_skins/skins/default/cursors/text.png differ
diff --git a/modules/corelib/mouse.lua b/modules/corelib/mouse.lua
index 12ea4589..83d51c06 100644
--- a/modules/corelib/mouse.lua
+++ b/modules/corelib/mouse.lua
@@ -1,37 +1,4 @@
 -- @docclass
-g_mouse = {}
-
-local cursorChanged = false
-
-function g_mouse.setTargetCursor()
-  g_window.setMouseCursor('/cursors/targetcursor.png', {x=9,y=9})
-  cursorChanged = true
-end
-
-function g_mouse.setHorizontalCursor()
-  g_window.setMouseCursor('/cursors/horizontal.png', {x=9,y=4})
-  cursorChanged = true
-end
-
-function g_mouse.setVerticalCursor()
-  g_window.setMouseCursor('/cursors/vertical.png', {x=4,y=9})
-  cursorChanged = true
-end
-
-function g_mouse.restoreCursor()
-  g_window.restoreMouseCursor()
-  cursorChanged = false
-end
-
-function g_mouse.isCursorChanged()
-  return cursorChanged
-end
-
-function g_mouse.isPressed(button)
-  if not button then button = MouseLeftButton end
-  return g_window.isMouseButtonPressed(button)
-end
-
 function g_mouse.bindAutoPress(widget, callback, delay, button)
   local button = button or MouseLeftButton
   connect(widget, { onMousePress = function(widget, mousePos, mouseButton)
diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt
index bfd5b070..06b2bb06 100644
--- a/src/framework/CMakeLists.txt
+++ b/src/framework/CMakeLists.txt
@@ -368,6 +368,9 @@ if(FRAMEWORK_GRAPHICS)
         ${CMAKE_CURRENT_LIST_DIR}/platform/x11window.cpp
         ${CMAKE_CURRENT_LIST_DIR}/platform/x11window.h
 
+        # window input
+        ${CMAKE_CURRENT_LIST_DIR}/input/mouse.cpp
+        ${CMAKE_CURRENT_LIST_DIR}/input/mouse.h
 
         ${CMAKE_CURRENT_LIST_DIR}/core/graphicalapplication.cpp
         ${CMAKE_CURRENT_LIST_DIR}/core/graphicalapplication.h
diff --git a/src/framework/input/mouse.cpp b/src/framework/input/mouse.cpp
new file mode 100644
index 00000000..8983d595
--- /dev/null
+++ b/src/framework/input/mouse.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "mouse.h"
+#include <framework/ui/uiwidget.h>
+#include <framework/platform/platformwindow.h>
+
+Mouse g_mouse;
+
+void Mouse::setTargetCursor()
+{
+    g_window.setMouseCursor("/cursors/targetcursor.png", Point(9, 9));
+    m_cursorChanged = true;
+}
+
+void Mouse::setHorizontalCursor()
+{
+    g_window.setMouseCursor("/cursors/horizontal.png", Point(9, 4));
+    m_cursorChanged = true;
+}
+
+void Mouse::setVerticalCursor()
+{
+    g_window.setMouseCursor("/cursors/vertical.png", Point(4, 9));
+    m_cursorChanged = true;
+}
+
+void Mouse::setTextCursor()
+{
+    g_window.setMouseCursor("/cursors/text.png", Point(4, 9));
+    m_cursorChanged = true;
+}
+
+void Mouse::restoreCursor()
+{
+    g_window.restoreMouseCursor();
+    m_cursorChanged = false;
+}
+
+bool Mouse::isCursorChanged()
+{
+    return m_cursorChanged;
+}
+
+bool Mouse::isPressed(Fw::MouseButton mouseButton)
+{
+    return g_window.isMouseButtonPressed(mouseButton);
+}
diff --git a/src/framework/input/mouse.h b/src/framework/input/mouse.h
new file mode 100644
index 00000000..4b55bc3a
--- /dev/null
+++ b/src/framework/input/mouse.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <framework/global.h>
+
+class Mouse
+{
+public:
+    void setTargetCursor();
+    void setHorizontalCursor();
+    void setVerticalCursor();
+    void setTextCursor();
+    void restoreCursor();
+    bool isCursorChanged();
+    bool isPressed(Fw::MouseButton mouseButton);
+
+private:
+    bool m_cursorChanged;
+};
+
+extern Mouse g_mouse;
diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp
index 0a6c79f8..a17c3043 100644
--- a/src/framework/luafunctions.cpp
+++ b/src/framework/luafunctions.cpp
@@ -40,6 +40,7 @@
 #include <framework/graphics/particlemanager.h>
 #include <framework/graphics/fontmanager.h>
 #include <framework/ui/ui.h>
+#include <framework/input/mouse.h>
 #endif
 
 #ifdef FW_NET
@@ -240,6 +241,16 @@ void Application::registerLuaFunctions()
     g_lua.bindSingletonFunction("g_window", "isMaximized", &PlatformWindow::isMaximized, &g_window);
     g_lua.bindSingletonFunction("g_window", "hasFocus", &PlatformWindow::hasFocus, &g_window);
 
+    // Input
+    g_lua.registerSingletonClass("g_mouse");
+    g_lua.bindSingletonFunction("g_mouse", "setTargetCursor", &Mouse::setTargetCursor, &g_mouse);
+    g_lua.bindSingletonFunction("g_mouse", "setHorizontalCursor", &Mouse::setHorizontalCursor, &g_mouse);
+    g_lua.bindSingletonFunction("g_mouse", "setVerticalCursor", &Mouse::setVerticalCursor, &g_mouse);
+    g_lua.bindSingletonFunction("g_mouse", "setTextCursor", &Mouse::setTextCursor, &g_mouse);
+    g_lua.bindSingletonFunction("g_mouse", "restoreCursor", &Mouse::restoreCursor, &g_mouse);
+    g_lua.bindSingletonFunction("g_mouse", "isCursorChanged", &Mouse::isCursorChanged, &g_mouse);
+    g_lua.bindSingletonFunction("g_mouse", "isPressed", &Mouse::isPressed, &g_mouse);
+
     // Graphics
     g_lua.registerSingletonClass("g_graphics");
     g_lua.bindSingletonFunction("g_graphics", "isPainterEngineAvailable", &Graphics::isPainterEngineAvailable, &g_graphics);
diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp
index f20d8004..3a8d0f11 100644
--- a/src/framework/ui/uitextedit.cpp
+++ b/src/framework/ui/uitextedit.cpp
@@ -27,6 +27,7 @@
 #include <framework/core/clock.h>
 #include <framework/otml/otmlnode.h>
 #include <framework/core/application.h>
+#include <framework/input/mouse.h>
 
 UITextEdit::UITextEdit()
 {
@@ -391,6 +392,14 @@ std::string UITextEdit::getDisplayedText()
         return m_text;
 }
 
+void UITextEdit::onHoverChange(bool hovered)
+{
+    if(hovered)
+        g_mouse.setTextCursor();
+    else
+        g_mouse.restoreCursor();
+}
+
 void UITextEdit::onTextChange(const std::string& text, const std::string& oldText)
 {
     m_cursorPos = text.length();
diff --git a/src/framework/ui/uitextedit.h b/src/framework/ui/uitextedit.h
index 1a7ef69b..5e2fe721 100644
--- a/src/framework/ui/uitextedit.h
+++ b/src/framework/ui/uitextedit.h
@@ -62,6 +62,7 @@ public:
     bool isMultiline() { return m_multiline; }
 
 protected:
+    virtual void onHoverChange(bool hovered);
     virtual void onTextChange(const std::string& text, const std::string& oldText);
     virtual void onFontChange(const std::string& font);
     virtual void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);