Sanitize the types of keyboard events

Events emitted via the keyboard shortcut mixin are not normal
KeyboardEvents. Such eventhandlers need a different signature. This was
not very well understoof during the TypeScript migration, and the types
were a total mess. So let's clean this up here and clearly distinguish
KeyboardEvent and IronKeyboardEvent.

Change-Id: Ib4855dff32afda23abcf84a9766a6229c2842e21
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
index 9eb9b07..2d3b5c3 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-config-array-editor/gr-plugin-config-array-editor.ts
@@ -28,7 +28,6 @@
   PluginConfigOptionsChangedEventDetail,
   ArrayPluginOption,
 } from '../gr-repo-plugin-config/gr-repo-plugin-config-types';
-import {KeydownEvent} from '../../../types/events';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -75,7 +74,7 @@
     this._handleAdd();
   }
 
-  _handleInputKeydown(e: KeydownEvent) {
+  _handleInputKeydown(e: KeyboardEvent) {
     // Enter.
     if (e.keyCode === 13) {
       e.preventDefault();
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
index bedaed9..ac44908 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -46,9 +46,9 @@
   PreferencesInput,
 } from '../../../types/common';
 import {hasAttention} from '../../../utils/attention-set-util';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {IronKeyboardEvent} from '../../../types/events';
 import {fireEvent, fireReload} from '../../../utils/event-util';
-import {isShiftPressed} from '../../../utils/dom-util';
+import {isShiftPressed, modifierPressed} from '../../../utils/dom-util';
 import {ScrollMode} from '../../../constants/constants';
 
 const NUMBER_FIXED_COLUMNS = 3;
@@ -178,9 +178,7 @@
     super();
     this.cursor.scrollMode = ScrollMode.KEEP_VISIBLE;
     this.cursor.focusOnMove = true;
-    this.addEventListener('keydown', e =>
-      this._scopedKeydownHandler(e as unknown as CustomKeyboardEvent)
-    );
+    this.addEventListener('keydown', e => this._scopedKeydownHandler(e));
   }
 
   override ready() {
@@ -212,10 +210,10 @@
    *
    * Context: Issue 7294
    */
-  _scopedKeydownHandler(e: CustomKeyboardEvent) {
+  _scopedKeydownHandler(e: KeyboardEvent) {
     if (e.keyCode === 13) {
       // Enter.
-      this._openChange(e);
+      this.openChange(e);
     }
   }
 
@@ -408,7 +406,7 @@
     );
   }
 
-  _nextChange(e: CustomKeyboardEvent) {
+  _nextChange(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -420,7 +418,7 @@
     this.selectedIndex = this.cursor.index;
   }
 
-  _prevChange(e: CustomKeyboardEvent) {
+  _prevChange(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -432,17 +430,19 @@
     this.selectedIndex = this.cursor.index;
   }
 
-  _openChange(e: CustomKeyboardEvent) {
-    if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
-      return;
-    }
+  _openChange(e: IronKeyboardEvent) {
+    if (this.modifierPressed(e)) return;
+    this.openChange(e.detail.keyboardEvent);
+  }
 
+  openChange(e: KeyboardEvent) {
+    if (this.shortcuts.shouldSuppress(e) || modifierPressed(e)) return;
     e.preventDefault();
     const change = this._changeForIndex(this.selectedIndex);
     if (change) GerritNav.navigateToChange(change);
   }
 
-  _nextPage(e: CustomKeyboardEvent) {
+  _nextPage(e: IronKeyboardEvent) {
     if (
       this.shortcuts.shouldSuppress(e) ||
       (this.modifierPressed(e) && !isShiftPressed(e))
@@ -454,7 +454,7 @@
     fireEvent(this, 'next-page');
   }
 
-  _prevPage(e: CustomKeyboardEvent) {
+  _prevPage(e: IronKeyboardEvent) {
     if (
       this.shortcuts.shouldSuppress(e) ||
       (this.modifierPressed(e) && !isShiftPressed(e))
@@ -471,7 +471,7 @@
     );
   }
 
-  _toggleChangeReviewed(e: CustomKeyboardEvent) {
+  _toggleChangeReviewed(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -490,7 +490,7 @@
     changeEl.toggleReviewed();
   }
 
-  _refreshChangeList(e: CustomKeyboardEvent) {
+  _refreshChangeList(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -499,7 +499,7 @@
     fireReload(this);
   }
 
-  _toggleChangeStar(e: CustomKeyboardEvent) {
+  _toggleChangeStar(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 650b6d8..fd7b5d1 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -158,8 +158,9 @@
   ParsedChangeInfo,
 } from '../../../types/types';
 import {
+  IronKeyboardEventListener,
   CloseFixPreviewEvent,
-  CustomKeyboardEvent,
+  IronKeyboardEvent,
   EditableContentSaveEvent,
   EventType,
   OpenFixPreviewEvent,
@@ -537,7 +538,7 @@
   @property({type: Boolean})
   _showRobotCommentsButton = false;
 
-  _throttledToggleChangeStar?: EventListener;
+  _throttledToggleChangeStar?: IronKeyboardEventListener;
 
   @property({type: Boolean})
   _showChecksTab = false;
@@ -640,8 +641,8 @@
 
   override connectedCallback() {
     super.connectedCallback();
-    this._throttledToggleChangeStar = throttleWrap(e =>
-      this._handleToggleChangeStar(e as CustomKeyboardEvent)
+    this._throttledToggleChangeStar = throttleWrap<IronKeyboardEvent>(e =>
+      this._handleToggleChangeStar(e)
     );
     this._getServerConfig().then(config => {
       this._serverConfig = config;
@@ -750,7 +751,7 @@
     if (e.detail.fixApplied) fireReload(this);
   }
 
-  _handleToggleDiffMode(e: CustomKeyboardEvent) {
+  _handleToggleDiffMode(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1494,7 +1495,7 @@
     return label;
   }
 
-  _handleOpenReplyDialog(e: CustomKeyboardEvent) {
+  _handleOpenReplyDialog(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1509,7 +1510,7 @@
     });
   }
 
-  _handleOpenDownloadDialogShortcut(e: CustomKeyboardEvent) {
+  _handleOpenDownloadDialogShortcut(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1518,7 +1519,7 @@
     this._handleOpenDownloadDialog();
   }
 
-  _handleEditTopic(e: CustomKeyboardEvent) {
+  _handleEditTopic(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1527,7 +1528,7 @@
     this.$.metadata.editTopic();
   }
 
-  _handleOpenSubmitDialog(e: CustomKeyboardEvent) {
+  _handleOpenSubmitDialog(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || !this._submitEnabled) {
       return;
     }
@@ -1536,7 +1537,7 @@
     this.$.actions.showSubmitDialog();
   }
 
-  _handleToggleAttentionSet(e: CustomKeyboardEvent) {
+  _handleToggleAttentionSet(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1578,7 +1579,7 @@
     this._change = {...this._change};
   }
 
-  _handleDiffAgainstBase(e: CustomKeyboardEvent) {
+  _handleDiffAgainstBase(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1592,7 +1593,7 @@
     GerritNav.navigateToChange(this._change, this._patchRange.patchNum);
   }
 
-  _handleDiffBaseAgainstLeft(e: CustomKeyboardEvent) {
+  _handleDiffBaseAgainstLeft(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1606,7 +1607,7 @@
     GerritNav.navigateToChange(this._change, this._patchRange.basePatchNum);
   }
 
-  _handleDiffAgainstLatest(e: CustomKeyboardEvent) {
+  _handleDiffAgainstLatest(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1625,7 +1626,7 @@
     );
   }
 
-  _handleDiffRightAgainstLatest(e: CustomKeyboardEvent) {
+  _handleDiffRightAgainstLatest(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1644,7 +1645,7 @@
     );
   }
 
-  _handleDiffBaseAgainstLatest(e: CustomKeyboardEvent) {
+  _handleDiffBaseAgainstLatest(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1662,7 +1663,7 @@
     GerritNav.navigateToChange(this._change, latestPatchNum);
   }
 
-  _handleRefreshChange(e: CustomKeyboardEvent) {
+  _handleRefreshChange(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1670,7 +1671,7 @@
     fireReload(this, true);
   }
 
-  _handleToggleChangeStar(e: CustomKeyboardEvent) {
+  _handleToggleChangeStar(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1678,7 +1679,7 @@
     this.$.changeStar.toggleStar();
   }
 
-  _handleUpToDashboard(e: CustomKeyboardEvent) {
+  _handleUpToDashboard(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1687,7 +1688,7 @@
     this._determinePageBack();
   }
 
-  _handleExpandAllMessages(e: CustomKeyboardEvent) {
+  _handleExpandAllMessages(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1698,7 +1699,7 @@
     }
   }
 
-  _handleCollapseAllMessages(e: CustomKeyboardEvent) {
+  _handleCollapseAllMessages(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1709,7 +1710,7 @@
     }
   }
 
-  _handleOpenDiffPrefsShortcut(e: CustomKeyboardEvent) {
+  _handleOpenDiffPrefsShortcut(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index de24b9e..a82fceb 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -89,7 +89,10 @@
 import {AppElementChangeViewParams} from '../../gr-app-types';
 import {SinonFakeTimers, SinonStubbedMember} from 'sinon';
 import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {
+  IronKeyboardEvent,
+  IronKeyboardEventDetail,
+} from '../../../types/events';
 import {CommentThread, UIRobot} from '../../../utils/comment-util';
 import {GerritView} from '../../../services/router/router-model';
 import {ParsedChangeInfo} from '../../../types/types';
@@ -400,7 +403,7 @@
       patchNum: 3 as RevisionPatchSetNum,
       basePatchNum: 1 as BasePatchSetNum,
     };
-    element._handleDiffAgainstBase(new CustomEvent('') as CustomKeyboardEvent);
+    element._handleDiffAgainstBase(new CustomEvent('') as IronKeyboardEvent);
     assert(navigateToChangeStub.called);
     const args = navigateToChangeStub.getCall(0).args;
     assert.equal(args[0], element._change);
@@ -416,9 +419,7 @@
       basePatchNum: 1 as BasePatchSetNum,
       patchNum: 3 as RevisionPatchSetNum,
     };
-    element._handleDiffAgainstLatest(
-      new CustomEvent('') as CustomKeyboardEvent
-    );
+    element._handleDiffAgainstLatest(new CustomEvent('') as IronKeyboardEvent);
     assert(navigateToChangeStub.called);
     const args = navigateToChangeStub.getCall(0).args;
     assert.equal(args[0], element._change);
@@ -436,7 +437,7 @@
       basePatchNum: 1 as BasePatchSetNum,
     };
     element._handleDiffBaseAgainstLeft(
-      new CustomEvent('') as CustomKeyboardEvent
+      new CustomEvent('') as IronKeyboardEvent
     );
     assert(navigateToChangeStub.called);
     const args = navigateToChangeStub.getCall(0).args;
@@ -454,7 +455,7 @@
       patchNum: 3 as RevisionPatchSetNum,
     };
     element._handleDiffRightAgainstLatest(
-      new CustomEvent('') as CustomKeyboardEvent
+      new CustomEvent('') as IronKeyboardEvent
     );
     assert(navigateToChangeStub.called);
     const args = navigateToChangeStub.getCall(0).args;
@@ -472,7 +473,7 @@
       patchNum: 3 as RevisionPatchSetNum,
     };
     element._handleDiffBaseAgainstLatest(
-      new CustomEvent('') as CustomKeyboardEvent
+      new CustomEvent('') as IronKeyboardEvent
     );
     assert(navigateToChangeStub.called);
     const args = navigateToChangeStub.getCall(0).args;
@@ -500,15 +501,11 @@
     assert.isNotOk(element._change.attention_set);
     await element._getLoggedIn();
     await element.restApiService.getAccount();
-    element._handleToggleAttentionSet(
-      new CustomEvent('') as CustomKeyboardEvent
-    );
+    element._handleToggleAttentionSet(new CustomEvent('') as IronKeyboardEvent);
     assert.isTrue(addToAttentionSetStub.called);
     assert.isFalse(removeFromAttentionSetStub.called);
 
-    element._handleToggleAttentionSet(
-      new CustomEvent('') as CustomKeyboardEvent
-    );
+    element._handleToggleAttentionSet(new CustomEvent('') as IronKeyboardEvent);
     assert.isTrue(removeFromAttentionSetStub.called);
   });
 
@@ -827,7 +824,9 @@
         element.$.fileListHeader,
         'setDiffViewMode'
       );
-      const e = {preventDefault: () => {}} as CustomKeyboardEvent;
+      const e = new CustomEvent<IronKeyboardEventDetail>('keydown', {
+        detail: {keyboardEvent: new KeyboardEvent('keydown'), key: 'x'},
+      });
       flush();
 
       element.viewState.diffMode = DiffViewMode.SIDE_BY_SIDE;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index 1df8f7f..b78c78f 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -50,8 +50,8 @@
 } from '../../../constants/constants';
 import {
   descendedFromClass,
-  getKeyboardEvent,
   isShiftPressed,
+  modifierPressed,
   toggleClass,
 } from '../../../utils/dom-util';
 import {
@@ -78,7 +78,7 @@
 import {GrCursorManager} from '../../shared/gr-cursor-manager/gr-cursor-manager';
 import {PolymerSpliceChange} from '@polymer/polymer/interfaces';
 import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {IronKeyboardEvent} from '../../../types/events';
 import {ParsedChangeInfo, PatchSetFile} from '../../../types/types';
 import {Timing} from '../../../constants/reporting';
 import {RevisionInfo} from '../../shared/revision-info/revision-info';
@@ -363,9 +363,7 @@
     this.fileCursor.scrollMode = ScrollMode.KEEP_VISIBLE;
     this.fileCursor.cursorTargetClass = 'selected';
     this.fileCursor.focusOnMove = true;
-    this.addEventListener('keydown', e =>
-      this._scopedKeydownHandler(e as unknown as CustomKeyboardEvent)
-    );
+    this.addEventListener('keydown', e => this._scopedKeydownHandler(e));
   }
 
   override connectedCallback() {
@@ -435,13 +433,8 @@
    *
    * Context: Issue 7277
    */
-  _scopedKeydownHandler(e: CustomKeyboardEvent) {
-    if (e.keyCode === 13) {
-      // TODO(TS): e is not an instance of CustomKeyboardEvent.
-      // However, to fix it we should fix keyboard-shortcut-mixin first
-      // The keyboard-shortcut-mixin will be updated in a separate change
-      this._handleOpenFile(e as unknown as CustomKeyboardEvent);
-    }
+  _scopedKeydownHandler(e: KeyboardEvent) {
+    if (e.keyCode === 13) this.handleOpenFile(e);
   }
 
   reload() {
@@ -888,7 +881,7 @@
     return fileData;
   }
 
-  _handleLeftPane(e: CustomKeyboardEvent) {
+  _handleLeftPane(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this._noDiffsExpanded()) {
       return;
     }
@@ -897,7 +890,7 @@
     this.diffCursor.moveLeft();
   }
 
-  _handleRightPane(e: CustomKeyboardEvent) {
+  _handleRightPane(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this._noDiffsExpanded()) {
       return;
     }
@@ -906,7 +899,7 @@
     this.diffCursor.moveRight();
   }
 
-  _handleToggleInlineDiff(e: CustomKeyboardEvent) {
+  _handleToggleInlineDiff(e: IronKeyboardEvent) {
     if (
       this.shortcuts.shouldSuppress(e) ||
       this.modifierPressed(e) ||
@@ -920,7 +913,7 @@
     this._toggleFileExpandedByIndex(this.fileCursor.index);
   }
 
-  _handleToggleAllInlineDiffs(e: CustomKeyboardEvent) {
+  _handleToggleAllInlineDiffs(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || e.detail?.keyboardEvent?.repeat) {
       return;
     }
@@ -929,7 +922,7 @@
     this._toggleInlineDiffs();
   }
 
-  _handleToggleHideAllCommentThreads(e: CustomKeyboardEvent) {
+  _handleToggleHideAllCommentThreads(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -938,7 +931,7 @@
     toggleClass(this, 'hideComments');
   }
 
-  _handleCursorNext(e: CustomKeyboardEvent) {
+  _handleCursorNext(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -949,7 +942,7 @@
       this._displayLine = true;
     } else {
       // Down key
-      if (getKeyboardEvent(e).keyCode === 40) {
+      if (e.detail.keyboardEvent.keyCode === 40) {
         return;
       }
       e.preventDefault();
@@ -958,7 +951,7 @@
     }
   }
 
-  _handleCursorPrev(e: CustomKeyboardEvent) {
+  _handleCursorPrev(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -969,7 +962,7 @@
       this._displayLine = true;
     } else {
       // Up key
-      if (getKeyboardEvent(e).keyCode === 38) {
+      if (e.detail.keyboardEvent.keyCode === 38) {
         return;
       }
       e.preventDefault();
@@ -978,7 +971,7 @@
     }
   }
 
-  _handleNewComment(e: CustomKeyboardEvent) {
+  _handleNewComment(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -987,9 +980,9 @@
     this.diffCursor.createCommentInPlace();
   }
 
-  _handleOpenLastFile(e: CustomKeyboardEvent) {
+  _handleOpenLastFile(e: IronKeyboardEvent) {
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (this.shortcuts.shouldSuppress(e) || getKeyboardEvent(e).metaKey) {
+    if (this.shortcuts.shouldSuppress(e) || e.detail.keyboardEvent.metaKey) {
       return;
     }
 
@@ -997,9 +990,9 @@
     this._openSelectedFile(this._files.length - 1);
   }
 
-  _handleOpenFirstFile(e: CustomKeyboardEvent) {
+  _handleOpenFirstFile(e: IronKeyboardEvent) {
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (this.shortcuts.shouldSuppress(e) || getKeyboardEvent(e).metaKey) {
+    if (this.shortcuts.shouldSuppress(e) || e.detail.keyboardEvent.metaKey) {
       return;
     }
 
@@ -1007,8 +1000,13 @@
     this._openSelectedFile(0);
   }
 
-  _handleOpenFile(e: CustomKeyboardEvent) {
-    if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
+  _handleOpenFile(e: IronKeyboardEvent) {
+    if (this.modifierPressed(e)) return;
+    this.handleOpenFile(e.detail.keyboardEvent);
+  }
+
+  handleOpenFile(e: KeyboardEvent) {
+    if (this.shortcuts.shouldSuppress(e) || modifierPressed(e)) {
       return;
     }
     e.preventDefault();
@@ -1021,7 +1019,7 @@
     this._openSelectedFile();
   }
 
-  _handleNextChunk(e: CustomKeyboardEvent) {
+  _handleNextChunk(e: IronKeyboardEvent) {
     if (
       this.shortcuts.shouldSuppress(e) ||
       (this.modifierPressed(e) && !isShiftPressed(e)) ||
@@ -1038,7 +1036,7 @@
     }
   }
 
-  _handlePrevChunk(e: CustomKeyboardEvent) {
+  _handlePrevChunk(e: IronKeyboardEvent) {
     if (
       this.shortcuts.shouldSuppress(e) ||
       (this.modifierPressed(e) && !isShiftPressed(e)) ||
@@ -1055,7 +1053,7 @@
     }
   }
 
-  _handleToggleFileReviewed(e: CustomKeyboardEvent) {
+  _handleToggleFileReviewed(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
@@ -1067,7 +1065,7 @@
     this._reviewFile(this._files[this.fileCursor.index].__path);
   }
 
-  _handleToggleLeftPane(e: CustomKeyboardEvent) {
+  _handleToggleLeftPane(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
@@ -1544,7 +1542,7 @@
     return undefined;
   }
 
-  _handleEscKey(e: CustomKeyboardEvent) {
+  _handleEscKey(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e) || this.modifierPressed(e)) {
       return;
     }
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
index be15716..f4064da 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
@@ -602,15 +602,18 @@
           const openSelectedStub = sinon.stub(element, '_openSelectedFile');
           const expandStub = sinon.stub(element, '_toggleFileExpanded');
 
-          interact = function(opt_payload) {
+          interact = function() {
             openCursorStub.reset();
             openSelectedStub.reset();
             expandStub.reset();
 
-            const e = new CustomEvent('fake-keyboard-event', opt_payload);
-            sinon.stub(e, 'preventDefault');
+            const keyboardEvent = new KeyboardEvent('keydown');
+            const e = new CustomEvent('keydown', {
+              detail: {keyboardEvent, key: 'x'},
+            });
+            sinon.stub(keyboardEvent, 'preventDefault');
             element._handleOpenFile(e);
-            assert.isTrue(e.preventDefault.called);
+            assert.isTrue(keyboardEvent.preventDefault.called);
             const result = {};
             if (openCursorStub.called) {
               result.opened_cursor = true;
@@ -1708,7 +1711,10 @@
       sinon.stub(element, 'modifierPressed')
           .callsFake(() => false);
       element.filesExpanded = FilesExpandedState.ALL;
-      const mockEvent = {preventDefault() {}};
+      const mockEvent = {
+        preventDefault() {},
+        composedPath() { return []; },
+      };
 
       element._displayLine = false;
       element._handleCursorNext(mockEvent);
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index 18a619a..78c1ebd 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -31,10 +31,9 @@
   GrAutocomplete,
 } from '../../shared/gr-autocomplete/gr-autocomplete';
 import {getDocsBaseUrl} from '../../../utils/url-util';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {IronKeyboardEvent} from '../../../types/events';
 import {MergeabilityComputationBehavior} from '../../../constants/constants';
 import {appContext} from '../../../services/app-context';
-import {getKeyboardEvent} from '../../../utils/dom-util';
 
 // Possible static search options for auto complete, without negations.
 const SEARCH_OPERATORS: ReadonlyArray<string> = [
@@ -398,8 +397,8 @@
     });
   }
 
-  _handleSearch(e: CustomKeyboardEvent) {
-    const keyboardEvent = getKeyboardEvent(e);
+  _handleSearch(e: IronKeyboardEvent) {
+    const keyboardEvent = e.detail.keyboardEvent;
     if (
       this.shortcuts.shouldSuppress(e) ||
       (this.modifierPressed(e) && !keyboardEvent.shiftKey)
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index 3b83fd8..e2baec9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -99,14 +99,15 @@
 } from '../../../utils/comment-util';
 import {AppElementParams} from '../../gr-app-types';
 import {
-  CustomKeyboardEvent,
+  IronKeyboardEventListener,
+  IronKeyboardEvent,
   EventType,
   OpenFixPreviewEvent,
 } from '../../../types/events';
 import {fireAlert, fireEvent, fireTitleChange} from '../../../utils/event-util';
 import {GerritView} from '../../../services/router/router-model';
 import {assertIsDefined} from '../../../utils/common-util';
-import {toggleClass, getKeyboardEvent} from '../../../utils/dom-util';
+import {toggleClass} from '../../../utils/dom-util';
 import {CursorMoveResult} from '../../../api/core';
 import {throttleWrap} from '../../../utils/async-util';
 import {changeComments$} from '../../../services/comments/comments-model';
@@ -344,7 +345,7 @@
 
   private readonly shortcuts = appContext.shortcutsService;
 
-  _throttledToggleFileReviewed?: EventListener;
+  _throttledToggleFileReviewed?: IronKeyboardEventListener;
 
   _onRenderHandler?: EventListener;
 
@@ -355,7 +356,7 @@
   override connectedCallback() {
     super.connectedCallback();
     this._throttledToggleFileReviewed = throttleWrap(e =>
-      this._handleToggleFileReviewed(e as CustomKeyboardEvent)
+      this._handleToggleFileReviewed(e)
     );
     this._getLoggedIn().then(loggedIn => {
       this._loggedIn = loggedIn;
@@ -521,7 +522,7 @@
     );
   }
 
-  _handleToggleFileReviewed(e: CustomKeyboardEvent) {
+  _handleToggleFileReviewed(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
 
@@ -529,7 +530,7 @@
     this._setReviewed(!this.$.reviewed.checked);
   }
 
-  _handleEscKey(e: CustomKeyboardEvent) {
+  _handleEscKey(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
 
@@ -537,21 +538,21 @@
     this.$.diffHost.displayLine = false;
   }
 
-  _handleLeftPane(e: CustomKeyboardEvent) {
+  _handleLeftPane(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     e.preventDefault();
     this.cursor.moveLeft();
   }
 
-  _handleRightPane(e: CustomKeyboardEvent) {
+  _handleRightPane(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     e.preventDefault();
     this.cursor.moveRight();
   }
 
-  _handlePrevLineOrFileWithComments(e: CustomKeyboardEvent) {
+  _handlePrevLineOrFileWithComments(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     if (
@@ -571,7 +572,7 @@
     this.cursor.moveUp();
   }
 
-  _handleVisibleLine(e: CustomKeyboardEvent) {
+  _handleVisibleLine(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     e.preventDefault();
@@ -582,7 +583,7 @@
     this.$.applyFixDialog.open(e);
   }
 
-  _handleNextLineOrFileWithComments(e: CustomKeyboardEvent) {
+  _handleNextLineOrFileWithComments(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     if (
@@ -641,38 +642,40 @@
     );
   }
 
-  _handleNewComment(e: CustomKeyboardEvent) {
-    if (this.shortcuts.shouldSuppress(e)) return;
-    if (this.modifierPressed(e)) return;
+  _handleNewComment(ike: IronKeyboardEvent) {
+    if (this.shortcuts.shouldSuppress(ike)) return;
+    if (this.modifierPressed(ike)) return;
 
-    e.preventDefault();
+    ike.preventDefault();
     this.classList.remove('hideComments');
     this.cursor.createCommentInPlace();
   }
 
-  _handlePrevFile(e: CustomKeyboardEvent) {
-    if (this.shortcuts.shouldSuppress(e)) return;
+  _handlePrevFile(ike: IronKeyboardEvent) {
+    const ke = ike.detail.keyboardEvent;
+    if (this.shortcuts.shouldSuppress(ike)) return;
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (getKeyboardEvent(e).metaKey) return;
+    if (ke.metaKey) return;
     if (!this._path) return;
     if (!this._fileList) return;
 
-    e.preventDefault();
+    ike.preventDefault();
     this._navToFile(this._path, this._fileList, -1);
   }
 
-  _handleNextFile(e: CustomKeyboardEvent) {
-    if (this.shortcuts.shouldSuppress(e)) return;
+  _handleNextFile(ike: IronKeyboardEvent) {
+    const ke = ike.detail.keyboardEvent;
+    if (this.shortcuts.shouldSuppress(ike)) return;
     // Check for meta key to avoid overriding native chrome shortcut.
-    if (getKeyboardEvent(e).metaKey) return;
+    if (ke.metaKey) return;
     if (!this._path) return;
     if (!this._fileList) return;
 
-    e.preventDefault();
+    ike.preventDefault();
     this._navToFile(this._path, this._fileList, 1);
   }
 
-  _handleNextChunkOrCommentThread(e: CustomKeyboardEvent) {
+  _handleNextChunkOrCommentThread(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     e.preventDefault();
@@ -733,7 +736,7 @@
     this._navToFile(this._path, unreviewedFiles, direction === 'next' ? 1 : -1);
   }
 
-  _handlePrevChunkOrCommentThread(e: CustomKeyboardEvent) {
+  _handlePrevChunkOrCommentThread(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     e.preventDefault();
@@ -749,7 +752,7 @@
   }
 
   // Similar to gr-change-view._handleOpenReplyDialog
-  _handleOpenReplyDialog(e: CustomKeyboardEvent) {
+  _handleOpenReplyDialog(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
     this._getLoggedIn().then(isLoggedIn => {
@@ -764,7 +767,7 @@
     });
   }
 
-  _handleToggleLeftPane(e: CustomKeyboardEvent) {
+  _handleToggleLeftPane(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (!e.detail.keyboardEvent?.shiftKey) return;
 
@@ -772,7 +775,7 @@
     this.$.diffHost.toggleLeftDiff();
   }
 
-  _handleOpenDownloadDialog(e: CustomKeyboardEvent) {
+  _handleOpenDownloadDialog(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
 
@@ -781,7 +784,7 @@
     this._navToChangeView();
   }
 
-  _handleUpToChange(e: CustomKeyboardEvent) {
+  _handleUpToChange(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
 
@@ -789,7 +792,7 @@
     this._navToChangeView();
   }
 
-  _handleCommaKey(e: CustomKeyboardEvent) {
+  _handleCommaKey(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
     if (this._diffPrefsDisabled) return;
@@ -798,7 +801,7 @@
     this.$.diffPreferencesDialog.open();
   }
 
-  _handleToggleDiffMode(e: CustomKeyboardEvent) {
+  _handleToggleDiffMode(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
 
@@ -1695,27 +1698,27 @@
     this._loadBlame();
   }
 
-  _handleToggleBlame(e: CustomKeyboardEvent) {
+  _handleToggleBlame(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
 
     this._toggleBlame();
   }
 
-  _handleToggleHideAllCommentThreads(e: CustomKeyboardEvent) {
+  _handleToggleHideAllCommentThreads(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
 
     toggleClass(this, 'hideComments');
   }
 
-  _handleOpenFileList(e: CustomKeyboardEvent) {
+  _handleOpenFileList(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (this.modifierPressed(e)) return;
     this.$.dropdown.open();
   }
 
-  _handleDiffAgainstBase(e: CustomKeyboardEvent) {
+  _handleDiffAgainstBase(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (!this._change) return;
     if (!this._path) return;
@@ -1732,7 +1735,7 @@
     );
   }
 
-  _handleDiffBaseAgainstLeft(e: CustomKeyboardEvent) {
+  _handleDiffBaseAgainstLeft(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (!this._change) return;
     if (!this._path) return;
@@ -1753,7 +1756,7 @@
     );
   }
 
-  _handleDiffAgainstLatest(e: CustomKeyboardEvent) {
+  _handleDiffAgainstLatest(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (!this._change) return;
     if (!this._path) return;
@@ -1773,7 +1776,7 @@
     );
   }
 
-  _handleDiffRightAgainstLatest(e: CustomKeyboardEvent) {
+  _handleDiffRightAgainstLatest(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (!this._change) return;
     if (!this._path) return;
@@ -1792,7 +1795,7 @@
     );
   }
 
-  _handleDiffBaseAgainstLatest(e: CustomKeyboardEvent) {
+  _handleDiffBaseAgainstLatest(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     if (!this._change) return;
     if (!this._path) return;
@@ -1830,7 +1833,7 @@
     return '';
   }
 
-  _handleToggleAllDiffContext(e: CustomKeyboardEvent) {
+  _handleToggleAllDiffContext(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
 
     this.$.diffHost.toggleAllContext();
@@ -1840,7 +1843,7 @@
     return disableDiffPrefs || !loggedIn;
   }
 
-  _handleNextUnreviewedFile(e: CustomKeyboardEvent) {
+  _handleNextUnreviewedFile(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     this._setReviewed(true);
     this.navigateToUnreviewedFile('next');
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
index a1ec6e2..735624a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
@@ -1477,7 +1477,9 @@
     });
 
     test('_handleToggleDiffMode', () => {
-      const e = {preventDefault: () => {}};
+      const e = new CustomEvent('keydown', {
+        detail: {keyboardEvent: new KeyboardEvent('keydown'), key: 'x'},
+      });
       // Initial state.
       assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
 
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
index f0a3ca1..d87b573 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
@@ -351,7 +351,7 @@
     }
   }
 
-  _handleKeyPress(event: InputEvent) {
+  _handleKeyPress(event: KeyboardEvent) {
     event.preventDefault();
     event.stopImmediatePropagation();
   }
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index 6f2d27e..ad7e015 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -47,6 +47,7 @@
 import {GrButton} from '../../shared/gr-button/gr-button';
 import {GrDefaultEditor} from '../gr-default-editor/gr-default-editor';
 import {GrEndpointDecorator} from '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
+import {IronKeyboardEvent} from '../../../types/events';
 
 const RESTORED_MESSAGE = 'Content restored from a previous edit.';
 const SAVING_MESSAGE = 'Saving changes...';
@@ -393,7 +394,7 @@
     );
   }
 
-  _handleSaveShortcut(e: KeyboardEvent) {
+  _handleSaveShortcut(e: IronKeyboardEvent) {
     e.preventDefault();
     if (!this._saveDisabled) {
       this._saveEdit();
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index aa5562d..3b93bea 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -68,7 +68,7 @@
 import {GrMainHeader} from './core/gr-main-header/gr-main-header';
 import {GrSettingsView} from './settings/gr-settings-view/gr-settings-view';
 import {
-  CustomKeyboardEvent,
+  IronKeyboardEvent,
   DialogChangeEventDetail,
   EventType,
   LocationChangeEvent,
@@ -502,7 +502,7 @@
     (this.shadowRoot!.querySelector('#keyboardShortcuts') as GrOverlay).open();
   }
 
-  _showKeyboardShortcuts(e: CustomKeyboardEvent) {
+  _showKeyboardShortcuts(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) return;
     // same shortcut should close the dialog if pressed again
     // when dialog is open
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
index 536beb4..bd6835c 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
@@ -26,7 +26,6 @@
 import {EditableAccountField} from '../../../constants/constants';
 import {appContext} from '../../../services/app-context';
 import {fireEvent} from '../../../utils/event-util';
-import {KeydownEvent} from '../../../types/events';
 
 @customElement('gr-account-info')
 export class GrAccountInfo extends PolymerElement {
@@ -247,7 +246,7 @@
     this._hasNameChange = true;
   }
 
-  _handleKeydown(e: KeydownEvent) {
+  _handleKeydown(e: KeyboardEvent) {
     if (e.keyCode === 13) {
       // Enter
       e.stopPropagation();
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
index 4096b02..c392a13 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
@@ -23,7 +23,6 @@
 import {htmlTemplate} from './gr-menu-editor_html';
 import {customElement, property} from '@polymer/decorators';
 import {TopMenuItemInfo} from '../../../types/common';
-import {KeydownEvent} from '../../../types/events';
 
 @customElement('gr-menu-editor')
 export class GrMenuEditor extends PolymerElement {
@@ -90,7 +89,7 @@
     return !newName?.length || !newUrl?.length;
   }
 
-  _handleInputKeydown(e: KeydownEvent) {
+  _handleInputKeydown(e: KeyboardEvent) {
     if (e.keyCode === 13) {
       e.stopPropagation();
       this._handleAddButton();
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 94333c7..3533fd6 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -62,7 +62,6 @@
 import {GrSshEditor} from '../gr-ssh-editor/gr-ssh-editor';
 import {GrGpgEditor} from '../gr-gpg-editor/gr-gpg-editor';
 import {GrEmailEditor} from '../gr-email-editor/gr-email-editor';
-import {KeydownEvent} from '../../../types/events';
 import {fireAlert, fireTitleChange} from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
 import {GerritView} from '../../../services/router/router-model';
@@ -489,7 +488,7 @@
     this.$.emailEditor.save();
   }
 
-  _handleNewEmailKeydown(e: KeydownEvent) {
+  _handleNewEmailKeydown(e: KeyboardEvent) {
     if (e.keyCode === 13) {
       // Enter
       e.stopPropagation();
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
index c5d1f03..d97e38e 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
@@ -39,7 +39,6 @@
 import {PaperInputElementExt} from '../../../types/types';
 import {fireAlert} from '../../../utils/event-util';
 import {accountOrGroupKey} from '../../../utils/account-util';
-import {KeydownEvent} from '../../../types/events';
 
 const VALID_EMAIL_ALERT = 'Please input a valid email.';
 
@@ -360,7 +359,7 @@
     }
   }
 
-  _handleChipKeydown(e: KeydownEvent) {
+  _handleChipKeydown(e: KeyboardEvent) {
     const chip = e.target as GrAccountChip;
     const chips = this.accountChips;
     const index = chips.indexOf(chip);
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index 9918f39..524b197 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -26,10 +26,10 @@
 import {property, customElement, observe} from '@polymer/decorators';
 import {GrAutocompleteDropdown} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
 import {PaperInputElementExt} from '../../../types/types';
-import {CustomKeyboardEvent} from '../../../types/events';
 import {fireEvent} from '../../../utils/event-util';
 import {debounce, DelayedTask} from '../../../utils/async-util';
 import {PropertyType} from '../../../types/common';
+import {modifierPressed} from '../../../utils/dom-util';
 
 const TOKENIZE_REGEX = /(?:[^\s"]+|"[^"]*")+/g;
 const DEBOUNCE_WAIT_MS = 200;
@@ -358,7 +358,7 @@
    * _handleKeydown used for key handling in the this.$.input AND all child
    * autocomplete options.
    */
-  _handleKeydown(e: CustomKeyboardEvent) {
+  _handleKeydown(e: KeyboardEvent) {
     this._focused = true;
     switch (e.keyCode) {
       case 38: // Up
@@ -383,7 +383,7 @@
         }
         break;
       case 13: // Enter
-        if (this.modifierPressed(e)) {
+        if (modifierPressed(e)) {
           break;
         }
         e.preventDefault();
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
index 7017c9c..8dc23e2 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
@@ -19,14 +19,9 @@
 import {votingStyles} from '../../../styles/gr-voting-styles';
 import {css, html, LitElement, PropertyValues} from 'lit';
 import {customElement, property} from 'lit/decorators';
-import {
-  getEventPath,
-  getKeyboardEvent,
-  isModifierPressed,
-} from '../../../utils/dom-util';
+import {getEventPath, modifierPressed} from '../../../utils/dom-util';
 import {appContext} from '../../../services/app-context';
 import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
-import {CustomKeyboardEvent} from '../../../types/events';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -206,9 +201,7 @@
     super();
     this.initialTabindex = this.getAttribute('tabindex') || '0';
     this.addEventListener('click', e => this._handleAction(e));
-    this.addEventListener('keydown', e =>
-      this._handleKeydown(e as unknown as CustomKeyboardEvent)
-    );
+    this.addEventListener('keydown', e => this._handleKeydown(e));
   }
 
   override updated(changedProperties: PropertyValues) {
@@ -247,11 +240,8 @@
     this.reporting.reportInteraction('button-click', {path: getEventPath(e)});
   }
 
-  _handleKeydown(e: CustomKeyboardEvent) {
-    if (isModifierPressed(e)) {
-      return;
-    }
-    e = getKeyboardEvent(e);
+  _handleKeydown(e: KeyboardEvent) {
+    if (modifierPressed(e)) return;
     // Handle `enter`, `space`.
     if (e.keyCode === 13 || e.keyCode === 32) {
       e.preventDefault();
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index db4c7e0..72e6de6 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -52,7 +52,7 @@
 } from '../../../types/common';
 import {GrComment} from '../gr-comment/gr-comment';
 import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {IronKeyboardEvent} from '../../../types/events';
 import {LineNumber, FILE} from '../../diff/gr-diff/gr-diff-line';
 import {GrButton} from '../gr-button/gr-button';
 import {KnownExperimentId} from '../../../services/flags/flags';
@@ -496,7 +496,7 @@
     return this._orderedComments[this._orderedComments.length - 1] || {};
   }
 
-  _handleEKey(e: CustomKeyboardEvent) {
+  _handleEKey(e: IronKeyboardEvent) {
     if (this.shortcuts.shouldSuppress(e)) {
       return;
     }
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
index 27c6341..74e34a0 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
@@ -21,7 +21,6 @@
 import {htmlTemplate} from './gr-dialog_html';
 import {customElement, property, observe} from '@polymer/decorators';
 import {GrButton} from '../gr-button/gr-button';
-import {KeydownEvent} from '../../../types/events';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -109,7 +108,7 @@
     );
   }
 
-  _handleKeydown(e: KeydownEvent) {
+  _handleKeydown(e: KeyboardEvent) {
     if (this.confirmOnEnter && e.keyCode === 13) {
       this._handleConfirm(e);
     }
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
index bd1046f..13b195e 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
@@ -26,12 +26,11 @@
 import {IronDropdownElement} from '@polymer/iron-dropdown/iron-dropdown';
 import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
 import {PaperInputElementExt} from '../../../types/types';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {IronKeyboardEvent} from '../../../types/events';
 import {
   AutocompleteQuery,
   GrAutocomplete,
 } from '../gr-autocomplete/gr-autocomplete';
-import {getKeyboardEvent} from '../../../utils/dom-util';
 
 const AWAIT_MAX_ITERS = 10;
 const AWAIT_STEP = 5;
@@ -205,8 +204,8 @@
       this.getGrAutocomplete()) as HTMLInputElement;
   }
 
-  _handleEnter(e: CustomKeyboardEvent) {
-    e = getKeyboardEvent(e);
+  _handleEnter(event: IronKeyboardEvent) {
+    const e = event.detail.keyboardEvent;
     const target = (dom(e) as EventApi).rootTarget;
     if (target === this._nativeInput) {
       e.preventDefault();
@@ -214,8 +213,8 @@
     }
   }
 
-  _handleEsc(e: CustomKeyboardEvent) {
-    e = getKeyboardEvent(e);
+  _handleEsc(event: IronKeyboardEvent) {
+    const e = event.detail.keyboardEvent;
     const target = (dom(e) as EventApi).rootTarget;
     if (target === this._nativeInput) {
       e.preventDefault();
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
index ce1eec3..434da1f 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
@@ -33,7 +33,7 @@
   Item,
   ItemSelectedEvent,
 } from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {IronKeyboardEvent} from '../../../types/events';
 
 const MAX_ITEMS_DROPDOWN = 10;
 
@@ -238,7 +238,7 @@
     this._setEmoji(this.$.emojiSuggestions.getCurrentText());
   }
 
-  _handleEnterByKey(e: CustomKeyboardEvent) {
+  _handleEnterByKey(e: IronKeyboardEvent) {
     // Enter should have newline behavior if the picker is closed or if the user
     // has only typed ':'. Also make sure that shortcuts aren't clobbered.
     if (this._hideEmojiAutocomplete || this.disableEnterKeyForSelectingEmoji) {
@@ -420,7 +420,7 @@
     );
   }
 
-  private indent(e: CustomKeyboardEvent): void {
+  private indent(e: IronKeyboardEvent): void {
     if (!document.queryCommandSupported('insertText')) {
       return;
     }
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
index 7790c73..7e59692 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
@@ -20,7 +20,7 @@
 import {GrTextarea} from './gr-textarea';
 import {html} from '@polymer/polymer/lib/utils/html-tag';
 import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
-import {CustomKeyboardEvent} from '../../../types/events';
+import {IronKeyboardEvent} from '../../../types/events';
 import {ItemSelectedEvent} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
 
 const basicFixture = fixtureFromElement('gr-textarea');
@@ -240,7 +240,7 @@
     element._handleEnterByKey(
       new CustomEvent('keydown', {
         detail: {keyboardEvent: {keyCode: 13}},
-      }) as CustomKeyboardEvent
+      }) as IronKeyboardEvent
     );
     await flush();
     assert.deepEqual(indentCommand.args[0], ['insertText', false, '\n    ']);
@@ -252,7 +252,7 @@
     element._handleEnterByKey(
       new CustomEvent('keydown', {
         detail: {keyboardEvent: {keyCode: 13, ctrlKey: true}},
-      }) as CustomKeyboardEvent
+      }) as IronKeyboardEvent
     );
     await flush();
     assert.isTrue(indentCommand.notCalled);
@@ -260,7 +260,7 @@
     element._handleEnterByKey(
       new CustomEvent('keydown', {
         detail: {keyboardEvent: {keyCode: 13, metaKey: true}},
-      }) as CustomKeyboardEvent
+      }) as IronKeyboardEvent
     );
     await flush();
     assert.isTrue(indentCommand.notCalled);
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
index d11d71e..3d1e120 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
@@ -19,8 +19,8 @@
 import {property} from '@polymer/decorators';
 import {PolymerElement} from '@polymer/polymer';
 import {check, Constructor} from '../../utils/common-util';
-import {getKeyboardEvent, isModifierPressed} from '../../utils/dom-util';
-import {CustomKeyboardEvent} from '../../types/events';
+import {isModifierPressed} from '../../utils/dom-util';
+import {IronKeyboardEvent} from '../../types/events';
 import {appContext} from '../../services/app-context';
 import {
   Shortcut,
@@ -100,22 +100,16 @@
     /** Are shortcuts currently enabled? True only when element is visible. */
     private bindingsEnabled = false;
 
-    modifierPressed(event: CustomKeyboardEvent) {
+    modifierPressed(e: IronKeyboardEvent) {
       /* We are checking for g/v as modifiers pressed. There are cases such as
        * pressing v and then /, where we want the handler for / to be triggered.
        * TODO(dhruvsri): find a way to support that keyboard combination
        */
-      const e = getKeyboardEvent(event);
       return (
         isModifierPressed(e) || !!this._inGoKeyMode() || !!this.inVKeyMode()
       );
     }
 
-    // Alias for getKeyboardEvent.
-    getKeyboardEvent(e: CustomKeyboardEvent) {
-      return getKeyboardEvent(e);
-    }
-
     _addOwnKeyBindings(shortcut: Shortcut, handler: string) {
       const bindings = this.shortcuts.getBindingsForShortcut(shortcut);
       if (!bindings) {
@@ -237,7 +231,7 @@
       return {};
     }
 
-    _handleVKeyDown(e: CustomKeyboardEvent) {
+    _handleVKeyDown(e: IronKeyboardEvent) {
       if (this.shortcuts.shouldSuppress(e)) return;
       this._shortcut_v_key_last_pressed = Date.now();
     }
@@ -255,7 +249,7 @@
       );
     }
 
-    _handleVAction(e: CustomKeyboardEvent) {
+    _handleVAction(e: IronKeyboardEvent) {
       if (
         !this.inVKeyMode() ||
         !this._shortcut_v_table.has(e.detail.key) ||
@@ -272,7 +266,7 @@
       }
     }
 
-    _handleGoKeyDown(e: CustomKeyboardEvent) {
+    _handleGoKeyDown(e: IronKeyboardEvent) {
       if (this.shortcuts.shouldSuppress(e)) return;
       this._shortcut_go_key_last_pressed = Date.now();
     }
@@ -292,7 +286,7 @@
       );
     }
 
-    _handleGoAction(e: CustomKeyboardEvent) {
+    _handleGoAction(e: IronKeyboardEvent) {
       if (
         !this._inGoKeyMode() ||
         !this._shortcut_go_table.has(e.detail.key) ||
@@ -340,7 +334,7 @@
 /** The interface corresponding to KeyboardShortcutMixin */
 export interface KeyboardShortcutMixinInterface {
   keyboardShortcuts(): {[key: string]: string | null};
-  modifierPressed(event: CustomKeyboardEvent): boolean;
+  modifierPressed(event: IronKeyboardEvent): boolean;
 }
 
 export interface KeyboardShortcutMixinInterfaceTesting {
@@ -348,5 +342,5 @@
   _shortcut_v_key_last_pressed: number | null;
   _shortcut_go_table: Map<string, string>;
   _shortcut_v_table: Map<string, string>;
-  _handleGoAction: (e: CustomKeyboardEvent) => void;
+  _handleGoAction: (e: IronKeyboardEvent) => void;
 }
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.ts b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.ts
index babe44a..01ad6cc 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.ts
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.ts
@@ -19,7 +19,7 @@
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import '../../elements/shared/gr-overlay/gr-overlay';
 import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
-import {CustomKeyboardEvent} from '../../types/events';
+import {IronKeyboardEvent} from '../../types/events';
 
 class GrKeyboardShortcutMixinTestElement extends KeyboardShortcutMixin(
   PolymerElement
@@ -95,7 +95,8 @@
       const e = {
         detail: {key: 'a'},
         preventDefault: () => {},
-      } as CustomKeyboardEvent;
+        composedPath: () => [],
+      } as unknown as IronKeyboardEvent;
       element._shortcut_go_key_last_pressed = 9000;
       element._handleGoAction(e);
       assert.isTrue(handlerStub.calledOnce);
@@ -106,7 +107,8 @@
       const e = {
         detail: {key: 'a'},
         preventDefault: () => {},
-      } as CustomKeyboardEvent;
+        composedPath: () => [],
+      } as unknown as IronKeyboardEvent;
       element._shortcut_go_key_last_pressed = null;
       element._handleGoAction(e);
       assert.isFalse(handlerStub.called);
@@ -116,7 +118,8 @@
       const e = {
         detail: {key: 'a'},
         preventDefault: () => {},
-      } as CustomKeyboardEvent;
+        composedPath: () => [],
+      } as unknown as IronKeyboardEvent;
       element._shortcut_go_key_last_pressed = 3000;
       element._handleGoAction(e);
       assert.isFalse(handlerStub.called);
@@ -126,7 +129,8 @@
       const e = {
         detail: {key: 'f'},
         preventDefault: () => {},
-      } as CustomKeyboardEvent;
+        composedPath: () => [],
+      } as unknown as IronKeyboardEvent;
       element._shortcut_go_key_last_pressed = 9000;
       element._handleGoAction(e);
       assert.isFalse(handlerStub.called);
diff --git a/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts b/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts
index c3aa06e..d0e2d49 100644
--- a/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts
+++ b/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts
@@ -22,8 +22,8 @@
   SPECIAL_SHORTCUT,
 } from './shortcuts-config';
 import {disableShortcuts$} from '../user/user-model';
-import {CustomKeyboardEvent} from '../../types/events';
-import {getKeyboardEvent, isElementTarget} from '../../utils/dom-util';
+import {IronKeyboardEvent, isIronKeyboardEvent} from '../../types/events';
+import {isElementTarget} from '../../utils/dom-util';
 import {ReportingService} from '../gr-reporting/gr-reporting';
 
 export type SectionView = Array<{binding: string[][]; text: string}>;
@@ -35,6 +35,8 @@
   viewMap?: Map<ShortcutSection, SectionView>
 ) => void;
 
+const COMBO_KEYS = ['g', 'v'];
+
 /**
  * Shortcuts service, holds all hosts, bindings and listeners.
  */
@@ -51,6 +53,14 @@
 
   private readonly listeners = new Set<ShortcutListener>();
 
+  /**
+   * Maps keys (e.g. 'g') to the timestamp when they have last been pressed.
+   * This enabled key combinations like 'g+o' where we can check whether 'g' was
+   * pressed recently when 'o' is processed. Keys of this map must be items of
+   * COMBO_KEYS. Values are Date timestamps in milliseconds.
+   */
+  private readonly keyLastPressed = new Map<string, number>();
+
   /** Keeps track of the corresponding user preference. */
   private shortcutsDisabled = false;
 
@@ -62,15 +72,20 @@
       }
     }
     disableShortcuts$.subscribe(x => (this.shortcutsDisabled = x));
+    document.addEventListener('keydown', (e: KeyboardEvent) => {
+      if (!COMBO_KEYS.includes(e.key)) return;
+      if (this.shouldSuppress(e)) return;
+      this.keyLastPressed.set(e.key, Date.now());
+    });
   }
 
   public _testOnly_isEmpty() {
     return this.activeHosts.size === 0 && this.listeners.size === 0;
   }
 
-  shouldSuppress(event: CustomKeyboardEvent) {
+  shouldSuppress(event: IronKeyboardEvent | KeyboardEvent) {
     if (this.shortcutsDisabled) return true;
-    const e = getKeyboardEvent(event);
+    const e = isIronKeyboardEvent(event) ? event.detail.keyboardEvent : event;
 
     // Note that when you listen on document, then `e.currentTarget` will be the
     // document and `e.target` will be `<gr-app>` due to shadow dom, but by
@@ -94,14 +109,13 @@
     ) {
       return true;
     }
-    for (let i = 0; e.path && i < e.path.length; i++) {
-      // TODO(TS): narrow this down to Element from EventTarget first
-      if ((e.path[i] as Element).tagName === 'GR-OVERLAY') {
-        return true;
-      }
+    const path: EventTarget[] = e.composedPath() ?? [];
+    for (const el of path) {
+      if (!isElementTarget(el)) continue;
+      if (el.tagName === 'GR-OVERLAY') return true;
     }
     // eg: {key: "k:keydown", ..., from: "gr-diff-view"}
-    let key = `${(e as unknown as KeyboardEvent).key}:${e.type}`;
+    let key = `${e.key}:${e.type}`;
     // TODO(brohlfs): Re-enable reporting of g- and v-keys.
     // if (this._inGoKeyMode()) key = 'g+' + key;
     // if (this.inVKeyMode()) key = 'v+' + key;
diff --git a/polygerrit-ui/app/services/shortcuts/shortcuts-service_test.ts b/polygerrit-ui/app/services/shortcuts/shortcuts-service_test.ts
index f795f78..0998a4c 100644
--- a/polygerrit-ui/app/services/shortcuts/shortcuts-service_test.ts
+++ b/polygerrit-ui/app/services/shortcuts/shortcuts-service_test.ts
@@ -18,20 +18,18 @@
 import {ShortcutsService} from '../../services/shortcuts/shortcuts-service';
 import {Shortcut, ShortcutSection} from './shortcuts-config';
 import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
-import {CustomKeyboardEvent} from '../../types/events';
 
 async function keyEventOn(
-  el: Element,
-  callback: (e: CustomKeyboardEvent) => void,
+  el: HTMLElement,
+  callback: (e: KeyboardEvent) => void,
   keyCode = 75,
   key = 'k'
-): Promise<CustomKeyboardEvent> {
-  let resolve: (e: CustomKeyboardEvent) => void;
-  const promise = new Promise<CustomKeyboardEvent>(r => (resolve = r));
-  el.addEventListener('keydown', e => {
-    const cke = e as CustomKeyboardEvent;
-    callback(cke);
-    resolve(cke);
+): Promise<KeyboardEvent> {
+  let resolve: (e: KeyboardEvent) => void;
+  const promise = new Promise<KeyboardEvent>(r => (resolve = r));
+  el.addEventListener('keydown', (e: KeyboardEvent) => {
+    callback(e);
+    resolve(e);
   });
   MockInteractions.keyDownOn(el, keyCode, null, key);
   return await promise;
diff --git a/polygerrit-ui/app/types/events.ts b/polygerrit-ui/app/types/events.ts
index 0069321..c78f61a 100644
--- a/polygerrit-ui/app/types/events.ts
+++ b/polygerrit-ui/app/types/events.ts
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
 import {PatchSetNum} from './common';
 import {UIComment} from '../utils/comment-util';
 import {FetchRequest} from './types';
@@ -69,10 +68,6 @@
     'editable-content-save': EditableContentSaveEvent;
     'location-change': LocationChangeEvent;
     'iron-announce': IronAnnounceEvent;
-    /* prettier-ignore */
-    'keydown': KeydownEvent;
-    /* prettier-ignore */
-    'keypress': KeypressEvent;
     'line-mouse-enter': LineNumberEvent;
     'line-mouse-leave': LineNumberEvent;
     'line-cursor-moved-in': LineNumberEvent;
@@ -148,10 +143,6 @@
 }
 export type IronAnnounceEvent = CustomEvent<IronAnnounceEventDetail>;
 
-export type KeydownEvent = CustomKeyboardEvent;
-
-export type KeypressEvent = InputEvent;
-
 export interface LocationChangeEventDetail {
   hash: string;
   pathname: string;
@@ -252,20 +243,28 @@
 export type TitleChangeEvent = CustomEvent<TitleChangeEventDetail>;
 
 /**
- * Keyboard events emitted from polymer elements.
+ * Keyboard events emitted from elements using IronA11yKeysBehavior: That means
+ * that the element returns a list of handlers from either `keyBindings()` or
+ * from `keyboardShortcuts()`. This event should not be used in Lit elements
+ * and will be obsolete once the Lit migration is completed.
  */
-export interface CustomKeyboardEvent extends CustomEvent, EventApi {
-  event: CustomKeyboardEvent;
-  detail: {
-    keyboardEvent?: CustomKeyboardEvent;
-    // TODO(TS): maybe should mark as optional and check before accessing
-    key: string;
-  };
-  readonly altKey: boolean;
-  readonly changedTouches: TouchList;
-  readonly ctrlKey: boolean;
-  readonly metaKey: boolean;
-  readonly shiftKey: boolean;
-  readonly keyCode: number;
-  readonly repeat: boolean;
+export interface IronKeyboardEvent extends CustomEvent {
+  detail: IronKeyboardEventDetail;
+}
+
+export interface IronKeyboardEventDetail {
+  keyboardEvent: KeyboardEvent;
+  key: string;
+  combo?: string;
+}
+
+export function isIronKeyboardEvent(
+  e: IronKeyboardEvent | Event | CustomEvent
+): e is IronKeyboardEvent {
+  const ike = e as IronKeyboardEvent;
+  return !!ike?.detail?.keyboardEvent;
+}
+
+export interface IronKeyboardEventListener {
+  (evt: IronKeyboardEvent): void;
 }
diff --git a/polygerrit-ui/app/utils/async-util.ts b/polygerrit-ui/app/utils/async-util.ts
index c82f5e4..90ee5a5 100644
--- a/polygerrit-ui/app/utils/async-util.ts
+++ b/polygerrit-ui/app/utils/async-util.ts
@@ -117,9 +117,9 @@
  * Ensure only one call is made within THROTTLE_INTERVAL_MS and any call within
  * this interval is ignored
  */
-export function throttleWrap(fn: (e: Event) => void) {
+export function throttleWrap<T>(fn: (e: T) => void) {
   let lastCall: number | undefined;
-  return (e: Event) => {
+  return (e: T) => {
     if (
       lastCall !== undefined &&
       Date.now() - lastCall < THROTTLE_INTERVAL_MS
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts
index 71f913d..ead47bb 100644
--- a/polygerrit-ui/app/utils/dom-util.ts
+++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -14,10 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
+import {EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
 import {check} from './common-util';
-import {CustomKeyboardEvent} from '../types/events';
+import {IronKeyboardEvent} from '../types/events';
 
 /**
  * Event emitted from polymer elements.
@@ -309,23 +308,14 @@
   return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey;
 }
 
-// Deprecated. Try using "normal" KeyboardEvent and modifierPressed() above.
-export function isModifierPressed(event: CustomKeyboardEvent) {
-  const e = getKeyboardEvent(event);
-  return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey;
-}
-
-export function isShiftPressed(event: CustomKeyboardEvent) {
-  const e = getKeyboardEvent(event);
+export function shiftPressed(e: KeyboardEvent) {
   return e.shiftKey;
 }
 
-export function getKeyboardEvent(e: CustomKeyboardEvent): CustomKeyboardEvent {
-  const event = dom(e.detail ? e.detail.keyboardEvent : e);
-  // TODO(TS): worth checking if this still holds or not, if no, remove this.
-  // When e is a keyboardEvent, e.event is not null.
-  if ('event' in event && (event as CustomKeyboardEvent).event) {
-    return (event as CustomKeyboardEvent).event;
-  }
-  return event as CustomKeyboardEvent;
+export function isModifierPressed(e: IronKeyboardEvent) {
+  return modifierPressed(e.detail.keyboardEvent);
+}
+
+export function isShiftPressed(e: IronKeyboardEvent) {
+  return shiftPressed(e.detail.keyboardEvent);
 }