Как игры для Mac OS X могут получать события ввода с клавиатуры низкого уровня? - PullRequest
24 голосов
/ 08 сентября 2011

Играм необходим низкоуровневый доступ к вводу с клавиатуры.В Windows есть DirectInput.Но какую технологию используют разработчики игр для Mac OS X?

Очевидно, что для Mac достаточно игр, которые правильно вводят данные с клавиатуры, без недостатков общеизвестных решений:

Решение №1: Использование событий keyUp / keyDown

-(void)keyUp:(NSEvent*)event;
-(void)keyDown:(NSEvent*)event;

Недопустимый недостаток: События keyDown повторяются на основе настроек системы для параметров «Скорость повторения ключа» и «Задержка повторения ключа».Это вызывает начальное событие keyDown, за которым следует пауза, прежде чем оно начнет повторяться со скоростью, определенной настройкой системы.Это решение не может быть использовано для непрерывных событий клавиш.

Интересно, можно ли отключить поведение повтора клавиш?Я полагаю, что вы могли бы прочитать первый ключ keyDown, а затем запомнить состояние «ключ с ключом x выключен» в вашем классе, пока для этого ключа не будет получено событие keyUp, что позволит обойти проблемы задержки и повторения.

Решение № 2: Использование отводов событий Quarts

См. Справочник по службам Quartz Event * .Кажется, он достаточно низкого уровня.

Недопустимый недостаток: требует, чтобы вспомогательные устройства были включены в системных настройках в разделе «Универсальный доступ - Клавиатура».Хотя это может быть включено по умолчанию, нет гарантии, что оно может быть отключено в некоторых системах.

Я также читал, что для прослушивания событий Quartz требуется, чтобы приложение запускалось от имени пользователя root, но не нашел подтверждения для этого.

Решение № 3: Carbon Events / IOKit HID

Справочник Carbon Event Manager помечен как устаревший и долженне будет использоваться для новых разработок.

Недопустимый недостаток: никто не знает, как долго события Carbon будут продолжать поддерживаться в будущих версиях Mac OS.

Помимо CarbonБудучи устаревшей платформой, это все еще кажется лучшим решением.Но есть ли другие недостатки в использовании Carbon Events?

Вопросы:

Какую технологию используют разработчики игр для Mac OS X для получения низкоуровневых событий ввода с клавиатуры?Если они используют одну из вышеуказанных технологий, как они обходят упомянутые мною недостатки?

ОБНОВЛЕНИЕ:

Я в конечном итоге обратился к использованию обычных сообщений NSEvent и завернул ихих в аккуратном API для опроса состояний клавиатуры .

Ответы [ 6 ]

9 голосов
/ 08 сентября 2011

Мне повезло с №3, но это требует большой нагрузки, если вы хотите поддерживать что-то кроме клавиатуры.

Один быстрый момент, прежде чем мы погрузимся в это, но Carbon и IOKit HID - это две разные вещи. Углерод может уйти в какой-то момент. Но IOKit HID здесь, чтобы остаться и только что получил хороший подтяжку лица в 10.5.

Для полного примера того, как все эти вещи объединяются, взгляните на https://github.com/OpenEmu/OpenEmu/blob/master/OpenEmu/OEHIDManager.m. Это небольшой кусочек головоломки, так как там есть и другие файлы.

Документацию о том, что вы хотите сделать, можно найти http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/HID/new_api_10_5/tn2187.html

Опять же, это не исчезнет в ближайшее время и будет полностью отделено от Carbon и Carbon Events.

2 голосов
/ 29 октября 2015

Я опоздал на эту вечеринку, но вот мое решение для игры для OSX, которую я пишу с использованием Swift.Это очень просто, и, кажется, работает довольно хорошо.

Сначала вы можете поместить этот код в контроллер, который получает события клавиатуры:

var keysDown = Set<UInt16>()

override func keyDown(e: NSEvent) {
    keysDown.insert(e.keyCode)
}

override func keyUp(e: NSEvent) {
    keysDown.remove(e.keyCode)
}

Затем другие части системы могутопределить, нажата ли конкретная клавиша:

if (keysDown.contains(49)) {
    // space bar is down
}

Или перебрать все клавиши, которые нажаты в данный момент

for char in keysDown {

    switch char {

    case 49:
        // space
        player.jump()
    case 126:
        // up
        player.moveForward()
    case 124:
        // right
        player.turnRight()

        //   ... etc ...

    default:
        // during development I have this line so I can easily see which keys have which codes
        print(char)
    }
}

Примечание keysDown - это быстрый набор, поэтому вам не нужнобеспокоиться о дубликатах или заказе.Ключ либо есть в наборе, либо его нет.

Я не слишком уверен, насколько стандартизированы коды клавиш.Но вы могли бы предложить страницу конфигурации клавиатуры, где пользователь может вводить клавиши для каждого действия, а затем сохранять любой код клавиши.

1 голос
/ 25 июля 2017

Хорошо, так что я действительно опаздываю на вечеринку, но я думаю, что мое дело прямо в точку и напоминает решение мистера Говарда выше.Имейте в виду, что этот вход используется для управления камерой в игре SpriteKit.Таким образом, вы получаете плавное непрерывное движение и точную остановку.

let moveRight: SKAction = SKAction.repeatForever(SKAction.moveBy(x: -5000, y: 0, duration: 1.5))
...

override func keyDown(with event: NSEvent) {
    camera!.constraints = [] // remove constraints usually added by a cameraComponent.

    let ekc = event.keyCode
    if ekc == 123 { camera!.run(moveLeft, withKey: "moveLeft") }
    if ekc == 124 { camera!.run(moveRight, withKey: "moveRight") }
    if ekc == 126 { camera!.run(moveUp, withKey: "moveUp") }
    if ekc == 125 { camera!.run(moveDown, withKey: "moveDown") }

    print("keyDown: \(event.characters!) keyCode: \(event.keyCode)")
}


override func keyUp(with event: NSEvent) {
    let ekc = event.keyCode
    if ekc == 123 { camera!.removeAction(forKey: "moveLeft") }
    if ekc == 124 { camera!.removeAction(forKey: "moveRight") }
    if ekc == 126 { camera!.removeAction(forKey: "moveUp") }
    if ekc == 125 { camera!.removeAction(forKey: "moveDown") }
}
0 голосов
/ 17 декабря 2014

Я нашел очень хороший пример с использованием Quartz Event Taps .

однако проблемы:

  1. для определенных типов событий, пользователь должен запустить приложение с правами суперпользователя.например, для перехвата событий keydown и keyup требуется root.

  2. перехват является общесистемным, что означает, что при запуске программы он будет захватывать все ключевые события, даже те, которые отправлены в другие приложения.Реализация должна быть очень осторожной, чтобы не сломать другие приложения.

0 голосов
/ 09 сентября 2011

В polkit (Obj-C toolkit) есть также несколько классов устройств, в том числе ...

  • HIDController для использования USB HID устройств
  • AppleRemote для использования Apple Remote
  • MidiController для использования устройств Midi
  • OSCController для использования OSC-совместимых устройств через UDP
  • SerialPort для использования любого устройства с последовательным портом
  • SC2004LCМодуль для использования SC 2004 с siliccraft.net

http://code.google.com/p/polkit/

0 голосов
/ 08 сентября 2011

Посмотрите на ControllerMate и manymouse.

http://icculus.org/manymouse/

http://www.orderedbytes.com/controllermate/

...