summaryrefslogtreecommitdiffstats
path: root/src/core/native_web_keyboard_event_qt_mac.mm
blob: 0f5b12db43d8f57fd14c023ae4b3ec9b0f65a7bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.Chromium file.

// This is a workaround to be able to include Qt headers without
// "redefinition of 'NSString' as different kind of symbol" errors.
// TODO: Remove this when namespace ambiguity issues are fixed properly,
// see get_forward_declaration_macro() in cmake/Functions.cmake
#undef Q_FORWARD_DECLARE_OBJC_CLASS

#include "native_web_keyboard_event_qt.h"

#include <AppKit/AppKit.h>

#include "base/apple/owned_objc.h"

#include <QtGui/QKeyEvent>
#include <QtGui/private/qapplekeymapper_p.h>

namespace QtWebEngineCore {

base::apple::OwnedNSEvent ToNativeEvent(QKeyEvent *keyEvent)
{
    NSEventType type;
    switch (keyEvent->type()) {
    case QEvent::KeyPress:
        type = NSEventTypeKeyDown;
        break;
    case QEvent::KeyRelease:
        type = NSEventTypeKeyUp;
        break;
    default:
        Q_UNREACHABLE();
        return base::apple::OwnedNSEvent();
    }

    NSString *text = keyEvent->text().toNSString();
    if (text.length == 0) {
        Qt::Key key = static_cast<Qt::Key>(keyEvent->key());
        QChar cocoaKey = QAppleKeyMapper::toCocoaKey(key);
        text = QStringView(&cocoaKey, 1).toNSString();
    }

    return base::apple::OwnedNSEvent([NSEvent
                       keyEventWithType:type
                               location:NSZeroPoint
                          modifierFlags:QAppleKeyMapper::toCocoaModifiers(keyEvent->modifiers())
                              timestamp:keyEvent->timestamp() / 1000
                           windowNumber:0
                                context:nil
                             characters:text
            charactersIgnoringModifiers:text
                              isARepeat:keyEvent->isAutoRepeat()
                                keyCode:keyEvent->nativeVirtualKey()
    ]);
}

// Based on qtbase/src/plugins/platforms/cocoa/qnsview_keys.mm (KeyEvent::KeyEvent())
QKeyEvent *ToKeyEvent(base::apple::OwnedNSEvent event)
{
    NSEvent *nsevent = event.Get();

    QEvent::Type type = QEvent::None;
    switch (nsevent.type) {
    case NSEventTypeKeyDown:
        type = QEvent::KeyPress;
        break;
    case NSEventTypeKeyUp:
        type = QEvent::KeyRelease;
        break;
    default:
        Q_UNREACHABLE();
        return nullptr;
    }

    // Scan codes are hardware dependent codes for each key. There is no way to get these
    // from Carbon or Cocoa, so leave it 0, as documented in QKeyEvent::nativeScanCode().
    quint32 nativeScanCode = 0;
    quint32 nativeVirtualKey = nsevent.keyCode;

    NSEventModifierFlags nativeModifiers = nsevent.modifierFlags;
    Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers);

    NSString *charactersIgnoringModifiers = nsevent.charactersIgnoringModifiers;
    NSString *characters = nsevent.characters;

    // If a dead key occurs as a result of pressing a key combination then
    // characters will have 0 length, but charactersIgnoringModifiers will
    // have a valid character in it. This enables key combinations such as
    // ALT+E to be used as a shortcut with an English keyboard even though
    // pressing ALT+E will give a dead key while doing normal text input.
    Qt::Key key = Qt::Key_unknown;
    if (characters.length || charactersIgnoringModifiers.length) {
        QChar character = QChar::ReplacementCharacter;
        if (nativeModifiers & (NSEventModifierFlagControl | NSEventModifierFlagOption)
            && charactersIgnoringModifiers.length)
            character = QChar([charactersIgnoringModifiers characterAtIndex:0]);
        else if (characters.length)
            character = QChar([characters characterAtIndex:0]);
        key = QAppleKeyMapper::fromCocoaKey(character);
    }

    QString text = QString::fromNSString(characters);
    bool autorep = nsevent.ARepeat;

    return new QKeyEvent(type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
                         text, autorep);
}

} // namespace QtWebEngineCore

namespace content {

NativeWebKeyboardEvent::NativeWebKeyboardEvent(const blink::WebKeyboardEvent &web_event, gfx::NativeView)
    : blink::WebKeyboardEvent(web_event)
    , skip_if_unhandled(false)
{
}

NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebInputEvent::Type type, int modifiers,
                                               base::TimeTicks timestamp)
    : blink::WebKeyboardEvent(type, modifiers, timestamp)
    , skip_if_unhandled(false)
{
}

NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event)
    : os_event(native_event) // FIXME: Copy?
    , skip_if_unhandled(false)
{
}

NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& other)
    : blink::WebKeyboardEvent(other)
    , os_event(other.os_event) // FIXME: Copy?
    , skip_if_unhandled(other.skip_if_unhandled)
{
}

NativeWebKeyboardEvent &NativeWebKeyboardEvent::operator=(const NativeWebKeyboardEvent &other)
{
    blink::WebKeyboardEvent::operator=(other);

    os_event = other.os_event; // FIXME: Copy?
    skip_if_unhandled = other.skip_if_unhandled;

    return *this;
}

NativeWebKeyboardEvent::~NativeWebKeyboardEvent() = default;

}  // namespace content