Как я могу захватить QKeySequence из QKeyEvent в зависимости от текущей раскладки клавиатуры?
Мне нужно сделать это для настройки моего приложения. У меня есть поле QLineEdit с переопределенным методом keyPressEvent.
QKeyEvent *ke = ...
QString txt;
if(ke->modifiers() & Qt::ControlModifier)
txt += "Ctrl+";
if(ke->modifiers() & Qt::AltModifier)
txt += "Alt+";
if(ke->modifiers() & Qt::ShiftModifier)
txt += "Shift+";
if(ke->key() >= Qt::Key_0 && ke->key() <= Qt::Key_9)
txt += ('0' + ke->key() - Qt::Key_0);
else if(ke->key() >= Qt::Key_A && ke->key() <= Qt::Key_Z)
txt += ('A' + ke->key() - Qt::Key_A);
ui->hotkeyEdit->setText(txt);
Но это решение может создавать ярлыки только с английскими буквами. Например, когда я использую русскую раскладку клавиатуры, этот код будет отображать ту же последовательность, но с английским символом, размещенным на той же клавише клавиатуры.
5 ответов
Что может оказаться очень полезным, так это функция QKeySequance(). ToString().
Ниже приведена часть кода, который я использую для захвата пользовательских ярлыков. С некоторыми изменениями он может делать все, что вам нужно в вашем проекте. Надеюсь, это поможет (извините за испорченную идентификацию):
if (event->type() == QEvent::KeyPress){
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
int keyInt = keyEvent->key();
Qt::Key key = static_cast<Qt::Key>(keyInt);
if(key == Qt::Key_unknown){
qDebug() << "Unknown key from a macro probably";
return;
}
// the user have clicked just and only the special keys Ctrl, Shift, Alt, Meta.
if(key == Qt::Key_Control ||
key == Qt::Key_Shift ||
key == Qt::Key_Alt ||
key == Qt::Key_Meta)
{
qDebug() << "Single click of special key: Ctrl, Shift, Alt or Meta";
qDebug() << "New KeySequence:" << QKeySequence(keyInt).toString(QKeySequence::NativeText);
return;
}
// check for a combination of user clicks
Qt::KeyboardModifiers modifiers = keyEvent->modifiers();
QString keyText = keyEvent->text();
// if the keyText is empty than it's a special key like F1, F5, ...
qDebug() << "Pressed Key:" << keyText;
QList<Qt::Key> modifiersList;
if(modifiers & Qt::ShiftModifier)
keyInt += Qt::SHIFT;
if(modifiers & Qt::ControlModifier)
keyInt += Qt::CTRL;
if(modifiers & Qt::AltModifier)
keyInt += Qt::ALT;
if(modifiers & Qt::MetaModifier)
keyInt += Qt::META;
qDebug() << "New KeySequence:" << QKeySequence(keyInt).toString(QKeySequence::NativeText);
}
Если кому-то небезразлична питонская версия решения Тихомира Долапчиева выше. Я только что перевел это, и это прекрасно работает. Просто отправляю на будущее.
class KeySequenceEdit(QtGui.QLineEdit):
"""
This class is mainly inspired by
http://stackru.com/a/6665017
"""
def __init__(self, keySequence, *args):
super(KeySequenceEdit, self).__init__(*args)
self.keySequence = keySequence
self.setKeySequence(keySequence)
def setKeySequence(self, keySequence):
self.keySequence = keySequence
self.setText(self.keySequence.toString(QtGui.QKeySequence.NativeText))
def keyPressEvent(self, e):
if e.type() == QtCore.QEvent.KeyPress:
key = e.key()
if key == QtCore.Qt.Key_unknown:
warnings.warn("Unknown key from a macro probably")
return
# the user have clicked just and only the special keys Ctrl, Shift, Alt, Meta.
if(key == QtCore.Qt.Key_Control or
key == QtCore.Qt.Key_Shift or
key == QtCore.Qt.Key_Alt or
key == QtCore.Qt.Key_Meta):
print("Single click of special key: Ctrl, Shift, Alt or Meta")
print("New KeySequence:", QtGui.QKeySequence(key).toString(QtGui.QKeySequence.NativeText))
return
# check for a combination of user clicks
modifiers = e.modifiers()
keyText = e.text()
# if the keyText is empty than it's a special key like F1, F5, ...
print("Pressed Key:", keyText)
if modifiers & QtCore.Qt.ShiftModifier:
key += QtCore.Qt.SHIFT
if modifiers & QtCore.Qt.ControlModifier:
key += QtCore.Qt.CTRL
if modifiers & QtCore.Qt.AltModifier:
key += QtCore.Qt.ALT
if modifiers & QtCore.Qt.MetaModifier:
key += QtCore.Qt.META
print("New KeySequence:", QtGui.QKeySequence(key).toString(QtGui.QKeySequence.NativeText))
self.setKeySequence(QtGui.QKeySequence(key))
Вы можете назначить сочетания клавиш для действий.
Вот как это сделать.
actionName->setShortcut(QKeySequence::New); //for predefined shortcuts like new, close, open..
или вы можете определить свой собственный ярлык с этим
actionName->setShortcut(QKeySequence("Ctrl+N")); // sets Ctrl + N for w.e the action does
В первом случае qt автоматически обнаруживает и назначает соответствующий ярлык для этого конкретного действия. Во втором случае вы можете выбрать собственный ярлык и ввести его в виде строки. Он автоматически разбирает его и понимает.
Это исключает необходимость использования захвата ключей для ненужных целей.
Самый простой способ это:
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
qDebug() << "delete" << keyEvent->matches(QKeySequence::Delete);
qDebug() << "copy" << keyEvent->matches(QKeySequence::Copy);
qDebug() << "paste" << keyEvent->matches(QKeySequence::Paste);
}
Предпочитаю стандартную последовательность.
Из вопросов раскладки клавиатуры:
В результате, как понятные человеку строки, так и жестко закодированные коды клавиш могут быть проблематичными для использования при указании последовательности клавиш, которая может использоваться на множестве различных раскладок клавиатуры. Только использование стандартных ярлыков гарантирует, что пользователь сможет использовать ярлыки, предназначенные разработчиком.
В случае, если пользователи Qt хотят это для Qml, вот как я это сделал.
Однако есть несколько дополнительных функций, которые могут вам не понадобиться. Я оставлю код здесь и позволю пользователям адаптироваться.
TextField {
Layout.fillWidth: true
placeholderText: qsTr("Shortcut")
text: shortcut
onTextChanged: myModel.setPropertyAndUpdate(index, "shortcut", text, this)
property var modifiers: ({ 0x02000000: "Shift", 0x04000000: "Ctrl", 0x08000000: "Alt", 0x10000000: "Meta", 0x20000000: "Keypad", 0x40000000: "GroupSwitch" })
property var keys: ({
0x01000000: "Escape", 0x01000001: "Tab", 0x01000002: "Backtab", 0x01000003: "Backspace", 0x01000004: "Return", 0x01000005: "Enter", 0x01000006: "Insert", 0x01000007: "Delete", 0x01000008: "Pause", 0x01000009: "Print", 0x0100000a: "SysReq", 0x0100000b: "Clear", 0x01000010: "Home", 0x01000011: "End", 0x01000012: "Left", 0x01000013: "Up", 0x01000014: "Right", 0x01000015: "Down", 0x01000016: "PageUp", 0x01000017: "PageDown", 0x01000020: "Shift", 0x01000021: "Control", 0x01000022: "Meta", 0x01000023: "Alt", 0x01001103: "AltGr", 0x01000024: "CapsLock", 0x01000025: "NumLock", 0x01000026: "ScrollLock", 0x01000030: "F1", 0x01000031: "F2", 0x01000032: "F3", 0x01000033: "F4", 0x01000034: "F5", 0x01000035: "F6", 0x01000036: "F7", 0x01000037: "F8", 0x01000038: "F9", 0x01000039: "F10", 0x0100003a: "F11", 0x0100003b: "F12", 0x0100003c: "F13", 0x0100003d: "F14", 0x0100003e: "F15", 0x0100003f: "F16", 0x01000040: "F17", 0x01000041: "F18", 0x01000042: "F19", 0x01000043: "F20", 0x01000044: "F21", 0x01000045: "F22", 0x01000046: "F23", 0x01000047: "F24", 0x01000048: "F25", 0x01000049: "F26", 0x0100004a: "F27", 0x0100004b: "F28", 0x0100004c: "F29", 0x0100004d: "F30", 0x0100004e: "F31", 0x0100004f: "F32", 0x01000050: "F33", 0x01000051: "F34", 0x01000052: "F35", 0x01000053: "Super_L", 0x01000054: "Super_R", 0x01000055: "Menu", 0x01000056: "Hyper_L", 0x01000057: "Hyper_R", 0x01000058: "Help", 0x01000059: "Direction_L", 0x01000060: "Direction_R", 0x20: "Space", 0x21: "Exclam", 0x22: "QuoteDbl", 0x23: "NumberSign", 0x24: "Dollar", 0x25: "Percent", 0x26: "Ampersand", 0x27: "Apostrophe", 0x28: "ParenLeft", 0x29: "ParenRight", 0x2a: "Asterisk", 0x2b: "Plus", 0x2c: "Comma", 0x2d: "Minus", 0x2e: "Period", 0x2f: "Slash", 0x30: "0", 0x31: "1", 0x32: "2", 0x33: "3", 0x34: "4", 0x35: "5", 0x36: "6", 0x37: "7", 0x38: "8", 0x39: "9", 0x3a: "Colon", 0x3b: "Semicolon", 0x3c: "Less", 0x3d: "Equal", 0x3e: "Greater", 0x3f: "Question", 0x40: "At", 0x41: "A", 0x42: "B", 0x43: "C", 0x44: "D", 0x45: "E", 0x46: "F", 0x47: "G", 0x48: "H", 0x49: "I", 0x4a: "J", 0x4b: "K", 0x4c: "L", 0x4d: "M", 0x4e: "N", 0x4f: "O", 0x50: "P", 0x51: "Q", 0x52: "R", 0x53: "S", 0x54: "T", 0x55: "U", 0x56: "V", 0x57: "W", 0x58: "X", 0x59: "Y", 0x5a: "Z", 0x5b: "BracketLeft", 0x5c: "Backslash", 0x5d: "BracketRight", 0x5e: "AsciiCircum", 0x5f: "Underscore", 0x60: "QuoteLeft", 0x7b: "BraceLeft", 0x7c: "Bar", 0x7d: "BraceRight", 0x7e: "AsciiTilde", 0x0a0: "nobreakspace", 0x0a1: "exclamdown", 0x0a2: "cent", 0x0a3: "sterling", 0x0a4: "currency", 0x0a5: "yen", 0x0a6: "brokenbar", 0x0a7: "section", 0x0a8: "diaeresis", 0x0a9: "copyright", 0x0aa: "ordfeminine", 0x0ab: "guillemotleft", 0x0ac: "notsign", 0x0ad: "hyphen", 0x0ae: "registered", 0x0af: "macron", 0x0b0: "degree", 0x0b1: "plusminus", 0x0b2: "twosuperior", 0x0b3: "threesuperior", 0x0b4: "acute", 0x0b5: "mu", 0x0b6: "paragraph", 0x0b7: "periodcentered", 0x0b8: "cedilla", 0x0b9: "onesuperior", 0x0ba: "masculine", 0x0bb: "guillemotright", 0x0bc: "onequarter", 0x0bd: "onehalf", 0x0be: "threequarters", 0x0bf: "questiondown", 0x0c0: "Agrave", 0x0c1: "Aacute", 0x0c2: "Acircumflex", 0x0c3: "Atilde", 0x0c4: "Adiaeresis", 0x0c5: "Aring", 0x0c6: "AE", 0x0c7: "Ccedilla", 0x0c8: "Egrave", 0x0c9: "Eacute", 0x0ca: "Ecircumflex", 0x0cb: "Ediaeresis", 0x0cc: "Igrave", 0x0cd: "Iacute", 0x0ce: "Icircumflex", 0x0cf: "Idiaeresis", 0x0d0: "ETH", 0x0d1: "Ntilde", 0x0d2: "Ograve", 0x0d3: "Oacute", 0x0d4: "Ocircumflex", 0x0d5: "Otilde", 0x0d6: "Odiaeresis", 0x0d7: "multiply", 0x0d8: "Ooblique", 0x0d9: "Ugrave", 0x0da: "Uacute", 0x0db: "Ucircumflex", 0x0dc: "Udiaeresis", 0x0dd: "Yacute", 0x0de: "THORN", 0x0df: "ssharp", 0x0f7: "division", 0x0ff: "ydiaeresis", 0x01001120: "Multi_key", 0x01001137: "Codeinput", 0x0100113c: "SingleCandidate", 0x0100113d: "MultipleCandidate", 0x0100113e: "PreviousCandidate", 0x0100117e: "Mode_switch", 0x01001121: "Kanji", 0x01001122: "Muhenkan", 0x01001123: "Henkan", 0x01001124: "Romaji", 0x01001125: "Hiragana", 0x01001126: "Katakana", 0x01001127: "Hiragana_Katakana", 0x01001128: "Zenkaku", 0x01001129: "Hankaku", 0x0100112a: "Zenkaku_Hankaku", 0x0100112b: "Touroku", 0x0100112c: "Massyo", 0x0100112d: "Kana_Lock", 0x0100112e: "Kana_Shift", 0x0100112f: "Eisu_Shift", 0x01001130: "Eisu_toggle", 0x01001131: "Hangul", 0x01001132: "Hangul_Start", 0x01001133: "Hangul_End", 0x01001134: "Hangul_Hanja", 0x01001135: "Hangul_Jamo", 0x01001136: "Hangul_Romaja", 0x01001138: "Hangul_Jeonja", 0x01001139: "Hangul_Banja", 0x0100113a: "Hangul_PreHanja", 0x0100113b: "Hangul_PostHanja", 0x0100113f: "Hangul_Special", 0x01001250: "Dead_Grave", 0x01001251: "Dead_Acute", 0x01001252: "Dead_Circumflex", 0x01001253: "Dead_Tilde", 0x01001254: "Dead_Macron", 0x01001255: "Dead_Breve", 0x01001256: "Dead_Abovedot", 0x01001257: "Dead_Diaeresis", 0x01001258: "Dead_Abovering", 0x01001259: "Dead_Doubleacute", 0x0100125a: "Dead_Caron", 0x0100125b: "Dead_Cedilla", 0x0100125c: "Dead_Ogonek", 0x0100125d: "Dead_Iota", 0x0100125e: "Dead_Voiced_Sound", 0x0100125f: "Dead_Semivoiced_Sound", 0x01001260: "Dead_Belowdot", 0x01001261: "Dead_Hook", 0x01001262: "Dead_Horn", 0x01001263: "Dead_Stroke", 0x01001264: "Dead_Abovecomma", 0x01001265: "Dead_Abovereversedcomma", 0x01001266: "Dead_Doublegrave", 0x01001267: "Dead_Belowring", 0x01001268: "Dead_Belowmacron", 0x01001269: "Dead_Belowcircumflex", 0x0100126a: "Dead_Belowtilde", 0x0100126b: "Dead_Belowbreve", 0x0100126c: "Dead_Belowdiaeresis", 0x0100126d: "Dead_Invertedbreve", 0x0100126e: "Dead_Belowcomma", 0x0100126f: "Dead_Currency", 0x01001280: "Dead_a", 0x01001281: "Dead_A", 0x01001282: "Dead_e", 0x01001283: "Dead_E", 0x01001284: "Dead_i", 0x01001285: "Dead_I", 0x01001286: "Dead_o", 0x01001287: "Dead_O", 0x01001288: "Dead_u", 0x01001289: "Dead_U", 0x0100128a: "Dead_Small_Schwa", 0x0100128b: "Dead_Capital_Schwa", 0x0100128c: "Dead_Greek", 0x01001290: "Dead_Lowline", 0x01001291: "Dead_Aboveverticalline", 0x01001292: "Dead_Belowverticalline", 0x01001293: "Dead_Longsolidusoverlay", 0x01000061: "Back", 0x01000062: "Forward", 0x01000063: "Stop", 0x01000064: "Refresh", 0x01000070: "VolumeDown", 0x01000071: "VolumeMute", 0x01000072: "VolumeUp", 0x01000073: "BassBoost", 0x01000074: "BassUp", 0x01000075: "BassDown", 0x01000076: "TrebleUp", 0x01000077: "TrebleDown", 0x01000080: "MediaPlay", 0x01000081: "MediaStop", 0x01000082: "MediaPrevious", 0x01000083: "MediaNext", 0x01000084: "MediaRecord", 0x1000085: "MediaPause", 0x1000086: "MediaTogglePlayPause", 0x01000090: "HomePage", 0x01000091: "Favorites", 0x01000092: "Search", 0x01000093: "Standby", 0x01000094: "OpenUrl", 0x010000a0: "LaunchMail", 0x010000a1: "LaunchMedia", 0x010000a2: "Launch0", 0x010000a3: "Launch1", 0x010000a4: "Launch2", 0x010000a5: "Launch3", 0x010000a6: "Launch4", 0x010000a7: "Launch5", 0x010000a8: "Launch6", 0x010000a9: "Launch7", 0x010000aa: "Launch8", 0x010000ab: "Launch9", 0x010000ac: "LaunchA", 0x010000ad: "LaunchB", 0x010000ae: "LaunchC", 0x010000af: "LaunchD", 0x010000b0: "LaunchE", 0x010000b1: "LaunchF", 0x0100010e: "LaunchG", 0x0100010f: "LaunchH", 0x010000b2: "MonBrightnessUp", 0x010000b3: "MonBrightnessDown", 0x010000b4: "KeyboardLightOnOff", 0x010000b5: "KeyboardBrightnessUp", 0x010000b6: "KeyboardBrightnessDown", 0x010000b7: "PowerOff", 0x010000b8: "WakeUp", 0x010000b9: "Eject", 0x010000ba: "ScreenSaver", 0x010000bb: "WWW", 0x010000bc: "Memo", 0x010000bd: "LightBulb", 0x010000be: "Shop", 0x010000bf: "History", 0x010000c0: "AddFavorite", 0x010000c1: "HotLinks", 0x010000c2: "BrightnessAdjust", 0x010000c3: "Finance", 0x010000c4: "Community", 0x010000c5: "AudioRewind", 0x010000c6: "BackForward", 0x010000c7: "ApplicationLeft", 0x010000c8: "ApplicationRight", 0x010000c9: "Book", 0x010000ca: "CD", 0x010000cb: "Calculator", 0x010000cc: "ToDoList", 0x010000cd: "ClearGrab", 0x010000ce: "Close", 0x010000cf: "Copy", 0x010000d0: "Cut", 0x010000d1: "Display", 0x010000d2: "DOS", 0x010000d3: "Documents", 0x010000d4: "Excel", 0x010000d5: "Explorer", 0x010000d6: "Game", 0x010000d7: "Go", 0x010000d8: "iTouch", 0x010000d9: "LogOff", 0x010000da: "Market", 0x010000db: "Meeting", 0x010000dc: "MenuKB", 0x010000dd: "MenuPB", 0x010000de: "MySites", 0x010000df: "News", 0x010000e0: "OfficeHome", 0x010000e1: "Option", 0x010000e2: "Paste", 0x010000e3: "Phone", 0x010000e4: "Calendar", 0x010000e5: "Reply", 0x010000e6: "Reload", 0x010000e7: "RotateWindows", 0x010000e8: "RotationPB", 0x010000e9: "RotationKB", 0x010000ea: "Save", 0x010000eb: "Send", 0x010000ec: "Spell", 0x010000ed: "SplitScreen", 0x010000ee: "Support", 0x010000ef: "TaskPane", 0x010000f0: "Terminal", 0x010000f1: "Tools", 0x010000f2: "Travel", 0x010000f3: "Video", 0x010000f4: "Word", 0x010000f5: "Xfer", 0x010000f6: "ZoomIn", 0x010000f7: "ZoomOut", 0x010000f8: "Away", 0x010000f9: "Messenger", 0x010000fa: "WebCam", 0x010000fb: "MailForward", 0x010000fc: "Pictures", 0x010000fd: "Music", 0x010000fe: "Battery", 0x010000ff: "Bluetooth", 0x01000100: "WLAN", 0x01000101: "UWB", 0x01000102: "AudioForward", 0x01000103: "AudioRepeat", 0x01000104: "AudioRandomPlay", 0x01000105: "Subtitle", 0x01000106: "AudioCycleTrack", 0x01000107: "Time", 0x01000108: "Hibernate", 0x01000109: "View", 0x0100010a: "TopMenu", 0x0100010b: "PowerDown", 0x0100010c: "Suspend", 0x0100010d: "ContrastAdjust", 0x01000110: "TouchpadToggle", 0x01000111: "TouchpadOn", 0x01000112: "TouchpadOff", 0x01000113: "MicMute", 0x01000114: "Red", 0x01000115: "Green", 0x01000116: "Yellow", 0x01000117: "Blue", 0x01000118: "ChannelUp", 0x01000119: "ChannelDown", 0x0100011a: "Guide", 0x0100011b: "Info", 0x0100011c: "Settings", 0x0100011d: "MicVolumeUp", 0x0100011e: "MicVolumeDown", 0x01000120: "New", 0x01000121: "Open", 0x01000122: "Find", 0x01000123: "Undo", 0x01000124: "Redo", 0x0100ffff: "MediaLast", 0x01ffffff: "unknown", 0x01100004: "Call", 0x01100020: "Camera", 0x01100021: "CameraFocus", 0x01100000: "Context1", 0x01100001: "Context2", 0x01100002: "Context3", 0x01100003: "Context4", 0x01100006: "Flip", 0x01100005: "Hangup", 0x01010002: "No", 0x01010000: "Select", 0x01010001: "Yes", 0x01100007: "ToggleCallHangup", 0x01100008: "VoiceDial", 0x01100009: "LastNumberRedial", 0x01020003: "Execute", 0x01020002: "Printer", 0x01020005: "Play", 0x01020004: "Sleep", 0x01020006: "Zoom", 0x0102000a: "Exit", 0x01020001: "Cancel"
})
property var modifierKeys: [Qt.Key_Alt, Qt.Key_Meta, Qt.Key_Control, Qt.Key_Shift, Qt.Key_NumLock, Qt.Key_Mode_switch]
property bool lastWasNotModifier: false
function parseKeyEvent(event, released) {
if (!autoShortcut.checked)
return
if (!released && (event.key == Qt.Key_Backspace || event.key == Qt.Key_Delete) && event.modifiers == Qt.NoModifier) {
text = ""
event.accepted = true
return
}
var isModifier = false
modifierKeys.forEach(function(modifKey) {
if (modifKey == event.key)
isModifier = true
})
if (released && lastWasNotModifier) {
event.accepted = true
return
}
lastWasNotModifier = !isModifier
if (event.key == Qt.Key_unknown) {
console.log("Unknown key from a macro probably")
//text = ""
event.accepted = true
return
}
var result = ""
// var result = lastWasNotModifier ? text + "," : ""
if (!(event.modifiers & Qt.NoModifier)) {
for(var modifier in modifiers) {
if (modifier & event.modifiers)
result += modifiers[modifier] + "+"
}
}
if (!released && !isModifier) {
result += keys[event.key]
}
if (text.endsWith('+')) {
var t = text.split(',')
text = t.slice(0, t.length - 1).join(',')
}
if (text) {
if (text.endsWith(','))
text = text + result
else
text = text + ',' + result
}
else {
text = result
}
event.accepted = true
}
Keys.onPressed: parseKeyEvent(event, false)
Keys.onReleased: parseKeyEvent(event, true)
ToolButton {
id: autoShortcut
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
bottomMargin: 2
topMargin: 2
rightMargin: 2
}
text: qsTr("auto")
checkable: true
checked: true
tooltip: qsTr("Wheter this line tries to create shortcut with you keypresses.\nIf disabled, you will be able to enter any key sequence as plain text")
}
}
Попытка перехватить QKeySequence в keyPressEvent может работать не так, как ожидалось. И я нашел решение:
// || event->type()== QEvent::ShortcutOverride is the key point
if (event->type() == QEvent::KeyPress || event->type()== QEvent::ShortcutOverride)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->matches(QKeySequence::Save))
{
// Do save
}
}
Я надеюсь, что это помогает кому-то.:)
Ссылка: QWidget:: eventFilter () не перехватывает комбинации клавиш