mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-03-28 14:56:19 +01:00
Push-To-Talk : add global and local ptt
It works with a Pimpl which the right pttlistener.cpp depending on the platform you are on (macOs, windows or X11). It is a global PTT which listen to key events during calls. If the global PTT is not supported, a local PTT is set. https://git.jami.net/savoirfairelinux/jami-project/-/issues/1402 Change-Id: I8399800966c737bb8e8a656ecbb6af7ac7cdde8c
This commit is contained in:
parent
d2e87150b4
commit
7a759dab7a
21 changed files with 2256 additions and 27 deletions
|
@ -245,7 +245,8 @@ set(COMMON_SOURCES
|
|||
${APP_SRC_DIR}/previewengine.cpp
|
||||
${APP_SRC_DIR}/imagedownloader.cpp
|
||||
${APP_SRC_DIR}/pluginversionmanager.cpp
|
||||
${APP_SRC_DIR}/connectioninfolistmodel.cpp)
|
||||
${APP_SRC_DIR}/connectioninfolistmodel.cpp
|
||||
${APP_SRC_DIR}/pluginversionmanager.cpp)
|
||||
|
||||
set(COMMON_HEADERS
|
||||
${APP_SRC_DIR}/avatarimageprovider.h
|
||||
|
@ -312,7 +313,8 @@ set(COMMON_HEADERS
|
|||
${APP_SRC_DIR}/htmlparser.h
|
||||
${APP_SRC_DIR}/imagedownloader.h
|
||||
${APP_SRC_DIR}/pluginversionmanager.h
|
||||
${APP_SRC_DIR}/connectioninfolistmodel.h)
|
||||
${APP_SRC_DIR}/connectioninfolistmodel.h
|
||||
${APP_SRC_DIR}/pttlistener.h)
|
||||
|
||||
# For libavutil/avframe.
|
||||
set(LIBJAMI_CONTRIB_DIR "${DAEMON_DIR}/contrib")
|
||||
|
@ -494,6 +496,29 @@ else()
|
|||
OPTIONAL_COMPONENTS LinguistTools)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if (DEFINED ENV{XDG_SESSION_TYPE})
|
||||
if ($ENV{XDG_SESSION_TYPE} STREQUAL "x11")
|
||||
set(PTT_PLATFORM "x11")
|
||||
list(APPEND COMMON_HEADER ${APP_SRC_DIR}/platform/X11/xcbkeyboard.H)
|
||||
# TODO: add Wayland support
|
||||
endif ()
|
||||
endif ()
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(PTT_PLATFORM "windows")
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(PTT_PLATFORM "macos")
|
||||
endif ()
|
||||
|
||||
if (NOT ${PTT_PLATFORM} STREQUAL "")
|
||||
message(STATUS "Platform: ${PTT_PLATFORM}")
|
||||
add_definitions(-DHAVE_GLOBAL_PTT)
|
||||
list(APPEND COMMON_SOURCES ${APP_SRC_DIR}/platform/${PTT_PLATFORM}/pttlistener.cpp)
|
||||
else ()
|
||||
message(WARNING "Global push-to-talk not supported.")
|
||||
list(APPEND COMMON_SOURCES ${APP_SRC_DIR}/platform/local/pttlistener.cpp)
|
||||
endif ()
|
||||
|
||||
# common includes
|
||||
include_directories(
|
||||
${PROJECT_SOURCE_DIR}
|
||||
|
@ -594,7 +619,6 @@ elseif (NOT APPLE)
|
|||
${GLIB_LIBRARIES}
|
||||
${GIO_LIBRARIES})
|
||||
|
||||
# Installation rules
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin)
|
||||
|
@ -725,7 +749,7 @@ else()
|
|||
list(APPEND CLIENT_LIBS
|
||||
"-framework AVFoundation"
|
||||
"-framework CoreAudio -framework CoreMedia -framework CoreVideo"
|
||||
"-framework VideoToolbox -framework AudioUnit"
|
||||
"-framework VideoToolbox -framework AudioUnit -framework Carbon"
|
||||
"-framework Security"
|
||||
compression
|
||||
resolv
|
||||
|
|
|
@ -36,5 +36,7 @@
|
|||
<string>Jami requires to access your microphone to make calls and record audio</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<true/>
|
||||
<key>NSAppleEventsUsageDescription</key>
|
||||
<string>Jami requires to monitor global key events for push-to-talk functionality.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -66,8 +66,9 @@ extern const QString defaultDownloadPath;
|
|||
X(ShowSendOption, false) \
|
||||
X(DonationVisibleDate, "2023-11-01 05:00") \
|
||||
X(IsDonationVisible, true) \
|
||||
X(DonationEndDate, "2024-01-01 00:00")
|
||||
|
||||
X(DonationEndDate, "2024-01-01 00:00") \
|
||||
X(EnablePtt, false) \
|
||||
X(pttKey, 36)
|
||||
/*
|
||||
* A class to expose settings keys in both c++ and QML.
|
||||
* Note: this is using a non-constructable class instead of a
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* Author: Isa Nanic <isa.nanic@savoirfairelinux.com>
|
||||
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||||
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
|
||||
* Author: Capucine Berthet <capucine.berthet@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -47,7 +48,7 @@ CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject*
|
|||
timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &CallAdapter::updateAdvancedInformation);
|
||||
|
||||
overlayModel_.reset(new CallOverlayModel(lrcInstance_, this));
|
||||
overlayModel_.reset(new CallOverlayModel(lrcInstance_, listener_, this));
|
||||
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, overlayModel_.get(), "CallOverlayModel");
|
||||
|
||||
accountId_ = lrcInstance_->get_currentAccountId();
|
||||
|
@ -97,6 +98,65 @@ CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject*
|
|||
&LRCInstance::selectedConvUidChanged,
|
||||
this,
|
||||
&CallAdapter::saveConferenceSubcalls);
|
||||
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
connectPtt();
|
||||
#endif
|
||||
}
|
||||
|
||||
CallAdapter::~CallAdapter()
|
||||
{
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
disconnectPtt();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::connectPtt()
|
||||
{
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
if (listener_->getPttState()) {
|
||||
QObject::connect(
|
||||
listener_,
|
||||
&PTTListener::pttKeyPressed,
|
||||
this,
|
||||
[this]() {
|
||||
const auto callId
|
||||
= lrcInstance_->getCallIdForConversationUid(lrcInstance_->get_selectedConvUid(),
|
||||
accountId_);
|
||||
try {
|
||||
isMicrophoneMuted_ = isMuted(callId);
|
||||
if (isMicrophoneMuted_)
|
||||
muteAudioToggle();
|
||||
} catch (const std::exception& e) {
|
||||
qWarning() << e.what();
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
||||
QObject::connect(
|
||||
listener_,
|
||||
&PTTListener::pttKeyReleased,
|
||||
this,
|
||||
[this]() {
|
||||
if (isMicrophoneMuted_) {
|
||||
muteAudioToggle();
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::disconnectPtt()
|
||||
{
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
if (listener_->getPttState()) {
|
||||
QObject::disconnect(listener_, &PTTListener::pttKeyPressed, this, nullptr);
|
||||
QObject::disconnect(listener_, &PTTListener::pttKeyReleased, this, nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -172,6 +232,12 @@ CallAdapter::onCallStarted(const QString& callId)
|
|||
// update call Information list by adding the new information related to the callId
|
||||
callInformationListModel_->addElement(
|
||||
qMakePair(callId, callModel->advancedInformationForCallId(callId)));
|
||||
if (listener_->getPttState()){
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
listener_->startListening();
|
||||
toMute += callId;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -181,6 +247,10 @@ CallAdapter::onCallEnded(const QString& callId)
|
|||
return;
|
||||
// update call Information list by removing information related to the callId
|
||||
callInformationListModel_->removeElement(callId);
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
if (listener_->getPttState() && !hasCall_)
|
||||
listener_->stopListening();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -271,6 +341,15 @@ CallAdapter::onCallStatusChanged(const QString& callId, int code)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::onCallInfosChanged(const QString& accountId, const QString& callId)
|
||||
{
|
||||
Q_UNUSED(accountId)
|
||||
auto mute = toMute.remove(callId);
|
||||
if (mute && listener_->getPttState())
|
||||
muteAudioToggle();
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::onCallAddedToConference(const QString& callId, const QString& confId)
|
||||
{
|
||||
|
@ -494,6 +573,12 @@ CallAdapter::connectCallModel(const QString& accountId)
|
|||
QOverload<const QString&, int>::of(&CallAdapter::onCallStatusChanged),
|
||||
Qt::UniqueConnection);
|
||||
|
||||
connect(accInfo.callModel.get(),
|
||||
&CallModel::callInfosChanged,
|
||||
this,
|
||||
&CallAdapter::onCallInfosChanged,
|
||||
Qt::UniqueConnection);
|
||||
|
||||
connect(accInfo.callModel.get(),
|
||||
&CallModel::callAddedToConference,
|
||||
this,
|
||||
|
@ -816,6 +901,23 @@ CallAdapter::holdThisCallToggle()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CallAdapter::isMuted(const QString& callId)
|
||||
{
|
||||
if (!(callId.isEmpty() || !lrcInstance_->getCurrentCallModel()->hasCall(callId))) {
|
||||
auto* callModel = lrcInstance_->getCurrentCallModel();
|
||||
if (callModel->hasCall(callId)) {
|
||||
const auto callInfo = lrcInstance_->getCurrentCallModel()->getCall(callId);
|
||||
auto mute = false;
|
||||
for (const auto& m : callInfo.mediaList)
|
||||
if (m[libjami::Media::MediaAttributeKey::LABEL] == "audio_0")
|
||||
mute = m[libjami::Media::MediaAttributeKey::MUTED] == TRUE_STR;
|
||||
return mute;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("CallAdapter::isMuted: callId is empty or call does not exist");
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::muteAudioToggle()
|
||||
{
|
||||
|
@ -825,13 +927,10 @@ CallAdapter::muteAudioToggle()
|
|||
return;
|
||||
}
|
||||
auto* callModel = lrcInstance_->getCurrentCallModel();
|
||||
if (callModel->hasCall(callId)) {
|
||||
const auto callInfo = lrcInstance_->getCurrentCallModel()->getCall(callId);
|
||||
auto mute = false;
|
||||
for (const auto& m : callInfo.mediaList)
|
||||
if (m[libjami::Media::MediaAttributeKey::LABEL] == "audio_0")
|
||||
mute = m[libjami::Media::MediaAttributeKey::MUTED] == FALSE_STR;
|
||||
callModel->muteMedia(callId, "audio_0", mute);
|
||||
try {
|
||||
callModel->muteMedia(callId, "audio_0", !isMuted(callId));
|
||||
} catch (const std::exception& e) {
|
||||
qWarning() << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
#include "screensaver.h"
|
||||
#include "calloverlaymodel.h"
|
||||
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
#include "pttlistener.h"
|
||||
#endif
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
@ -46,7 +50,7 @@ public:
|
|||
Q_ENUM(MuteStates)
|
||||
|
||||
explicit CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent = nullptr);
|
||||
~CallAdapter() = default;
|
||||
~CallAdapter();
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void startTimerInformation();
|
||||
|
@ -76,6 +80,9 @@ public:
|
|||
Q_INVOKABLE void holdThisCallToggle();
|
||||
Q_INVOKABLE void recordThisCallToggle();
|
||||
Q_INVOKABLE void muteAudioToggle();
|
||||
Q_INVOKABLE bool isMuted(const QString& callId);
|
||||
Q_INVOKABLE void connectPtt();
|
||||
Q_INVOKABLE void disconnectPtt();
|
||||
Q_INVOKABLE void muteCameraToggle();
|
||||
Q_INVOKABLE bool isRecordingThisCall();
|
||||
Q_INVOKABLE void muteParticipant(const QString& accountUri,
|
||||
|
@ -109,6 +116,7 @@ public Q_SLOTS:
|
|||
void onCallAddedToConference(const QString& callId, const QString& confId);
|
||||
void onCallStarted(const QString& callId);
|
||||
void onCallEnded(const QString& callId);
|
||||
void onCallInfosChanged(const QString& accountId, const QString& callId);
|
||||
|
||||
private:
|
||||
void showNotification(const QString& accountId, const QString& convUid);
|
||||
|
@ -121,6 +129,9 @@ private:
|
|||
SystemTray* systemTray_;
|
||||
QScopedPointer<CallOverlayModel> overlayModel_;
|
||||
VectorString currentConfSubcalls_;
|
||||
|
||||
std::unique_ptr<CallInformationListModel> callInformationListModel_;
|
||||
|
||||
PTTListener* listener_ = new PTTListener(systemTray_->getSettingsManager());
|
||||
bool isMicrophoneMuted_ = true;
|
||||
QSet<QString> toMute;
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QQuickWindow>
|
||||
#include <QKeyEvent>
|
||||
|
||||
IndexRangeFilterProxyModel::IndexRangeFilterProxyModel(QAbstractListModel* parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
|
@ -74,10 +75,10 @@ PendingConferenceesListModel::data(const QModelIndex& index, int role) const
|
|||
using namespace PendingConferences;
|
||||
|
||||
// WARNING: not swarm ready
|
||||
lrc::api::call::Status callStatus;
|
||||
QString pendingConferenceeCallId;
|
||||
QString pendingConferenceeContactUri;
|
||||
ContactModel* contactModel {nullptr};
|
||||
lrc::api::call::Status callStatus;
|
||||
try {
|
||||
auto callModel = lrcInstance_->getCurrentCallModel();
|
||||
auto currentPendingConferenceeInfo = callModel->getPendingConferencees().at(index.row());
|
||||
|
@ -268,7 +269,7 @@ CallControlListModel::clearData()
|
|||
data_.clear();
|
||||
}
|
||||
|
||||
CallOverlayModel::CallOverlayModel(LRCInstance* instance, QObject* parent)
|
||||
CallOverlayModel::CallOverlayModel(LRCInstance* instance, PTTListener* listener, QObject* parent)
|
||||
: QObject(parent)
|
||||
, lrcInstance_(instance)
|
||||
, primaryModel_(new CallControlListModel(this))
|
||||
|
@ -283,6 +284,10 @@ CallOverlayModel::CallOverlayModel(LRCInstance* instance, QObject* parent)
|
|||
this,
|
||||
&CallOverlayModel::setControlRanges);
|
||||
overflowVisibleModel_->setFilterRole(CallControl::Role::UrgentCount);
|
||||
|
||||
#ifndef HAVE_GLOBAL_PTT
|
||||
listener_ = listener;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -386,6 +391,19 @@ CallOverlayModel::eventFilter(QObject* object, QEvent* event)
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifndef HAVE_GLOBAL_PTT
|
||||
else if (event->type() == QEvent::KeyPress && listener_->getPttState()) {
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->key() == listener_->getCurrentKey() && !keyEvent->isAutoRepeat()) {
|
||||
Q_EMIT pttKeyPressed();
|
||||
}
|
||||
} else if (event->type() == QEvent::KeyRelease && listener_->getPttState()) {
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->key() == listener_->getCurrentKey() && !keyEvent->isAutoRepeat()) {
|
||||
Q_EMIT pttKeyReleased();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
#include "lrcinstance.h"
|
||||
#include "qtutils.h"
|
||||
#include "mainapplication.h"
|
||||
|
||||
#include "pttlistener.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
|
@ -36,7 +39,7 @@
|
|||
|
||||
namespace CallControl {
|
||||
Q_NAMESPACE
|
||||
enum Role { ItemAction = Qt::UserRole + 1, UrgentCount, Enabled};
|
||||
enum Role { ItemAction = Qt::UserRole + 1, UrgentCount, Enabled };
|
||||
Q_ENUM_NS(Role)
|
||||
|
||||
struct Item
|
||||
|
@ -121,7 +124,7 @@ class CallOverlayModel : public QObject
|
|||
QML_PROPERTY(int, overflowIndex)
|
||||
|
||||
public:
|
||||
CallOverlayModel(LRCInstance* instance, QObject* parent = nullptr);
|
||||
CallOverlayModel(LRCInstance* instance, PTTListener* listener, QObject* parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void addPrimaryControl(const QVariant& action, bool enabled);
|
||||
Q_INVOKABLE void addSecondaryControl(const QVariant& action, bool enabled);
|
||||
|
@ -142,6 +145,8 @@ public:
|
|||
|
||||
Q_SIGNALS:
|
||||
void mouseMoved(QQuickItem* item);
|
||||
void pttKeyPressed();
|
||||
void pttKeyReleased();
|
||||
|
||||
private Q_SLOTS:
|
||||
void setControlRanges();
|
||||
|
@ -157,4 +162,8 @@ private:
|
|||
PendingConferenceesListModel* pendingConferenceesModel_;
|
||||
|
||||
QList<QQuickItem*> watchedItems_;
|
||||
|
||||
#ifndef HAVE_GLOBAL_PTT
|
||||
PTTListener* listener_ {nullptr};
|
||||
#endif
|
||||
};
|
||||
|
|
123
src/app/commoncomponents/ChangePttKeyPopup.qml
Normal file
123
src/app/commoncomponents/ChangePttKeyPopup.qml
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
BaseModalDialog {
|
||||
id: pttPage
|
||||
|
||||
property string bestName: ""
|
||||
property string accountId: ""
|
||||
property int pressedKey: Qt.Key_unknown
|
||||
|
||||
signal accepted
|
||||
signal choiceMade(int chosenKey)
|
||||
|
||||
title: JamiStrings.changeShortcut
|
||||
|
||||
popupContent: ColumnLayout {
|
||||
id: deleteAccountContentColumnLayout
|
||||
anchors.centerIn: parent
|
||||
spacing: JamiTheme.preferredMarginSize
|
||||
|
||||
Component.onCompleted: keyItem.forceActiveFocus()
|
||||
Label {
|
||||
id: instructionLabel
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredWidth: JamiTheme.preferredDialogWidth - 4*JamiTheme.preferredMarginSize
|
||||
color: JamiTheme.textColor
|
||||
text: JamiStrings.assignmentIndication
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
font.pointSize: JamiTheme.textFontSize
|
||||
font.kerning: true
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
Label {
|
||||
id: keyLabel
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
color: JamiTheme.blackColor
|
||||
wrapMode: Text.WordWrap
|
||||
text: ""
|
||||
font.pointSize: JamiTheme.settingsFontSize
|
||||
font.kerning: true
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: keyLabel.width + 2 * JamiTheme.preferredMarginSize
|
||||
height: keyLabel.height + JamiTheme.preferredMarginSize
|
||||
color: JamiTheme.lightGrey_
|
||||
border.color: JamiTheme.darkGreyColor
|
||||
radius: 4
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: btnAssign
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
|
||||
preferredWidth: JamiTheme.preferredFieldWidth / 2 - 8
|
||||
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
|
||||
|
||||
color: JamiTheme.buttonTintedBlack
|
||||
hoveredColor: JamiTheme.buttonTintedBlackHovered
|
||||
pressedColor: JamiTheme.buttonTintedBlackPressed
|
||||
secondary: true
|
||||
|
||||
text: JamiStrings.assign
|
||||
autoAccelerator: true
|
||||
|
||||
onClicked: {
|
||||
if (!(pressedKey === Qt.Key_unknown)){
|
||||
pttListener.setPttKey(pressedKey);
|
||||
choiceMade(pressedKey);
|
||||
}
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: keyItem
|
||||
|
||||
Keys.onPressed: (event)=>{
|
||||
keyLabel.text = pttListener.keyToString(event.key);
|
||||
pressedKey = event.key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -83,6 +83,15 @@ Item {
|
|||
property string selectNewRingtone: qsTr("Select a new ringtone")
|
||||
property string certificateFile: qsTr("Certificate File (*.crt)")
|
||||
property string audioFile: qsTr("Audio File (*.wav *.ogg *.opus *.mp3 *.aiff *.wma)")
|
||||
property string pushToTalk: qsTr("Push-to-talk")
|
||||
property string enablePTT: qsTr("Enable push-to-talk")
|
||||
property string keyboardShortcut: qsTr("Keyboard shortcut")
|
||||
property string changeKeyboardShortcut: qsTr("Change keyboard shortcut")
|
||||
|
||||
// ChangePttKeyPopup
|
||||
property string changeShortcut: qsTr("Change shortcut")
|
||||
property string assignmentIndication: qsTr("Press the key to be assigned to push-to-talk shortcut")
|
||||
property string assign: qsTr("Assign")
|
||||
|
||||
// AdvancedChatSettings
|
||||
property string enableReadReceipts: qsTr("Enable read receipts")
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
#include "mainapplication.h"
|
||||
#include "pttlistener.h"
|
||||
|
||||
#include "qmlregister.h"
|
||||
#include "appsettingsmanager.h"
|
||||
|
@ -132,6 +133,7 @@ MainApplication::init()
|
|||
connectivityMonitor_.reset(new ConnectivityMonitor(this));
|
||||
settingsManager_.reset(new AppSettingsManager(this));
|
||||
systemTray_.reset(new SystemTray(settingsManager_.get(), this));
|
||||
listener_ = new PTTListener(settingsManager_.get(), this);
|
||||
|
||||
QObject::connect(settingsManager_.get(),
|
||||
&AppSettingsManager::retranslate,
|
||||
|
@ -350,6 +352,7 @@ MainApplication::initQmlLayer()
|
|||
|
||||
auto videoProvider = new VideoProvider(lrcInstance_->avModel(), this);
|
||||
engine_->rootContext()->setContextProperty("videoProvider", videoProvider);
|
||||
engine_->rootContext()->setContextProperty("pttListener", listener_);
|
||||
|
||||
engine_->load(QUrl(QStringLiteral("qrc:/MainApplicationWindow.qml")));
|
||||
qWarning().noquote() << "Main window loaded using" << getRenderInterfaceString();
|
||||
|
@ -409,10 +412,9 @@ MainApplication::cleanup()
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
void
|
||||
MainApplication::setEventFilter()
|
||||
{
|
||||
installEventFilter(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "imagedownloader.h"
|
||||
#include "lrcinstance.h"
|
||||
#include "qtutils.h"
|
||||
#include "pttlistener.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QApplication>
|
||||
|
@ -82,17 +83,20 @@ public:
|
|||
return runOptions_[opt];
|
||||
};
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
Q_INVOKABLE void setEventFilter();
|
||||
|
||||
bool eventFilter(QObject* object, QEvent* event)
|
||||
{
|
||||
#ifdef Q_OS_MACOS
|
||||
|
||||
if (event->type() == QEvent::ApplicationActivate) {
|
||||
restoreApp();
|
||||
}
|
||||
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
return QApplication::eventFilter(object, event);
|
||||
}
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
Q_SIGNALS:
|
||||
void closeRequested();
|
||||
|
@ -120,6 +124,8 @@ private:
|
|||
QScopedPointer<SystemTray> systemTray_;
|
||||
QScopedPointer<ImageDownloader> imageDownloader_;
|
||||
|
||||
PTTListener* listener_;
|
||||
|
||||
ScreenInfo screenInfo_;
|
||||
|
||||
bool isCleanupped;
|
||||
|
|
|
@ -25,7 +25,6 @@ import "../../commoncomponents"
|
|||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property alias chatViewContainer: ongoingCallPage.chatViewContainer
|
||||
property alias contentView: callStackMainView
|
||||
|
||||
|
@ -49,6 +48,16 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CallOverlayModel
|
||||
function onPttKeyPressed() {
|
||||
CallAdapter.muteAudioToggle();
|
||||
}
|
||||
function onPttKeyReleased() {
|
||||
CallAdapter.muteAudioToggle();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should all be done by listening to
|
||||
// parent visibility change or parent `Component.onDestruction`
|
||||
function needToCloseInCallConversationAndPotentialWindow() {
|
||||
|
|
42
src/app/platform/local/pttlistener.cpp
Normal file
42
src/app/platform/local/pttlistener.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pttlistener.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVariant>
|
||||
|
||||
class PTTListener::Impl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Impl(PTTListener* parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
~Impl() = default;
|
||||
};
|
||||
|
||||
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
|
||||
: settingsManager_(settingsManager)
|
||||
, QObject(parent)
|
||||
, pimpl_(std::make_unique<Impl>(this))
|
||||
{}
|
||||
|
||||
PTTListener::~PTTListener() = default;
|
||||
|
||||
#include "pttlistener.moc"
|
390
src/app/platform/macos/pttlistener.cpp
Normal file
390
src/app/platform/macos/pttlistener.cpp
Normal file
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include "pttlistener.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVariant>
|
||||
|
||||
class PTTListener::Impl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Impl(PTTListener* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
qApp->setProperty("PTTListener", QVariant::fromValue(parent));
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
stopListening();
|
||||
};
|
||||
|
||||
void startListening()
|
||||
{
|
||||
CGEventMask eventMask = (1 << kCGEventKeyDown) | (1 << kCGEventKeyUp);
|
||||
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap,
|
||||
kCGHeadInsertEventTap,
|
||||
kCGEventTapOptionDefault,
|
||||
eventMask,
|
||||
CGEventCallback,
|
||||
this);
|
||||
|
||||
if (eventTap) {
|
||||
CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
|
||||
eventTap,
|
||||
0);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
|
||||
CFRelease(runLoopSource);
|
||||
|
||||
CGEventTapEnable(eventTap, true);
|
||||
} else {
|
||||
qDebug() << "Impossible to create the keyboard tap.";
|
||||
}
|
||||
}
|
||||
|
||||
void stopListening()
|
||||
{
|
||||
if (eventTap) {
|
||||
CGEventTapEnable(eventTap, false);
|
||||
CFRelease(eventTap);
|
||||
}
|
||||
}
|
||||
|
||||
static CGEventRef CGEventCallback(CGEventTapProxy proxy,
|
||||
CGEventType type,
|
||||
CGEventRef event,
|
||||
void* refcon)
|
||||
{
|
||||
auto* pThis = qApp->property("PTTListener").value<PTTListener*>();
|
||||
CGKeyCode keycode = (CGKeyCode) CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
|
||||
if (pThis == nullptr) {
|
||||
qWarning() << "PTTListener not found";
|
||||
return {};
|
||||
}
|
||||
CGKeyCode pttKey = (CGKeyCode) pThis->pimpl_->qtKeyTokVKey(pThis->getCurrentKey());
|
||||
static bool isKeyDown = false;
|
||||
if (keycode == pttKey) {
|
||||
if (type == kCGEventKeyDown && !isKeyDown) {
|
||||
Q_EMIT pThis->pttKeyPressed();
|
||||
isKeyDown = true;
|
||||
} else if (type == kCGEventKeyUp && isKeyDown) {
|
||||
Q_EMIT pThis->pttKeyReleased();
|
||||
isKeyDown = false;
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
quint32 qtKeyTokVKey(Qt::Key key);
|
||||
|
||||
private:
|
||||
CFMachPortRef eventTap;
|
||||
};
|
||||
|
||||
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
|
||||
: settingsManager_(settingsManager)
|
||||
, QObject(parent)
|
||||
, pimpl_(std::make_unique<Impl>(this))
|
||||
{}
|
||||
|
||||
PTTListener::~PTTListener() = default;
|
||||
|
||||
void
|
||||
PTTListener::startListening()
|
||||
{
|
||||
pimpl_->startListening();
|
||||
}
|
||||
|
||||
void
|
||||
PTTListener::stopListening()
|
||||
{
|
||||
pimpl_->stopListening();
|
||||
}
|
||||
|
||||
quint32
|
||||
PTTListener::Impl::qtKeyTokVKey(Qt::Key key)
|
||||
{
|
||||
UTF16Char ch;
|
||||
// Constants found in NSEvent.h from AppKit.framework
|
||||
switch (key) {
|
||||
case Qt::Key_Return:
|
||||
return kVK_Return;
|
||||
case Qt::Key_Enter:
|
||||
return kVK_ANSI_KeypadEnter;
|
||||
case Qt::Key_Tab:
|
||||
return kVK_Tab;
|
||||
case Qt::Key_Space:
|
||||
return kVK_Space;
|
||||
case Qt::Key_Backspace:
|
||||
return kVK_Delete;
|
||||
case Qt::Key_Control:
|
||||
return kVK_Command;
|
||||
case Qt::Key_Shift:
|
||||
return kVK_Shift;
|
||||
case Qt::Key_CapsLock:
|
||||
return kVK_CapsLock;
|
||||
case Qt::Key_Option:
|
||||
return kVK_Option;
|
||||
case Qt::Key_Meta:
|
||||
return kVK_Control;
|
||||
case Qt::Key_F17:
|
||||
return kVK_F17;
|
||||
case Qt::Key_VolumeUp:
|
||||
return kVK_VolumeUp;
|
||||
case Qt::Key_VolumeDown:
|
||||
return kVK_VolumeDown;
|
||||
case Qt::Key_F18:
|
||||
return kVK_F18;
|
||||
case Qt::Key_F19:
|
||||
return kVK_F19;
|
||||
case Qt::Key_F20:
|
||||
return kVK_F20;
|
||||
case Qt::Key_F5:
|
||||
return kVK_F5;
|
||||
case Qt::Key_F6:
|
||||
return kVK_F6;
|
||||
case Qt::Key_F7:
|
||||
return kVK_F7;
|
||||
case Qt::Key_F3:
|
||||
return kVK_F3;
|
||||
case Qt::Key_F8:
|
||||
return kVK_F8;
|
||||
case Qt::Key_F9:
|
||||
return kVK_F9;
|
||||
case Qt::Key_F11:
|
||||
return kVK_F11;
|
||||
case Qt::Key_F13:
|
||||
return kVK_F13;
|
||||
case Qt::Key_F16:
|
||||
return kVK_F16;
|
||||
case Qt::Key_F14:
|
||||
return kVK_F14;
|
||||
case Qt::Key_F10:
|
||||
return kVK_F10;
|
||||
case Qt::Key_F12:
|
||||
return kVK_F12;
|
||||
case Qt::Key_F15:
|
||||
return kVK_F15;
|
||||
case Qt::Key_Help:
|
||||
return kVK_Help;
|
||||
case Qt::Key_Home:
|
||||
return kVK_Home;
|
||||
case Qt::Key_PageUp:
|
||||
return kVK_PageUp;
|
||||
case Qt::Key_Delete:
|
||||
return kVK_ForwardDelete;
|
||||
case Qt::Key_F4:
|
||||
return kVK_F4;
|
||||
case Qt::Key_End:
|
||||
return kVK_End;
|
||||
case Qt::Key_F2:
|
||||
return kVK_F2;
|
||||
case Qt::Key_PageDown:
|
||||
return kVK_PageDown;
|
||||
case Qt::Key_F1:
|
||||
return kVK_F1;
|
||||
case Qt::Key_Left:
|
||||
return kVK_LeftArrow;
|
||||
case Qt::Key_Right:
|
||||
return kVK_RightArrow;
|
||||
case Qt::Key_Down:
|
||||
return kVK_DownArrow;
|
||||
case Qt::Key_Up:
|
||||
return kVK_UpArrow;
|
||||
default:;
|
||||
}
|
||||
|
||||
if (key == Qt::Key_Escape)
|
||||
ch = 27;
|
||||
else if (key == Qt::Key_Return)
|
||||
ch = 13;
|
||||
else if (key == Qt::Key_Enter)
|
||||
ch = 3;
|
||||
else if (key == Qt::Key_Tab)
|
||||
ch = 9;
|
||||
else
|
||||
ch = key;
|
||||
|
||||
CFDataRef currentLayoutData;
|
||||
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
|
||||
|
||||
if (currentKeyboard == nullptr)
|
||||
return 0;
|
||||
|
||||
currentLayoutData = (CFDataRef) TISGetInputSourceProperty(currentKeyboard,
|
||||
kTISPropertyUnicodeKeyLayoutData);
|
||||
CFRelease(currentKeyboard);
|
||||
if (currentLayoutData == nullptr)
|
||||
return 0;
|
||||
|
||||
UCKeyboardLayout* header = (UCKeyboardLayout*) CFDataGetBytePtr(currentLayoutData);
|
||||
UCKeyboardTypeHeader* table = header->keyboardTypeList;
|
||||
|
||||
uint8_t* data = (uint8_t*) header;
|
||||
// God, would a little documentation for this shit kill you...
|
||||
for (quint32 i = 0; i < header->keyboardTypeCount; i++) {
|
||||
UCKeyStateRecordsIndex* stateRec = 0;
|
||||
if (table[i].keyStateRecordsIndexOffset != 0) {
|
||||
stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(
|
||||
data + table[i].keyStateRecordsIndexOffset);
|
||||
if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat)
|
||||
stateRec = 0;
|
||||
}
|
||||
|
||||
UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(
|
||||
data + table[i].keyToCharTableIndexOffset);
|
||||
if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat)
|
||||
continue;
|
||||
|
||||
for (quint32 j = 0; j < charTable->keyToCharTableCount; j++) {
|
||||
UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(
|
||||
data + charTable->keyToCharTableOffsets[j]);
|
||||
for (quint32 k = 0; k < charTable->keyToCharTableSize; k++) {
|
||||
if (keyToChar[k] & kUCKeyOutputTestForIndexMask) {
|
||||
long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
|
||||
if (stateRec && idx < stateRec->keyStateRecordCount) {
|
||||
UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(
|
||||
data + stateRec->keyStateRecordOffsets[idx]);
|
||||
if (rec->stateZeroCharData == ch)
|
||||
return k;
|
||||
}
|
||||
} else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask)
|
||||
&& keyToChar[k] < 0xFFFE) {
|
||||
if (keyToChar[k] == ch)
|
||||
return k;
|
||||
}
|
||||
} // for k
|
||||
} // for j
|
||||
} // for i
|
||||
|
||||
// The code above fails to translate keys like semicolon with Qt 5.7.1.
|
||||
// Last resort is to try mapping the rest of the keys directly.
|
||||
switch (key) {
|
||||
case Qt::Key_A:
|
||||
return kVK_ANSI_A;
|
||||
case Qt::Key_S:
|
||||
return kVK_ANSI_S;
|
||||
case Qt::Key_D:
|
||||
return kVK_ANSI_D;
|
||||
case Qt::Key_F:
|
||||
return kVK_ANSI_F;
|
||||
case Qt::Key_H:
|
||||
return kVK_ANSI_H;
|
||||
case Qt::Key_G:
|
||||
return kVK_ANSI_G;
|
||||
case Qt::Key_Z:
|
||||
return kVK_ANSI_Z;
|
||||
case Qt::Key_X:
|
||||
return kVK_ANSI_X;
|
||||
case Qt::Key_C:
|
||||
return kVK_ANSI_C;
|
||||
case Qt::Key_V:
|
||||
return kVK_ANSI_V;
|
||||
case Qt::Key_B:
|
||||
return kVK_ANSI_B;
|
||||
case Qt::Key_Q:
|
||||
return kVK_ANSI_Q;
|
||||
case Qt::Key_W:
|
||||
return kVK_ANSI_W;
|
||||
case Qt::Key_E:
|
||||
return kVK_ANSI_E;
|
||||
case Qt::Key_R:
|
||||
return kVK_ANSI_R;
|
||||
case Qt::Key_Y:
|
||||
return kVK_ANSI_Y;
|
||||
case Qt::Key_T:
|
||||
return kVK_ANSI_T;
|
||||
case Qt::Key_1:
|
||||
return kVK_ANSI_1;
|
||||
case Qt::Key_2:
|
||||
return kVK_ANSI_2;
|
||||
case Qt::Key_3:
|
||||
return kVK_ANSI_3;
|
||||
case Qt::Key_4:
|
||||
return kVK_ANSI_4;
|
||||
case Qt::Key_6:
|
||||
return kVK_ANSI_6;
|
||||
case Qt::Key_5:
|
||||
return kVK_ANSI_5;
|
||||
case Qt::Key_Equal:
|
||||
return kVK_ANSI_Equal;
|
||||
case Qt::Key_9:
|
||||
return kVK_ANSI_9;
|
||||
case Qt::Key_7:
|
||||
return kVK_ANSI_7;
|
||||
case Qt::Key_Minus:
|
||||
return kVK_ANSI_Minus;
|
||||
case Qt::Key_8:
|
||||
return kVK_ANSI_8;
|
||||
case Qt::Key_0:
|
||||
return kVK_ANSI_0;
|
||||
case Qt::Key_BracketRight:
|
||||
return kVK_ANSI_RightBracket;
|
||||
case Qt::Key_O:
|
||||
return kVK_ANSI_O;
|
||||
case Qt::Key_U:
|
||||
return kVK_ANSI_U;
|
||||
case Qt::Key_BracketLeft:
|
||||
return kVK_ANSI_LeftBracket;
|
||||
case Qt::Key_I:
|
||||
return kVK_ANSI_I;
|
||||
case Qt::Key_P:
|
||||
return kVK_ANSI_P;
|
||||
case Qt::Key_L:
|
||||
return kVK_ANSI_L;
|
||||
case Qt::Key_J:
|
||||
return kVK_ANSI_J;
|
||||
case Qt::Key_QuoteDbl:
|
||||
return kVK_ANSI_Quote;
|
||||
case Qt::Key_K:
|
||||
return kVK_ANSI_K;
|
||||
case Qt::Key_Semicolon:
|
||||
return kVK_ANSI_Semicolon;
|
||||
case Qt::Key_Backslash:
|
||||
return kVK_ANSI_Backslash;
|
||||
case Qt::Key_Comma:
|
||||
return kVK_ANSI_Comma;
|
||||
case Qt::Key_Slash:
|
||||
return kVK_ANSI_Slash;
|
||||
case Qt::Key_N:
|
||||
return kVK_ANSI_N;
|
||||
case Qt::Key_M:
|
||||
return kVK_ANSI_M;
|
||||
case Qt::Key_Period:
|
||||
return kVK_ANSI_Period;
|
||||
case Qt::Key_Dead_Grave:
|
||||
return kVK_ANSI_Grave;
|
||||
case Qt::Key_Asterisk:
|
||||
return kVK_ANSI_KeypadMultiply;
|
||||
case Qt::Key_Plus:
|
||||
return kVK_ANSI_KeypadPlus;
|
||||
case Qt::Key_Clear:
|
||||
return kVK_ANSI_KeypadClear;
|
||||
case Qt::Key_Escape:
|
||||
return kVK_Escape;
|
||||
default:;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "pttlistener.moc"
|
309
src/app/platform/windows/pttlistener.cpp
Normal file
309
src/app/platform/windows/pttlistener.cpp
Normal file
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pttlistener.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVariant>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
class PTTListener::Impl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Impl(PTTListener* parent)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
qApp->setProperty("PTTListener", QVariant::fromValue(parent));
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
stopListening();
|
||||
};
|
||||
|
||||
void startListening()
|
||||
{
|
||||
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, GlobalKeyboardProc, NULL, 0);
|
||||
}
|
||||
|
||||
void stopListening()
|
||||
{
|
||||
UnhookWindowsHookEx(keyboardHook);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK GlobalKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
auto* pThis = qApp->property("PTTListener").value<PTTListener*>();
|
||||
if (pThis == nullptr) {
|
||||
qWarning() << "PTTListener not found";
|
||||
return {};
|
||||
}
|
||||
auto* keyboardHook = pThis->pimpl_->keyboardHook;
|
||||
|
||||
quint32 key = qtKeyToVKey(pThis->getCurrentKey());
|
||||
static bool isKeyDown = false;
|
||||
if (nCode == HC_ACTION) {
|
||||
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
|
||||
KBDLLHOOKSTRUCT* keyInfo = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
if (keyInfo->vkCode == key && !isKeyDown) {
|
||||
Q_EMIT pThis->pttKeyPressed();
|
||||
isKeyDown = true;
|
||||
}
|
||||
} else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
|
||||
KBDLLHOOKSTRUCT* keyInfo = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
if (keyInfo->vkCode == key) {
|
||||
Q_EMIT pThis->pttKeyReleased();
|
||||
isKeyDown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
HHOOK keyboardHook;
|
||||
|
||||
static quint32 qtKeyToVKey(Qt::Key key);
|
||||
|
||||
};
|
||||
|
||||
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
|
||||
: settingsManager_(settingsManager)
|
||||
, QObject(parent)
|
||||
, pimpl_(std::make_unique<Impl>(this))
|
||||
{}
|
||||
|
||||
PTTListener::~PTTListener() = default;
|
||||
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
void
|
||||
PTTListener::startListening()
|
||||
{
|
||||
pimpl_->startListening();
|
||||
}
|
||||
|
||||
void
|
||||
PTTListener::stopListening()
|
||||
{
|
||||
pimpl_->stopListening();
|
||||
}
|
||||
#endif
|
||||
|
||||
quint32
|
||||
PTTListener::Impl::qtKeyToVKey(Qt::Key key)
|
||||
{
|
||||
switch (key) {
|
||||
case Qt::Key_Escape:
|
||||
return VK_ESCAPE;
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
return VK_TAB;
|
||||
case Qt::Key_Backspace:
|
||||
return VK_BACK;
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
return VK_RETURN;
|
||||
case Qt::Key_Insert:
|
||||
return VK_INSERT;
|
||||
case Qt::Key_Delete:
|
||||
return VK_DELETE;
|
||||
case Qt::Key_Pause:
|
||||
return VK_PAUSE;
|
||||
case Qt::Key_Print:
|
||||
return VK_PRINT;
|
||||
case Qt::Key_Clear:
|
||||
return VK_CLEAR;
|
||||
case Qt::Key_Home:
|
||||
return VK_HOME;
|
||||
case Qt::Key_End:
|
||||
return VK_END;
|
||||
case Qt::Key_Left:
|
||||
return VK_LEFT;
|
||||
case Qt::Key_Up:
|
||||
return VK_UP;
|
||||
case Qt::Key_Right:
|
||||
return VK_RIGHT;
|
||||
case Qt::Key_Down:
|
||||
return VK_DOWN;
|
||||
case Qt::Key_PageUp:
|
||||
return VK_PRIOR;
|
||||
case Qt::Key_PageDown:
|
||||
return VK_NEXT;
|
||||
case Qt::Key_F1:
|
||||
return VK_F1;
|
||||
case Qt::Key_F2:
|
||||
return VK_F2;
|
||||
case Qt::Key_F3:
|
||||
return VK_F3;
|
||||
case Qt::Key_F4:
|
||||
return VK_F4;
|
||||
case Qt::Key_F5:
|
||||
return VK_F5;
|
||||
case Qt::Key_F6:
|
||||
return VK_F6;
|
||||
case Qt::Key_F7:
|
||||
return VK_F7;
|
||||
case Qt::Key_F8:
|
||||
return VK_F8;
|
||||
case Qt::Key_F9:
|
||||
return VK_F9;
|
||||
case Qt::Key_F10:
|
||||
return VK_F10;
|
||||
case Qt::Key_F11:
|
||||
return VK_F11;
|
||||
case Qt::Key_F12:
|
||||
return VK_F12;
|
||||
case Qt::Key_F13:
|
||||
return VK_F13;
|
||||
case Qt::Key_F14:
|
||||
return VK_F14;
|
||||
case Qt::Key_F15:
|
||||
return VK_F15;
|
||||
case Qt::Key_F16:
|
||||
return VK_F16;
|
||||
case Qt::Key_F17:
|
||||
return VK_F17;
|
||||
case Qt::Key_F18:
|
||||
return VK_F18;
|
||||
case Qt::Key_F19:
|
||||
return VK_F19;
|
||||
case Qt::Key_F20:
|
||||
return VK_F20;
|
||||
case Qt::Key_F21:
|
||||
return VK_F21;
|
||||
case Qt::Key_F22:
|
||||
return VK_F22;
|
||||
case Qt::Key_F23:
|
||||
return VK_F23;
|
||||
case Qt::Key_F24:
|
||||
return VK_F24;
|
||||
case Qt::Key_Space:
|
||||
return VK_SPACE;
|
||||
case Qt::Key_Asterisk:
|
||||
return VK_MULTIPLY;
|
||||
case Qt::Key_Plus:
|
||||
return VK_ADD;
|
||||
case Qt::Key_Minus:
|
||||
return VK_SUBTRACT;
|
||||
case Qt::Key_Slash:
|
||||
return VK_DIVIDE;
|
||||
case Qt::Key_MediaNext:
|
||||
return VK_MEDIA_NEXT_TRACK;
|
||||
case Qt::Key_MediaPrevious:
|
||||
return VK_MEDIA_PREV_TRACK;
|
||||
case Qt::Key_MediaPlay:
|
||||
return VK_MEDIA_PLAY_PAUSE;
|
||||
case Qt::Key_MediaStop:
|
||||
return VK_MEDIA_STOP;
|
||||
// couldn't find those in VK_*
|
||||
// case Qt::Key_MediaLast:
|
||||
// case Qt::Key_MediaRecord:
|
||||
case Qt::Key_VolumeDown:
|
||||
return VK_VOLUME_DOWN;
|
||||
case Qt::Key_VolumeUp:
|
||||
return VK_VOLUME_UP;
|
||||
case Qt::Key_VolumeMute:
|
||||
return VK_VOLUME_MUTE;
|
||||
case Qt::Key_0:
|
||||
return VK_NUMPAD0;
|
||||
case Qt::Key_1:
|
||||
return VK_NUMPAD1;
|
||||
case Qt::Key_2:
|
||||
return VK_NUMPAD2;
|
||||
case Qt::Key_3:
|
||||
return VK_NUMPAD3;
|
||||
case Qt::Key_4:
|
||||
return VK_NUMPAD4;
|
||||
case Qt::Key_5:
|
||||
return VK_NUMPAD5;
|
||||
case Qt::Key_6:
|
||||
return VK_NUMPAD6;
|
||||
case Qt::Key_7:
|
||||
return VK_NUMPAD7;
|
||||
case Qt::Key_8:
|
||||
return VK_NUMPAD8;
|
||||
case Qt::Key_9:
|
||||
return VK_NUMPAD9;
|
||||
case Qt::Key_A:
|
||||
return 'A';
|
||||
case Qt::Key_B:
|
||||
return 'B';
|
||||
case Qt::Key_C:
|
||||
return 'C';
|
||||
case Qt::Key_D:
|
||||
return 'D';
|
||||
case Qt::Key_E:
|
||||
return 'E';
|
||||
case Qt::Key_F:
|
||||
return 'F';
|
||||
case Qt::Key_G:
|
||||
return 'G';
|
||||
case Qt::Key_H:
|
||||
return 'H';
|
||||
case Qt::Key_I:
|
||||
return 'I';
|
||||
case Qt::Key_J:
|
||||
return 'J';
|
||||
case Qt::Key_K:
|
||||
return 'K';
|
||||
case Qt::Key_L:
|
||||
return 'L';
|
||||
case Qt::Key_M:
|
||||
return 'M';
|
||||
case Qt::Key_N:
|
||||
return 'N';
|
||||
case Qt::Key_O:
|
||||
return 'O';
|
||||
case Qt::Key_P:
|
||||
return 'P';
|
||||
case Qt::Key_Q:
|
||||
return 'Q';
|
||||
case Qt::Key_R:
|
||||
return 'R';
|
||||
case Qt::Key_S:
|
||||
return 'S';
|
||||
case Qt::Key_T:
|
||||
return 'T';
|
||||
case Qt::Key_U:
|
||||
return 'U';
|
||||
case Qt::Key_V:
|
||||
return 'V';
|
||||
case Qt::Key_W:
|
||||
return 'W';
|
||||
case Qt::Key_X:
|
||||
return 'X';
|
||||
case Qt::Key_Y:
|
||||
return 'Y';
|
||||
case Qt::Key_Z:
|
||||
return 'Z';
|
||||
|
||||
default:
|
||||
//Try to get virtual key from current keyboard layout or US.
|
||||
const HKL layout = GetKeyboardLayout(0);
|
||||
int vk = VkKeyScanEx(key, layout);
|
||||
if (vk == -1) {
|
||||
const HKL layoutUs = GetKeyboardLayout(0x409);
|
||||
vk = VkKeyScanEx(key, layoutUs);
|
||||
}
|
||||
return vk == -1 ? 0 : vk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include "pttlistener.moc"
|
192
src/app/platform/x11/pttlistener.cpp
Normal file
192
src/app/platform/x11/pttlistener.cpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Savoir-faire Linux Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pttlistener.h"
|
||||
#include "appsettingsmanager.h"
|
||||
#include "xcbkeyboard.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QVariant>
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
class PTTListener::Impl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Impl(PTTListener* parent)
|
||||
: QObject(nullptr)
|
||||
, parent_(*parent)
|
||||
, display_(XOpenDisplay(NULL))
|
||||
, root_(DefaultRootWindow(display_))
|
||||
{
|
||||
thread_.reset(new QThread());
|
||||
moveToThread(thread_.get());
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
stopListening();
|
||||
XCloseDisplay(display_);
|
||||
};
|
||||
|
||||
void startListening()
|
||||
{
|
||||
stop_.store(false);
|
||||
connect(thread_.get(), &QThread::started, this, &Impl::processEvents);
|
||||
thread_->start();
|
||||
}
|
||||
|
||||
void stopListening()
|
||||
{
|
||||
stop_.store(true);
|
||||
thread_->quit();
|
||||
thread_->wait();
|
||||
}
|
||||
|
||||
static const unsigned int* keyTbl_;
|
||||
|
||||
KeySym getKeySymFromQtKey(Qt::Key qtKey);
|
||||
|
||||
QString keySymToQString(KeySym ks);
|
||||
|
||||
KeySym qtKeyToXKeySym(Qt::Key key);
|
||||
|
||||
private Q_SLOTS:
|
||||
void processEvents()
|
||||
{
|
||||
Window curFocus;
|
||||
char buf[17];
|
||||
KeySym ks;
|
||||
XComposeStatus comp;
|
||||
int len;
|
||||
int revert;
|
||||
static auto flags = KeyPressMask | KeyReleaseMask | FocusChangeMask;
|
||||
|
||||
XGetInputFocus(display_, &curFocus, &revert);
|
||||
XSelectInput(display_, curFocus, flags);
|
||||
bool pressed = false;
|
||||
KeySym key = qtKeyToXKeySym(parent_.getCurrentKey());
|
||||
|
||||
while (!stop_.load()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
while (XPending(display_)) {
|
||||
XEvent ev;
|
||||
|
||||
XNextEvent(display_, &ev);
|
||||
XLookupString(&ev.xkey, buf, 16, &ks, &comp);
|
||||
switch (ev.type) {
|
||||
case FocusOut:
|
||||
if (curFocus != root_)
|
||||
XSelectInput(display_, curFocus, 0);
|
||||
XGetInputFocus(display_, &curFocus, &revert);
|
||||
if (curFocus == PointerRoot)
|
||||
curFocus = root_;
|
||||
XSelectInput(display_, curFocus, flags);
|
||||
break;
|
||||
|
||||
case KeyPress: {
|
||||
if (!(pressed) && ks == key) {
|
||||
Q_EMIT parent_.pttKeyPressed();
|
||||
pressed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyRelease:
|
||||
bool is_retriggered = false;
|
||||
if (XEventsQueued(display_, QueuedAfterReading)) {
|
||||
XEvent nev;
|
||||
XPeekEvent(display_, &nev);
|
||||
if (nev.type == KeyPress && nev.xkey.time == ev.xkey.time
|
||||
&& nev.xkey.keycode == ev.xkey.keycode) {
|
||||
is_retriggered = true;
|
||||
}
|
||||
}
|
||||
if (!is_retriggered && ks == key) {
|
||||
Q_EMIT parent_.pttKeyReleased();
|
||||
pressed = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PTTListener& parent_;
|
||||
Display* display_;
|
||||
Window root_;
|
||||
QScopedPointer<QThread> thread_;
|
||||
std::atomic_bool stop_ {false};
|
||||
};
|
||||
|
||||
QString
|
||||
PTTListener::Impl::keySymToQString(KeySym ks)
|
||||
{
|
||||
return QString::fromUtf8(XKeysymToString(ks));
|
||||
}
|
||||
|
||||
KeySym
|
||||
PTTListener::Impl::qtKeyToXKeySym(Qt::Key key)
|
||||
{
|
||||
const auto keySym = getKeySymFromQtKey(key);
|
||||
if (keySym != NoSymbol) {
|
||||
return keySym;
|
||||
}
|
||||
for (int i = 0; keyTbl_[i] != 0; i += 2) {
|
||||
if (keyTbl_[i + 1] == key)
|
||||
return keyTbl_[i];
|
||||
}
|
||||
|
||||
return static_cast<ushort>(key);
|
||||
}
|
||||
|
||||
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
|
||||
: settingsManager_(settingsManager)
|
||||
, QObject(parent)
|
||||
, pimpl_(std::make_unique<Impl>(this))
|
||||
{}
|
||||
|
||||
PTTListener::~PTTListener() = default;
|
||||
|
||||
void
|
||||
PTTListener::startListening()
|
||||
{
|
||||
pimpl_->startListening();
|
||||
}
|
||||
|
||||
void
|
||||
PTTListener::stopListening()
|
||||
{
|
||||
pimpl_->stopListening();
|
||||
}
|
||||
KeySym
|
||||
PTTListener::Impl::getKeySymFromQtKey(Qt::Key qtKey)
|
||||
{
|
||||
QString keyString = QKeySequence(qtKey).toString().toLower();
|
||||
KeySym keySym = XStringToKeysym(keyString.toUtf8().data());
|
||||
return keySym;
|
||||
}
|
||||
|
||||
const unsigned int* PTTListener::Impl::keyTbl_ = keyTable;
|
||||
|
||||
#include "pttlistener.moc"
|
856
src/app/platform/x11/xcbkeyboard.h
Normal file
856
src/app/platform/x11/xcbkeyboard.h
Normal file
|
@ -0,0 +1,856 @@
|
|||
#include "pttlistener.h"
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// Following definitions and table are taken from
|
||||
// "qt5/qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp".
|
||||
|
||||
#include <Qt>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#ifndef XK_ISO_Left_Tab
|
||||
#define XK_ISO_Left_Tab 0xFE20
|
||||
#endif
|
||||
|
||||
#ifndef XK_dead_hook
|
||||
#define XK_dead_hook 0xFE61
|
||||
#endif
|
||||
|
||||
#ifndef XK_dead_horn
|
||||
#define XK_dead_horn 0xFE62
|
||||
#endif
|
||||
|
||||
#ifndef XK_Codeinput
|
||||
#define XK_Codeinput 0xFF37
|
||||
#endif
|
||||
|
||||
#ifndef XK_Kanji_Bangou
|
||||
#define XK_Kanji_Bangou 0xFF37 /* same as codeinput */
|
||||
#endif
|
||||
|
||||
// Fix old X libraries
|
||||
#ifndef XK_KP_Home
|
||||
#define XK_KP_Home 0xFF95
|
||||
#endif
|
||||
#ifndef XK_KP_Left
|
||||
#define XK_KP_Left 0xFF96
|
||||
#endif
|
||||
#ifndef XK_KP_Up
|
||||
#define XK_KP_Up 0xFF97
|
||||
#endif
|
||||
#ifndef XK_KP_Right
|
||||
#define XK_KP_Right 0xFF98
|
||||
#endif
|
||||
#ifndef XK_KP_Down
|
||||
#define XK_KP_Down 0xFF99
|
||||
#endif
|
||||
#ifndef XK_KP_Prior
|
||||
#define XK_KP_Prior 0xFF9A
|
||||
#endif
|
||||
#ifndef XK_KP_Next
|
||||
#define XK_KP_Next 0xFF9B
|
||||
#endif
|
||||
#ifndef XK_KP_End
|
||||
#define XK_KP_End 0xFF9C
|
||||
#endif
|
||||
#ifndef XK_KP_Insert
|
||||
#define XK_KP_Insert 0xFF9E
|
||||
#endif
|
||||
#ifndef XK_KP_Delete
|
||||
#define XK_KP_Delete 0xFF9F
|
||||
#endif
|
||||
|
||||
// the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining some special
|
||||
// multimedia keys. They are included here as not every system has them.
|
||||
#define XF86XK_MonBrightnessUp 0x1008FF02
|
||||
#define XF86XK_MonBrightnessDown 0x1008FF03
|
||||
#define XF86XK_KbdLightOnOff 0x1008FF04
|
||||
#define XF86XK_KbdBrightnessUp 0x1008FF05
|
||||
#define XF86XK_KbdBrightnessDown 0x1008FF06
|
||||
#define XF86XK_Standby 0x1008FF10
|
||||
#define XF86XK_AudioLowerVolume 0x1008FF11
|
||||
#define XF86XK_AudioMute 0x1008FF12
|
||||
#define XF86XK_AudioRaiseVolume 0x1008FF13
|
||||
#define XF86XK_AudioPlay 0x1008FF14
|
||||
#define XF86XK_AudioStop 0x1008FF15
|
||||
#define XF86XK_AudioPrev 0x1008FF16
|
||||
#define XF86XK_AudioNext 0x1008FF17
|
||||
#define XF86XK_HomePage 0x1008FF18
|
||||
#define XF86XK_Mail 0x1008FF19
|
||||
#define XF86XK_Start 0x1008FF1A
|
||||
#define XF86XK_Search 0x1008FF1B
|
||||
#define XF86XK_AudioRecord 0x1008FF1C
|
||||
#define XF86XK_Calculator 0x1008FF1D
|
||||
#define XF86XK_Memo 0x1008FF1E
|
||||
#define XF86XK_ToDoList 0x1008FF1F
|
||||
#define XF86XK_Calendar 0x1008FF20
|
||||
#define XF86XK_PowerDown 0x1008FF21
|
||||
#define XF86XK_ContrastAdjust 0x1008FF22
|
||||
#define XF86XK_Back 0x1008FF26
|
||||
#define XF86XK_Forward 0x1008FF27
|
||||
#define XF86XK_Stop 0x1008FF28
|
||||
#define XF86XK_Refresh 0x1008FF29
|
||||
#define XF86XK_PowerOff 0x1008FF2A
|
||||
#define XF86XK_WakeUp 0x1008FF2B
|
||||
#define XF86XK_Eject 0x1008FF2C
|
||||
#define XF86XK_ScreenSaver 0x1008FF2D
|
||||
#define XF86XK_WWW 0x1008FF2E
|
||||
#define XF86XK_Sleep 0x1008FF2F
|
||||
#define XF86XK_Favorites 0x1008FF30
|
||||
#define XF86XK_AudioPause 0x1008FF31
|
||||
#define XF86XK_AudioMedia 0x1008FF32
|
||||
#define XF86XK_MyComputer 0x1008FF33
|
||||
#define XF86XK_LightBulb 0x1008FF35
|
||||
#define XF86XK_Shop 0x1008FF36
|
||||
#define XF86XK_History 0x1008FF37
|
||||
#define XF86XK_OpenURL 0x1008FF38
|
||||
#define XF86XK_AddFavorite 0x1008FF39
|
||||
#define XF86XK_HotLinks 0x1008FF3A
|
||||
#define XF86XK_BrightnessAdjust 0x1008FF3B
|
||||
#define XF86XK_Finance 0x1008FF3C
|
||||
#define XF86XK_Community 0x1008FF3D
|
||||
#define XF86XK_AudioRewind 0x1008FF3E
|
||||
#define XF86XK_BackForward 0x1008FF3F
|
||||
#define XF86XK_Launch0 0x1008FF40
|
||||
#define XF86XK_Launch1 0x1008FF41
|
||||
#define XF86XK_Launch2 0x1008FF42
|
||||
#define XF86XK_Launch3 0x1008FF43
|
||||
#define XF86XK_Launch4 0x1008FF44
|
||||
#define XF86XK_Launch5 0x1008FF45
|
||||
#define XF86XK_Launch6 0x1008FF46
|
||||
#define XF86XK_Launch7 0x1008FF47
|
||||
#define XF86XK_Launch8 0x1008FF48
|
||||
#define XF86XK_Launch9 0x1008FF49
|
||||
#define XF86XK_LaunchA 0x1008FF4A
|
||||
#define XF86XK_LaunchB 0x1008FF4B
|
||||
#define XF86XK_LaunchC 0x1008FF4C
|
||||
#define XF86XK_LaunchD 0x1008FF4D
|
||||
#define XF86XK_LaunchE 0x1008FF4E
|
||||
#define XF86XK_LaunchF 0x1008FF4F
|
||||
#define XF86XK_ApplicationLeft 0x1008FF50
|
||||
#define XF86XK_ApplicationRight 0x1008FF51
|
||||
#define XF86XK_Book 0x1008FF52
|
||||
#define XF86XK_CD 0x1008FF53
|
||||
#define XF86XK_Calculater 0x1008FF54
|
||||
#define XF86XK_Clear 0x1008FF55
|
||||
#define XF86XK_ClearGrab 0x1008FE21
|
||||
#define XF86XK_Close 0x1008FF56
|
||||
#define XF86XK_Copy 0x1008FF57
|
||||
#define XF86XK_Cut 0x1008FF58
|
||||
#define XF86XK_Display 0x1008FF59
|
||||
#define XF86XK_DOS 0x1008FF5A
|
||||
#define XF86XK_Documents 0x1008FF5B
|
||||
#define XF86XK_Excel 0x1008FF5C
|
||||
#define XF86XK_Explorer 0x1008FF5D
|
||||
#define XF86XK_Game 0x1008FF5E
|
||||
#define XF86XK_Go 0x1008FF5F
|
||||
#define XF86XK_iTouch 0x1008FF60
|
||||
#define XF86XK_LogOff 0x1008FF61
|
||||
#define XF86XK_Market 0x1008FF62
|
||||
#define XF86XK_Meeting 0x1008FF63
|
||||
#define XF86XK_MenuKB 0x1008FF65
|
||||
#define XF86XK_MenuPB 0x1008FF66
|
||||
#define XF86XK_MySites 0x1008FF67
|
||||
#define XF86XK_New 0x1008FF68
|
||||
#define XF86XK_News 0x1008FF69
|
||||
#define XF86XK_OfficeHome 0x1008FF6A
|
||||
#define XF86XK_Open 0x1008FF6B
|
||||
#define XF86XK_Option 0x1008FF6C
|
||||
#define XF86XK_Paste 0x1008FF6D
|
||||
#define XF86XK_Phone 0x1008FF6E
|
||||
#define XF86XK_Reply 0x1008FF72
|
||||
#define XF86XK_Reload 0x1008FF73
|
||||
#define XF86XK_RotateWindows 0x1008FF74
|
||||
#define XF86XK_RotationPB 0x1008FF75
|
||||
#define XF86XK_RotationKB 0x1008FF76
|
||||
#define XF86XK_Save 0x1008FF77
|
||||
#define XF86XK_Send 0x1008FF7B
|
||||
#define XF86XK_Spell 0x1008FF7C
|
||||
#define XF86XK_SplitScreen 0x1008FF7D
|
||||
#define XF86XK_Support 0x1008FF7E
|
||||
#define XF86XK_TaskPane 0x1008FF7F
|
||||
#define XF86XK_Terminal 0x1008FF80
|
||||
#define XF86XK_Tools 0x1008FF81
|
||||
#define XF86XK_Travel 0x1008FF82
|
||||
#define XF86XK_Video 0x1008FF87
|
||||
#define XF86XK_Word 0x1008FF89
|
||||
#define XF86XK_Xfer 0x1008FF8A
|
||||
#define XF86XK_ZoomIn 0x1008FF8B
|
||||
#define XF86XK_ZoomOut 0x1008FF8C
|
||||
#define XF86XK_Away 0x1008FF8D
|
||||
#define XF86XK_Messenger 0x1008FF8E
|
||||
#define XF86XK_WebCam 0x1008FF8F
|
||||
#define XF86XK_MailForward 0x1008FF90
|
||||
#define XF86XK_Pictures 0x1008FF91
|
||||
#define XF86XK_Music 0x1008FF92
|
||||
#define XF86XK_Battery 0x1008FF93
|
||||
#define XF86XK_Bluetooth 0x1008FF94
|
||||
#define XF86XK_WLAN 0x1008FF95
|
||||
#define XF86XK_UWB 0x1008FF96
|
||||
#define XF86XK_AudioForward 0x1008FF97
|
||||
#define XF86XK_AudioRepeat 0x1008FF98
|
||||
#define XF86XK_AudioRandomPlay 0x1008FF99
|
||||
#define XF86XK_Subtitle 0x1008FF9A
|
||||
#define XF86XK_AudioCycleTrack 0x1008FF9B
|
||||
#define XF86XK_Time 0x1008FF9F
|
||||
#define XF86XK_Select 0x1008FFA0
|
||||
#define XF86XK_View 0x1008FFA1
|
||||
#define XF86XK_TopMenu 0x1008FFA2
|
||||
#define XF86XK_Red 0x1008FFA3
|
||||
#define XF86XK_Green 0x1008FFA4
|
||||
#define XF86XK_Yellow 0x1008FFA5
|
||||
#define XF86XK_Blue 0x1008FFA6
|
||||
#define XF86XK_Suspend 0x1008FFA7
|
||||
#define XF86XK_Hibernate 0x1008FFA8
|
||||
#define XF86XK_TouchpadToggle 0x1008FFA9
|
||||
#define XF86XK_TouchpadOn 0x1008FFB0
|
||||
#define XF86XK_TouchpadOff 0x1008FFB1
|
||||
#define XF86XK_AudioMicMute 0x1008FFB2
|
||||
|
||||
// end of XF86keysyms.h
|
||||
|
||||
// keyboard mapping table
|
||||
static const unsigned int keyTable[] = {
|
||||
|
||||
// misc keys
|
||||
|
||||
XK_Escape,
|
||||
Qt::Key_Escape,
|
||||
XK_Tab,
|
||||
Qt::Key_Tab,
|
||||
XK_ISO_Left_Tab,
|
||||
Qt::Key_Backtab,
|
||||
XK_BackSpace,
|
||||
Qt::Key_Backspace,
|
||||
XK_Return,
|
||||
Qt::Key_Return,
|
||||
XK_Insert,
|
||||
Qt::Key_Insert,
|
||||
XK_Delete,
|
||||
Qt::Key_Delete,
|
||||
XK_Clear,
|
||||
Qt::Key_Delete,
|
||||
XK_Pause,
|
||||
Qt::Key_Pause,
|
||||
XK_Print,
|
||||
Qt::Key_Print,
|
||||
0x1005FF60,
|
||||
Qt::Key_SysReq, // hardcoded Sun SysReq
|
||||
0x1007ff00,
|
||||
Qt::Key_SysReq, // hardcoded X386 SysReq
|
||||
|
||||
// cursor movement
|
||||
|
||||
XK_Home,
|
||||
Qt::Key_Home,
|
||||
XK_End,
|
||||
Qt::Key_End,
|
||||
XK_Left,
|
||||
Qt::Key_Left,
|
||||
XK_Up,
|
||||
Qt::Key_Up,
|
||||
XK_Right,
|
||||
Qt::Key_Right,
|
||||
XK_Down,
|
||||
Qt::Key_Down,
|
||||
XK_Prior,
|
||||
Qt::Key_PageUp,
|
||||
XK_Next,
|
||||
Qt::Key_PageDown,
|
||||
|
||||
// modifiers
|
||||
|
||||
XK_Shift_L,
|
||||
Qt::Key_Shift,
|
||||
XK_Shift_R,
|
||||
Qt::Key_Shift,
|
||||
XK_Shift_Lock,
|
||||
Qt::Key_Shift,
|
||||
XK_Control_L,
|
||||
Qt::Key_Control,
|
||||
XK_Control_R,
|
||||
Qt::Key_Control,
|
||||
XK_Meta_L,
|
||||
Qt::Key_Meta,
|
||||
XK_Meta_R,
|
||||
Qt::Key_Meta,
|
||||
XK_Alt_L,
|
||||
Qt::Key_Alt,
|
||||
XK_Alt_R,
|
||||
Qt::Key_Alt,
|
||||
XK_Caps_Lock,
|
||||
Qt::Key_CapsLock,
|
||||
XK_Num_Lock,
|
||||
Qt::Key_NumLock,
|
||||
XK_Scroll_Lock,
|
||||
Qt::Key_ScrollLock,
|
||||
XK_Super_L,
|
||||
Qt::Key_Super_L,
|
||||
XK_Super_R,
|
||||
Qt::Key_Super_R,
|
||||
XK_Menu,
|
||||
Qt::Key_Menu,
|
||||
XK_Hyper_L,
|
||||
Qt::Key_Hyper_L,
|
||||
XK_Hyper_R,
|
||||
Qt::Key_Hyper_R,
|
||||
XK_Help,
|
||||
Qt::Key_Help,
|
||||
0x1000FF74,
|
||||
Qt::Key_Backtab, // hardcoded HP backtab
|
||||
0x1005FF10,
|
||||
Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
|
||||
0x1005FF11,
|
||||
Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
|
||||
|
||||
// numeric and function keypad keys
|
||||
|
||||
XK_KP_Space,
|
||||
Qt::Key_Space,
|
||||
XK_KP_Tab,
|
||||
Qt::Key_Tab,
|
||||
XK_KP_Enter,
|
||||
Qt::Key_Enter,
|
||||
XK_KP_F1,
|
||||
Qt::Key_F1,
|
||||
XK_F2,
|
||||
Qt::Key_F2,
|
||||
XK_F3,
|
||||
Qt::Key_F3,
|
||||
XK_F4,
|
||||
Qt::Key_F4,
|
||||
XK_F5,
|
||||
Qt::Key_F5,
|
||||
XK_F6,
|
||||
Qt::Key_F6,
|
||||
XK_F7,
|
||||
Qt::Key_F7,
|
||||
XK_F8,
|
||||
Qt::Key_F8,
|
||||
XK_F9,
|
||||
Qt::Key_F9,
|
||||
XK_F10,
|
||||
Qt::Key_F10,
|
||||
XK_KP_Home,
|
||||
Qt::Key_Home,
|
||||
XK_KP_Left,
|
||||
Qt::Key_Left,
|
||||
XK_KP_Up,
|
||||
Qt::Key_Up,
|
||||
XK_KP_Right,
|
||||
Qt::Key_Right,
|
||||
XK_KP_Down,
|
||||
Qt::Key_Down,
|
||||
XK_KP_Prior,
|
||||
Qt::Key_PageUp,
|
||||
XK_KP_Next,
|
||||
Qt::Key_PageDown,
|
||||
XK_KP_End,
|
||||
Qt::Key_End,
|
||||
XK_KP_Begin,
|
||||
Qt::Key_Clear,
|
||||
XK_KP_Insert,
|
||||
Qt::Key_Insert,
|
||||
XK_KP_Delete,
|
||||
Qt::Key_Delete,
|
||||
XK_KP_Equal,
|
||||
Qt::Key_Equal,
|
||||
XK_KP_Multiply,
|
||||
Qt::Key_Asterisk,
|
||||
XK_KP_Add,
|
||||
Qt::Key_Plus,
|
||||
XK_KP_Separator,
|
||||
Qt::Key_Comma,
|
||||
XK_KP_Subtract,
|
||||
Qt::Key_Minus,
|
||||
XK_KP_Decimal,
|
||||
Qt::Key_Period,
|
||||
XK_KP_Divide,
|
||||
Qt::Key_Slash,
|
||||
|
||||
// International input method support keys
|
||||
|
||||
// International & multi-key character composition
|
||||
XK_ISO_Level3_Shift,
|
||||
Qt::Key_AltGr,
|
||||
XK_Multi_key,
|
||||
Qt::Key_Multi_key,
|
||||
XK_Codeinput,
|
||||
Qt::Key_Codeinput,
|
||||
XK_SingleCandidate,
|
||||
Qt::Key_SingleCandidate,
|
||||
XK_MultipleCandidate,
|
||||
Qt::Key_MultipleCandidate,
|
||||
XK_PreviousCandidate,
|
||||
Qt::Key_PreviousCandidate,
|
||||
|
||||
// Misc Functions
|
||||
XK_Mode_switch,
|
||||
Qt::Key_Mode_switch,
|
||||
XK_script_switch,
|
||||
Qt::Key_Mode_switch,
|
||||
|
||||
// Japanese keyboard support
|
||||
XK_Kanji,
|
||||
Qt::Key_Kanji,
|
||||
XK_Muhenkan,
|
||||
Qt::Key_Muhenkan,
|
||||
// XK_Henkan_Mode, Qt::Key_Henkan_Mode,
|
||||
XK_Henkan_Mode,
|
||||
Qt::Key_Henkan,
|
||||
XK_Henkan,
|
||||
Qt::Key_Henkan,
|
||||
XK_Romaji,
|
||||
Qt::Key_Romaji,
|
||||
XK_Hiragana,
|
||||
Qt::Key_Hiragana,
|
||||
XK_Katakana,
|
||||
Qt::Key_Katakana,
|
||||
XK_Hiragana_Katakana,
|
||||
Qt::Key_Hiragana_Katakana,
|
||||
XK_Zenkaku,
|
||||
Qt::Key_Zenkaku,
|
||||
XK_Hankaku,
|
||||
Qt::Key_Hankaku,
|
||||
XK_Zenkaku_Hankaku,
|
||||
Qt::Key_Zenkaku_Hankaku,
|
||||
XK_Touroku,
|
||||
Qt::Key_Touroku,
|
||||
XK_Massyo,
|
||||
Qt::Key_Massyo,
|
||||
XK_Kana_Lock,
|
||||
Qt::Key_Kana_Lock,
|
||||
XK_Kana_Shift,
|
||||
Qt::Key_Kana_Shift,
|
||||
XK_Eisu_Shift,
|
||||
Qt::Key_Eisu_Shift,
|
||||
XK_Eisu_toggle,
|
||||
Qt::Key_Eisu_toggle,
|
||||
// XK_Kanji_Bangou, Qt::Key_Kanji_Bangou,
|
||||
// XK_Zen_Koho, Qt::Key_Zen_Koho,
|
||||
// XK_Mae_Koho, Qt::Key_Mae_Koho,
|
||||
XK_Kanji_Bangou,
|
||||
Qt::Key_Codeinput,
|
||||
XK_Zen_Koho,
|
||||
Qt::Key_MultipleCandidate,
|
||||
XK_Mae_Koho,
|
||||
Qt::Key_PreviousCandidate,
|
||||
|
||||
#ifdef XK_KOREAN
|
||||
// Korean keyboard support
|
||||
XK_Hangul,
|
||||
Qt::Key_Hangul,
|
||||
XK_Hangul_Start,
|
||||
Qt::Key_Hangul_Start,
|
||||
XK_Hangul_End,
|
||||
Qt::Key_Hangul_End,
|
||||
XK_Hangul_Hanja,
|
||||
Qt::Key_Hangul_Hanja,
|
||||
XK_Hangul_Jamo,
|
||||
Qt::Key_Hangul_Jamo,
|
||||
XK_Hangul_Romaja,
|
||||
Qt::Key_Hangul_Romaja,
|
||||
// XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
|
||||
XK_Hangul_Codeinput,
|
||||
Qt::Key_Codeinput,
|
||||
XK_Hangul_Jeonja,
|
||||
Qt::Key_Hangul_Jeonja,
|
||||
XK_Hangul_Banja,
|
||||
Qt::Key_Hangul_Banja,
|
||||
XK_Hangul_PreHanja,
|
||||
Qt::Key_Hangul_PreHanja,
|
||||
XK_Hangul_PostHanja,
|
||||
Qt::Key_Hangul_PostHanja,
|
||||
// XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
|
||||
// XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
|
||||
// XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
|
||||
XK_Hangul_SingleCandidate,
|
||||
Qt::Key_SingleCandidate,
|
||||
XK_Hangul_MultipleCandidate,
|
||||
Qt::Key_MultipleCandidate,
|
||||
XK_Hangul_PreviousCandidate,
|
||||
Qt::Key_PreviousCandidate,
|
||||
XK_Hangul_Special,
|
||||
Qt::Key_Hangul_Special,
|
||||
// XK_Hangul_switch, Qt::Key_Hangul_switch,
|
||||
XK_Hangul_switch,
|
||||
Qt::Key_Mode_switch,
|
||||
#endif // XK_KOREAN
|
||||
|
||||
// dead keys
|
||||
XK_dead_grave,
|
||||
Qt::Key_Dead_Grave,
|
||||
XK_dead_acute,
|
||||
Qt::Key_Dead_Acute,
|
||||
XK_dead_circumflex,
|
||||
Qt::Key_Dead_Circumflex,
|
||||
XK_dead_tilde,
|
||||
Qt::Key_Dead_Tilde,
|
||||
XK_dead_macron,
|
||||
Qt::Key_Dead_Macron,
|
||||
XK_dead_breve,
|
||||
Qt::Key_Dead_Breve,
|
||||
XK_dead_abovedot,
|
||||
Qt::Key_Dead_Abovedot,
|
||||
XK_dead_diaeresis,
|
||||
Qt::Key_Dead_Diaeresis,
|
||||
XK_dead_abovering,
|
||||
Qt::Key_Dead_Abovering,
|
||||
XK_dead_doubleacute,
|
||||
Qt::Key_Dead_Doubleacute,
|
||||
XK_dead_caron,
|
||||
Qt::Key_Dead_Caron,
|
||||
XK_dead_cedilla,
|
||||
Qt::Key_Dead_Cedilla,
|
||||
XK_dead_ogonek,
|
||||
Qt::Key_Dead_Ogonek,
|
||||
XK_dead_iota,
|
||||
Qt::Key_Dead_Iota,
|
||||
XK_dead_voiced_sound,
|
||||
Qt::Key_Dead_Voiced_Sound,
|
||||
XK_dead_semivoiced_sound,
|
||||
Qt::Key_Dead_Semivoiced_Sound,
|
||||
XK_dead_belowdot,
|
||||
Qt::Key_Dead_Belowdot,
|
||||
XK_dead_hook,
|
||||
Qt::Key_Dead_Hook,
|
||||
XK_dead_horn,
|
||||
Qt::Key_Dead_Horn,
|
||||
|
||||
// Special keys from X.org - This include multimedia keys,
|
||||
// wireless/bluetooth/uwb keys, special launcher keys, etc.
|
||||
XF86XK_Back,
|
||||
Qt::Key_Back,
|
||||
XF86XK_Forward,
|
||||
Qt::Key_Forward,
|
||||
XF86XK_Stop,
|
||||
Qt::Key_Stop,
|
||||
XF86XK_Refresh,
|
||||
Qt::Key_Refresh,
|
||||
XF86XK_Favorites,
|
||||
Qt::Key_Favorites,
|
||||
XF86XK_AudioMedia,
|
||||
Qt::Key_LaunchMedia,
|
||||
XF86XK_OpenURL,
|
||||
Qt::Key_OpenUrl,
|
||||
XF86XK_HomePage,
|
||||
Qt::Key_HomePage,
|
||||
XF86XK_Search,
|
||||
Qt::Key_Search,
|
||||
XF86XK_AudioLowerVolume,
|
||||
Qt::Key_VolumeDown,
|
||||
XF86XK_AudioMute,
|
||||
Qt::Key_VolumeMute,
|
||||
XF86XK_AudioRaiseVolume,
|
||||
Qt::Key_VolumeUp,
|
||||
XF86XK_AudioPlay,
|
||||
Qt::Key_MediaPlay,
|
||||
XF86XK_AudioStop,
|
||||
Qt::Key_MediaStop,
|
||||
XF86XK_AudioPrev,
|
||||
Qt::Key_MediaPrevious,
|
||||
XF86XK_AudioNext,
|
||||
Qt::Key_MediaNext,
|
||||
XF86XK_AudioRecord,
|
||||
Qt::Key_MediaRecord,
|
||||
XF86XK_AudioPause,
|
||||
Qt::Key_MediaPause,
|
||||
XF86XK_Mail,
|
||||
Qt::Key_LaunchMail,
|
||||
XF86XK_MyComputer,
|
||||
Qt::Key_Launch0, // ### Qt 6: remap properly
|
||||
XF86XK_Calculator,
|
||||
Qt::Key_Launch1,
|
||||
XF86XK_Memo,
|
||||
Qt::Key_Memo,
|
||||
XF86XK_ToDoList,
|
||||
Qt::Key_ToDoList,
|
||||
XF86XK_Calendar,
|
||||
Qt::Key_Calendar,
|
||||
XF86XK_PowerDown,
|
||||
Qt::Key_PowerDown,
|
||||
XF86XK_ContrastAdjust,
|
||||
Qt::Key_ContrastAdjust,
|
||||
XF86XK_Standby,
|
||||
Qt::Key_Standby,
|
||||
XF86XK_MonBrightnessUp,
|
||||
Qt::Key_MonBrightnessUp,
|
||||
XF86XK_MonBrightnessDown,
|
||||
Qt::Key_MonBrightnessDown,
|
||||
XF86XK_KbdLightOnOff,
|
||||
Qt::Key_KeyboardLightOnOff,
|
||||
XF86XK_KbdBrightnessUp,
|
||||
Qt::Key_KeyboardBrightnessUp,
|
||||
XF86XK_KbdBrightnessDown,
|
||||
Qt::Key_KeyboardBrightnessDown,
|
||||
XF86XK_PowerOff,
|
||||
Qt::Key_PowerOff,
|
||||
XF86XK_WakeUp,
|
||||
Qt::Key_WakeUp,
|
||||
XF86XK_Eject,
|
||||
Qt::Key_Eject,
|
||||
XF86XK_ScreenSaver,
|
||||
Qt::Key_ScreenSaver,
|
||||
XF86XK_WWW,
|
||||
Qt::Key_WWW,
|
||||
XF86XK_Sleep,
|
||||
Qt::Key_Sleep,
|
||||
XF86XK_LightBulb,
|
||||
Qt::Key_LightBulb,
|
||||
XF86XK_Shop,
|
||||
Qt::Key_Shop,
|
||||
XF86XK_History,
|
||||
Qt::Key_History,
|
||||
XF86XK_AddFavorite,
|
||||
Qt::Key_AddFavorite,
|
||||
XF86XK_HotLinks,
|
||||
Qt::Key_HotLinks,
|
||||
XF86XK_BrightnessAdjust,
|
||||
Qt::Key_BrightnessAdjust,
|
||||
XF86XK_Finance,
|
||||
Qt::Key_Finance,
|
||||
XF86XK_Community,
|
||||
Qt::Key_Community,
|
||||
XF86XK_AudioRewind,
|
||||
Qt::Key_AudioRewind,
|
||||
XF86XK_BackForward,
|
||||
Qt::Key_BackForward,
|
||||
XF86XK_ApplicationLeft,
|
||||
Qt::Key_ApplicationLeft,
|
||||
XF86XK_ApplicationRight,
|
||||
Qt::Key_ApplicationRight,
|
||||
XF86XK_Book,
|
||||
Qt::Key_Book,
|
||||
XF86XK_CD,
|
||||
Qt::Key_CD,
|
||||
XF86XK_Calculater,
|
||||
Qt::Key_Calculator,
|
||||
XF86XK_Clear,
|
||||
Qt::Key_Clear,
|
||||
XF86XK_ClearGrab,
|
||||
Qt::Key_ClearGrab,
|
||||
XF86XK_Close,
|
||||
Qt::Key_Close,
|
||||
XF86XK_Copy,
|
||||
Qt::Key_Copy,
|
||||
XF86XK_Cut,
|
||||
Qt::Key_Cut,
|
||||
XF86XK_Display,
|
||||
Qt::Key_Display,
|
||||
XF86XK_DOS,
|
||||
Qt::Key_DOS,
|
||||
XF86XK_Documents,
|
||||
Qt::Key_Documents,
|
||||
XF86XK_Excel,
|
||||
Qt::Key_Excel,
|
||||
XF86XK_Explorer,
|
||||
Qt::Key_Explorer,
|
||||
XF86XK_Game,
|
||||
Qt::Key_Game,
|
||||
XF86XK_Go,
|
||||
Qt::Key_Go,
|
||||
XF86XK_iTouch,
|
||||
Qt::Key_iTouch,
|
||||
XF86XK_LogOff,
|
||||
Qt::Key_LogOff,
|
||||
XF86XK_Market,
|
||||
Qt::Key_Market,
|
||||
XF86XK_Meeting,
|
||||
Qt::Key_Meeting,
|
||||
XF86XK_MenuKB,
|
||||
Qt::Key_MenuKB,
|
||||
XF86XK_MenuPB,
|
||||
Qt::Key_MenuPB,
|
||||
XF86XK_MySites,
|
||||
Qt::Key_MySites,
|
||||
#if QT_VERSION >= 0x050400
|
||||
XF86XK_New,
|
||||
Qt::Key_New,
|
||||
#endif
|
||||
XF86XK_News,
|
||||
Qt::Key_News,
|
||||
XF86XK_OfficeHome,
|
||||
Qt::Key_OfficeHome,
|
||||
#if QT_VERSION >= 0x050400
|
||||
XF86XK_Open,
|
||||
Qt::Key_Open,
|
||||
#endif
|
||||
XF86XK_Option,
|
||||
Qt::Key_Option,
|
||||
XF86XK_Paste,
|
||||
Qt::Key_Paste,
|
||||
XF86XK_Phone,
|
||||
Qt::Key_Phone,
|
||||
XF86XK_Reply,
|
||||
Qt::Key_Reply,
|
||||
XF86XK_Reload,
|
||||
Qt::Key_Reload,
|
||||
XF86XK_RotateWindows,
|
||||
Qt::Key_RotateWindows,
|
||||
XF86XK_RotationPB,
|
||||
Qt::Key_RotationPB,
|
||||
XF86XK_RotationKB,
|
||||
Qt::Key_RotationKB,
|
||||
XF86XK_Save,
|
||||
Qt::Key_Save,
|
||||
XF86XK_Send,
|
||||
Qt::Key_Send,
|
||||
XF86XK_Spell,
|
||||
Qt::Key_Spell,
|
||||
XF86XK_SplitScreen,
|
||||
Qt::Key_SplitScreen,
|
||||
XF86XK_Support,
|
||||
Qt::Key_Support,
|
||||
XF86XK_TaskPane,
|
||||
Qt::Key_TaskPane,
|
||||
XF86XK_Terminal,
|
||||
Qt::Key_Terminal,
|
||||
XF86XK_Tools,
|
||||
Qt::Key_Tools,
|
||||
XF86XK_Travel,
|
||||
Qt::Key_Travel,
|
||||
XF86XK_Video,
|
||||
Qt::Key_Video,
|
||||
XF86XK_Word,
|
||||
Qt::Key_Word,
|
||||
XF86XK_Xfer,
|
||||
Qt::Key_Xfer,
|
||||
XF86XK_ZoomIn,
|
||||
Qt::Key_ZoomIn,
|
||||
XF86XK_ZoomOut,
|
||||
Qt::Key_ZoomOut,
|
||||
XF86XK_Away,
|
||||
Qt::Key_Away,
|
||||
XF86XK_Messenger,
|
||||
Qt::Key_Messenger,
|
||||
XF86XK_WebCam,
|
||||
Qt::Key_WebCam,
|
||||
XF86XK_MailForward,
|
||||
Qt::Key_MailForward,
|
||||
XF86XK_Pictures,
|
||||
Qt::Key_Pictures,
|
||||
XF86XK_Music,
|
||||
Qt::Key_Music,
|
||||
XF86XK_Battery,
|
||||
Qt::Key_Battery,
|
||||
XF86XK_Bluetooth,
|
||||
Qt::Key_Bluetooth,
|
||||
XF86XK_WLAN,
|
||||
Qt::Key_WLAN,
|
||||
XF86XK_UWB,
|
||||
Qt::Key_UWB,
|
||||
XF86XK_AudioForward,
|
||||
Qt::Key_AudioForward,
|
||||
XF86XK_AudioRepeat,
|
||||
Qt::Key_AudioRepeat,
|
||||
XF86XK_AudioRandomPlay,
|
||||
Qt::Key_AudioRandomPlay,
|
||||
XF86XK_Subtitle,
|
||||
Qt::Key_Subtitle,
|
||||
XF86XK_AudioCycleTrack,
|
||||
Qt::Key_AudioCycleTrack,
|
||||
XF86XK_Time,
|
||||
Qt::Key_Time,
|
||||
XF86XK_Select,
|
||||
Qt::Key_Select,
|
||||
XF86XK_View,
|
||||
Qt::Key_View,
|
||||
XF86XK_TopMenu,
|
||||
Qt::Key_TopMenu,
|
||||
#if QT_VERSION >= 0x050400
|
||||
XF86XK_Red,
|
||||
Qt::Key_Red,
|
||||
XF86XK_Green,
|
||||
Qt::Key_Green,
|
||||
XF86XK_Yellow,
|
||||
Qt::Key_Yellow,
|
||||
XF86XK_Blue,
|
||||
Qt::Key_Blue,
|
||||
#endif
|
||||
XF86XK_Bluetooth,
|
||||
Qt::Key_Bluetooth,
|
||||
XF86XK_Suspend,
|
||||
Qt::Key_Suspend,
|
||||
XF86XK_Hibernate,
|
||||
Qt::Key_Hibernate,
|
||||
#if QT_VERSION >= 0x050400
|
||||
XF86XK_TouchpadToggle,
|
||||
Qt::Key_TouchpadToggle,
|
||||
XF86XK_TouchpadOn,
|
||||
Qt::Key_TouchpadOn,
|
||||
XF86XK_TouchpadOff,
|
||||
Qt::Key_TouchpadOff,
|
||||
XF86XK_AudioMicMute,
|
||||
Qt::Key_MicMute,
|
||||
#endif
|
||||
XF86XK_Launch0,
|
||||
Qt::Key_Launch2, // ### Qt 6: remap properly
|
||||
XF86XK_Launch1,
|
||||
Qt::Key_Launch3,
|
||||
XF86XK_Launch2,
|
||||
Qt::Key_Launch4,
|
||||
XF86XK_Launch3,
|
||||
Qt::Key_Launch5,
|
||||
XF86XK_Launch4,
|
||||
Qt::Key_Launch6,
|
||||
XF86XK_Launch5,
|
||||
Qt::Key_Launch7,
|
||||
XF86XK_Launch6,
|
||||
Qt::Key_Launch8,
|
||||
XF86XK_Launch7,
|
||||
Qt::Key_Launch9,
|
||||
XF86XK_Launch8,
|
||||
Qt::Key_LaunchA,
|
||||
XF86XK_Launch9,
|
||||
Qt::Key_LaunchB,
|
||||
XF86XK_LaunchA,
|
||||
Qt::Key_LaunchC,
|
||||
XF86XK_LaunchB,
|
||||
Qt::Key_LaunchD,
|
||||
XF86XK_LaunchC,
|
||||
Qt::Key_LaunchE,
|
||||
XF86XK_LaunchD,
|
||||
Qt::Key_LaunchF,
|
||||
XF86XK_LaunchE,
|
||||
Qt::Key_LaunchG,
|
||||
XF86XK_LaunchF,
|
||||
Qt::Key_LaunchH,
|
||||
|
||||
0,
|
||||
0};
|
52
src/app/pttlistener.h
Normal file
52
src/app/pttlistener.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "systemtray.h"
|
||||
#include "appsettingsmanager.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QKeyEvent>
|
||||
|
||||
class PTTListener : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_INVOKABLE Qt::Key getCurrentKey()
|
||||
{
|
||||
int keyInt = settingsManager_->getValue(Settings::Key::pttKey).toInt();
|
||||
Qt::Key key = static_cast<Qt::Key>(keyInt);
|
||||
return key;
|
||||
}
|
||||
|
||||
Q_INVOKABLE QString keyToString(Qt::Key key)
|
||||
{
|
||||
return QKeySequence(key).toString();
|
||||
}
|
||||
Q_INVOKABLE void setPttKey(Qt::Key key)
|
||||
{
|
||||
settingsManager_->setValue(Settings::Key::pttKey, key);
|
||||
}
|
||||
Q_INVOKABLE bool getPttState()
|
||||
{
|
||||
return settingsManager_->getValue(Settings::Key::EnablePtt).toBool();
|
||||
}
|
||||
|
||||
PTTListener(AppSettingsManager* settingsManager, QObject* parent = nullptr);
|
||||
~PTTListener();
|
||||
|
||||
Q_SIGNALS:
|
||||
void pttKeyPressed();
|
||||
void pttKeyReleased();
|
||||
|
||||
#ifdef HAVE_GLOBAL_PTT
|
||||
public Q_SLOTS:
|
||||
void startListening();
|
||||
void stopListening();
|
||||
#endif
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl_;
|
||||
AppSettingsManager* settingsManager_;
|
||||
};
|
|
@ -28,11 +28,13 @@ import "../../commoncomponents"
|
|||
import "../../mainview/components"
|
||||
import "../../mainview/js/contactpickercreation.js" as ContactPickerCreation
|
||||
|
||||
|
||||
SettingsPageBase {
|
||||
id: root
|
||||
|
||||
property bool isSIP: CurrentAccount.type === Profile.Type.SIP
|
||||
property int itemWidth: 132
|
||||
property string key: pttListener.keyToString(pttListener.getCurrentKey())
|
||||
title: JamiStrings.callSettingsTitle
|
||||
|
||||
function updateAndShowModeratorsSlot() {
|
||||
|
@ -374,5 +376,72 @@ SettingsPageBase {
|
|||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout{
|
||||
width: parent.width
|
||||
spacing: 9
|
||||
Text {
|
||||
text: JamiStrings.pushToTalk
|
||||
color: JamiTheme.textColor
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: JamiTheme.settingsTitlePixelSize
|
||||
font.kerning: true
|
||||
}
|
||||
ToggleSwitch {
|
||||
id: pttToggle
|
||||
labelText: JamiStrings.enablePTT
|
||||
checked: UtilsAdapter.getAppValue(Settings.EnablePtt)
|
||||
onSwitchToggled: {
|
||||
UtilsAdapter.setAppValue(Settings.Key.EnablePtt, checked)
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
visible: pttToggle.checked
|
||||
Layout.preferredWidth: parent.width
|
||||
|
||||
Label {
|
||||
color: JamiTheme.textColor
|
||||
wrapMode: Text.WordWrap
|
||||
text: JamiStrings.keyboardShortcut
|
||||
font.pointSize: JamiTheme.settingsFontSize
|
||||
font.kerning: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Label {
|
||||
id: keyLabel
|
||||
color: JamiTheme.blackColor
|
||||
wrapMode: Text.WordWrap
|
||||
text: key
|
||||
font.pointSize: JamiTheme.settingsFontSize
|
||||
font.kerning: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
anchors.centerIn: parent
|
||||
width: keyLabel.width + 2 * JamiTheme.preferredMarginSize
|
||||
height: keyLabel.height + JamiTheme.preferredMarginSize
|
||||
color: JamiTheme.lightGrey_
|
||||
border.color: JamiTheme.darkGreyColor
|
||||
radius: 4
|
||||
}
|
||||
}
|
||||
MaterialButton {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
|
||||
primary: true
|
||||
toolTipText: JamiStrings.changeKeyboardShortcut
|
||||
text: JamiStrings.change
|
||||
onClicked: {
|
||||
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/ChangePttKeyPopup.qml");
|
||||
dlg.choiceMade.connect(function (chosenKey) {
|
||||
keyLabel.text = pttListener.keyToString(chosenKey);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,11 @@ public:
|
|||
explicit SystemTray(AppSettingsManager* settingsManager, QObject* parent = nullptr);
|
||||
~SystemTray();
|
||||
|
||||
AppSettingsManager* getSettingsManager()
|
||||
{
|
||||
return settingsManager_;
|
||||
}
|
||||
|
||||
void onNotificationCountChanged(int count);
|
||||
#ifdef Q_OS_LINUX
|
||||
bool hideNotification(const QString& id);
|
||||
|
|
|
@ -454,6 +454,8 @@ CallModel::muteMedia(const QString& callId, const QString& label, bool mute)
|
|||
return;
|
||||
|
||||
auto proposedList = callInfo->mediaList;
|
||||
if (proposedList.isEmpty())
|
||||
return;
|
||||
for (auto& media : proposedList)
|
||||
if (media[MediaAttributeKey::LABEL] == label)
|
||||
media[MediaAttributeKey::MUTED] = mute ? TRUE_STR : FALSE_STR;
|
||||
|
@ -1413,8 +1415,7 @@ CallModelPimpl::slotCallStateChanged(const QString& accountId,
|
|||
callInfo->mediaList = {};
|
||||
calls.emplace(callId, std::move(callInfo));
|
||||
|
||||
if (!(details["CALL_TYPE"] == "1")
|
||||
&& !linked.owner.confProperties.allowIncoming
|
||||
if (!(details["CALL_TYPE"] == "1") && !linked.owner.confProperties.allowIncoming
|
||||
&& linked.owner.profileInfo.type == profile::Type::JAMI) {
|
||||
linked.refuse(callId);
|
||||
return;
|
||||
|
|
Loading…
Add table
Reference in a new issue