You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
11 KiB
342 lines
11 KiB
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "vlchotkeyconverter.hpp"
|
|
#include "qt.hpp"
|
|
|
|
#include <QKeyEvent>
|
|
#include <QWheelEvent>
|
|
#include <QApplication>
|
|
#include <vlc_actions.h>
|
|
|
|
/***************************************************************************
|
|
* Hotkeys converters
|
|
***************************************************************************/
|
|
int qtKeyModifiersToVLC( const QInputEvent& e )
|
|
{
|
|
int i_keyModifiers = 0;
|
|
if( e.modifiers() & Qt::ShiftModifier ) i_keyModifiers |= KEY_MODIFIER_SHIFT;
|
|
if( e.modifiers() & Qt::AltModifier ) i_keyModifiers |= KEY_MODIFIER_ALT;
|
|
if( e.modifiers() & Qt::ControlModifier ) i_keyModifiers |= KEY_MODIFIER_CTRL;
|
|
if( e.modifiers() & Qt::MetaModifier ) i_keyModifiers |= KEY_MODIFIER_META;
|
|
return i_keyModifiers;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
int qt;
|
|
uint32_t vlc;
|
|
} vlc_qt_key_t;
|
|
|
|
static const vlc_qt_key_t keys[] =
|
|
{
|
|
{ Qt::Key_Escape, KEY_ESC },
|
|
{ Qt::Key_Tab, '\t', },
|
|
// Qt::Key_Backtab
|
|
{ Qt::Key_Backspace, '\b' },
|
|
{ Qt::Key_Return, '\r' },
|
|
{ Qt::Key_Enter, '\r' }, // numeric pad
|
|
{ Qt::Key_Insert, KEY_INSERT },
|
|
{ Qt::Key_Delete, KEY_DELETE },
|
|
{ Qt::Key_Pause, KEY_PAUSE },
|
|
{ Qt::Key_Print, KEY_PRINT },
|
|
// Qt::Key_SysReq
|
|
// Qt::Key_Clear
|
|
{ Qt::Key_Home, KEY_HOME },
|
|
{ Qt::Key_End, KEY_END },
|
|
{ Qt::Key_Left, KEY_LEFT },
|
|
{ Qt::Key_Up, KEY_UP },
|
|
{ Qt::Key_Right, KEY_RIGHT },
|
|
{ Qt::Key_Down, KEY_DOWN },
|
|
{ Qt::Key_PageUp, KEY_PAGEUP },
|
|
{ Qt::Key_PageDown, KEY_PAGEDOWN },
|
|
// Qt::Key_Shift
|
|
// Qt::Key_Control
|
|
// Qt::Key_Meta
|
|
// Qt::Key_Alt
|
|
// Qt::Key_CapsLock
|
|
// Qt::Key_NumLock
|
|
// Qt::Key_ScrollLock
|
|
/* F1 - F35 - Qt goes to F35, VLC stops at F12 */
|
|
{ Qt::Key_F1, KEY_F1 },
|
|
{ Qt::Key_F2, KEY_F2 },
|
|
{ Qt::Key_F3, KEY_F3 },
|
|
{ Qt::Key_F4, KEY_F4 },
|
|
{ Qt::Key_F5, KEY_F5 },
|
|
{ Qt::Key_F6, KEY_F6 },
|
|
{ Qt::Key_F7, KEY_F7 },
|
|
{ Qt::Key_F8, KEY_F8 },
|
|
{ Qt::Key_F9, KEY_F9 },
|
|
{ Qt::Key_F10, KEY_F10 },
|
|
{ Qt::Key_F11, KEY_F11 },
|
|
{ Qt::Key_F12, KEY_F12 },
|
|
{ Qt::Key_F13, KEY_F(13) },
|
|
{ Qt::Key_F14, KEY_F(14) },
|
|
{ Qt::Key_F15, KEY_F(15) },
|
|
{ Qt::Key_F16, KEY_F(16) },
|
|
{ Qt::Key_F17, KEY_F(17) },
|
|
{ Qt::Key_F18, KEY_F(18) },
|
|
{ Qt::Key_F19, KEY_F(19) },
|
|
{ Qt::Key_F20, KEY_F(20) },
|
|
{ Qt::Key_F21, KEY_F(21) },
|
|
{ Qt::Key_F22, KEY_F(22) },
|
|
{ Qt::Key_F23, KEY_F(23) },
|
|
{ Qt::Key_F24, KEY_F(24) },
|
|
{ Qt::Key_F25, KEY_F(25) },
|
|
{ Qt::Key_F26, KEY_F(26) },
|
|
{ Qt::Key_F27, KEY_F(27) },
|
|
{ Qt::Key_F28, KEY_F(28) },
|
|
{ Qt::Key_F29, KEY_F(29) },
|
|
{ Qt::Key_F30, KEY_F(30) },
|
|
{ Qt::Key_F31, KEY_F(31) },
|
|
{ Qt::Key_F32, KEY_F(32) },
|
|
{ Qt::Key_F33, KEY_F(33) },
|
|
{ Qt::Key_F34, KEY_F(34) },
|
|
{ Qt::Key_F35, KEY_F(35) },
|
|
|
|
// Qt::Key_Super_L
|
|
// Qt::Key_Super_R
|
|
{ Qt::Key_Menu, KEY_MENU },
|
|
// Qt::Key_Hyper_L
|
|
// Qt::Key_Hyper_R
|
|
// Qt::Key_Help
|
|
// Qt::Key_Direction_L
|
|
// Qt::Key_Direction_R
|
|
|
|
// Qt::Key_Multi_key
|
|
// Qt::Key_Codeinput
|
|
// Qt::Key_SingleCandidate
|
|
// Qt::Key_MultipleCandidate
|
|
// Qt::Key_PreviousCandidate
|
|
// Qt::Key_Mode_switch
|
|
// Qt::Key_Kanji
|
|
// Qt::Key_Muhenkan
|
|
// Qt::Key_Henkan
|
|
// Qt::Key_Romaji
|
|
// Qt::Key_Hiragana
|
|
// Qt::Key_Katakana
|
|
// Qt::Key_Hiragana_Katakana
|
|
// Qt::Key_Zenkaku
|
|
// Qt::Key_Hankaku
|
|
// Qt::Key_Zenkaku_Hankaku
|
|
// Qt::Key_Touroku
|
|
// Qt::Key_Massyo
|
|
// Qt::Key_Kana_Lock
|
|
// Qt::Key_Kana_Shift
|
|
// Qt::Key_Eisu_Shift
|
|
// Qt::Key_Eisu_toggle
|
|
// Qt::Key_Hangul
|
|
// Qt::Key_Hangul_Start
|
|
// Qt::Key_Hangul_End
|
|
// Qt::Key_Hangul_Hanja
|
|
// Qt::Key_Hangul_Jamo
|
|
// Qt::Key_Hangul_Romaja
|
|
// Qt::Key_Hangul_Jeonja
|
|
// Qt::Key_Hangul_Banja
|
|
// Qt::Key_Hangul_PreHanja
|
|
// Qt::Key_Hangul_PostHanja
|
|
// Qt::Key_Hangul_Special
|
|
// Qt::Key_Dead_Grave
|
|
// Qt::Key_Dead_Acute
|
|
// Qt::Key_Dead_Circumflex
|
|
// Qt::Key_Dead_Tilde
|
|
// Qt::Key_Dead_Macron
|
|
// Qt::Key_Dead_Breve
|
|
// Qt::Key_Dead_Abovedot
|
|
// Qt::Key_Dead_Diaeresis
|
|
// Qt::Key_Dead_Abovering
|
|
// Qt::Key_Dead_Doubleacute
|
|
// Qt::Key_Dead_Caron
|
|
// Qt::Key_Dead_Cedilla
|
|
// Qt::Key_Dead_Ogonek
|
|
// Qt::Key_Dead_Iota
|
|
// Qt::Key_Dead_Voiced_Sound
|
|
// Qt::Key_Dead_Semivoiced_Sound
|
|
// Qt::Key_Dead_Belowdot
|
|
// Qt::Key_Dead_Hook
|
|
// Qt::Key_Dead_Horn
|
|
{ Qt::Key_Back, KEY_BROWSER_BACK },
|
|
{ Qt::Key_Forward, KEY_BROWSER_FORWARD },
|
|
{ Qt::Key_Stop, KEY_BROWSER_STOP },
|
|
{ Qt::Key_Refresh, KEY_BROWSER_REFRESH },
|
|
{ Qt::Key_VolumeDown, KEY_VOLUME_DOWN },
|
|
{ Qt::Key_VolumeMute, KEY_VOLUME_MUTE },
|
|
{ Qt::Key_VolumeUp, KEY_VOLUME_UP },
|
|
// Qt::Key_BassBoost
|
|
// Qt::Key_BassUp
|
|
// Qt::Key_BassDown
|
|
// Qt::Key_TrebleUp
|
|
// Qt::Key_TrebleDown
|
|
{ Qt::Key_MediaPlay, KEY_MEDIA_PLAY_PAUSE },
|
|
{ Qt::Key_MediaStop, KEY_MEDIA_STOP },
|
|
{ Qt::Key_MediaPrevious, KEY_MEDIA_PREV_TRACK },
|
|
{ Qt::Key_MediaNext, KEY_MEDIA_NEXT_TRACK },
|
|
// Qt::Key_MediaRecord
|
|
{ Qt::Key_HomePage, KEY_BROWSER_HOME },
|
|
{ Qt::Key_Favorites, KEY_BROWSER_FAVORITES },
|
|
{ Qt::Key_Search, KEY_BROWSER_SEARCH },
|
|
// Qt::Key_Standby
|
|
// Qt::Key_OpenUrl
|
|
// Qt::Key_LaunchMail
|
|
// Qt::Key_LaunchMedia
|
|
/* Qt::Key_Launch0 through Qt::Key_LaunchF */
|
|
/* ... */
|
|
{ Qt::Key_Reload, KEY_BROWSER_REFRESH },
|
|
};
|
|
|
|
static int keycmp( const void *a, const void *b )
|
|
{
|
|
const int *q = (const int *)a;
|
|
const vlc_qt_key_t *m = (const vlc_qt_key_t *)b;
|
|
|
|
return *q - m->qt;
|
|
}
|
|
|
|
int qtEventToVLCKey( QKeyEvent *e )
|
|
{
|
|
int qtk = e->key();
|
|
uint32_t i_vlck = 0;
|
|
|
|
if( qtk <= 0xff )
|
|
{
|
|
/* VLC and X11 use lowercase whereas Qt uses uppercase, this
|
|
* method should be equal to towlower in case of latin1 */
|
|
if( qtk >= 'A' && qtk <= 'Z' ) i_vlck = qtk+32;
|
|
else if( qtk >= 0xC0 && qtk <= 0xDE && qtk != 0xD7) i_vlck = qtk+32;
|
|
else i_vlck = qtk;
|
|
}
|
|
else
|
|
{
|
|
const vlc_qt_key_t *map;
|
|
|
|
map = (const vlc_qt_key_t *)
|
|
bsearch( &qtk, (const void *)keys, sizeof(keys)/sizeof(keys[0]),
|
|
sizeof(*keys), keycmp );
|
|
if( map != NULL )
|
|
i_vlck = map->vlc;
|
|
}
|
|
|
|
/* Handle modifiers */
|
|
i_vlck |= qtKeyModifiersToVLC( *e );
|
|
return i_vlck;
|
|
}
|
|
|
|
Qt::Orientations WheelToVLCConverter::getWheelOrientation(int x, int y)
|
|
{
|
|
const qreal v_cos_deadzone = 0.45; // ~63 degrees
|
|
const qreal h_cos_deadzone = 0.95; // ~15 degrees
|
|
|
|
if (x == 0 && y == 0)
|
|
return Qt::Orientations{};
|
|
|
|
qreal cos = qFabs(x)/qSqrt(x*x + y*y);
|
|
if (cos < v_cos_deadzone)
|
|
return Qt::Vertical;
|
|
else if (cos > h_cos_deadzone)
|
|
return Qt::Horizontal;
|
|
return Qt::Orientations{};
|
|
}
|
|
|
|
void WheelToVLCConverter::wheelEvent( const QWheelEvent* e )
|
|
{
|
|
if (!e)
|
|
return;
|
|
|
|
const int deltaPerStep = QWheelEvent::DefaultDeltasPerStep;
|
|
|
|
if (e->modifiers() != m_modifiers)
|
|
{
|
|
m_scrollAmount = {};
|
|
m_modifiers = e->modifiers();
|
|
}
|
|
if (e->buttons() != m_buttons)
|
|
{
|
|
m_scrollAmount = {};
|
|
m_buttons = e->buttons();
|
|
}
|
|
|
|
QPoint p = e->angleDelta();
|
|
if (e->inverted())
|
|
{
|
|
const Qt::Orientations preliminaryOrientation = getWheelOrientation(p.x(), p.y());
|
|
if (preliminaryOrientation == Qt::Vertical)
|
|
p.setY(-p.y());
|
|
else if (preliminaryOrientation == Qt::Horizontal)
|
|
p.setX(-p.x());
|
|
}
|
|
p += m_scrollAmount;
|
|
|
|
if (p.isNull())
|
|
return;
|
|
|
|
int i_vlck = qtKeyModifiersToVLC(*e); // Handle modifiers
|
|
Qt::Orientations orientation = getWheelOrientation(p.x(), p.y());
|
|
if (orientation == Qt::Vertical && qAbs(p.y()) >= deltaPerStep)
|
|
{
|
|
if (p.y() > 0)
|
|
i_vlck |= KEY_MOUSEWHEELUP;
|
|
else
|
|
i_vlck |= KEY_MOUSEWHEELDOWN;
|
|
|
|
const int steps = p.y() / deltaPerStep;
|
|
|
|
emit wheelUpDown(steps, e->modifiers());
|
|
//in practice this will emit once
|
|
for (int i = 0; i < qAbs(steps); i++)
|
|
emit vlcWheelKey(i_vlck);
|
|
|
|
m_scrollAmount.setX(0);
|
|
m_scrollAmount.setY(p.y() % deltaPerStep);
|
|
|
|
}
|
|
else if (orientation == Qt::Horizontal && qAbs(p.x()) >= deltaPerStep)
|
|
{
|
|
if (p.x() > 0)
|
|
i_vlck |= KEY_MOUSEWHEELLEFT;
|
|
else
|
|
i_vlck |= KEY_MOUSEWHEELRIGHT;
|
|
|
|
const int steps = p.x() / deltaPerStep;
|
|
|
|
emit wheelLeftRight(steps, e->modifiers());
|
|
//in practice this will emit once
|
|
for (int i = 0; i < qAbs(steps); i++)
|
|
emit vlcWheelKey(i_vlck);
|
|
|
|
m_scrollAmount.setY(0);
|
|
m_scrollAmount.setX(p.x() % deltaPerStep);
|
|
}
|
|
else
|
|
{
|
|
m_scrollAmount = p;
|
|
}
|
|
}
|
|
|
|
void WheelToVLCConverter::qmlWheelEvent( const QObject* e )
|
|
{
|
|
assert(e);
|
|
assert(e->inherits("QQuickWheelEvent"));
|
|
|
|
QPoint pixelDelta = e->property("pixelDelta").toPoint();
|
|
QPoint angleDelta = e->property("angleDelta").toPoint();
|
|
auto buttons = Qt::MouseButtons::fromInt(e->property("buttons").toInt());
|
|
auto modifiers = Qt::KeyboardModifiers::fromInt(e->property("modifiers").toInt());
|
|
bool inverted = e->property("inverted").toBool();
|
|
|
|
QWheelEvent event({}, {}, pixelDelta, angleDelta, buttons, modifiers, Qt::ScrollPhase::NoScrollPhase, inverted);
|
|
wheelEvent(&event);
|
|
}
|
|
|
|
QString VLCKeyToString( unsigned val, bool locale )
|
|
{
|
|
char *base = vlc_keycode2str (val, locale);
|
|
if (base == NULL)
|
|
return qfu( "" );
|
|
|
|
QString r = qfu( base );
|
|
|
|
free( base );
|
|
return r;
|
|
}
|
|
|