Mac OS X 游戏如何接收低级键盘输入事件?

发布于 2024-12-03 17:13:00 字数 1920 浏览 2 评论 0原文

游戏需要对键盘输入进行低级访问。在 Windows 上,有 DirectInput。但 Mac OS X 游戏开发人员使用什么技术呢?

显然,有足够多的 Mac 游戏可以正确地进行键盘输入,而没有常见解决方案的缺点:

解决方案#1:使用 keyUp / keyDown 事件

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

不可接受的缺点: keyDown 事件重复基于“按键重复率”和“按键重复延迟”的系统首选项设置。这会导致初始 keyDown 事件,然后暂停,然后开始以系统首选项设置定义的速率重复。该方案不能用于连续按键事件。

我想知道是否可以禁用按键重复行为?我想您可以读取第一个 keyDown 键,然后记住类中的“带有 keyCode x 的键按下”状态,直到收到该键的 keyUp 事件,从而绕过重复延迟和重复率问题。

解决方案#2:使用 Quarts 事件点击

请参阅 Quartz 事件服务参考。这似乎是足够低水平的。

不可接受的缺点:需要在通用访问 - 键盘下的系统偏好设置中启用辅助设备。虽然默认情况下此功能可能处于打开状态,但不能保证它在某些系统上可能会被关闭。

我还读到 Quartz 事件点击需要应用程序以 root 身份运行,但没有找到对此的确认。

解决方案#3:Carbon 事件/IOKit HID

Carbon 事件管理器参考 已标记作为遗留物,不应用于新的开发。

不可接受的缺点:没有人知道未来的 Mac OS 版本将继续支持 Carbon 事件多久。

除了 Carbon 是一个遗留框架之外,这似乎仍然是最好的解决方案。但是使用 Carbon Events 还有其他缺点吗?

问题

Mac OS X 游戏开发人员使用哪些技术来接收低级键盘输入事件?如果他们使用上述技术之一,他们如何解决我提到的缺点?

更新:

我最终转向使用常规 NSEvent 消息并将它们包装在 用于轮询键盘状态的简洁 API

Games need low-level access to keyboard input. On Windows, there's DirectInput. But what technology do Mac OS X game developers use?

Obviously, there's enough Mac games which get keyboard input just right, without the drawbacks of the commonly known solutions:

Solution #1: Use keyUp / keyDown events

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

Inacceptable drawback: keyDown events are repeated based on the system preference settings for "key repeat rate" and "key repeat delay". This causes an initial keyDown event followed by a pause before it starts repeating at a rate defined by a system preference setting. This solution can not be used for continuous key events.

I wonder if the key repeat behavior can be disabled? I suppose that you could read the first keyDown key, then remember the "key with keyCode x is down" state in your class until the keyUp event is received for that key, thus bypassing the repeat delay and repeat rate issues.

Solution #2: Use Quarts Event Taps

See Quartz Event Services Reference. It seems to be sufficiently low-level.

Inacceptable drawback: requires Assistive Devices to be enabled in system preferences under Universal Access - Keyboard. While this may be on by default, there is no guarantee that it might be turned off on some systems.

I also read that Quartz event taps require the app to run as root, but found no confirmation for this.

Solution #3: Carbon Events / IOKit HID

The Carbon Event Manager Reference is marked as legacy and should not be used for new development.

Inacceptable Drawback: no one knows how long the Carbon events will continue to be supported in future Mac OS versions.

Apart from Carbon being a legacy framework, this still seems to be the best solution. But are there any other drawbacks for using Carbon Events?

Questions:

Which technology do Mac OS X game developers use for receiving low-level keyboard input events? If they use one of the above technologies, how do they work around the drawbacks I mentioned?

UPDATE:

I eventually turned to using the regular NSEvent messages and wrapped them in a neat API for polling the keyboard states.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

撧情箌佬 2024-12-10 17:13:00

我在#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

同样,这不会很快消失,并且与碳和碳事件完全分开。

I have had good luck with #3, but it requires a lot of heavy lifting if you want to support anything beyond the keyboard.

One quick point before we dive in though, Carbon and IOKit HID are two separate thing. Carbon may go away at some point. But IOKit HID is here to stay and just got a nice facelift in 10.5.

For a full example of how this stuff all fits together, take a look at https://github.com/OpenEmu/OpenEmu/blob/master/OpenEmu/OEHIDManager.m. That is a small piece of the puzzle as there are other files in there as well.

The documentation for what you're wanting to do can be found http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/HID/new_api_10_5/tn2187.html

Again, this is not going to disappear anytime soon and is completely separate from Carbon and Carbon Events.

恬淡成诗 2024-12-10 17:13:00

我参加这个聚会迟到了,但这是我使用 Swift 编写的 OSX 游戏的解决方案。这非常简单,而且看起来效果很好。

首先,您可以将此代码放入正在接收键盘事件的控制器中:

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 是一个 Swift Set,因此您可以不必担心重复或排序。密钥要么在集合中,要么不在集合中。

我不太确定键码的标准化程度如何。但是您可以提供一个键盘配置页面,用户可以在其中为每个操作键入按键,然后保存发生的任何键码。

I'm late to this party, but here's my solution for an OSX game I'm writing using Swift. It's very simple, and seems to be working pretty well.

First you can put this code in the controller which is receiving keyboard events:

var keysDown = Set<UInt16>()

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

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

Then, other parts of the system can determine if a particular key is down:

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

Or loop through all the keys which are currently pressed

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)
    }
}

Note keysDown is a Swift Set, so you don't have to worry about duplicates or ordering. A key is either in the set or it isn't.

I'm not too sure how standardised the keycodes are. But you could offer a keyboard configuration page where the user can type keys for each action, and then save whatever keycode this happened to be.

多情出卖 2024-12-10 17:13:00

好吧,我参加聚会确实迟到了,但我认为我的解决方案是开门见山的,类似于上面霍华德先生的解决方案。请记住,此输入用于控制 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") }
}

Ok so I'm really late to the party but I think mine is just straight to the point and resembles Mr. Howards solution above. Keep in mind this input is being used to control the camera in a SpriteKit game. This way you get smooth continuous movement and precise stopping.

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") }
}
扎心 2024-12-10 17:13:00

polkit(Obj-C 工具包)中还有一些设备类,包括...

  • HIDController 使用 USB HID 设备
  • AppleRemote 使用 Apple Remote
  • MidiController 使用 Midi 设备
  • OSCController 通过 UDP SerialPort 使用 OSC 兼容设备
  • 以使用任何串行端口设备
  • SC2004LCDModule 使用来自 Siliconcraft.net 的 SC 2004

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

There are also some Device Classes in polkit (Obj-C toolkit) including ...

  • HIDController to use USB HID devices
  • AppleRemote to use the Apple Remote
  • MidiController to use Midi devices
  • OSCController to use OSC compatible devices over UDP
  • SerialPort to use any serial port device
  • SC2004LCDModule to use the SC 2004 from siliconcraft.net

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

与往事干杯 2024-12-10 17:13:00

我发现了一个使用 Quartz Event Taps 的很好的例子。

但问题是:

  1. 对于某些事件类型,用户需要以 root 权限运行应用程序。例如,拦截 keydown 和 keyup 事件需要 root。

  2. 拦截是系统范围的,这意味着当程序运行时,它将捕获所有关键事件,甚至是发送到其他应用程序的事件。实施时需要非常小心,以免破坏其他应用程序。

I found a very good example of using Quartz Event Taps.

however the problems are:

  1. for certain event types, the user needs to run the application in root privilege. for example intercepting keydown and keyup events requires root.

  2. the interception is system wide, which means when the program runs, it will capture all key events even those sent to other applications. implementation needs to be very careful in order to not to break other applications.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文