From a181e471beaa72e7a0213ec669d92360df98a7ac Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 13 Jul 2009 17:03:26 +0000 Subject: [PATCH] osx plugin key events etc --- direct/src/plugin/p3dInstance.cxx | 63 +++++- direct/src/plugin/p3dInstance.h | 1 + panda/src/display/subprocessWindow.cxx | 215 ++++++++++++++++++--- panda/src/display/subprocessWindow.h | 8 +- panda/src/display/subprocessWindowBuffer.h | 28 ++- 5 files changed, 281 insertions(+), 34 deletions(-) diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index eca7e98bcb..68f39e9719 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -485,24 +485,58 @@ handle_event(P3D_event_data event) { case mouseDown: case mouseUp: { + // Need to ensure we have the correct port set, in order to + // convert the mouse coordinates successfully via + // GlobalToLocal(). + GrafPtr out_port = _wparams.get_parent_window()._port; + GrafPtr portSave = NULL; + Boolean portChanged = QDSwapPort(out_port, &portSave); + Point pt = er->where; GlobalToLocal(&pt); P3D_window_handle window = _wparams.get_parent_window(); cerr << "mouse " << pt.h << " " << pt.v << "\n"; if (_swbuffer != NULL) { SubprocessWindowBuffer::Event swb_event; - swb_event._up = (er->what == mouseUp); + swb_event._source = SubprocessWindowBuffer::ES_mouse; + swb_event._code = 0; + if (er->what == mouseUp) { + swb_event._trans = SubprocessWindowBuffer::BT_up; + } else { + swb_event._trans = SubprocessWindowBuffer::BT_down; + } swb_event._x = pt.h; swb_event._y = pt.v; + swb_event._flags = SubprocessWindowBuffer::EF_mouse_position; + add_modifier_flags(swb_event._flags, er->modifiers); _swbuffer->add_event(swb_event); } + + if (portChanged) { + QDSwapPort(portSave, NULL); + } } break; case keyDown: case keyUp: case autoKey: - cerr << "keycode: " << (er->message & 0xffff) << "\n"; + cerr << "keycode: " << hex << (er->message & 0xffff) << dec << "\n"; + if (_swbuffer != NULL) { + SubprocessWindowBuffer::Event swb_event; + swb_event._source = SubprocessWindowBuffer::ES_keyboard; + swb_event._code = er->message; + if (er->what == keyUp) { + swb_event._trans = SubprocessWindowBuffer::BT_up; + } else if (er->what == keyDown) { + swb_event._trans = SubprocessWindowBuffer::BT_down; + } else { + swb_event._trans = SubprocessWindowBuffer::BT_again; + } + swb_event._flags = 0; + add_modifier_flags(swb_event._flags, er->modifiers); + _swbuffer->add_event(swb_event); + } break; case updateEvt: @@ -1005,6 +1039,31 @@ paint_window() { #endif // __APPLE__ } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::add_modifier_flags +// Access: Private +// Description: OSX only: adds the appropriate bits to the Event flag +// bitmask to correspond to the modifier buttons held in +// the MacOS-style EventRecord::modifiers mask. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +add_modifier_flags(unsigned int &swb_flags, int modifiers) { +#ifdef __APPLE__ + if (modifiers & cmdKey) { + swb_flags |= SubprocessWindowBuffer::EF_meta_held; + } + if (modifiers & shiftKey) { + swb_flags |= SubprocessWindowBuffer::EF_shift_held; + } + if (modifiers & optionKey) { + swb_flags |= SubprocessWindowBuffer::EF_alt_held; + } + if (modifiers & controlKey) { + swb_flags |= SubprocessWindowBuffer::EF_control_held; + } +#endif // __APPLE__ +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::SplashDownload::Constructor // Access: Public diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index c3598dc9ca..7829338654 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -108,6 +108,7 @@ private: void install_progress(P3DPackage *package, double progress); void paint_window(); + void add_modifier_flags(unsigned int &swb_flags, int modifiers); P3D_request_ready_func *_func; P3D_object *_browser_script_object; diff --git a/panda/src/display/subprocessWindow.cxx b/panda/src/display/subprocessWindow.cxx index 5f60df305b..97b58cccc9 100644 --- a/panda/src/display/subprocessWindow.cxx +++ b/panda/src/display/subprocessWindow.cxx @@ -63,6 +63,7 @@ SubprocessWindow(GraphicsEngine *engine, GraphicsPipe *pipe, _mmap_size = 0; _filename = filename; _swbuffer = NULL; + _last_event_flags = 0; } //////////////////////////////////////////////////////////////////// @@ -93,14 +94,45 @@ process_events() { GraphicsWindow::process_events(); if (_swbuffer != NULL) { - SubprocessWindowBuffer::Event event; - while (_swbuffer->get_event(event)) { - // Deal with this event. For now, we only have mouse down/up. - _input_devices[0].set_pointer_in_window(event._x, event._y); - if (event._up) { - _input_devices[0].button_up(MouseButton::one()); + SubprocessWindowBuffer::Event swb_event; + while (_swbuffer->get_event(swb_event)) { + // Deal with this event. + if (swb_event._flags & SubprocessWindowBuffer::EF_mouse_position) { + _input_devices[0].set_pointer_in_window(swb_event._x, swb_event._y); + } + + unsigned int diff = swb_event._flags ^ _last_event_flags; + _last_event_flags = swb_event._flags; + + if (diff & SubprocessWindowBuffer::EF_shift_held) { + transition_button(swb_event._flags & SubprocessWindowBuffer::EF_shift_held, KeyboardButton::shift()); + } + if (diff & SubprocessWindowBuffer::EF_control_held) { + transition_button(swb_event._flags & SubprocessWindowBuffer::EF_control_held, KeyboardButton::control()); + } + if (diff & SubprocessWindowBuffer::EF_alt_held) { + transition_button(swb_event._flags & SubprocessWindowBuffer::EF_alt_held, KeyboardButton::alt()); + } + if (diff & SubprocessWindowBuffer::EF_meta_held) { + transition_button(swb_event._flags & SubprocessWindowBuffer::EF_meta_held, KeyboardButton::meta()); + } + + ButtonHandle button; + if (swb_event._source == SubprocessWindowBuffer::ES_mouse) { + button = MouseButton::button(swb_event._code); + } else { - _input_devices[0].button_down(MouseButton::one()); + int keycode; + button = translate_key(keycode, swb_event._code, swb_event._flags); + if (keycode != 0 && swb_event._trans != SubprocessWindowBuffer::BT_up) { + _input_devices[0].keystroke(keycode); + } + } + + if (swb_event._trans == SubprocessWindowBuffer::BT_up) { + _input_devices[0].button_up(button); + } else if (swb_event._trans == SubprocessWindowBuffer::BT_down) { + _input_devices[0].button_down(button); } } } @@ -249,27 +281,156 @@ open_window() { } //////////////////////////////////////////////////////////////////// -// Function: SubprocessWindow::set_properties_now -// Access: Public, Virtual -// Description: Applies the requested set of properties to the -// window, if possible, for instance to request a change -// in size or minimization status. -// -// The window properties are applied immediately, rather -// than waiting until the next frame. This implies that -// this method may *only* be called from within the -// window thread. -// -// The properties that have been applied are cleared -// from the structure by this function; so on return, -// whatever remains in the properties structure are -// those that were unchanged for some reason (probably -// because the underlying interface does not support -// changing that property on an open window). +// Function: SubprocessWindow::translate_key +// Access: Private +// Description: Converts the os-specific keycode into the appropriate +// ButtonHandle object. Also stores the corresponding +// Unicode keycode in keycode, if any; or 0 otherwise. //////////////////////////////////////////////////////////////////// -void SubprocessWindow:: -set_properties_now(WindowProperties &properties) { - GraphicsWindow::set_properties_now(properties); +ButtonHandle SubprocessWindow:: +translate_key(int &keycode, int os_code, unsigned int flags) const { + keycode = 0; + ButtonHandle nk = ButtonHandle::none(); + +#ifdef __APPLE__ + switch ((os_code >> 8) & 0xff) { + case 0: nk = KeyboardButton::ascii_key('a'); break; + case 11: nk = KeyboardButton::ascii_key('b'); break; + case 8: nk = KeyboardButton::ascii_key('c'); break; + case 2: nk = KeyboardButton::ascii_key('d'); break; + case 14: nk = KeyboardButton::ascii_key('e'); break; + case 3: nk = KeyboardButton::ascii_key('f'); break; + case 5: nk = KeyboardButton::ascii_key('g'); break; + case 4: nk = KeyboardButton::ascii_key('h'); break; + case 34: nk = KeyboardButton::ascii_key('i'); break; + case 38: nk = KeyboardButton::ascii_key('j'); break; + case 40: nk = KeyboardButton::ascii_key('k'); break; + case 37: nk = KeyboardButton::ascii_key('l'); break; + case 46: nk = KeyboardButton::ascii_key('m'); break; + case 45: nk = KeyboardButton::ascii_key('n'); break; + case 31: nk = KeyboardButton::ascii_key('o'); break; + case 35: nk = KeyboardButton::ascii_key('p'); break; + case 12: nk = KeyboardButton::ascii_key('q'); break; + case 15: nk = KeyboardButton::ascii_key('r'); break; + case 1: nk = KeyboardButton::ascii_key('s'); break; + case 17: nk = KeyboardButton::ascii_key('t'); break; + case 32: nk = KeyboardButton::ascii_key('u'); break; + case 9: nk = KeyboardButton::ascii_key('v'); break; + case 13: nk = KeyboardButton::ascii_key('w'); break; + case 7: nk = KeyboardButton::ascii_key('x'); break; + case 16: nk = KeyboardButton::ascii_key('y'); break; + case 6: nk = KeyboardButton::ascii_key('z'); break; + + // top row numbers + case 29: nk = KeyboardButton::ascii_key('0'); break; + case 18: nk = KeyboardButton::ascii_key('1'); break; + case 19: nk = KeyboardButton::ascii_key('2'); break; + case 20: nk = KeyboardButton::ascii_key('3'); break; + case 21: nk = KeyboardButton::ascii_key('4'); break; + case 23: nk = KeyboardButton::ascii_key('5'); break; + case 22: nk = KeyboardButton::ascii_key('6'); break; + case 26: nk = KeyboardButton::ascii_key('7'); break; + case 28: nk = KeyboardButton::ascii_key('8'); break; + case 25: nk = KeyboardButton::ascii_key('9'); break; + + // key pad ... do they really map to the top number in panda ? + case 82: nk = KeyboardButton::ascii_key('0'); break; + case 83: nk = KeyboardButton::ascii_key('1'); break; + case 84: nk = KeyboardButton::ascii_key('2'); break; + case 85: nk = KeyboardButton::ascii_key('3'); break; + case 86: nk = KeyboardButton::ascii_key('4'); break; + case 87: nk = KeyboardButton::ascii_key('5'); break; + case 88: nk = KeyboardButton::ascii_key('6'); break; + case 89: nk = KeyboardButton::ascii_key('7'); break; + case 91: nk = KeyboardButton::ascii_key('8'); break; + case 92: nk = KeyboardButton::ascii_key('9'); break; + + // case 36: nk = KeyboardButton::ret(); break; // no return in panda ??? + case 49: nk = KeyboardButton::space(); break; + case 51: nk = KeyboardButton::backspace(); break; + case 48: nk = KeyboardButton::tab(); break; + case 53: nk = KeyboardButton::escape(); break; + case 76: nk = KeyboardButton::enter(); break; + case 36: nk = KeyboardButton::enter(); break; + + case 123: nk = KeyboardButton::left(); break; + case 124: nk = KeyboardButton::right(); break; + case 125: nk = KeyboardButton::down(); break; + case 126: nk = KeyboardButton::up(); break; + case 116: nk = KeyboardButton::page_up(); break; + case 121: nk = KeyboardButton::page_down(); break; + case 115: nk = KeyboardButton::home(); break; + case 119: nk = KeyboardButton::end(); break; + case 114: nk = KeyboardButton::help(); break; + case 117: nk = KeyboardButton::del(); break; + + // case 71: nk = KeyboardButton::num_lock() break; + + case 122: nk = KeyboardButton::f1(); break; + case 120: nk = KeyboardButton::f2(); break; + case 99: nk = KeyboardButton::f3(); break; + case 118: nk = KeyboardButton::f4(); break; + case 96: nk = KeyboardButton::f5(); break; + case 97: nk = KeyboardButton::f6(); break; + case 98: nk = KeyboardButton::f7(); break; + case 100: nk = KeyboardButton::f8(); break; + case 101: nk = KeyboardButton::f9(); break; + case 109: nk = KeyboardButton::f10(); break; + case 103: nk = KeyboardButton::f11(); break; + case 111: nk = KeyboardButton::f12(); break; + + case 105: nk = KeyboardButton::f13(); break; + case 107: nk = KeyboardButton::f14(); break; + case 113: nk = KeyboardButton::f15(); break; + case 106: nk = KeyboardButton::f16(); break; + + // shiftable chartablet + case 50: nk = KeyboardButton::ascii_key('`'); break; + case 27: nk = KeyboardButton::ascii_key('-'); break; + case 24: nk = KeyboardButton::ascii_key('='); break; + case 33: nk = KeyboardButton::ascii_key('['); break; + case 30: nk = KeyboardButton::ascii_key(']'); break; + case 42: nk = KeyboardButton::ascii_key('\\'); break; + case 41: nk = KeyboardButton::ascii_key(';'); break; + case 39: nk = KeyboardButton::ascii_key('\''); break; + case 43: nk = KeyboardButton::ascii_key(','); break; + case 47: nk = KeyboardButton::ascii_key('.'); break; + case 44: nk = KeyboardButton::ascii_key('/'); break; + + default: + // Punt. + nk = KeyboardButton::ascii_key(os_code & 0xff); + } + + if (nk.has_ascii_equivalent()) { + // If we assigned an ASCII button, then get the original ASCII + // code from the event (it will include shift et al). + + // TODO: is it possible to get any international characters via + // this old EventRecord interface? + keycode = os_code & 0xff; + } + +#endif __APPLE__ + + return nk; } +//////////////////////////////////////////////////////////////////// +// Function: SubprocessWindow::transition_button +// Access: Private +// Description: Sends the appropriate up/down transition for the +// indicated modifier key, as determined implicitly from +// the flags. +//////////////////////////////////////////////////////////////////// +void SubprocessWindow:: +transition_button(unsigned int flags, ButtonHandle button) { + if (flags) { + _input_devices[0].button_down(button); + } else { + _input_devices[0].button_up(button); + } +} + + #endif // SUPPORT_SUBPROCESS_WINDOW diff --git a/panda/src/display/subprocessWindow.h b/panda/src/display/subprocessWindow.h index bc2accce02..c6445fcdc3 100644 --- a/panda/src/display/subprocessWindow.h +++ b/panda/src/display/subprocessWindow.h @@ -65,12 +65,14 @@ public: virtual void end_frame(FrameMode mode, Thread *current_thread); virtual void begin_flip(); - virtual void set_properties_now(WindowProperties &properties); - protected: virtual void close_window(); virtual bool open_window(); +private: + ButtonHandle translate_key(int &keycode, int os_code, unsigned int flags) const; + void transition_button(unsigned int flag, ButtonHandle button); + private: PT(GraphicsBuffer) _buffer; PT(Texture) _texture; @@ -80,6 +82,8 @@ private: string _filename; SubprocessWindowBuffer *_swbuffer; + unsigned int _last_event_flags; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/display/subprocessWindowBuffer.h b/panda/src/display/subprocessWindowBuffer.h index 721f86e652..70c14c4b6b 100644 --- a/panda/src/display/subprocessWindowBuffer.h +++ b/panda/src/display/subprocessWindowBuffer.h @@ -75,11 +75,33 @@ public: inline void *open_write_framebuffer(); inline void close_write_framebuffer(); + enum EventSource { + ES_mouse, + ES_keyboard + }; + + enum ButtonTransition { + BT_down, + BT_up, + BT_again // if supported + }; + + enum EventFlags { + EF_mouse_position = 0x0001, + EF_shift_held = 0x0002, + EF_control_held = 0x0004, + EF_alt_held = 0x0008, + EF_meta_held = 0x0010, + EF_caps_lock = 0x0020, + }; + class Event { public: - // int _key; TODO. - bool _up; - int _x, _y; // position of mouse at the time of the event + EventSource _source; + int _code; // mouse button, or os-specific keycode. + ButtonTransition _trans; + int _x, _y; // position of mouse at the time of the event, if EF_mouse_position is set + unsigned int _flags; }; inline bool add_event(const Event &event);