in web/app.js [2740:3083]
function onKeyDown(evt) {
this._isCtrlKeyDown = evt.key === "Control";
if (
this.editorUndoBar?.isOpen &&
evt.keyCode !== 9 &&
evt.keyCode !== 16 &&
!(
(evt.keyCode === 13 || evt.keyCode === 32) &&
getActiveOrFocusedElement() === this.appConfig.editorUndoBar.undoButton
)
) {
// Hide undo bar on keypress except for Shift, Tab, Shift+Tab.
// Also avoid hiding if the undo button is triggered.
this.editorUndoBar.hide();
}
if (this.overlayManager.active) {
return;
}
const { eventBus, pdfViewer } = this;
const isViewerInPresentationMode = pdfViewer.isInPresentationMode;
let handled = false,
ensureViewerFocused = false;
const cmd =
(evt.ctrlKey ? 1 : 0) |
(evt.altKey ? 2 : 0) |
(evt.shiftKey ? 4 : 0) |
(evt.metaKey ? 8 : 0);
// First, handle the key bindings that are independent whether an input
// control is selected or not.
if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
// either CTRL or META key with optional SHIFT.
switch (evt.keyCode) {
case 70: // f
if (!this.supportsIntegratedFind && !evt.shiftKey) {
this.findBar?.open();
handled = true;
}
break;
case 71: // g
if (!this.supportsIntegratedFind) {
const { state } = this.findController;
if (state) {
const newState = {
source: window,
type: "again",
findPrevious: cmd === 5 || cmd === 12,
};
eventBus.dispatch("find", { ...state, ...newState });
}
handled = true;
}
break;
case 61: // FF/Mac '='
case 107: // FF '+' and '='
case 187: // Chrome '+'
case 171: // FF with German keyboard
this.zoomIn();
handled = true;
break;
case 173: // FF/Mac '-'
case 109: // FF '-'
case 189: // Chrome '-'
this.zoomOut();
handled = true;
break;
case 48: // '0'
case 96: // '0' on Numpad of Swedish keyboard
if (!isViewerInPresentationMode) {
// keeping it unhandled (to restore page zoom to 100%)
setTimeout(() => {
// ... and resetting the scale after browser adjusts its scale
this.zoomReset();
});
handled = false;
}
break;
case 38: // up arrow
if (isViewerInPresentationMode || this.page > 1) {
this.page = 1;
handled = true;
ensureViewerFocused = true;
}
break;
case 40: // down arrow
if (isViewerInPresentationMode || this.page < this.pagesCount) {
this.page = this.pagesCount;
handled = true;
ensureViewerFocused = true;
}
break;
}
}
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC || CHROME")) {
// CTRL or META without shift
if (cmd === 1 || cmd === 8) {
switch (evt.keyCode) {
case 83: // s
eventBus.dispatch("download", { source: window });
handled = true;
break;
case 79: // o
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
eventBus.dispatch("openfile", { source: window });
handled = true;
}
break;
}
}
}
// CTRL+ALT or Option+Command
if (cmd === 3 || cmd === 10) {
switch (evt.keyCode) {
case 80: // p
this.requestPresentationMode();
handled = true;
this.externalServices.reportTelemetry({
type: "buttons",
data: { id: "presentationModeKeyboard" },
});
break;
case 71: // g
// focuses input#pageNumber field
if (this.appConfig.toolbar) {
this.appConfig.toolbar.pageNumber.select();
handled = true;
}
break;
}
}
if (handled) {
if (ensureViewerFocused && !isViewerInPresentationMode) {
pdfViewer.focus();
}
evt.preventDefault();
return;
}
// Some shortcuts should not get handled if a control/input element
// is selected.
const curElement = getActiveOrFocusedElement();
const curElementTagName = curElement?.tagName.toUpperCase();
if (
curElementTagName === "INPUT" ||
curElementTagName === "TEXTAREA" ||
curElementTagName === "SELECT" ||
(curElementTagName === "BUTTON" &&
(evt.keyCode === /* Enter = */ 13 || evt.keyCode === /* Space = */ 32)) ||
curElement?.isContentEditable
) {
// Make sure that the secondary toolbar is closed when Escape is pressed.
if (evt.keyCode !== /* Esc = */ 27) {
return;
}
}
// No control key pressed at all.
if (cmd === 0) {
let turnPage = 0,
turnOnlyIfPageFit = false;
switch (evt.keyCode) {
case 38: // up arrow
if (this.supportsCaretBrowsingMode) {
this.moveCaret(/* isUp = */ true, /* select = */ false);
handled = true;
break;
}
/* falls through */
case 33: // pg up
// vertical scrolling using arrow/pg keys
if (pdfViewer.isVerticalScrollbarEnabled) {
turnOnlyIfPageFit = true;
}
turnPage = -1;
break;
case 8: // backspace
if (!isViewerInPresentationMode) {
turnOnlyIfPageFit = true;
}
turnPage = -1;
break;
case 37: // left arrow
if (this.supportsCaretBrowsingMode) {
return;
}
// horizontal scrolling using arrow keys
if (pdfViewer.isHorizontalScrollbarEnabled) {
turnOnlyIfPageFit = true;
}
/* falls through */
case 75: // 'k'
case 80: // 'p'
turnPage = -1;
break;
case 27: // esc key
if (this.secondaryToolbar?.isOpen) {
this.secondaryToolbar.close();
handled = true;
}
if (!this.supportsIntegratedFind && this.findBar?.opened) {
this.findBar.close();
handled = true;
}
break;
case 40: // down arrow
if (this.supportsCaretBrowsingMode) {
this.moveCaret(/* isUp = */ false, /* select = */ false);
handled = true;
break;
}
/* falls through */
case 34: // pg down
// vertical scrolling using arrow/pg keys
if (pdfViewer.isVerticalScrollbarEnabled) {
turnOnlyIfPageFit = true;
}
turnPage = 1;
break;
case 13: // enter key
case 32: // spacebar
if (!isViewerInPresentationMode) {
turnOnlyIfPageFit = true;
}
turnPage = 1;
break;
case 39: // right arrow
if (this.supportsCaretBrowsingMode) {
return;
}
// horizontal scrolling using arrow keys
if (pdfViewer.isHorizontalScrollbarEnabled) {
turnOnlyIfPageFit = true;
}
/* falls through */
case 74: // 'j'
case 78: // 'n'
turnPage = 1;
break;
case 36: // home
if (isViewerInPresentationMode || this.page > 1) {
this.page = 1;
handled = true;
ensureViewerFocused = true;
}
break;
case 35: // end
if (isViewerInPresentationMode || this.page < this.pagesCount) {
this.page = this.pagesCount;
handled = true;
ensureViewerFocused = true;
}
break;
case 83: // 's'
this.pdfCursorTools?.switchTool(CursorTool.SELECT);
break;
case 72: // 'h'
this.pdfCursorTools?.switchTool(CursorTool.HAND);
break;
case 82: // 'r'
this.rotatePages(90);
break;
case 115: // F4
this.pdfSidebar?.toggle();
break;
}
if (
turnPage !== 0 &&
(!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")
) {
if (turnPage > 0) {
pdfViewer.nextPage();
} else {
pdfViewer.previousPage();
}
handled = true;
}
}
// shift-key
if (cmd === 4) {
switch (evt.keyCode) {
case 13: // enter key
case 32: // spacebar
if (
!isViewerInPresentationMode &&
pdfViewer.currentScaleValue !== "page-fit"
) {
break;
}
pdfViewer.previousPage();
handled = true;
break;
case 38: // up arrow
this.moveCaret(/* isUp = */ true, /* select = */ true);
handled = true;
break;
case 40: // down arrow
this.moveCaret(/* isUp = */ false, /* select = */ true);
handled = true;
break;
case 82: // 'r'
this.rotatePages(-90);
break;
}
}
if (!handled && !isViewerInPresentationMode) {
// 33=Page Up 34=Page Down 35=End 36=Home
// 37=Left 38=Up 39=Right 40=Down
// 32=Spacebar
if (
(evt.keyCode >= 33 && evt.keyCode <= 40) ||
(evt.keyCode === 32 && curElementTagName !== "BUTTON")
) {
ensureViewerFocused = true;
}
}
if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) {
// The page container is not focused, but a page navigation key has been
// pressed. Change the focus to the viewer container to make sure that
// navigation by keyboard works as expected.
pdfViewer.focus();
}
if (handled) {
evt.preventDefault();
}
}