Bug 1514940 - part 1: Forcibly disable new keyCode/charCode value of keypress events if the document is Confluence r=smaug,Ehsan,kmag a=lizzard
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 05 Feb 2019 11:35:43 +0000
changeset 515840 59b0981f244c1d330541d4593fcafa2635c3ac6b
parent 515839 476f22e149ba9a9eef995cf3d90f42e44f82e5c4
child 515841 546e05b0e3d22b9957fff74c7c5a0f0c8617494f
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, Ehsan, kmag, lizzard
bugs1514940
milestone66.0
Bug 1514940 - part 1: Forcibly disable new keyCode/charCode value of keypress events if the document is Confluence r=smaug,Ehsan,kmag a=lizzard Old Confluence does not aware of conflated model keypress event (see UI Events spec, https://w3c.github.io/uievents/#determine-keypress-keyCode). Additionally, Confluence can be hosted with any domains. Therefore, we cannot use blacklist to disable the conflated model keypress event only on it. This patch checks whether current or parent document is Confluence with JS module, called KeyPressEventModelCheckerChild. For kicking this module, nsHTMLDocument dispatches an custom event, CheckKeyPressEventModel, when it becomes editable only first time. Finally, if it's a Confluence instance, the module let PresShell know that we need to use split model keypress event in it. Differential Revision: https://phabricator.services.mozilla.com/D17907
dom/events/test/mochitest.ini
dom/events/test/test_bug1514940.html
dom/html/nsHTMLDocument.cpp
dom/html/nsHTMLDocument.h
dom/webidl/HTMLDocument.webidl
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsIPresShell.h
toolkit/actors/KeyPressEventModelCheckerChild.jsm
toolkit/actors/moz.build
toolkit/modules/ActorManagerParent.jsm
xpcom/ds/StaticAtoms.py
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -145,16 +145,18 @@ support-files = bug1017086_inner.html
 [test_bug1079236.html]
 [test_bug1127588.html]
 [test_bug1145910.html]
 [test_bug1150308.html]
 [test_bug1248459.html]
 [test_bug1264380.html]
 [test_bug1327798.html]
 subsuite = clipboard
+[test_bug1514940.html]
+skip-if = !debug
 [test_click_on_reframed_generated_text.html]
 [test_clickevent_on_input.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_continuous_wheel_events.html]
 skip-if = (verify && debug && (os == 'linux' || os == 'win'))
 [test_dblclick_explicit_original_target.html]
 [test_dom_activate_event.html]
 [test_dom_keyboard_event.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_bug1514940.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1514940
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Testing whether "keypress" event model is forcibly split model if the document is old Confluence instance</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1514940">Bug 1514940</a>
+<p id="display"></p>
+<pre id="test"></pre>
+<input id="input">
+<iframe id="iframe" srcdoc="<html><body><p>Here is editor</p></body></html>"></iframe>
+<script>
+// Emulate window.tinyMCE.CursorTargetPlugin().getInfo() which is referred by
+// KeyPresEventModelCheckerChild.
+class CursorTargetPluginImpl {
+  getInfo() {
+    return {
+      longname: "Cursor Target plugin",
+      author: "Atlassian",
+      authorurl: "http://www.atlassian.com",
+      version: "1.0",
+    };
+  }
+}
+var tinyMCE = {
+  plugins: {
+    CursorTargetPlugin: CursorTargetPluginImpl,
+  },
+};
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async function doTests() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value", true],
+    ],
+  });
+
+  let iframe = document.getElementById("iframe");
+  let waitForCheckKeyPressEventModelEvent = new Promise(resolve => {
+    SpecialPowers.addSystemEventListener(iframe.contentDocument, "CheckKeyPressEventModel", () => {
+      resolve();
+    }, false);
+  });
+  iframe.contentDocument.body.setAttribute("contenteditable", "true");
+  await waitForCheckKeyPressEventModelEvent;
+  iframe.contentDocument.body.focus();
+  let keypressEvent;
+  iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+  synthesizeKey("a", {}, iframe.contentWindow);
+  is(keypressEvent.keyCode, 0,
+     "keyCode value of 'a' should be 0");
+  is(keypressEvent.charCode, "a".charCodeAt(0),
+     "charCode value of 'a' should be 'a'");
+
+  iframe.contentDocument.body.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+  synthesizeKey("KEY_Enter", {}, iframe.contentWindow);
+  is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+     "keyCode value of 'Enter' should be DOM_VK_RETURN");
+  is(keypressEvent.charCode, 0,
+     "charCode value of 'Enter' should be 0");
+
+  let input = document.getElementById("input");
+  input.focus();
+  input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+  synthesizeKey("a", {});
+  is(keypressEvent.keyCode, "a".charCodeAt(0),
+     "keyCode value of 'a' in the parent document should be 'a'");
+  is(keypressEvent.charCode, "a".charCodeAt(0),
+     "charCode value of 'a' in the parent document should be 'a'");
+
+  input.addEventListener("keypress", aEvent => keypressEvent = aEvent, {once: true});
+  synthesizeKey("KEY_Enter");
+  is(keypressEvent.keyCode, KeyboardEvent.DOM_VK_RETURN,
+     "keyCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+  is(keypressEvent.charCode, KeyboardEvent.DOM_VK_RETURN,
+     "charCode value of 'Enter' in the parent document should be DOM_VK_RETURN");
+
+  SimpleTest.finish();
+});
+</script>
+</body>
+</html>
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -171,17 +171,18 @@ nsHTMLDocument::nsHTMLDocument()
       mWriteLevel(0),
       mLoadFlags(0),
       mTooDeepWriteRecursion(false),
       mDisableDocWrite(false),
       mWarnedWidthHeight(false),
       mContentEditableCount(0),
       mEditingState(EditingState::eOff),
       mDisableCookieAccess(false),
-      mPendingMaybeEditingStateChanged(false) {
+      mPendingMaybeEditingStateChanged(false),
+      mHasBeenEditable(false) {
   mType = eHTML;
   mDefaultElementType = kNameSpaceID_XHTML;
   mCompatMode = eCompatibility_NavQuirks;
 }
 
 nsHTMLDocument::~nsHTMLDocument() {}
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsHTMLDocument, Document, mAll,
@@ -2429,19 +2430,55 @@ nsresult nsHTMLDocument::EditingStateCha
     RefPtr<Selection> spellCheckSelection = selectionController->GetSelection(
         nsISelectionController::SELECTION_SPELLCHECK);
     if (spellCheckSelection) {
       spellCheckSelection->RemoveAllRanges(IgnoreErrors());
     }
   }
   htmlEditor->SyncRealTimeSpell();
 
+  MaybeDispatchCheckKeyPressEventModelEvent();
+
   return NS_OK;
 }
 
+void nsHTMLDocument::MaybeDispatchCheckKeyPressEventModelEvent() {
+  // Currently, we need to check only when we're becoming editable for
+  // contenteditable.
+  if (mEditingState != eContentEditable) {
+    return;
+  }
+
+  if (mHasBeenEditable) {
+    return;
+  }
+  mHasBeenEditable = true;
+
+  // Dispatch "CheckKeyPressEventModel" event.  That is handled only by
+  // KeyPressEventModelCheckerChild.  Then, it calls SetKeyPressEventModel()
+  // with proper keypress event for the active web app.
+  WidgetEvent checkEvent(true, eUnidentifiedEvent);
+  checkEvent.mSpecifiedEventType = nsGkAtoms::onCheckKeyPressEventModel;
+  checkEvent.mFlags.mCancelable = false;
+  checkEvent.mFlags.mBubbles = false;
+  checkEvent.mFlags.mOnlySystemGroupDispatch = true;
+  // Post the event rather than dispatching it synchronously because we need
+  // a call of SetKeyPressEventModel() before first key input.  Therefore, we
+  // can avoid paying unnecessary runtime cost for most web apps.
+  (new AsyncEventDispatcher(this, checkEvent))->PostDOMEvent();
+}
+
+void nsHTMLDocument::SetKeyPressEventModel(uint16_t aKeyPressEventModel) {
+  nsIPresShell* presShell = GetShell();
+  if (!presShell) {
+    return;
+  }
+  presShell->SetKeyPressEventModel(aKeyPressEventModel);
+}
+
 void nsHTMLDocument::SetDesignMode(const nsAString& aDesignMode,
                                    nsIPrincipal& aSubjectPrincipal,
                                    ErrorResult& rv) {
   SetDesignMode(aDesignMode, Some(&aSubjectPrincipal), rv);
 }
 
 void nsHTMLDocument::SetDesignMode(
     const nsAString& aDesignMode, const Maybe<nsIPrincipal*>& aSubjectPrincipal,
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -208,16 +208,18 @@ class nsHTMLDocument : public mozilla::d
   static bool MatchFormControls(Element* aElement, int32_t aNamespaceID,
                                 nsAtom* aAtom, void* aData);
 
   void GetFormsAndFormControls(nsContentList** aFormList,
                                nsContentList** aFormControlList);
 
   void UserInteractionForTesting();
 
+  void SetKeyPressEventModel(uint16_t aKeyPressEventModel);
+
  protected:
   ~nsHTMLDocument();
 
   nsresult GetBodySize(int32_t* aWidth, int32_t* aHeight);
 
   nsIContent* MatchId(nsIContent* aContent, const nsAString& aId);
 
   static void DocumentWriteTerminationFunc(nsISupports* aRef);
@@ -295,16 +297,25 @@ class nsHTMLDocument : public mozilla::d
   void TryTLD(int32_t& aCharsetSource, NotNull<const Encoding*>& aCharset);
   static void TryFallback(int32_t& aCharsetSource,
                           NotNull<const Encoding*>& aEncoding);
 
   // Override so we can munge the charset on our wyciwyg channel as needed.
   virtual void SetDocumentCharacterSet(
       NotNull<const Encoding*> aEncoding) override;
 
+  /**
+   * MaybeDispatchCheckKeyPressEventModelEvent() dispatches
+   * "CheckKeyPressEventModel" event to check whether we should dispatch
+   * keypress events in confluent model or split model.  This should be
+   * called only when mEditingState is changed to eDesignMode or
+   * eConentEditable at first time.
+   */
+  void MaybeDispatchCheckKeyPressEventModelEvent();
+
   // Tracks if we are currently processing any document.write calls (either
   // implicit or explicit). Note that if a write call writes out something which
   // would block the parser, then mWriteLevel will be incorrect until the parser
   // finishes processing that script.
   uint32_t mWriteLevel;
 
   // Load flags of the document's channel
   uint32_t mLoadFlags;
@@ -332,16 +343,20 @@ class nsHTMLDocument : public mozilla::d
   // When false, the .cookies property is completely disabled
   bool mDisableCookieAccess;
 
   /**
    * Temporary flag that is set in EndUpdate() to ignore
    * MaybeEditingStateChanged() script runners from a nested scope.
    */
   bool mPendingMaybeEditingStateChanged;
+
+  // mHasBeenEditable is set to true when mEditingState is firstly set to
+  // eDesignMode or eContentEditable.
+  bool mHasBeenEditable;
 };
 
 namespace mozilla {
 namespace dom {
 
 inline nsHTMLDocument* Document::AsHTMLDocument() {
   MOZ_ASSERT(IsHTMLOrXHTML());
   return static_cast<nsHTMLDocument*>(this);
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -71,9 +71,34 @@ partial interface HTMLDocument {
    * List of nodes that have been blocked by
    * the Safebrowsing API to prevent tracking.
    */
   [ChromeOnly, Pure]
   readonly attribute NodeList blockedTrackingNodes;
 
   [ChromeOnly]
   void userInteractionForTesting();
+
+  /**
+   * setKeyPressEventModel() is called when we need to check whether the web
+   * app requires specific keypress event model or not.
+   *
+   * @param aKeyPressEventModel  Proper keypress event model for the web app.
+   *   KEYPRESS_EVENT_MODEL_DEFAULT:
+   *     Use default keypress event model.  I.e., depending on
+   *     "dom.keyboardevent.keypress.set_keycode_and_charcode_to_same_value"
+   *     pref.
+   *   KEYPRESS_EVENT_MODEL_SPLIT:
+   *     Use split model.  I.e, if keypress event inputs a character,
+   *     keyCode should be 0.  Otherwise, charCode should be 0.
+   *   KEYPRESS_EVENT_MODEL_CONFLATED:
+   *     Use conflated model.  I.e., keyCode and charCode values of each
+   *     keypress event should be set to same value.
+   */
+  [ChromeOnly]
+  const unsigned short KEYPRESS_EVENT_MODEL_DEFAULT = 0;
+  [ChromeOnly]
+  const unsigned short KEYPRESS_EVENT_MODEL_SPLIT = 1;
+  [ChromeOnly]
+  const unsigned short KEYPRESS_EVENT_MODEL_CONFLATED = 2;
+  [ChromeOnly]
+  void setKeyPressEventModel(unsigned short aKeyPressEventModel);
 };
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -7645,17 +7645,17 @@ nsresult PresShell::DispatchEventToDOM(W
       // we should keep using legacy our behavior.
       if (!mInitializedWithKeyPressEventDispatchingBlacklist) {
         mInitializedWithKeyPressEventDispatchingBlacklist = true;
         nsCOMPtr<nsIURI> uri = GetDocumentURIToCompareWithBlacklist(*this);
         mForceDispatchKeyPressEventsForNonPrintableKeys =
             nsContentUtils::IsURIInPrefList(
                 uri,
                 "dom.keyboardevent.keypress.hack.dispatch_non_printable_keys");
-        mForceUseLegacyKeyCodeAndCharCodeValues =
+        mForceUseLegacyKeyCodeAndCharCodeValues |=
             nsContentUtils::IsURIInPrefList(uri,
                                             "dom.keyboardevent.keypress.hack."
                                             "use_legacy_keycode_and_charcode");
       }
       if (mForceDispatchKeyPressEventsForNonPrintableKeys) {
         aEvent->mFlags.mOnlySystemGroupDispatchInContent = false;
       }
       if (mForceUseLegacyKeyCodeAndCharCodeValues) {
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -7,16 +7,17 @@
 /* a presentation of a document, part 2 */
 
 #ifndef mozilla_PresShell_h
 #define mozilla_PresShell_h
 
 #include "MobileViewportManager.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
+#include "mozilla/dom/HTMLDocumentBinding.h"
 #include "mozilla/layers/FocusTarget.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/UniquePtr.h"
 #include "nsContentUtils.h"  // For AddScriptBlocker().
 #include "nsCRT.h"
 #include "nsIObserver.h"
 #include "nsIPresShell.h"
@@ -378,16 +379,22 @@ class PresShell final : public nsIPresSh
                                          uint32_t aSheetType) override;
   void NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
                                            uint32_t aSheetType) override;
 
   bool HasHandledUserInput() const override { return mHasHandledUserInput; }
 
   void FireResizeEvent() override;
 
+  void SetKeyPressEventModel(uint16_t aKeyPressEventModel) override {
+    mForceUseLegacyKeyCodeAndCharCodeValues |=
+        aKeyPressEventModel ==
+        dom::HTMLDocument_Binding::KEYPRESS_EVENT_MODEL_SPLIT;
+  }
+
   static PresShell* GetShellForEventTarget(nsIFrame* aFrame,
                                            nsIContent* aContent);
   static PresShell* GetShellForTouchEvent(WidgetGUIEvent* aEvent);
 
  private:
   ~PresShell();
 
   void HandlePostedReflowCallbacks(bool aInterruptible);
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1602,16 +1602,22 @@ class nsIPresShell : public nsStubDocume
    * Returns whether or not the document has ever handled user input
    */
   virtual bool HasHandledUserInput() const = 0;
 
   virtual void FireResizeEvent() = 0;
 
   void NativeAnonymousContentRemoved(nsIContent* aAnonContent);
 
+  /**
+   * See HTMLDocument.setKeyPressEventModel() in HTMLDocument.webidl for the
+   * detail.
+   */
+  virtual void SetKeyPressEventModel(uint16_t aKeyPressEventModel) = 0;
+
  protected:
   /**
    * Refresh observer management.
    */
   void DoObserveStyleFlushes();
   void DoObserveLayoutFlushes();
 
   /**
new file mode 100644
--- /dev/null
+++ b/toolkit/actors/KeyPressEventModelCheckerChild.jsm
@@ -0,0 +1,76 @@
+/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var EXPORTED_SYMBOLS = ["KeyPressEventModelCheckerChild"];
+
+ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
+ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+
+class KeyPressEventModelCheckerChild extends ActorChild {
+  // Currently, the event is dispatched only when the document becomes editable
+  // because of contenteditable.  If you need to add new editor which is in
+  // designMode, you need to change MaybeDispatchCheckKeyPressEventModelEvent()
+  // of nsHTMLDocument.
+  handleEvent(aEvent) {
+    if (!AppConstants.DEBUG) {
+      // Stop propagation in opt build to save the propagation cost.
+      // However, the event is necessary for running test_bug1514940.html.
+      // Therefore, we need to keep propagating it at least on debug build.
+      aEvent.stopImmediatePropagation();
+    }
+
+    // Currently, even if we set HTMLDocument.KEYPRESS_EVENT_MODEL_CONFLATED
+    // here, conflated model isn't used forcibly.  If you need it, you need
+    // to change WidgetKeyboardEvent, dom::KeyboardEvent and PresShell.
+    let model = HTMLDocument.KEYPRESS_EVENT_MODEL_DEFAULT;
+    if (this._isOldConfluence(aEvent.target.ownerGlobal)) {
+      model = HTMLDocument.KEYPRESS_EVENT_MODEL_SPLIT;
+    }
+    aEvent.target.setKeyPressEventModel(model);
+  }
+
+  _isOldConfluence(aWindow) {
+    if (!aWindow) {
+      return false;
+    }
+    // aWindow should be an editor window in <iframe>.  However, we don't know
+    // whether it can be without <iframe>.  Anyway, there should be tinyMCE
+    // object in the parent window or in the window.
+    let tinyMCEObject;
+    // First, try to retrieve tinyMCE object from parent window.
+    try {
+      tinyMCEObject = ChromeUtils.waiveXrays(aWindow.parent).tinyMCE;
+    } catch (e) {
+      // Ignore the exception for now.
+    }
+    // Next, if there is no tinyMCE object in the parent window, let's check
+    // the window.
+    if (!tinyMCEObject) {
+      try {
+        tinyMCEObject = ChromeUtils.waiveXrays(aWindow).tinyMCE;
+      } catch (e) {
+        // Fallthrough to return false below.
+      }
+      // If we couldn't find tinyMCE object, let's assume that it's not
+      // Confluence instance.
+      if (!tinyMCEObject) {
+        return false;
+      }
+    }
+    // If there is tinyMCE object, we can assume that we loaded Confluence
+    // instance.  So, let's check the version whether it allows conflated
+    // keypress event model.
+    try {
+      let {author, version} =
+          new tinyMCEObject.plugins.CursorTargetPlugin().getInfo();
+      return author === "Atlassian" && version === "1.0";
+    } catch (e) {
+      return false;
+    }
+  }
+}
--- a/toolkit/actors/moz.build
+++ b/toolkit/actors/moz.build
@@ -5,25 +5,29 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'General')
 
 with Files('Finder*.jsm'):
     BUG_COMPONENT = ('Toolkit', 'Find Toolbar')
 
+with Files('KeyPressEventModelCheckerChild.jsm'):
+    BUG_COMPONENT = ('Core', 'DOM: Events')
+
 FINAL_TARGET_FILES.actors += [
     'AudioPlaybackChild.jsm',
     'AutoplayChild.jsm',
     'BrowserChild.jsm',
     'ControllersChild.jsm',
     'DateTimePickerChild.jsm',
     'ExtFindChild.jsm',
     'FindBarChild.jsm',
     'FinderChild.jsm',
+    'KeyPressEventModelCheckerChild.jsm',
     'PopupBlockingChild.jsm',
     'PrintingChild.jsm',
     'PurgeSessionHistoryChild.jsm',
     'SelectChild.jsm',
     'SelectionSourceChild.jsm',
     'ThumbnailsChild.jsm',
     'UAWidgetsChild.jsm',
     'UnselectedTabHoverChild.jsm',
--- a/toolkit/modules/ActorManagerParent.jsm
+++ b/toolkit/modules/ActorManagerParent.jsm
@@ -180,16 +180,25 @@ let ACTORS = {
     child: {
       module: "resource://gre/actors/FinderChild.jsm",
       messages: [
         "Finder:Initialize",
       ],
     },
   },
 
+  KeyPressEventModelChecker: {
+    child: {
+      module: "resource://gre/actors/KeyPressEventModelCheckerChild.jsm",
+      events: {
+        "CheckKeyPressEventModel": {capture: true, mozSystemGroup: true},
+      },
+    },
+  },
+
   ManifestMessages: {
     child: {
       module: "resource://gre/modules/ManifestMessagesChild.jsm",
       messages: [
         "DOM:Manifest:FireAppInstalledEvent",
         "DOM:ManifestObtainer:Obtain",
         "DOM:WebManifest:fetchIcon",
         "DOM:WebManifest:hasManifestLink",
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -743,16 +743,17 @@ STATIC_ATOMS = [
     Atom("onbufferedamountlow", "onbufferedamountlow"),
     Atom("oncached", "oncached"),
     Atom("oncancel", "oncancel"),
     Atom("onchange", "onchange"),
     Atom("onchargingchange", "onchargingchange"),
     Atom("onchargingtimechange", "onchargingtimechange"),
     Atom("onchecking", "onchecking"),
     Atom("onCheckboxStateChange", "onCheckboxStateChange"),
+    Atom("onCheckKeyPressEventModel", "onCheckKeyPressEventModel"),
     Atom("onclick", "onclick"),
     Atom("onclose", "onclose"),
     Atom("oncommand", "oncommand"),
     Atom("oncommandupdate", "oncommandupdate"),
     Atom("oncomplete", "oncomplete"),
     Atom("oncompositionend", "oncompositionend"),
     Atom("oncompositionstart", "oncompositionstart"),
     Atom("oncompositionupdate", "oncompositionupdate"),