Обработка событий клавиатуры в AppKit с помощью Swift
У меня есть пользовательский подкласс NSView, который должен обрабатывать некоторые события клавиатуры. В Objective-C я могу справиться с этим следующим образом:
-(void)keyDown:(NSEvent *)event
{
unichar ch = [[event charactersIgnoringModifiers] characterAtIndex:0];
if (ch == NSUpArrowFunctionKey && (event.modifierFlags & NSCommandKeyMask)) {
// Scroll to top
return;
}
else if (ch == NSDownArrowFunctionKey && (event.modifierFlags & NSCommandKeyMask)) {
// Scroll to bottom
return;
}
switch (ch) {
case NSRightArrowFunctionKey:
// Select the current row
return;
case ' ':
// Scroll down one page
return;
default:
break;
}
[super keyDown:event];
}
В Swift, однако, characterAtIndex:
возвращает a unichar
, а NSUpArrowFunctionKey: Int
и " ": String
(или Character
). Мне не ясно, как преобразовать unichar в String
или Character
.
Я получил эту работу, но это похоже на уродливое обходное решение. Есть ли лучший способ?
func keyDown(theEvent: NSEvent) {
let char = Int(theEvent.charactersIgnoringModifiers.utf16[0]) // <----- This seems ugly
let hasCommand = (theEvent.modifierFlags & .CommandKeyMask).value != 0
switch char {
case NSUpArrowFunctionKey where hasCommand == true:
// Scroll to top
break
case NSDownArrowFunctionKey where hasCommand == true:
// Scroll to bottom
break
case NSRightArrowFunctionKey where hasCommand == true:
// Select the current row
break
case Int(" ".utf16[0]): // <---- Surely there a better way of doing this?
// Scroll down one page
break
default:
super.keyDown(theEvent)
}
}
Ответы
Ответ 1
Пусть часто пропускаемый interpretKeyEvents()
сделает для вас беспорядочные биты. Он знает обо всех видах клавиш, включая клавиши со стрелками:
override func keyDown(event: NSEvent) {
interpretKeyEvents([event]) // calls insertText(_:), moveUp(_:), etc.
}
override func insertText(insertString: AnyObject) {
let str = insertString as! String
switch str {
case " ":
println("User hit the spacebar.")
default:
println("Unrecognized input: \(str)")
}
}
override func moveUp(sender: AnyObject?) {
println("Up arrow.")
}
override func moveLeft(sender: AnyObject?) {
println("Left arrow.")
}
override func deleteBackward(sender: AnyObject?) {
println("Delete.")
}
Раздел Ссылка на класс NSResponder Отвечая на сообщения о действиях, перечисляет эти и другие методы обработки событий клавиатуры.
Ответ 2
Почему бы не использовать расширения?
extension NSEvent {
var character: Int {
// Note that you could also use Int(keyCode)
return Int(charactersIgnoringModifiers.utf16[0])
}
}
override func keyDown(theEvent: NSEvent!) {
switch theEvent.character {
case NSUpArrowFunctionKey:
println("up!")
case 0x20:
println("spacebar!")
default:
super.mouseDown(theEvent)
}
}
Также обратите внимание, что, как указано в этом ответе, не существует общедоступного перечисления, определяющего все коды клавиш для каждого ключа. Проще всего проверить, какое это значение, с помощью println()
, а затем использовать это значение в операторе switch.
Изменить
Или вы также можете расширить класс Character
import Foundation
extension Character {
var keyCode: Int {
return Int(String(self).utf16[String.UTF16View.Index(0)])
}
}
и проверить это следующим образом
case Character(" ").keyCode: // Spacebar
println("spacebar!")
Ответ 3
OSX обрабатывает ключевые события, используя как минимум два разных уровня.
keyCode
. Я считаю, что это код, сопоставленный с каждой клавишей аппаратной клавиатуры.
- Unicode. Предопределенная кодовая точка Unicode, сопоставленная с семантическим виртуальным ключом.
Вам нужно использовать ключ Unicode для правильной обработки пользовательских событий.
Вы можете взять кодовую точку Unicode из объекта события следующим образом.
override func keyDown(theEvent: NSEvent) {
let s = theEvent.charactersIgnoringModifiers!
let s1 = s.unicodeScalars
let s2 = s1[s1.startIndex].value
let s3 = Int(s2)
switch s3 {
case NSUpArrowFunctionKey:
wc1.navigateUp()
return
case NSDownArrowFunctionKey:
wc1.navigateDown()
return
default:
break
}
super.keyDown(theEvent)
}
Позаботьтесь о том, чтобы unicodeScalars
не был доступен в произвольном порядке, поэтому вам нужно использовать явный индексный объект --- startIndex
.