finish workaround for Vista keyboard issue

This commit is contained in:
David Rose 2009-10-02 20:23:09 +00:00
parent 8061092d8e
commit 13877e26b1
14 changed files with 260 additions and 51 deletions

View File

@ -13,11 +13,14 @@
////////////////////////////////////////////////////////////////////
#include "binaryXml.h"
#include "p3d_lock.h"
#include <sstream>
static const bool debug_xml_output = false;
static LOCK xml_lock;
static bool xml_lock_initialized = false;
#define DO_BINARY_XML 1
enum NodeType {
@ -251,6 +254,11 @@ read_xml_node(istream &in, char *&buffer, size_t &buffer_length,
////////////////////////////////////////////////////////////////////
void
write_xml(ostream &out, TiXmlDocument *doc, ostream &logfile) {
if (!xml_lock_initialized) {
INIT_LOCK(xml_lock);
}
ACQUIRE_LOCK(xml_lock);
#ifdef DO_BINARY_XML
// Binary write.
write_xml_node(out, doc);
@ -274,6 +282,8 @@ write_xml(ostream &out, TiXmlDocument *doc, ostream &logfile) {
logout << "sent: " << *doc << "\n";
logfile << logout.str() << flush;
}
RELEASE_LOCK(xml_lock);
}
////////////////////////////////////////////////////////////////////
@ -291,6 +301,11 @@ write_xml(ostream &out, TiXmlDocument *doc, ostream &logfile) {
////////////////////////////////////////////////////////////////////
TiXmlDocument *
read_xml(istream &in, ostream &logfile) {
if (!xml_lock_initialized) {
INIT_LOCK(xml_lock);
}
ACQUIRE_LOCK(xml_lock);
#if DO_BINARY_XML
// binary read.
size_t buffer_length = 128;
@ -298,6 +313,7 @@ read_xml(istream &in, ostream &logfile) {
TiXmlNode *xnode = read_xml_node(in, buffer, buffer_length, logfile);
delete[] buffer;
if (xnode == NULL) {
RELEASE_LOCK(xml_lock);
return NULL;
}
@ -310,6 +326,7 @@ read_xml(istream &in, ostream &logfile) {
in >> *doc;
if (in.fail() || in.eof()) {
delete doc;
RELEASE_LOCK(xml_lock);
return NULL;
}
#endif
@ -321,6 +338,7 @@ read_xml(istream &in, ostream &logfile) {
logout << "received: " << *doc << "\n";
logfile << logout.str() << flush;
}
RELEASE_LOCK(xml_lock);
return doc;
}

View File

@ -1426,7 +1426,6 @@ void P3DInstance::
handle_notify_request(const string &message) {
// We look for certain notify events that have particular meaning
// to this instance.
nout << "Got notify: " << message << "\n";
if (message == "onpythonload") {
// Once Python is up and running, we can get the actual main
// object from the Python side, and merge it with our own.
@ -1459,13 +1458,13 @@ handle_notify_request(const string &message) {
} else if (message == "onwindowopen") {
// The process told us that it just succesfully opened its
// window. Tear down the splash window.
// window. Hide the splash window.
_instance_window_opened = true;
if (_splash_window != NULL) {
delete _splash_window;
_splash_window = NULL;
_splash_window->set_visible(false);
}
// Guess we won't be using these images any more.
for (int i = 0; i < (int)IT_num_image_types; ++i) {
_image_files[i].cleanup();
}
@ -1497,7 +1496,9 @@ handle_notify_request(const string &message) {
auth_finished_main_thread();
} else if (message == "keyboardfocus") {
request_keyboard_focus();
if (_splash_window != NULL) {
_splash_window->request_keyboard_focus();
}
}
}
@ -1597,19 +1598,6 @@ handle_script_request(const string &operation, P3D_object *object,
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::request_keyboard_focus
// Access: Private
// Description: The Panda window is asking us to manage keyboard
// focus in proxy for it. This is used on Vista, where
// the Panda window may be disallowed from directly
// assigning itself keyboard focus.
////////////////////////////////////////////////////////////////////
void P3DInstance::
request_keyboard_focus() {
nout << "request_keyboard_focus\n";
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::make_splash_window
// Access: Private
@ -1618,8 +1606,24 @@ request_keyboard_focus() {
////////////////////////////////////////////////////////////////////
void P3DInstance::
make_splash_window() {
if (_splash_window != NULL || _instance_window_opened) {
// Already got one, or we're already showing the real instance.
// Should we make the splash window visible?
bool make_visible = true;
if (_instance_window_opened) {
// Not once we've opened the main window.
make_visible = false;
}
if (_wparams.get_window_type() != P3D_WT_embedded &&
!_stuff_to_download && _auto_start && _p3d_trusted) {
// If it's a toplevel or fullscreen window, then we don't want a
// splash window unless we have stuff to download, or a button to
// display.
make_visible = false;
}
if (_splash_window != NULL) {
// Already got one.
_splash_window->set_visible(make_visible);
return;
}
if (!_got_wparams) {
@ -1630,18 +1634,11 @@ make_splash_window() {
// We're hidden, and so is the splash window.
return;
}
if (_wparams.get_window_type() != P3D_WT_embedded &&
!_stuff_to_download && _auto_start && _p3d_trusted) {
// If it's a toplevel or fullscreen window, then we don't want a
// splash window unless we have stuff to download, or a button to
// display.
return;
}
_splash_window = new SplashWindowType(this);
_splash_window = new SplashWindowType(this, make_visible);
_splash_window->set_wparams(_wparams);
_splash_window->set_install_label(_install_label);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
// Go get the required images.

View File

@ -162,7 +162,6 @@ private:
void handle_script_request(const string &operation, P3D_object *object,
const string &property_name, P3D_object *value,
bool needs_response, int unique_id);
void request_keyboard_focus();
void make_splash_window();
void set_background_image(ImageType image_type);

View File

@ -29,8 +29,8 @@
// Description:
////////////////////////////////////////////////////////////////////
P3DOsxSplashWindow::
P3DOsxSplashWindow(P3DInstance *inst) :
P3DSplashWindow(inst)
P3DOsxSplashWindow(P3DInstance *inst, bool make_visible) :
P3DSplashWindow(inst, make_visible)
{
_install_progress = 0;
_got_wparams = false;
@ -226,10 +226,13 @@ handle_event(P3D_event_data event) {
////////////////////////////////////////////////////////////////////
void P3DOsxSplashWindow::
refresh() {
if (!_visible) {
return;
}
if (_toplevel_window != NULL) {
Rect r = { 0, 0, _win_height, _win_width };
InvalWindowRect(_toplevel_window, &r);
} else {
_inst->request_refresh();
}
@ -242,7 +245,7 @@ refresh() {
////////////////////////////////////////////////////////////////////
void P3DOsxSplashWindow::
paint_window() {
if (!_got_wparams) {
if (!_visible) {
return;
}

View File

@ -30,7 +30,7 @@
////////////////////////////////////////////////////////////////////
class P3DOsxSplashWindow : public P3DSplashWindow {
public:
P3DOsxSplashWindow(P3DInstance *inst);
P3DOsxSplashWindow(P3DInstance *inst, bool make_visible);
virtual ~P3DOsxSplashWindow();
virtual void set_wparams(const P3DWindowParams &wparams);

View File

@ -403,8 +403,6 @@ run_python() {
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
request_keyboard_focus(P3DCInstance *inst) {
cerr << "requesting keyboard focus\n";
TiXmlDocument doc;
TiXmlElement *xrequest = new TiXmlElement("request");
xrequest->SetAttribute("instance_id", inst->get_instance_id());
@ -509,6 +507,18 @@ handle_command(TiXmlDocument *doc) {
setup_window(instance_id, xwparams);
}
} else if (strcmp(cmd, "windows_message") == 0) {
assert(!needs_response);
// This is a special message that we use to proxy keyboard
// events from the parent process down into Panda, a necessary
// hack on Vista.
int instance_id = 0, msg = 0, wparam = 0, lparam = 0;
xcommand->Attribute("instance_id", &instance_id);
xcommand->Attribute("msg", &msg);
xcommand->Attribute("wparam", &wparam);
xcommand->Attribute("lparam", &lparam);
send_windows_message(instance_id, msg, wparam, lparam);
} else if (strcmp(cmd, "exit") == 0) {
assert(!needs_response);
terminate_session();
@ -1362,6 +1372,25 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) {
Py_XDECREF(result);
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::send_windows_message
// Access: Public
// Description: This is used to deliver a windows keyboard message to
// the Panda process from the parent process, a
// necessary hack on Vista.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
send_windows_message(int id, unsigned int msg, int wparam, int lparam) {
Instances::iterator ii = _instances.find(id);
if (ii == _instances.end()) {
return;
}
P3DCInstance *inst = (*ii).second;
if (inst->_parent_window_handle != (WindowHandle *)NULL) {
inst->_parent_window_handle->send_windows_message(msg, wparam, lparam);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::terminate_session
@ -1719,7 +1748,7 @@ rt_thread_run() {
P3DPythonRun::P3DWindowHandle::
P3DWindowHandle(P3DPythonRun *p3dpython, P3DCInstance *inst,
const WindowHandle &copy) :
WindowHandle(copy.get_os_handle()),
WindowHandle(copy),
_p3dpython(p3dpython),
_inst(inst)
{

View File

@ -100,6 +100,8 @@ private:
void set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams);
void setup_window(int id, TiXmlElement *xwparams);
void setup_window(P3DCInstance *inst, TiXmlElement *xwparams);
void send_windows_message(int id, unsigned int msg, int wparam, int lparam);
void terminate_session();
@ -108,7 +110,7 @@ private:
PyObject *xml_to_pyobj(TiXmlElement *xvalue);
private:
// This subclass of P3DWindowHandle is associated with the parent
// This subclass of WindowHandle is associated with the parent
// window we are given by the parent process. We use it to add
// hooks for communicating with the parent window, for instance to
// ask for the parent window to manage keyboard focus when
@ -118,13 +120,13 @@ private:
P3DWindowHandle(P3DPythonRun *p3dpython, P3DCInstance *inst,
const WindowHandle &copy);
protected:
virtual void request_keyboard_focus(WindowHandle *child);
private:
P3DPythonRun *_p3dpython;
P3DCInstance *_inst;
protected:
virtual void request_keyboard_focus(WindowHandle *child);
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -583,6 +583,29 @@ p3dobj_to_xml(P3D_object *obj) {
return xvalue;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::send_windows_message
// Access: Public
// Description: This is called by the splash window to deliver a
// windows keyboard message to the Panda process. It
// will be called in a sub-thread, but that's OK, since
// write_xml() supports locking.
////////////////////////////////////////////////////////////////////
void P3DSession::
send_windows_message(P3DInstance *inst, unsigned int msg, int wparam, int lparam) {
if (_p3dpython_started) {
TiXmlDocument doc;
TiXmlElement *xcommand = new TiXmlElement("command");
xcommand->SetAttribute("cmd", "windows_message");
xcommand->SetAttribute("instance_id", inst->get_instance_id());
xcommand->SetAttribute("msg", msg);
xcommand->SetAttribute("wparam", wparam);
xcommand->SetAttribute("lparam", lparam);
doc.LinkEndChild(xcommand);
write_xml(_pipe_write, &doc, nout);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::signal_request_ready
// Access: Public

View File

@ -54,6 +54,8 @@ public:
TiXmlDocument *command_and_response(TiXmlDocument *command);
P3D_object *xml_to_p3dobj(const TiXmlElement *xvalue);
TiXmlElement *p3dobj_to_xml(P3D_object *obj);
void send_windows_message(P3DInstance *inst, unsigned int msg,
int wparam, int lparam);
void signal_request_ready(P3DInstance *inst);

View File

@ -49,11 +49,12 @@ METHODDEF(void) my_error_exit (j_common_ptr cinfo) {
// them both into this class for reference.
////////////////////////////////////////////////////////////////////
P3DSplashWindow::
P3DSplashWindow(P3DInstance *inst) :
P3DSplashWindow(P3DInstance *inst, bool make_visible) :
_inst(inst),
_fparams(inst->get_fparams()),
_wparams(inst->get_wparams())
{
_visible = make_visible;
_button_width = 0;
_button_height = 0;
_button_x = 0;
@ -87,6 +88,20 @@ set_wparams(const P3DWindowParams &wparams) {
_wparams = wparams;
_win_width = _wparams.get_win_width();
_win_height = _wparams.get_win_height();
_visible = true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_visible
// Access: Public, Virtual
// Description: Makes the splash window visible or invisible, so as
// not to compete with the embedded Panda window in the
// same space.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_visible(bool visible) {
nout << "P3DSplashWindow::set_visible(" << visible << ")\n";
_visible = visible;
}
////////////////////////////////////////////////////////////////////
@ -152,6 +167,18 @@ set_button_active(bool flag) {
set_mouse_data(_mouse_x, _mouse_y, _mouse_down);
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::request_keyboard_focus
// Access: Private
// Description: The Panda window is asking us to manage keyboard
// focus in proxy for it. This is used on Vista, where
// the Panda window may be disallowed from directly
// assigning itself keyboard focus.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
request_keyboard_focus() {
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::read_image_data
// Access: Protected

View File

@ -33,7 +33,7 @@ class P3DInstance;
////////////////////////////////////////////////////////////////////
class P3DSplashWindow {
public:
P3DSplashWindow(P3DInstance *inst);
P3DSplashWindow(P3DInstance *inst, bool make_visible);
virtual ~P3DSplashWindow();
inline const P3DFileParams &get_fparams() const;
@ -41,6 +41,8 @@ public:
virtual void set_wparams(const P3DWindowParams &wparams);
inline const P3DWindowParams &get_wparams() const;
virtual void set_visible(bool visible);
enum ImagePlacement {
IP_background,
IP_button_ready,
@ -57,6 +59,7 @@ public:
virtual bool handle_event(P3D_event_data event);
virtual void set_button_active(bool flag);
virtual void request_keyboard_focus();
protected:
// This ImageData base class provides minimal functionality for
@ -96,6 +99,7 @@ protected:
P3DFileParams _fparams;
P3DWindowParams _wparams;
int _win_width, _win_height;
bool _visible;
// The region of the window for accepting button clicks.
int _button_width, _button_height;

View File

@ -16,6 +16,10 @@
#ifdef _WIN32
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL 0x20a
#endif
bool P3DWinSplashWindow::_registered_window_class = false;
////////////////////////////////////////////////////////////////////
@ -24,8 +28,8 @@ bool P3DWinSplashWindow::_registered_window_class = false;
// Description:
////////////////////////////////////////////////////////////////////
P3DWinSplashWindow::
P3DWinSplashWindow(P3DInstance *inst) :
P3DSplashWindow(inst)
P3DWinSplashWindow(P3DInstance *inst, bool make_visible) :
P3DSplashWindow(inst, make_visible)
{
_thread = NULL;
_thread_id = 0;
@ -36,6 +40,9 @@ P3DWinSplashWindow(P3DInstance *inst) :
_drawn_bstate = BS_hidden;
_drawn_progress = 0.0;
_focus_seq = 0;
_request_focus_tick = 0;
INIT_LOCK(_install_lock);
}
@ -68,6 +75,24 @@ set_wparams(const P3DWindowParams &wparams) {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::set_visible
// Access: Public, Virtual
// Description: Makes the splash window visible or invisible, so as
// not to compete with the embedded Panda window in the
// same space.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
set_visible(bool visible) {
P3DSplashWindow::set_visible(visible);
if (_visible) {
ShowWindow(_hwnd, SW_SHOWNORMAL);
} else {
ShowWindow(_hwnd, SW_HIDE);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::set_image_filename
// Access: Public, Virtual
@ -166,6 +191,30 @@ set_install_progress(double install_progress) {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::request_keyboard_focus
// Access: Private
// Description: The Panda window is asking us to manage keyboard
// focus in proxy for it. This is used on Vista, where
// the Panda window may be disallowed from directly
// assigning itself keyboard focus.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
request_keyboard_focus() {
// Store the time at which we last requested focus.
_request_focus_tick = GetTickCount();
// Increment the _focus_seq to tell the thread to call SetFocus().
ACQUIRE_LOCK(_install_lock);
++_focus_seq;
RELEASE_LOCK(_install_lock);
if (_thread_id != 0) {
// Post a silly message to spin the message loop.
PostThreadMessage(_thread_id, WM_USER, 0, 0);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::register_window_class
// Access: Public, Static
@ -277,6 +326,7 @@ void P3DWinSplashWindow::
thread_run() {
make_window();
int last_focus_seq = 0;
MSG msg;
int retval;
retval = GetMessage(&msg, NULL, 0, 0);
@ -312,6 +362,14 @@ thread_run() {
_drawn_bstate = _bstate;
InvalidateRect(_hwnd, NULL, TRUE);
}
if (_focus_seq != last_focus_seq) {
last_focus_seq = _focus_seq;
if (SetFocus(_hwnd) == NULL && GetLastError() != 0) {
nout << "SetFocus(" << _hwnd << ") failed: " << GetLastError() << "\n";
}
}
RELEASE_LOCK(_install_lock);
retval = GetMessage(&msg, NULL, 0, 0);
@ -396,7 +454,13 @@ make_window() {
}
}
SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this);
ShowWindow(_hwnd, SW_SHOWNORMAL);
nout << "Created splash window " << _hwnd << "\n";
if (_visible) {
ShowWindow(_hwnd, SW_SHOWNORMAL);
} else {
ShowWindow(_hwnd, SW_HIDE);
}
_blue_brush = CreateSolidBrush(RGB(108, 165, 224));
}
@ -802,6 +866,41 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
set_mouse_data(_mouse_x, _mouse_y, false);
ReleaseCapture();
break;
case WM_KILLFOCUS:
// Someone on the desktop is playing games with us. It keeps
// wanting to grab the keyboard focus back immediately after we
// successfully call SetFocus(). Well, we really mean it, darn it
// all. If we got a WM_KILLFOCUS within a few milliseconds of
// calling SetFocus(), well, call SetFocus() again, until it
// sticks.
{
int elapsed = GetTickCount() - _request_focus_tick;
if (elapsed < 200) {
if (SetFocus(_hwnd) == NULL && GetLastError() != 0) {
nout << "Secondary SetFocus failed: " << GetLastError() << "\n";
}
}
}
break;
// Keyboard events that are to be proxied to the Panda window.
case WM_MOUSEWHEEL:
case WM_IME_SETCONTEXT:
case WM_IME_NOTIFY:
case WM_IME_STARTCOMPOSITION:
case WM_IME_ENDCOMPOSITION:
case WM_IME_COMPOSITION:
case WM_CHAR:
case WM_SYSKEYDOWN:
case WM_SYSCOMMAND:
case WM_KEYDOWN:
case WM_SYSKEYUP:
case WM_KEYUP:
if (_inst->get_session() != NULL) {
_inst->get_session()->send_windows_message(_inst, msg, wparam, lparam);
}
break;
};
return DefWindowProc(hwnd, msg, wparam, lparam);

View File

@ -31,14 +31,17 @@
////////////////////////////////////////////////////////////////////
class P3DWinSplashWindow : public P3DSplashWindow {
public:
P3DWinSplashWindow(P3DInstance *inst);
P3DWinSplashWindow(P3DInstance *inst, bool make_visible);
virtual ~P3DWinSplashWindow();
virtual void set_wparams(const P3DWindowParams &wparams);
virtual void set_visible(bool visible);
virtual void set_image_filename(const string &image_filename,
ImagePlacement image_placement);
virtual void set_install_label(const string &install_label);
virtual void set_install_progress(double install_progress);
virtual void request_keyboard_focus();
static void register_window_class();
static void unregister_window_class();
@ -92,6 +95,9 @@ private:
ButtonState _drawn_bstate;
string _drawn_label;
double _drawn_progress;
int _focus_seq;
int _request_focus_tick;
bool _thread_continue;
bool _thread_running;

View File

@ -34,7 +34,7 @@
////////////////////////////////////////////////////////////////////
class P3DX11SplashWindow : public P3DSplashWindow {
public:
P3DX11SplashWindow(P3DInstance *inst);
P3DX11SplashWindow(P3DInstance *inst, bool make_visible);
virtual ~P3DX11SplashWindow();
virtual void set_wparams(const P3DWindowParams &wparams);