diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 78efcf634da6e2f86801f41434cbe146349d4cbe..26134908bf4d94c5cfc56a6062013756f0c69c38 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -47,6 +47,80 @@ namespace {
 
 #ifndef NO_DECLARATIVE_BACKEND
 
+class QmlAttachedKeys: public ObjectValue
+{
+    static const char **builtinPropertyNames()
+    {
+        static const char *properties[] = {
+            "enabledChanged",
+            "pressed",
+            "released",
+            "digit0Pressed",
+            "digit1Pressed",
+            "digit2Pressed",
+            "digit3Pressed",
+            "digit4Pressed",
+            "digit5Pressed",
+            "digit6Pressed",
+            "digit7Pressed",
+            "digit8Pressed",
+            "digit9Pressed",
+            "leftPressed",
+            "rightPressed",
+            "upPressed",
+            "downPressed",
+            "asteriskPressed",
+            "numberSignPressed",
+            "escapePressed",
+            "returnPressed",
+            "enterPressed",
+            "deletePressed",
+            "spacePressed",
+            "backPressed",
+            "cancelPressed",
+            "selectPressed",
+            "yesPressed",
+            "noPressed",
+            "context1Pressed",
+            "context2Pressed",
+            "context3Pressed",
+            "context4Pressed",
+            "callPressed",
+            "hangupPressed",
+            "flipPressed",
+            "menuPressed",
+            "volumeUpPressed",
+            "volumeDownPressed",
+            0
+        };
+
+        return properties;
+    }
+
+    QSet<QString> _generatedSlots;
+
+public:
+    QmlAttachedKeys(Engine *engine)
+        : ObjectValue(engine)
+    {
+        for (const char **it = builtinPropertyNames(); *it; ++it) {
+            QString signalName = QLatin1String(*it);
+            QString generatedSlot = QLatin1String("on");
+            generatedSlot += signalName.at(0).toUpper();
+            generatedSlot += signalName.midRef(1);
+            _generatedSlots.insert(generatedSlot);
+        }
+    }
+
+    virtual void processMembers(MemberProcessor *processor) const
+    {
+        foreach (const QString &generatedSlot, _generatedSlots)
+            processor->processSlot(generatedSlot, engine()->undefinedValue());
+
+        ObjectValue::processMembers(processor);
+    }
+};
+
 class MetaFunction: public FunctionValue
 {
     QMetaMethod _method;
@@ -1140,6 +1214,7 @@ Engine::Engine()
       _regexpCtor(0),
       _globalObject(0),
       _mathObject(0),
+      _qmlKeysObject(0),
       _convertToNumber(this),
       _convertToString(this),
       _convertToObject(this)
@@ -1594,6 +1669,15 @@ void Engine::initializePrototypes()
     _globalObject->setProperty("Number", numberCtor());
     _globalObject->setProperty("Date", dateCtor());
     _globalObject->setProperty("RegExp", regexpCtor());
+
+    _qmlKeysObject = new QmlAttachedKeys(this);
+    _globalObject->setProperty("Keys", _qmlKeysObject); // ### attach it to the current scope, and not to the global object
+    registerObject(_qmlKeysObject);
+}
+
+const ObjectValue *Engine::qmlKeysObject()
+{
+    return _qmlKeysObject;
 }
 
 ObjectValue *Engine::newQmlObject(const QString &name)
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index f5fb5699e234b849cf8c7e6100071cff707f9270..0e7664c9706570447780451b2c76e1dd9d8aace9 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -441,6 +441,7 @@ public:
 
     // QML objects
     ObjectValue *newQmlObject(const QString &name);
+    const ObjectValue *qmlKeysObject();
 
     // global object
     ObjectValue *globalObject() const;
@@ -502,6 +503,7 @@ private:
 
     ObjectValue *_globalObject;
     ObjectValue *_mathObject;
+    ObjectValue *_qmlKeysObject;
 
     NullValue _nullValue;
     UndefinedValue _undefinedValue;