add support for OS time for keypress/release

This commit is contained in:
David Rose 2003-12-26 20:26:56 +00:00
parent f3dc49baed
commit 038230f7ec
12 changed files with 268 additions and 155 deletions

View File

@ -594,6 +594,20 @@ class ShowBase(DirectObject.DirectObject):
mods.addButton(KeyboardButton.alt())
self.buttonThrower.node().setModifierButtons(mods)
# A special ButtonThrower to generate keyboard events and
# include the time from the OS. This is separate only to
# support legacy code that did not expect a time parameter; it
# will eventually be folded into the normal ButtonThrower,
# above.
# Temporary hasattr() for old pandas.
if hasattr(ButtonThrower, "setTimeFlag"):
self.timeButtonThrower = self.mouseWatcher.attachNewNode(ButtonThrower('timeButtons'))
self.timeButtonThrower.node().setPrefix('time-')
self.timeButtonThrower.node().setTimeFlag(1)
else:
self.timeButtonThrower = None
# Tell the gui system about our new mouse watcher.
self.aspect2d.node().setMouseWatcher(self.mouseWatcherNode)
self.mouseWatcherNode.addRegion(PGMouseWatcherBackground())

View File

@ -154,8 +154,8 @@ get_button_event() {
// Description: Records that the indicated button has been depressed.
////////////////////////////////////////////////////////////////////
void GraphicsWindowInputDevice::
button_down(ButtonHandle button) {
_button_events.push_back(ButtonEvent(button, ButtonEvent::T_down));
button_down(ButtonHandle button, double time) {
_button_events.push_back(ButtonEvent(button, ButtonEvent::T_down, time));
}
////////////////////////////////////////////////////////////////////
@ -167,8 +167,8 @@ button_down(ButtonHandle button) {
// state of modifier keys.
////////////////////////////////////////////////////////////////////
void GraphicsWindowInputDevice::
button_resume_down(ButtonHandle button) {
_button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down));
button_resume_down(ButtonHandle button, double time) {
_button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down, time));
}
////////////////////////////////////////////////////////////////////
@ -177,8 +177,8 @@ button_resume_down(ButtonHandle button) {
// Description: Records that the indicated button has been released.
////////////////////////////////////////////////////////////////////
void GraphicsWindowInputDevice::
button_up(ButtonHandle button) {
_button_events.push_back(ButtonEvent(button, ButtonEvent::T_up));
button_up(ButtonHandle button, double time) {
_button_events.push_back(ButtonEvent(button, ButtonEvent::T_up, time));
}
////////////////////////////////////////////////////////////////////
@ -188,6 +188,6 @@ button_up(ButtonHandle button) {
// generated.
////////////////////////////////////////////////////////////////////
void GraphicsWindowInputDevice::
keystroke(int keycode) {
_button_events.push_back(ButtonEvent(keycode));
keystroke(int keycode, double time) {
_button_events.push_back(ButtonEvent(keycode, time));
}

View File

@ -23,6 +23,7 @@
#include "buttonEvent.h"
#include "mouseData.h"
#include "clockObject.h"
#include "pdeque.h"
#include "pvector.h"
@ -61,10 +62,10 @@ public:
public:
// The following interface is for the various kinds of
// GraphicsWindows to record the data incoming on the device.
void button_down(ButtonHandle button);
void button_resume_down(ButtonHandle button);
void button_up(ButtonHandle button);
void keystroke(int keycode);
void button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
void button_resume_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
void button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
void keystroke(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
INLINE void set_pointer_in_window(int x, int y);
INLINE void set_pointer_out_of_window();

View File

@ -26,7 +26,8 @@ INLINE ButtonEvent::
ButtonEvent() :
_button(ButtonHandle::none()),
_keycode(0),
_type(T_down)
_type(T_down),
_time(0.0)
{
}
@ -36,10 +37,11 @@ ButtonEvent() :
// Description:
////////////////////////////////////////////////////////////////////
INLINE ButtonEvent::
ButtonEvent(ButtonHandle button, ButtonEvent::Type type) :
ButtonEvent(ButtonHandle button, ButtonEvent::Type type, double time) :
_button(button),
_keycode(0),
_type(type)
_type(type),
_time(time)
{
}
@ -49,10 +51,11 @@ ButtonEvent(ButtonHandle button, ButtonEvent::Type type) :
// Description:
////////////////////////////////////////////////////////////////////
INLINE ButtonEvent::
ButtonEvent(short keycode) :
ButtonEvent(short keycode, double time) :
_button(ButtonHandle::none()),
_keycode(keycode),
_type(T_keystroke)
_type(T_keystroke),
_time(time)
{
}
@ -65,7 +68,8 @@ INLINE ButtonEvent::
ButtonEvent(const ButtonEvent &copy) :
_button(copy._button),
_keycode(copy._keycode),
_type(copy._type)
_type(copy._type),
_time(copy._time)
{
}
@ -79,12 +83,14 @@ operator = (const ButtonEvent &copy) {
_button = copy._button;
_keycode = copy._keycode;
_type = copy._type;
_time = copy._time;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEvent::Equality Operator
// Access: Public
// Description:
// Description: The equality operator does not consider time
// significant.
////////////////////////////////////////////////////////////////////
INLINE bool ButtonEvent::
operator == (const ButtonEvent &other) const {

View File

@ -22,6 +22,7 @@
#include "pandabase.h"
#include "buttonHandle.h"
#include "clockObject.h"
////////////////////////////////////////////////////////////////////
// Class : ButtonEvent
@ -71,8 +72,8 @@ public:
};
INLINE ButtonEvent();
INLINE ButtonEvent(ButtonHandle button, Type type);
INLINE ButtonEvent(short keycode);
INLINE ButtonEvent(ButtonHandle button, Type type, double time = ClockObject::get_global_clock()->get_frame_time());
INLINE ButtonEvent(short keycode, double time = ClockObject::get_global_clock()->get_frame_time());
INLINE ButtonEvent(const ButtonEvent &copy);
INLINE void operator = (const ButtonEvent &copy);
@ -90,7 +91,14 @@ public:
// the Unicode character that was typed.
short _keycode;
// This is the type of the button event (see above).
Type _type;
// This is the time the event occurred, as recorded from the OS if
// that information is available. It is in seconds elapsed from an
// arbitrary epoch, and it matches the time reported by
// ClockObject::get_global_clock().
double _time;
};
INLINE ostream &operator << (ostream &out, const ButtonEvent &be) {

View File

@ -10,7 +10,7 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
buttonThrower.h \
buttonThrower.I buttonThrower.h \
config_tform.h \
driveInterface.I driveInterface.h \
mouseWatcher.I mouseWatcher.h \
@ -31,7 +31,7 @@
transform2sg.cxx
#define INSTALL_HEADERS \
buttonThrower.h \
buttonThrower.I buttonThrower.h \
driveInterface.I driveInterface.h \
mouseWatcher.I mouseWatcher.h \
mouseWatcherGroup.h \

View File

@ -0,0 +1,148 @@
// Filename: buttonThrower.I
// Created by: drose (26Dec03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::set_prefix
// Access: Published
// Description: Sets the prefix which is prepended to all event names
// thrown by this object.
////////////////////////////////////////////////////////////////////
INLINE void ButtonThrower::
set_prefix(const string &prefix) {
_prefix = prefix;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::has_prefix
// Access: Published
// Description: Returns true if the ButtonThrower has a prefix set,
// false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool ButtonThrower::
has_prefix() const {
return !_prefix.empty();
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::get_prefix
// Access: Published
// Description: Returns the prefix that has been set on this
// ButtonThrower. See set_prefix().
////////////////////////////////////////////////////////////////////
INLINE string ButtonThrower::
get_prefix() const {
return _prefix;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::set_time_flag
// Access: Published
// Description: Sets the flag that indicates whether the time of the
// button event should be passed as a parameter or not.
// When this is true, an additional parameter is
// generated on each event (before all the parameters
// named by add_parameter) that consists of a single
// double value, and reflects the time the button was
// pressed or released, as a value from
// ClockObject::get_global_clock().
////////////////////////////////////////////////////////////////////
INLINE void ButtonThrower::
set_time_flag(bool time_flag) {
_time_flag = time_flag;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::get_time_flag
// Access: Published
// Description: Returns the flag that indicates whether the time of
// the button event should be passed as a parameter.
////////////////////////////////////////////////////////////////////
INLINE bool ButtonThrower::
get_time_flag() const {
return _time_flag;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::get_modifier_buttons
// Access: Published
// Description: Returns the set of ModifierButtons that the
// ButtonThrower will consider important enough to
// prepend the event name with. Normally, this set will
// be empty, and the ButtonThrower will therefore ignore
// all ModifierButtons attached to the key events, but
// if one or more buttons have been added to this set,
// and those modifier buttons are set on the button
// event, then the event name will be prepended with the
// names of the modifier buttons.
////////////////////////////////////////////////////////////////////
INLINE const ModifierButtons &ButtonThrower::
get_modifier_buttons() const {
return _mods;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::set_modifier_buttons
// Access: Published
// Description: Changes the set of ModifierButtons that the
// ButtonThrower will consider important enough to
// prepend the event name with. Normally, this set will
// be empty, and the ButtonThrower will therefore ignore
// all ModifierButtons attached to the key events, but
// if one or more buttons have been added to this set,
// then the event name will be prepended with the names
// of the modifier buttons.
//
// It is recommended that you change this setting by
// first calling get_modifier_buttons(), making
// adjustments, and passing the new value to
// set_modifier_buttons(). This way the current state
// of the modifier buttons will not be lost.
////////////////////////////////////////////////////////////////////
INLINE void ButtonThrower::
set_modifier_buttons(const ModifierButtons &mods) {
_mods = mods;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::set_throw_buttons_active
// Access: Published
// Description: Sets the flag that indicates whether the
// ButtonThrower will only process events for the
// explicitly named buttons or not. Normally this is
// false, meaning all buttons are processed; set it true
// to indicate that only some buttons should be
// processed. See add_throw_button().
////////////////////////////////////////////////////////////////////
INLINE void ButtonThrower::
set_throw_buttons_active(bool flag) {
_throw_buttons_active = flag;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::get_throw_buttons_active
// Access: Published
// Description: Returns the flag that indicates whether the
// ButtonThrower will only process events for the
// explicitly named buttons or not. See
// set_throw_buttons_active().
////////////////////////////////////////////////////////////////////
INLINE bool ButtonThrower::
get_throw_buttons_active() const {
return _throw_buttons_active;
}

View File

@ -43,6 +43,7 @@ ButtonThrower(const string &name) :
_button_events = new ButtonEventList;
_time_flag = false;
_throw_buttons_active = false;
}
@ -56,40 +57,6 @@ ButtonThrower::
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::set_prefix
// Access: Published
// Description: Sets the prefix which is prepended to all event names
// thrown by this object.
////////////////////////////////////////////////////////////////////
void ButtonThrower::
set_prefix(const string &prefix) {
_prefix = prefix;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::has_prefix
// Access: Published
// Description: Returns true if the ButtonThrower has a prefix set,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool ButtonThrower::
has_prefix() const {
return !_prefix.empty();
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::get_prefix
// Access: Published
// Description: Returns the prefix that has been set on this
// ButtonThrower. See set_prefix().
////////////////////////////////////////////////////////////////////
string ButtonThrower::
get_prefix() const {
return _prefix;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::add_parameter
// Access: Public
@ -128,75 +95,6 @@ get_parameter(int n) const {
return _parameters[n];
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::get_modifier_buttons
// Access: Published
// Description: Returns the set of ModifierButtons that the
// ButtonThrower will consider important enough to
// prepend the event name with. Normally, this set will
// be empty, and the ButtonThrower will therefore ignore
// all ModifierButtons attached to the key events, but
// if one or more buttons have been added to this set,
// and those modifier buttons are set on the button
// event, then the event name will be prepended with the
// names of the modifier buttons.
////////////////////////////////////////////////////////////////////
const ModifierButtons &ButtonThrower::
get_modifier_buttons() const {
return _mods;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::set_modifier_buttons
// Access: Published
// Description: Changes the set of ModifierButtons that the
// ButtonThrower will consider important enough to
// prepend the event name with. Normally, this set will
// be empty, and the ButtonThrower will therefore ignore
// all ModifierButtons attached to the key events, but
// if one or more buttons have been added to this set,
// then the event name will be prepended with the names
// of the modifier buttons.
//
// It is recommended that you change this setting by
// first calling get_modifier_buttons(), making
// adjustments, and passing the new value to
// set_modifier_buttons(). This way the current state
// of the modifier buttons will not be lost.
////////////////////////////////////////////////////////////////////
void ButtonThrower::
set_modifier_buttons(const ModifierButtons &mods) {
_mods = mods;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::set_throw_buttons_active
// Access: Published
// Description: Sets the flag that indicates whether the
// ButtonThrower will only process events for the
// explicitly named buttons or not. Normally this is
// false, meaning all buttons are processed; set it true
// to indicate that only some buttons should be
// processed. See add_throw_button().
////////////////////////////////////////////////////////////////////
void ButtonThrower::
set_throw_buttons_active(bool flag) {
_throw_buttons_active = flag;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::get_throw_buttons_active
// Access: Published
// Description: Returns the flag that indicates whether the
// ButtonThrower will only process events for the
// explicitly named buttons or not. See
// set_throw_buttons_active().
////////////////////////////////////////////////////////////////////
bool ButtonThrower::
get_throw_buttons_active() const {
return _throw_buttons_active;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonThrower::add_throw_button
// Access: Published
@ -370,9 +268,13 @@ write(ostream &out, int indent_level) const {
// all of the user-requested parameters.
////////////////////////////////////////////////////////////////////
void ButtonThrower::
do_throw_event(const string &event_name) {
do_throw_event(const string &event_name, double time) {
Event *event = new Event(_prefix + event_name);
if (_time_flag) {
event->add_parameter(time);
}
ParameterList::const_iterator pi;
for (pi = _parameters.begin(); pi != _parameters.end(); ++pi) {
event->add_parameter(*pi);
@ -419,7 +321,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
if (!_throw_buttons_active || has_throw_button(_mods, be._button)) {
// Process this button.
do_throw_event(event_name);
do_throw_event(event_name, be._time);
} else {
// Don't process this button; instead, pass it down to future
@ -442,7 +344,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
// definition for the button at all, regardless of the state
// of the modifier keys.
if (!_throw_buttons_active || has_throw_button(be._button)) {
do_throw_event(event_name + "-up");
do_throw_event(event_name + "-up", be._time);
}
if (_throw_buttons_active) {
// Now pass the event on to future generations. We always

View File

@ -45,19 +45,22 @@ PUBLISHED:
ButtonThrower(const string &name);
~ButtonThrower();
void set_prefix(const string &prefix);
bool has_prefix() const;
string get_prefix() const;
INLINE void set_prefix(const string &prefix);
INLINE bool has_prefix() const;
INLINE string get_prefix() const;
INLINE void set_time_flag(bool time_flag);
INLINE bool get_time_flag() const;
void add_parameter(const EventParameter &obj);
int get_num_parameters() const;
EventParameter get_parameter(int n) const;
const ModifierButtons &get_modifier_buttons() const;
void set_modifier_buttons(const ModifierButtons &mods);
INLINE const ModifierButtons &get_modifier_buttons() const;
INLINE void set_modifier_buttons(const ModifierButtons &mods);
void set_throw_buttons_active(bool flag);
bool get_throw_buttons_active() const;
INLINE void set_throw_buttons_active(bool flag);
INLINE bool get_throw_buttons_active() const;
bool add_throw_button(const ModifierButtons &mods, const ButtonHandle &button);
bool remove_throw_button(const ModifierButtons &mods, const ButtonHandle &button);
@ -69,12 +72,14 @@ public:
virtual void write(ostream &out, int indent_level = 0) const;
private:
void do_throw_event(const string &event_name);
void do_throw_event(const string &event_name, double time);
private:
string _prefix;
ModifierButtons _mods;
bool _time_flag;
typedef pvector<EventParameter> ParameterList;
ParameterList _parameters;
@ -114,4 +119,6 @@ private:
static TypeHandle _type_handle;
};
#include "buttonThrower.I"
#endif

View File

@ -23,10 +23,10 @@
// Description:
////////////////////////////////////////////////////////////////////
INLINE void WinGraphicsWindow::
handle_keypress(ButtonHandle key, int x, int y) {
handle_keypress(ButtonHandle key, int x, int y, double time) {
_input_devices[0].set_pointer_in_window(x, y);
if (key != ButtonHandle::none()) {
_input_devices[0].button_down(key);
_input_devices[0].button_down(key, time);
}
}
@ -38,9 +38,9 @@ handle_keypress(ButtonHandle key, int x, int y) {
// tracking the state of modifier keys.
////////////////////////////////////////////////////////////////////
INLINE void WinGraphicsWindow::
handle_keyresume(ButtonHandle key) {
handle_keyresume(ButtonHandle key, double time) {
if (key != ButtonHandle::none()) {
_input_devices[0].button_resume_down(key);
_input_devices[0].button_resume_down(key, time);
}
}
@ -50,9 +50,9 @@ handle_keyresume(ButtonHandle key) {
// Description:
////////////////////////////////////////////////////////////////////
INLINE void WinGraphicsWindow::
handle_keyrelease(ButtonHandle key) {
handle_keyrelease(ButtonHandle key, double time) {
if (key != ButtonHandle::none()) {
_input_devices[0].button_up(key);
_input_devices[0].button_up(key, time);
}
}
@ -108,3 +108,19 @@ set_cursor_out_of_window() {
update_cursor_window(NULL);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinGraphicsWindow::get_message_time
// Access: Private, Static
// Description: May be called only during the servicing of a Windows
// message. This returns the time the message was added
// to the Windows message queue (as reported via
// GetMessageTime()), converted into global clock units.
////////////////////////////////////////////////////////////////////
INLINE double WinGraphicsWindow::
get_message_time() {
DWORD now_ticks = GetTickCount();
double now_time = ClockObject::get_global_clock()->get_real_time();
DWORD elapsed_ticks = now_ticks - GetMessageTime();
return now_time - (double)elapsed_ticks / 1000.0;
}

View File

@ -782,7 +782,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
}
SetCapture(hwnd);
handle_keypress(MouseButton::button(button),
translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)),
get_message_time());
break;
case WM_LBUTTONUP:
@ -801,7 +802,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
button = 2;
}
ReleaseCapture();
handle_keyrelease(MouseButton::button(button));
handle_keyrelease(MouseButton::button(button), get_message_time());
break;
case WM_IME_NOTIFY:
@ -913,7 +914,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
POINT point;
GetCursorPos(&point);
ScreenToClient(hwnd, &point);
handle_keypress(lookup_key(wparam), point.x, point.y);
handle_keypress(lookup_key(wparam), point.x, point.y,
get_message_time());
if (wparam == VK_F10) {
// bypass default windproc F10 behavior (it activates the main
// menu, but we have none)
@ -944,12 +946,17 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
windisplay_cat.debug()
<< "keydown: " << wparam << " (" << lookup_key(wparam) << ")\n";
}
{
// If this bit is not zero, this is just a keyrepeat echo; we
// ignore these for handle_keypress (we respect keyrepeat only
// for handle_keystroke).
if ((lparam & 0x40000000) == 0) {
POINT point;
GetCursorPos(&point);
ScreenToClient(hwnd, &point);
handle_keypress(lookup_key(wparam), point.x, point.y);
handle_keypress(lookup_key(wparam), point.x, point.y,
get_message_time());
// Handle Cntrl-V paste from clipboard. Is there a better way
// to detect this hotkey?
@ -987,7 +994,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
windisplay_cat.debug()
<< "keyup: " << wparam << " (" << lookup_key(wparam) << ")\n";
}
handle_keyrelease(lookup_key(wparam));
handle_keyrelease(lookup_key(wparam), get_message_time());
break;
case WM_KILLFOCUS:
@ -1017,10 +1024,11 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
// If we don't want to remember the keystate while the
// window focus is lost, then generate a keyup event
// right now for each key currently held.
double message_time = get_message_time();
for (int i = 0; i < num_virtual_keys; i++) {
if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) {
if ((_keyboard_state[i] & 0x80) != 0) {
handle_keyrelease(lookup_key(i));
handle_keyrelease(lookup_key(i), message_time);
_keyboard_state[i] &= ~0x80;
}
}
@ -1135,6 +1143,7 @@ resend_lost_keypresses() {
BYTE new_keyboard_state[num_virtual_keys];
GetKeyboardState(new_keyboard_state);
double message_time = get_message_time();
for (int i = 0; i < num_virtual_keys; i++) {
// Filter out these particular three. We don't want to test
// these, because these are virtual duplicates for
@ -1152,14 +1161,14 @@ resend_lost_keypresses() {
<< "key has gone down: " << i << " (" << lookup_key(i) << ")\n";
}
handle_keyresume(lookup_key(i));
handle_keyresume(lookup_key(i), message_time);
} else {
// The key is now released.
if (windisplay_cat.is_debug()) {
windisplay_cat.debug()
<< "key has gone up: " << i << " (" << lookup_key(i) << ")\n";
}
handle_keyrelease(lookup_key(i));
handle_keyrelease(lookup_key(i), message_time);
}
} else {
// This key is in the same state.

View File

@ -85,14 +85,16 @@ private:
static void process_1_event();
INLINE void handle_keypress(ButtonHandle key, int x, int y);
INLINE void handle_keyresume(ButtonHandle key);
INLINE void handle_keyrelease(ButtonHandle key);
INLINE void handle_keypress(ButtonHandle key, int x, int y, double time);
INLINE void handle_keyresume(ButtonHandle key, double time);
INLINE void handle_keyrelease(ButtonHandle key, double time);
ButtonHandle lookup_key(WPARAM wparam) const;
INLINE int translate_mouse(int pos) const;
INLINE void set_cursor_in_window();
INLINE void set_cursor_out_of_window();
INLINE static double get_message_time();
void resend_lost_keypresses();
static void update_cursor_window(WinGraphicsWindow *to_window);