void MainWindow::keyPressEvent(QKeyEvent* event)
{
    if (event->isAccepted() && event->key() != Qt::Key_F12) return;

    bool handled = true;

    switch (event->key()) {
    case Qt::Key_Home:
        m_player->seek(0);
        break;
    case Qt::Key_End:
        if (MLT.producer())
            m_player->seek(MLT.producer()->get_length() - 1);
        break;
    case Qt::Key_Left:
        if ((event->modifiers() & Qt::ControlModifier) && m_timelineDock->isVisible()) {
            if (m_timelineDock->selection().isEmpty()) {
                m_timelineDock->selectClipUnderPlayhead();
            } else if (m_timelineDock->selection().size() == 1) {
                int newIndex = m_timelineDock->selection().first().x() - 1;
                if (newIndex < 0)
                    break;
                m_timelineDock->setSelection(QList<QPoint>() << QPoint(newIndex, m_timelineDock->selection().first().y()));
                m_navigationPosition = m_timelineDock->centerOfClip(m_timelineDock->currentTrack(), newIndex);
            }
        } else {
            stepLeftOneFrame();
        }
        break;
    case Qt::Key_Right:
        if ((event->modifiers() & Qt::ControlModifier) && m_timelineDock->isVisible()) {
            if (m_timelineDock->selection().isEmpty()) {
                m_timelineDock->selectClipUnderPlayhead();
            } else if (m_timelineDock->selection().size() == 1) {
                int newIndex = m_timelineDock->selection().first().x() + 1;
                if (newIndex >= m_timelineDock->clipCount(-1))
                    break;
                m_timelineDock->setSelection(QList<QPoint>() << QPoint(newIndex, m_timelineDock->selection().first().y()));
                m_navigationPosition = m_timelineDock->centerOfClip(m_timelineDock->currentTrack(), newIndex);
            }
        } else {
            stepRightOneFrame();
        }
        break;
    case Qt::Key_PageUp:
    case Qt::Key_PageDown:
        {
            int directionMultiplier = event->key() == Qt::Key_PageUp ? -1 : 1;
            int seconds = 1;
            if (event->modifiers() & Qt::ControlModifier)
                seconds *= 5;
            if (event->modifiers() & Qt::ShiftModifier)
                seconds *= 2;
            stepLeftBySeconds(seconds * directionMultiplier);
        }
        break;
    case Qt::Key_Space:
#ifdef Q_OS_MAC
        // Spotlight defaults to Cmd+Space, so also accept Ctrl+Space.
        if ((event->modifiers() == Qt::MetaModifier || (event->modifiers() & Qt::ControlModifier)) && m_timelineDock->isVisible())
#else
        if (event->modifiers() == Qt::ControlModifier && m_timelineDock->isVisible())
#endif
            m_timelineDock->selectClipUnderPlayhead();
        else
            handled = false;
        break;
    case Qt::Key_A:
        if (event->modifiers() == Qt::ShiftModifier) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_actionAppendCut_triggered();
        } else if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::ShiftModifier)) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_actionSelectAll_triggered();
        } else if (event->modifiers() == Qt::ControlModifier) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->selectAll();
        } else if (event->modifiers() == Qt::NoModifier) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->append(-1);
        }
        break;
    case Qt::Key_C:
        if (event->modifiers() == Qt::ShiftModifier && m_playlistDock->model()->rowCount() > 0) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_actionCopy_triggered();
        } else if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::AltModifier)) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->copyToSource();
        } else if (isMultitrackValid()) {
            m_timelineDock->show();
            m_timelineDock->raise();
            if (m_timelineDock->selection().isEmpty()) {
                m_timelineDock->copyClip(-1, -1);
            } else {
                auto& selected = m_timelineDock->selection().first();
                m_timelineDock->copyClip(selected.y(), selected.x());
            }
        }
        break;
    case Qt::Key_D:
        if (event->modifiers() == Qt::ControlModifier) {
            m_timelineDock->setSelection();
            m_timelineDock->model()->reload();
        } else if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::ShiftModifier)) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_actionSelectNone_triggered();
        } else {
            handled = false;
        }
        break;
    case Qt::Key_F:
        if (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::ControlModifier) {
            m_filtersDock->show();
            m_filtersDock->raise();
            m_filtersDock->widget()->setFocus();
            m_filtersDock->openFilterMenu();
        } else if (event->modifiers() == Qt::ShiftModifier) {
            filterController()->removeCurrent();
        } else {
            handled = false;
        }
        break;
    case Qt::Key_H:
#ifdef Q_OS_MAC
        // OS X uses Cmd+H to hide an app.
        if (event->modifiers() & Qt::MetaModifier && isMultitrackValid())
#else
        if (event->modifiers() & Qt::ControlModifier && isMultitrackValid())
#endif
            m_timelineDock->toggleTrackHidden(m_timelineDock->currentTrack());
        break;
    case Qt::Key_J:
        if (m_isKKeyPressed)
            m_player->seek(m_player->position() - 1);
        else
            m_player->rewind(false);
        break;
    case Qt::Key_K:
            m_player->pause();
            m_isKKeyPressed = true;
        break;
    case Qt::Key_L:
#ifdef Q_OS_MAC
        // OS X uses Cmd+H to hide an app and Cmd+M to minimize. Therefore, we force
        // it to be the apple keyboard control key aka meta. Therefore, to be
        // consistent with all track header toggles, we make the lock toggle also use
        // meta.
        if (event->modifiers() & Qt::MetaModifier && isMultitrackValid())
#else
        if (event->modifiers() & Qt::ControlModifier && isMultitrackValid())
#endif
            m_timelineDock->setTrackLock(m_timelineDock->currentTrack(), !m_timelineDock->isTrackLocked(m_timelineDock->currentTrack()));
        else if (m_isKKeyPressed)
            m_player->seek(m_player->position() + 1);
        else
            m_player->fastForward(false);
        break;
    case Qt::Key_M:
#ifdef Q_OS_MAC
        // OS X uses Cmd+M to minimize an app.
        if (event->modifiers() & Qt::MetaModifier && isMultitrackValid())
#else
        if (event->modifiers() & Qt::ControlModifier && isMultitrackValid())
#endif
            m_timelineDock->toggleTrackMute(m_timelineDock->currentTrack());
        break;
    case Qt::Key_I:
        if (event->modifiers() == Qt::ControlModifier) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->addVideoTrack();
        } else if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::AltModifier)) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->insertTrack();
        } else {
            setInToCurrent(event->modifiers() & Qt::ShiftModifier);
        }
        break;
    case Qt::Key_O:
        setOutToCurrent(event->modifiers() & Qt::ShiftModifier);
        break;
    case Qt::Key_P:
        if (event->modifiers() == Qt::ControlModifier) {
            Settings.setTimelineSnap(!Settings.timelineSnap());
        }
        break;
    case Qt::Key_R:
        if (event->modifiers() & Qt::ControlModifier) {
            if (event->modifiers() & Qt::AltModifier) {
                Settings.setTimelineRippleAllTracks(!Settings.timelineRippleAllTracks());
            } else if (event->modifiers() & Qt::ShiftModifier) {
                Settings.setTimelineRippleAllTracks(!Settings.timelineRipple());
                Settings.setTimelineRipple(!Settings.timelineRipple());
            } else {
                Settings.setTimelineRipple(!Settings.timelineRipple());
            }
        } else if (isMultitrackValid()) {
            m_timelineDock->show();
            m_timelineDock->raise();
            if (MLT.isClip() || m_timelineDock->selection().isEmpty()) {
                m_timelineDock->replace(-1, -1);
            } else {
                auto& selected = m_timelineDock->selection().first();
                m_timelineDock->replace(selected.y(), selected.x());
            }
        }
        break;
    case Qt::Key_S:
        if (isMultitrackValid())
            m_timelineDock->splitClip();
        break;
    case Qt::Key_U:
        if (event->modifiers() == Qt::ControlModifier) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->addAudioTrack();
        } else if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::AltModifier)) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->removeTrack();
        }
        break;
    case Qt::Key_V: // Avid Splice In
        if (event->modifiers() == Qt::ShiftModifier) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_actionInsertCut_triggered();
        } else {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->insert(-1);
        }
        break;
    case Qt::Key_B:
        if (event->modifiers() & Qt::ControlModifier && event->modifiers() & Qt::AltModifier) {
            // Toggle track blending.
            int trackIndex = m_timelineDock->currentTrack();
            bool isBottomVideo = m_timelineDock->model()->data(m_timelineDock->model()->index(trackIndex), MultitrackModel::IsBottomVideoRole).toBool();
            if (!isBottomVideo) {
                bool isComposite = m_timelineDock->model()->data(m_timelineDock->model()->index(trackIndex), MultitrackModel::IsCompositeRole).toBool();
                m_timelineDock->setTrackComposite(trackIndex, !isComposite);
            }
        } else if (event->modifiers() == Qt::ShiftModifier) {
            if (m_playlistDock->model()->rowCount() > 0) {
                // Update playlist item.
                m_playlistDock->show();
                m_playlistDock->raise();
                m_playlistDock->on_actionUpdate_triggered();
            }
        } else {
            // Overwrite on timeline.
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->overwrite(-1);
        }
        break;
    case Qt::Key_Escape: // Avid Toggle Active Monitor
        if (MLT.isPlaylist()) {
            if (isMultitrackValid())
                m_player->onTabBarClicked(Player::ProjectTabIndex);
            else if (MLT.savedProducer())
                m_player->onTabBarClicked(Player::SourceTabIndex);
            else
                m_playlistDock->on_actionOpen_triggered();
        } else if (MLT.isMultitrack()) {
            if (MLT.savedProducer())
                m_player->onTabBarClicked(Player::SourceTabIndex);
            // TODO else open clip under playhead of current track if available
        } else {
            if (isMultitrackValid() || (playlist() && playlist()->count() > 0))
                m_player->onTabBarClicked(Player::ProjectTabIndex);
        }
        break;
    case Qt::Key_Up:
        if (m_playlistDock->isVisible() && event->modifiers() & Qt::AltModifier && m_playlistDock->model()->rowCount() > 0) {
            m_playlistDock->raise();
            m_playlistDock->decrementIndex();
            m_playlistDock->on_actionOpen_triggered();
        } else if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::ShiftModifier)) {
            if (m_playlistDock->model()->rowCount() > 0) {
                m_playlistDock->raise();
                m_playlistDock->moveClipUp();
                m_playlistDock->decrementIndex();
            }
        } else if (isMultitrackValid()) {
            int newClipIndex = -1;
            int trackIndex = m_timelineDock->currentTrack() - 1;
            if ((event->modifiers() & Qt::ControlModifier) &&
                    !m_timelineDock->selection().isEmpty() &&
                    trackIndex > -1) {

                newClipIndex = m_timelineDock->clipIndexAtPosition(trackIndex, m_navigationPosition);
            }

            m_timelineDock->incrementCurrentTrack(-1);

            if (newClipIndex >= 0) {
                newClipIndex = qMin(newClipIndex, m_timelineDock->clipCount(trackIndex) - 1);
                m_timelineDock->setSelection(QList<QPoint>() << QPoint(newClipIndex, trackIndex));
            }

        }
        break;
    case Qt::Key_Down:
        if (m_playlistDock->isVisible() && event->modifiers() & Qt::AltModifier && m_playlistDock->model()->rowCount() > 0) {
            m_playlistDock->raise();
            m_playlistDock->incrementIndex();
            m_playlistDock->on_actionOpen_triggered();
        } else if ((event->modifiers() & Qt::ControlModifier) && (event->modifiers() & Qt::ShiftModifier)) {
            if (m_playlistDock->model()->rowCount() > 0) {
                m_playlistDock->raise();
                m_playlistDock->moveClipDown();
                m_playlistDock->incrementIndex();
            }
        } else if (isMultitrackValid()) {
            int newClipIndex = -1;
            int trackIndex = m_timelineDock->currentTrack() + 1;
            if ((event->modifiers() & Qt::ControlModifier) &&
                    !m_timelineDock->selection().isEmpty() &&
                    trackIndex < m_timelineDock->model()->trackList().count()) {

                newClipIndex = m_timelineDock->clipIndexAtPosition(trackIndex, m_navigationPosition);
            }

            m_timelineDock->incrementCurrentTrack(1);

            if (newClipIndex >= 0) {
                newClipIndex = qMin(newClipIndex, m_timelineDock->clipCount(trackIndex) - 1);
                m_timelineDock->setSelection(QList<QPoint>() << QPoint(newClipIndex, trackIndex));
            }

        }
        break;
    case Qt::Key_1:
    case Qt::Key_2:
    case Qt::Key_3:
    case Qt::Key_4:
    case Qt::Key_5:
    case Qt::Key_6:
    case Qt::Key_7:
    case Qt::Key_8:
    case Qt::Key_9:
        if (!event->modifiers() && m_playlistDock->isVisible() && m_playlistDock->model()->rowCount() > 0) {
            m_playlistDock->raise();
            m_playlistDock->setIndex(event->key() - Qt::Key_1);
        }
        break;
    case Qt::Key_0:
        if (!event->modifiers() ) {
            if (m_timelineDock->isVisible()) {
                m_timelineDock->resetZoom();
            } else if (m_playlistDock->isVisible() && m_playlistDock->model()->rowCount() > 0) {
                m_playlistDock->raise();
                m_playlistDock->setIndex(9);
            }
        }
        if (m_keyframesDock->isVisible() && (event->modifiers() & Qt::AltModifier)) {
            emit m_keyframesDock->resetZoom();
        }
        break;
    case Qt::Key_X: // Avid Extract
        if (event->modifiers() == Qt::ShiftModifier && m_playlistDock->model()->rowCount() > 0) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_removeButton_clicked();
        } else if (isMultitrackValid()) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->removeSelection();
        }
        break;
    case Qt::Key_Backspace:
    case Qt::Key_Delete:
        if (isMultitrackValid()) {
            m_timelineDock->show();
            m_timelineDock->raise();
            if (event->modifiers() == Qt::ShiftModifier)
                m_timelineDock->removeSelection();
            else
                m_timelineDock->liftSelection();
        } else if (m_playlistDock->model()->rowCount() > 0) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_removeButton_clicked();
        }
        break;
    case Qt::Key_Z: // Avid Lift
        if (event->modifiers() == Qt::ShiftModifier && m_playlistDock->model()->rowCount() > 0) {
            m_playlistDock->show();
            m_playlistDock->raise();
            m_playlistDock->on_removeButton_clicked();
        } else if (isMultitrackValid() && event->modifiers() == Qt::NoModifier) {
            m_timelineDock->show();
            m_timelineDock->raise();
            m_timelineDock->liftSelection();
        }
        break;
    case Qt::Key_Minus:
        if (m_timelineDock->isVisible() && !(event->modifiers() & Qt::AltModifier)) {
            if (event->modifiers() & Qt::ControlModifier)
                m_timelineDock->makeTracksShorter();
            else
                m_timelineDock->zoomOut();
        }
        if (m_keyframesDock->isVisible() && (event->modifiers() & Qt::AltModifier)) {
            emit m_keyframesDock->zoomOut();
        }
        break;
    case Qt::Key_Equal:
    case Qt::Key_Plus:
        if (m_timelineDock->isVisible() && !(event->modifiers() & Qt::AltModifier)) {
            if (event->modifiers() & Qt::ControlModifier)
                m_timelineDock->makeTracksTaller();
            else
                m_timelineDock->zoomIn();
        }
        if (m_keyframesDock->isVisible() && (event->modifiers() & Qt::AltModifier)) {
            emit m_keyframesDock->zoomIn();
        }
        break;
    case Qt::Key_Enter: // Seek to current playlist item
    case Qt::Key_Return:
        if (m_playlistDock->isVisible() && m_playlistDock->position() >= 0) {
            if (event->modifiers() == Qt::ShiftModifier)
                seekPlaylist(m_playlistDock->position());
            else if (event->modifiers() == Qt::ControlModifier)
                m_playlistDock->on_actionOpen_triggered();
        }
        break;
    case Qt::Key_F2:
        onPropertiesDockTriggered(true);
        emit renameRequested();
        break;
    case Qt::Key_F3:
        onRecentDockTriggered(true);
        m_recentDock->find();
        break;
    case Qt::Key_F5:
        m_timelineDock->model()->reload();
        m_keyframesDock->model().reload();
        break;
    case Qt::Key_F12:
        LOG_DEBUG() << "event isAccepted:" << event->isAccepted();
        LOG_DEBUG() << "Current focusWidget:" << QApplication::focusWidget();
        LOG_DEBUG() << "Current focusObject:" << QApplication::focusObject();
        LOG_DEBUG() << "Current focusWindow:" << QApplication::focusWindow();
        break;
    case Qt::Key_BracketLeft:
        if (filterController()->currentFilter() && m_filtersDock->qmlProducer()) {
            if (event->modifiers() == Qt::AltModifier) {
                emit m_keyframesDock->seekPreviousSimple();
            } else {
                int i = m_filtersDock->qmlProducer()->position() + m_filtersDock->qmlProducer()->in();
                filterController()->currentFilter()->setIn(i);
            }
        }
        break;
    case Qt::Key_BracketRight:
        if (filterController()->currentFilter() && m_filtersDock->qmlProducer()) {
            if (event->modifiers() == Qt::AltModifier) {
                emit m_keyframesDock->seekNextSimple();
            } else {
                int i = m_filtersDock->qmlProducer()->position() + m_filtersDock->qmlProducer()->in();
                filterController()->currentFilter()->setOut(i);
            }
        }
        break;
    case Qt::Key_BraceLeft:
        if (filterController()->currentFilter() && m_filtersDock->qmlProducer()) {
            int i = m_filtersDock->qmlProducer()->position() + m_filtersDock->qmlProducer()->in() - filterController()->currentFilter()->in();
            filterController()->currentFilter()->setAnimateIn(i);
        }
        break;
    case Qt::Key_BraceRight:
        if (filterController()->currentFilter() && m_filtersDock->qmlProducer()) {
            int i = filterController()->currentFilter()->out() - (m_filtersDock->qmlProducer()->position() + m_filtersDock->qmlProducer()->in());
            filterController()->currentFilter()->setAnimateOut(i);
        }
        break;
    case Qt::Key_Semicolon:
        if (filterController()->currentFilter() && m_filtersDock->qmlProducer() && m_keyframesDock->currentParameter() >= 0) {
            auto position = m_filtersDock->qmlProducer()->position() - (filterController()->currentFilter()->in() - m_filtersDock->qmlProducer()->in());
            auto parameterIndex = m_keyframesDock->currentParameter();
            if (m_keyframesDock->model().isKeyframe(parameterIndex, position)) {
                auto keyframeIndex = m_keyframesDock->model().keyframeIndex(parameterIndex, position);
                m_keyframesDock->model().remove(parameterIndex, keyframeIndex);
            } else {
                m_keyframesDock->model().addKeyframe(parameterIndex, position);
            }
        }
        break;
    default:
        handled = false;
        break;
    }

    if (handled)
        event->setAccepted(handled);
    else
        QMainWindow::keyPressEvent(event);
}