mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
Improve key events on Cocoa: add support for the brand new raw key event system, distinguish between left/right modifier keys, fix the lack of down event on help/insert key, fix the lack of up-event while command is pressed
This commit is contained in:
parent
c897b0ece1
commit
0b99086e8c
@ -17,13 +17,14 @@
|
||||
cocoaGraphicsPipe.h cocoaGraphicsPipe.I \
|
||||
cocoaGraphicsWindow.h cocoaGraphicsWindow.I \
|
||||
cocoaGraphicsStateGuardian.h cocoaGraphicsStateGuardian.I \
|
||||
cocoaPandaView.h cocoaPandaWindowDelegate.h
|
||||
cocoaPandaApp.h cocoaPandaView.h cocoaPandaWindowDelegate.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
config_cocoadisplay.mm \
|
||||
cocoaGraphicsPipe.mm \
|
||||
cocoaGraphicsStateGuardian.mm \
|
||||
cocoaGraphicsWindow.mm \
|
||||
cocoaPandaApp.mm \
|
||||
cocoaPandaView.mm \
|
||||
cocoaPandaWindow.mm \
|
||||
cocoaPandaWindowDelegate.mm
|
||||
|
@ -16,6 +16,7 @@
|
||||
//#include "cocoaGraphicsBuffer.h"
|
||||
#include "cocoaGraphicsWindow.h"
|
||||
#include "cocoaGraphicsStateGuardian.h"
|
||||
#include "cocoaPandaApp.h"
|
||||
#include "config_cocoadisplay.h"
|
||||
#include "frameBufferProperties.h"
|
||||
|
||||
@ -32,7 +33,7 @@ TypeHandle CocoaGraphicsPipe::_type_handle;
|
||||
static void init_app() {
|
||||
if (NSApp == nil) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
[NSApplication sharedApplication];
|
||||
[CocoaPandaApp sharedApplication];
|
||||
|
||||
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
@ -80,7 +80,9 @@ protected:
|
||||
private:
|
||||
NSImage *load_image(const Filename &filename);
|
||||
|
||||
ButtonHandle map_key(unsigned short keycode);
|
||||
void handle_modifier(NSUInteger modifierFlags, NSUInteger mask, ButtonHandle button);
|
||||
ButtonHandle map_key(unsigned short c);
|
||||
ButtonHandle map_raw_key(unsigned short keycode);
|
||||
|
||||
private:
|
||||
NSWindow *_window;
|
||||
|
@ -1495,54 +1495,73 @@ void CocoaGraphicsWindow::
|
||||
handle_key_event(NSEvent *event) {
|
||||
NSUInteger modifierFlags = [event modifierFlags];
|
||||
|
||||
if ((modifierFlags ^ _modifier_keys) & NSAlphaShiftKeyMask) {
|
||||
if (modifierFlags & NSAlphaShiftKeyMask) {
|
||||
_input_devices[0].button_down(KeyboardButton::caps_lock());
|
||||
} else {
|
||||
_input_devices[0].button_up(KeyboardButton::caps_lock());
|
||||
}
|
||||
}
|
||||
//NB. This is actually a on-off toggle, not up-down.
|
||||
// Should we instead rapidly fire two successive up-down events?
|
||||
handle_modifier(modifierFlags, NSAlphaShiftKeyMask, KeyboardButton::caps_lock());
|
||||
|
||||
if ((modifierFlags ^ _modifier_keys) & NSShiftKeyMask) {
|
||||
if (modifierFlags & NSShiftKeyMask) {
|
||||
_input_devices[0].button_down(KeyboardButton::shift());
|
||||
} else {
|
||||
_input_devices[0].button_up(KeyboardButton::shift());
|
||||
}
|
||||
}
|
||||
// Check if any of the modifier keys have changed.
|
||||
handle_modifier(modifierFlags, NSShiftKeyMask, KeyboardButton::shift());
|
||||
handle_modifier(modifierFlags, NSControlKeyMask, KeyboardButton::control());
|
||||
handle_modifier(modifierFlags, NSAlternateKeyMask, KeyboardButton::alt());
|
||||
handle_modifier(modifierFlags, NSCommandKeyMask, KeyboardButton::meta());
|
||||
|
||||
if ((modifierFlags ^ _modifier_keys) & NSControlKeyMask) {
|
||||
if (modifierFlags & NSControlKeyMask) {
|
||||
_input_devices[0].button_down(KeyboardButton::control());
|
||||
} else {
|
||||
_input_devices[0].button_up(KeyboardButton::control());
|
||||
}
|
||||
}
|
||||
|
||||
if ((modifierFlags ^ _modifier_keys) & NSAlternateKeyMask) {
|
||||
if (modifierFlags & NSAlternateKeyMask) {
|
||||
_input_devices[0].button_down(KeyboardButton::alt());
|
||||
} else {
|
||||
_input_devices[0].button_up(KeyboardButton::alt());
|
||||
}
|
||||
}
|
||||
|
||||
if ((modifierFlags ^ _modifier_keys) & NSCommandKeyMask) {
|
||||
if (modifierFlags & NSCommandKeyMask) {
|
||||
_input_devices[0].button_down(KeyboardButton::meta());
|
||||
} else {
|
||||
_input_devices[0].button_up(KeyboardButton::meta());
|
||||
}
|
||||
}
|
||||
|
||||
// I'd add the help key too, but something else in Cocoa messes
|
||||
// around with it. The up event is registered fine below, but
|
||||
// the down event isn't, and the modifier flag gets stuck after 1 press.
|
||||
// More testing is needed, but I don't think it's worth it until
|
||||
// we encounter someone who requires support for the help key.
|
||||
// These are not documented, but they seem to be a reliable indicator
|
||||
// of the status of the left/right modifier keys.
|
||||
handle_modifier(modifierFlags, 0x0002, KeyboardButton::lshift());
|
||||
handle_modifier(modifierFlags, 0x0004, KeyboardButton::rshift());
|
||||
handle_modifier(modifierFlags, 0x0001, KeyboardButton::lcontrol());
|
||||
handle_modifier(modifierFlags, 0x2000, KeyboardButton::rcontrol());
|
||||
handle_modifier(modifierFlags, 0x0020, KeyboardButton::lalt());
|
||||
handle_modifier(modifierFlags, 0x0040, KeyboardButton::ralt());
|
||||
handle_modifier(modifierFlags, 0x0008, KeyboardButton::lmeta());
|
||||
handle_modifier(modifierFlags, 0x0010, KeyboardButton::rmeta());
|
||||
|
||||
_modifier_keys = modifierFlags;
|
||||
|
||||
// Get the raw button and send it.
|
||||
ButtonHandle raw_button = map_raw_key([event keyCode]);
|
||||
if (raw_button != ButtonHandle::none()) {
|
||||
// This is not perfect. Eventually, this whole thing should
|
||||
// probably be replaced with something that uses IOKit or so.
|
||||
// In particular, the flaws are:
|
||||
// - OS eats unmodified F11, F12, scroll lock, pause
|
||||
// - no up events for caps lock
|
||||
// - no robust way to distinguish up/down for modkeys
|
||||
if ([event type] == NSKeyUp) {
|
||||
_input_devices[0].raw_button_up(raw_button);
|
||||
|
||||
} else if ([event type] == NSFlagsChanged) {
|
||||
bool down = false;
|
||||
if (raw_button == KeyboardButton::lshift()) {
|
||||
down = (modifierFlags & 0x0002);
|
||||
} else if (raw_button == KeyboardButton::rshift()) {
|
||||
down = (modifierFlags & 0x0004);
|
||||
} else if (raw_button == KeyboardButton::lcontrol()) {
|
||||
down = (modifierFlags & 0x0001);
|
||||
} else if (raw_button == KeyboardButton::rcontrol()) {
|
||||
down = (modifierFlags & 0x2000);
|
||||
} else if (raw_button == KeyboardButton::lalt()) {
|
||||
down = (modifierFlags & 0x0020);
|
||||
} else if (raw_button == KeyboardButton::ralt()) {
|
||||
down = (modifierFlags & 0x0040);
|
||||
} else if (raw_button == KeyboardButton::lmeta()) {
|
||||
down = (modifierFlags & 0x0008);
|
||||
} else if (raw_button == KeyboardButton::rmeta()) {
|
||||
down = (modifierFlags & 0x0010);
|
||||
} else if (raw_button == KeyboardButton::caps_lock()) {
|
||||
// Emulate down-up, annoying hack!
|
||||
_input_devices[0].raw_button_down(raw_button);
|
||||
}
|
||||
if (down) {
|
||||
_input_devices[0].raw_button_down(raw_button);
|
||||
} else {
|
||||
_input_devices[0].raw_button_up(raw_button);
|
||||
}
|
||||
} else if (![event isARepeat]) {
|
||||
_input_devices[0].raw_button_down(raw_button);
|
||||
}
|
||||
}
|
||||
|
||||
// FlagsChanged events only carry modifier key information.
|
||||
if ([event type] == NSFlagsChanged) {
|
||||
return;
|
||||
@ -1597,6 +1616,23 @@ handle_key_event(NSEvent *event) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CocoaGraphicsWindow::handle_modifier
|
||||
// Access: Private
|
||||
// Description: Called by handle_key_event to read the state of
|
||||
// a modifier key.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CocoaGraphicsWindow::
|
||||
handle_modifier(NSUInteger modifierFlags, NSUInteger mask, ButtonHandle button) {
|
||||
if ((modifierFlags ^ _modifier_keys) & mask) {
|
||||
if (modifierFlags & mask) {
|
||||
_input_devices[0].button_down(button);
|
||||
} else {
|
||||
_input_devices[0].button_up(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CocoaGraphicsWindow::handle_mouse_button_event
|
||||
// Access: Public
|
||||
@ -1697,11 +1733,11 @@ handle_wheel_event(double x, double y) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CocoaGraphicsWindow::map_key
|
||||
// Access: Private
|
||||
// Description:
|
||||
// Description: Maps a Cocoa key character to a ButtonHandle.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ButtonHandle CocoaGraphicsWindow::
|
||||
map_key(unsigned short keycode) {
|
||||
switch (keycode) {
|
||||
map_key(unsigned short c) {
|
||||
switch (c) {
|
||||
case NSEnterCharacter:
|
||||
return KeyboardButton::enter();
|
||||
case NSBackspaceCharacter:
|
||||
@ -1713,6 +1749,11 @@ map_key(unsigned short keycode) {
|
||||
// BackTabCharacter is sent when shift-tab is used.
|
||||
return KeyboardButton::tab();
|
||||
|
||||
case 16:
|
||||
// No idea where this constant comes from, but it
|
||||
// is sent whenever the menu key is pressed.
|
||||
return KeyboardButton::menu();
|
||||
|
||||
case NSUpArrowFunctionKey:
|
||||
return KeyboardButton::up();
|
||||
case NSDownArrowFunctionKey:
|
||||
@ -1824,3 +1865,124 @@ map_key(unsigned short keycode) {
|
||||
}
|
||||
return ButtonHandle::none();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CocoaGraphicsWindow::map_raw_key
|
||||
// Access: Private
|
||||
// Description: Maps a keycode to a ButtonHandle.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ButtonHandle CocoaGraphicsWindow::
|
||||
map_raw_key(unsigned short keycode) {
|
||||
if (keycode > 0x7f) {
|
||||
return ButtonHandle::none();
|
||||
}
|
||||
switch ((unsigned char) keycode) {
|
||||
/* See HIToolBox/Events.h */
|
||||
case 0x00: return KeyboardButton::ascii_key('a');
|
||||
case 0x01: return KeyboardButton::ascii_key('s');
|
||||
case 0x02: return KeyboardButton::ascii_key('d');
|
||||
case 0x03: return KeyboardButton::ascii_key('f');
|
||||
case 0x04: return KeyboardButton::ascii_key('h');
|
||||
case 0x05: return KeyboardButton::ascii_key('g');
|
||||
case 0x06: return KeyboardButton::ascii_key('z');
|
||||
case 0x07: return KeyboardButton::ascii_key('x');
|
||||
case 0x08: return KeyboardButton::ascii_key('c');
|
||||
case 0x09: return KeyboardButton::ascii_key('v');
|
||||
case 0x0B: return KeyboardButton::ascii_key('b');
|
||||
case 0x0C: return KeyboardButton::ascii_key('q');
|
||||
case 0x0D: return KeyboardButton::ascii_key('w');
|
||||
case 0x0E: return KeyboardButton::ascii_key('e');
|
||||
case 0x0F: return KeyboardButton::ascii_key('r');
|
||||
case 0x10: return KeyboardButton::ascii_key('y');
|
||||
case 0x11: return KeyboardButton::ascii_key('t');
|
||||
case 0x12: return KeyboardButton::ascii_key('1');
|
||||
case 0x13: return KeyboardButton::ascii_key('2');
|
||||
case 0x14: return KeyboardButton::ascii_key('3');
|
||||
case 0x15: return KeyboardButton::ascii_key('4');
|
||||
case 0x16: return KeyboardButton::ascii_key('6');
|
||||
case 0x17: return KeyboardButton::ascii_key('5');
|
||||
case 0x18: return KeyboardButton::ascii_key('=');
|
||||
case 0x19: return KeyboardButton::ascii_key('9');
|
||||
case 0x1A: return KeyboardButton::ascii_key('7');
|
||||
case 0x1B: return KeyboardButton::ascii_key('-');
|
||||
case 0x1C: return KeyboardButton::ascii_key('8');
|
||||
case 0x1D: return KeyboardButton::ascii_key('0');
|
||||
case 0x1E: return KeyboardButton::ascii_key(']');
|
||||
case 0x1F: return KeyboardButton::ascii_key('o');
|
||||
case 0x20: return KeyboardButton::ascii_key('u');
|
||||
case 0x21: return KeyboardButton::ascii_key('[');
|
||||
case 0x22: return KeyboardButton::ascii_key('i');
|
||||
case 0x23: return KeyboardButton::ascii_key('p');
|
||||
case 0x24: return KeyboardButton::enter();
|
||||
case 0x25: return KeyboardButton::ascii_key('l');
|
||||
case 0x26: return KeyboardButton::ascii_key('j');
|
||||
case 0x27: return KeyboardButton::ascii_key('\'');
|
||||
case 0x28: return KeyboardButton::ascii_key('k');
|
||||
case 0x29: return KeyboardButton::ascii_key(';');
|
||||
case 0x2A: return KeyboardButton::ascii_key('\\');
|
||||
case 0x2B: return KeyboardButton::ascii_key(',');
|
||||
case 0x2C: return KeyboardButton::ascii_key('/');
|
||||
case 0x2D: return KeyboardButton::ascii_key('n');
|
||||
case 0x2E: return KeyboardButton::ascii_key('m');
|
||||
case 0x2F: return KeyboardButton::ascii_key('.');
|
||||
case 0x30: return KeyboardButton::tab();
|
||||
case 0x31: return KeyboardButton::ascii_key(' ');
|
||||
case 0x32: return KeyboardButton::ascii_key('`');
|
||||
case 0x33: return KeyboardButton::backspace();
|
||||
case 0x35: return KeyboardButton::escape();
|
||||
case 0x36: return KeyboardButton::rmeta();
|
||||
case 0x37: return KeyboardButton::lmeta();
|
||||
case 0x38: return KeyboardButton::lshift();
|
||||
case 0x39: return KeyboardButton::caps_lock();
|
||||
case 0x3A: return KeyboardButton::lalt();
|
||||
case 0x3B: return KeyboardButton::lcontrol();
|
||||
case 0x3C: return KeyboardButton::rshift();
|
||||
case 0x3D: return KeyboardButton::ralt();
|
||||
case 0x3E: return KeyboardButton::rcontrol();
|
||||
case 0x41: return KeyboardButton::ascii_key('.');
|
||||
case 0x43: return KeyboardButton::ascii_key('*');
|
||||
case 0x45: return KeyboardButton::ascii_key('+');
|
||||
case 0x47: return KeyboardButton::num_lock();
|
||||
case 0x4B: return KeyboardButton::ascii_key('/');
|
||||
case 0x4C: return KeyboardButton::enter();
|
||||
case 0x4E: return KeyboardButton::ascii_key('-');
|
||||
case 0x51: return KeyboardButton::ascii_key('=');
|
||||
case 0x52: return KeyboardButton::ascii_key('0');
|
||||
case 0x53: return KeyboardButton::ascii_key('1');
|
||||
case 0x54: return KeyboardButton::ascii_key('2');
|
||||
case 0x55: return KeyboardButton::ascii_key('3');
|
||||
case 0x56: return KeyboardButton::ascii_key('4');
|
||||
case 0x57: return KeyboardButton::ascii_key('5');
|
||||
case 0x58: return KeyboardButton::ascii_key('6');
|
||||
case 0x59: return KeyboardButton::ascii_key('7');
|
||||
case 0x5B: return KeyboardButton::ascii_key('8');
|
||||
case 0x5C: return KeyboardButton::ascii_key('9');
|
||||
case 0x60: return KeyboardButton::f5();
|
||||
case 0x61: return KeyboardButton::f6();
|
||||
case 0x62: return KeyboardButton::f7();
|
||||
case 0x63: return KeyboardButton::f3();
|
||||
case 0x64: return KeyboardButton::f8();
|
||||
case 0x65: return KeyboardButton::f9();
|
||||
case 0x67: return KeyboardButton::f11();
|
||||
case 0x69: return KeyboardButton::print_screen();
|
||||
case 0x6B: return KeyboardButton::scroll_lock();
|
||||
case 0x6D: return KeyboardButton::f10();
|
||||
case 0x6E: return KeyboardButton::menu();
|
||||
case 0x6F: return KeyboardButton::f12();
|
||||
case 0x71: return KeyboardButton::pause();
|
||||
case 0x72: return KeyboardButton::insert();
|
||||
case 0x73: return KeyboardButton::home();
|
||||
case 0x74: return KeyboardButton::page_up();
|
||||
case 0x75: return KeyboardButton::del();
|
||||
case 0x76: return KeyboardButton::f4();
|
||||
case 0x77: return KeyboardButton::end();
|
||||
case 0x78: return KeyboardButton::f2();
|
||||
case 0x79: return KeyboardButton::page_down();
|
||||
case 0x7A: return KeyboardButton::f1();
|
||||
case 0x7B: return KeyboardButton::left();
|
||||
case 0x7C: return KeyboardButton::right();
|
||||
case 0x7D: return KeyboardButton::down();
|
||||
case 0x7E: return KeyboardButton::up();
|
||||
default: return ButtonHandle::none();
|
||||
}
|
||||
}
|
||||
|
21
panda/src/cocoadisplay/cocoaPandaApp.h
Normal file
21
panda/src/cocoadisplay/cocoaPandaApp.h
Normal file
@ -0,0 +1,21 @@
|
||||
// Filename: cocoaPandaApp.h
|
||||
// Created by: rdb (08Mar14)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#import <AppKit/NSApplication.h>
|
||||
|
||||
// This class solely exists so that we can override sendEvent in order
|
||||
// to prevent NSApplication from eating certain keyboard events.
|
||||
@interface CocoaPandaApp : NSApplication
|
||||
- (void) sendEvent: (NSEvent *) event;
|
||||
@end
|
29
panda/src/cocoadisplay/cocoaPandaApp.mm
Normal file
29
panda/src/cocoadisplay/cocoaPandaApp.mm
Normal file
@ -0,0 +1,29 @@
|
||||
// Filename: cocoaPandaApp.mm
|
||||
// Created by: rdb (08Mar14)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#import "cocoaPandaApp.h"
|
||||
|
||||
@implementation CocoaPandaApp
|
||||
- (void) sendEvent: (NSEvent *) event {
|
||||
// This is a hack that allows us to receive cmd-key-up events correctly.
|
||||
// Also prevent it from eating the insert/help key.
|
||||
if (([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask))
|
||||
||([event type] == NSKeyDown && [event keyCode] == 0x72)) {
|
||||
|
||||
[[self keyWindow] sendEvent: event];
|
||||
} else {
|
||||
[super sendEvent: event];
|
||||
}
|
||||
}
|
||||
@end
|
@ -2,6 +2,7 @@
|
||||
#include "cocoaGraphicsPipe.mm"
|
||||
#include "cocoaGraphicsStateGuardian.mm"
|
||||
#include "cocoaGraphicsWindow.mm"
|
||||
#include "cocoaPandaApp.mm"
|
||||
#include "cocoaPandaView.mm"
|
||||
#include "cocoaPandaWindow.mm"
|
||||
#include "cocoaPandaWindowDelegate.mm"
|
Loading…
x
Reference in New Issue
Block a user