diff --git a/panda/src/display/windowHandle.cxx b/panda/src/display/windowHandle.cxx index 0fa64bffcb..a030a936e5 100644 --- a/panda/src/display/windowHandle.cxx +++ b/panda/src/display/windowHandle.cxx @@ -27,18 +27,18 @@ WindowHandle:: } //////////////////////////////////////////////////////////////////// -// Function: WindowHandle::send_keyboard_event +// Function: WindowHandle::send_windows_message // Access: Published // Description: Call this method on a parent WindowHandle to deliver -// a button event to the current child window, if any. +// a Windows message to the current child window, if any. // This is used in the web plugin system to deliver // button events detected directly by the browser system -// into Panda. +// into Panda, which is particularly necessary on Vista. //////////////////////////////////////////////////////////////////// void WindowHandle:: -send_keyboard_event(const ButtonEvent &event) { +send_windows_message(unsigned int msg, int wparam, int lparam) { if (_keyboard_window != NULL) { - _keyboard_window->receive_keyboard_event(event); + _keyboard_window->receive_windows_message(msg, wparam, lparam); } } @@ -106,13 +106,14 @@ request_keyboard_focus(WindowHandle *child) { } //////////////////////////////////////////////////////////////////// -// Function: WindowHandle::receive_keyboard_event +// Function: WindowHandle::receive_windows_message // Access: Public, Virtual // Description: Called on a child handle to deliver a keyboard button // event generated in the parent window. //////////////////////////////////////////////////////////////////// void WindowHandle:: -receive_keyboard_event(const ButtonEvent &event) { +receive_windows_message(unsigned int msg, int wparam, int lparam) { + nout << "receive_windows_message(" << msg << ", " << wparam << ", " << lparam << ")\n"; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/windowHandle.h b/panda/src/display/windowHandle.h index 10204bdfe0..54ad80cba3 100644 --- a/panda/src/display/windowHandle.h +++ b/panda/src/display/windowHandle.h @@ -20,8 +20,6 @@ #include "typedReferenceCount.h" #include "pointerTo.h" -class ButtonEvent; - //////////////////////////////////////////////////////////////////// // Class : WindowHandle // Description : This object represents a window on the desktop, not @@ -50,7 +48,7 @@ PUBLISHED: INLINE OSHandle *get_os_handle() const; INLINE void set_os_handle(OSHandle *os_handle); - void send_keyboard_event(const ButtonEvent &event); + void send_windows_message(unsigned int msg, int wparam, int lparam); size_t get_int_handle() const; @@ -62,7 +60,7 @@ public: virtual void detach_child(WindowHandle *child); virtual void request_keyboard_focus(WindowHandle *child); - virtual void receive_keyboard_event(const ButtonEvent &event); + virtual void receive_windows_message(unsigned int msg, int wparam, int lparam); PUBLISHED: // This internal pointer within WindowHandle stores the actual diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index f74be43b39..8a2b867eb9 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -33,6 +33,7 @@ TypeHandle WinGraphicsWindow::_type_handle; +TypeHandle WinGraphicsWindow::WinWindowHandle::_type_handle; WinGraphicsWindow::WindowHandles WinGraphicsWindow::_window_handles; WinGraphicsWindow *WinGraphicsWindow::_creating_window = NULL; @@ -117,6 +118,9 @@ WinGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, //////////////////////////////////////////////////////////////////// WinGraphicsWindow:: ~WinGraphicsWindow() { + if (_window_handle != (WindowHandle *)NULL) { + DCAST(WinWindowHandle, _window_handle)->clear_window(); + } } //////////////////////////////////////////////////////////////////// @@ -437,6 +441,20 @@ open_window() { Rid.hwndTarget = _hWnd; pRegisterRawInputDevices(&Rid, 1, sizeof (Rid)); } + + // Create a WindowHandle for ourselves + _window_handle = NativeWindowHandle::make_win(_hWnd); + + // Actually, we want a WinWindowHandle. + _window_handle = new WinWindowHandle(this, *_window_handle); + + // And tell our parent window that we're now its child. + if (_parent_window_handle != (WindowHandle *)NULL) { + _parent_window_handle->attach_child(_window_handle); + } + + // set us as the focus window for keyboard input + set_focus(); return true; } @@ -741,6 +759,9 @@ open_fullscreen_window() _properties.set_size(640, 480); } + // No parent window for a fullscreen window. + _parent_window_handle = NULL; + HWND hDesktopWindow = GetDesktopWindow(); HDC scrnDC = GetDC(hDesktopWindow); DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL); @@ -888,6 +909,7 @@ open_regular_window() { } } } + _parent_window_handle = window_handle; if (!_hparent) { _hWnd = CreateWindow(wclass._name.c_str(), title.c_str(), window_style, @@ -905,13 +927,11 @@ open_regular_window() { y_origin = _properties.get_y_origin(); } - nout << "Creating embedded window\n"; _hWnd = CreateWindow(wclass._name.c_str(), title.c_str(), WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS , x_origin,y_origin, x_size, y_size, _hparent, NULL, hinstance, 0); - nout << "Done creating embedded window, _hwnd = " << _hWnd << "\n"; if (_hWnd) { // join our keyboard state with the parents @@ -920,9 +940,6 @@ open_regular_window() { // It causes problems with the browser plugin--it deadlocks when // the parent process is waiting on the child process. //AttachThreadInput(GetWindowThreadProcessId(_hparent,NULL), GetCurrentThreadId(),TRUE); - - // set us as the focus window for keyboard input - SetFocus(_hWnd); WindowProperties properties; properties.set_foreground(true); @@ -1038,8 +1055,52 @@ track_mouse_leaving(HWND hwnd) { } //////////////////////////////////////////////////////////////////// -// Function: WinGraphicsWindow::window_proc +// Function: WinGraphicsWindow::set_focus // Access: Private +// Description: Attempts to set this window as the "focus" window, so +// that keyboard events come here. +//////////////////////////////////////////////////////////////////// +void WinGraphicsWindow:: +set_focus() { + if (SetFocus(_hWnd) == NULL && GetLastError() != 0) { + // If the SetFocus() request failed, maybe we're running in the + // plugin environment on Vista, with UAC enabled. In this case, + // we're not allowed to assign focus to the Panda window for some + // stupid reason. So instead, we have to ask the parent window + // (in the browser process) to proxy our keyboard events for us. + if (_parent_window_handle != NULL && _window_handle != NULL) { + _parent_window_handle->request_keyboard_focus(_window_handle); + } else { + // Otherwise, something is wrong. + windisplay_cat.error() + << "SetFocus failed: " << GetLastError() << "\n"; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: WinGraphicsWindow::receive_windows_message +// Access: Public +// Description: This is called to receive a keyboard event generated +// by proxy by another window in a parent process. This +// hacky system is used in the web plugin system to +// allow the Panda window to receive keyboard events on +// Vista, which doesn't allow the Panda window to set +// keyboard focus to itself. +//////////////////////////////////////////////////////////////////// +void WinGraphicsWindow:: +receive_windows_message(unsigned int msg, int wparam, int lparam) { + // Well, we'll just deliver this directly to window_proc(), + // supplying our own window handle. For the most part, we don't + // care about the window handle anyway, but this might become an + // issue for the IME. TODO: investigate IME issues. + + window_proc(_hWnd, msg, wparam, lparam); +} + +//////////////////////////////////////////////////////////////////// +// Function: WinGraphicsWindow::window_proc +// Access: Public, Virtual // Description: This is the nonstatic window_proc function. It is // called to handle window events for this particular // window. @@ -1226,7 +1287,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { SetCapture(hwnd); _input_devices[0].set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); _input_devices[0].button_down(MouseButton::button(0), get_message_time()); - SetFocus(hwnd); // [gjeon] to get the keyboard event + + // A button-click in the window means to grab the keyboard focus. + set_focus(); break; case WM_MBUTTONDOWN: @@ -1236,7 +1299,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { SetCapture(hwnd); _input_devices[0].set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); _input_devices[0].button_down(MouseButton::button(1), get_message_time()); - SetFocus(hwnd); // [gjeon] to get the keyboard event + // A button-click in the window means to grab the keyboard focus. + set_focus(); break; case WM_RBUTTONDOWN: @@ -1246,7 +1310,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { SetCapture(hwnd); _input_devices[0].set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))); _input_devices[0].button_down(MouseButton::button(2), get_message_time()); - SetFocus(hwnd); // [gjeon] to get the keyboard event + // A button-click in the window means to grab the keyboard focus. + set_focus(); break; case WM_XBUTTONDOWN: @@ -2469,6 +2534,45 @@ register_window_class(const WindowProperties &props) { return wclass; } +//////////////////////////////////////////////////////////////////// +// Function: WinGraphicsWindow::WinWindowHandle::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +WinGraphicsWindow::WinWindowHandle:: +WinWindowHandle(WinGraphicsWindow *window, const WindowHandle ©) : + WindowHandle(copy), + _window(window) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: WinGraphicsWindow::WinWindowHandle::clear_window +// Access: Public +// Description: Should be called by the WinGraphicsWindow's +// destructor, so that we don't end up with a floating +// pointer should this object persist beyond the +// lifespan of its window. +//////////////////////////////////////////////////////////////////// +void WinGraphicsWindow::WinWindowHandle:: +clear_window() { + _window = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: WinGraphicsWindow::WinWindowHandle::receive_windows_message +// Access: Public, Virtual +// Description: Called on a child handle to deliver a keyboard button +// event generated in the parent window. +//////////////////////////////////////////////////////////////////// +void WinGraphicsWindow::WinWindowHandle:: +receive_windows_message(unsigned int msg, int wparam, int lparam) { + if (_window != NULL) { + _window->receive_windows_message(msg, wparam, lparam); + } +} + + // pops up MsgBox w/system error msg void PrintErrorMessage(DWORD msgID) { LPTSTR pMessageBuffer; @@ -2535,5 +2639,3 @@ void get_client_rect_screen(HWND hwnd, RECT *view_rect) { view_rect->right = lr.x; view_rect->bottom = lr.y; } - - diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index 0bd7736ad9..9afbf71aac 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -62,6 +62,7 @@ public: virtual void process_events(); virtual void set_properties_now(WindowProperties &properties); + void receive_windows_message(unsigned int msg, int wparam, int lparam); virtual LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); virtual bool handle_mouse_motion(int x, int y); @@ -97,6 +98,8 @@ private: void handle_raw_input(HRAWINPUT hraw); void track_mouse_leaving(HWND hwnd); + void set_focus(); + static void process_1_event(); INLINE void handle_keypress(ButtonHandle key, int x, int y, double time); @@ -213,6 +216,41 @@ private: static int _window_class_index; static const WindowClass ®ister_window_class(const WindowProperties &props); +private: + // This subclass of WindowHandle is stored in _window_handle to + // represent this particular window. We use it to add hooks for + // communicating with the parent window, in particular to receive + // keyboard events from the parent window when necessary. + class WinWindowHandle : public WindowHandle { + public: + WinWindowHandle(WinGraphicsWindow *window, + const WindowHandle ©); + void clear_window(); + + protected: + virtual void receive_windows_message(unsigned int msg, int wparam, int lparam); + + private: + // Not reference-counted, to avoid a circular reference count. + WinGraphicsWindow *_window; + + public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + WindowHandle::init_type(); + register_type(_type_handle, "WinWindowHandle", + WindowHandle::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + + private: + static TypeHandle _type_handle; + }; public: static TypeHandle get_class_type() { @@ -222,6 +260,7 @@ public: GraphicsWindow::init_type(); register_type(_type_handle, "WinGraphicsWindow", GraphicsWindow::get_class_type()); + WinWindowHandle::init_type(); } virtual TypeHandle get_type() const { return get_class_type();