From 28d62c55ef60bbba753f4ba8b1c0ab83a980df6b Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 4 Feb 2005 05:24:47 +0000 Subject: [PATCH] latest merges from Schell Games --- direct/src/ffi/DoGenPyCode.py | 13 +- direct/src/ffi/FFIInterrogateDatabase.py | 9 +- dtool/pptempl/Template.nmake.pp | 26 +++- panda/src/audiotraits/fmodAudioManager.cxx | 67 ++++++++- panda/src/audiotraits/fmodAudioManager.h | 5 + panda/src/putil/buttonHandle.I | 17 +++ panda/src/putil/buttonHandle.cxx | 22 +++ panda/src/putil/buttonHandle.h | 4 + panda/src/putil/buttonRegistry.I | 21 ++- panda/src/putil/buttonRegistry.cxx | 26 +++- panda/src/putil/buttonRegistry.h | 10 +- panda/src/putil/keyboardButton.cxx | 34 ++++- panda/src/putil/keyboardButton.h | 7 + panda/src/putil/modifierButtons.cxx | 12 +- panda/src/windisplay/winGraphicsWindow.cxx | 164 +++++++++++++++++++-- panda/src/windisplay/winGraphicsWindow.h | 12 ++ 16 files changed, 395 insertions(+), 54 deletions(-) diff --git a/direct/src/ffi/DoGenPyCode.py b/direct/src/ffi/DoGenPyCode.py index 1f588e6714..b88a905e74 100644 --- a/direct/src/ffi/DoGenPyCode.py +++ b/direct/src/ffi/DoGenPyCode.py @@ -38,6 +38,7 @@ Options: -r remove the default library list; instrument only named libraries -O no C++ comments or assertion statements -n Don't use squeezeTool to squeeze the result into one .pyz file + -s Don't delete source files after squeezing Any additional names listed on the command line are taken to be names of libraries that are to be instrumented. @@ -50,7 +51,8 @@ extensionsDir = '' interrogateLib = '' codeLibs = [] etcPath = [] -doSqueeze = 1 +doSqueeze = True +deleteSourceAfterSqueeze = True def doGetopts(): global outputDir @@ -58,6 +60,7 @@ def doGetopts(): global interrogateLib global codeLibs global doSqueeze + global deleteSourceAfterSqueeze global etcPath # These options are allowed but are flagged as warnings (they are @@ -73,7 +76,7 @@ def doGetopts(): # Extract the args the user passed in try: - opts, pargs = getopt.getopt(sys.argv[1:], 'hvOd:x:i:e:rngtpo') + opts, pargs = getopt.getopt(sys.argv[1:], 'hvOd:x:i:e:rnsgtpo') except Exception, e: # User passed in a bad option, print the error and the help, then exit print e @@ -105,7 +108,9 @@ def doGetopts(): FFIConstants.wantComments = 0 FFIConstants.wantTypeChecking = 0 elif (flag == '-n'): - doSqueeze = 0 + doSqueeze = False + elif (flag == '-s'): + deleteSourceAfterSqueeze = False elif (flag in ['-g', '-t', '-p', '-o']): FFIConstants.notify.warning("option is deprecated: %s" % (flag)) @@ -191,4 +196,4 @@ def run(): db.generateCode(outputDir, extensionsDir) if doSqueeze: - db.squeezeGeneratedCode(outputDir) + db.squeezeGeneratedCode(outputDir, deleteSourceAfterSqueeze) diff --git a/direct/src/ffi/FFIInterrogateDatabase.py b/direct/src/ffi/FFIInterrogateDatabase.py index ba423a46de..0c959af23f 100644 --- a/direct/src/ffi/FFIInterrogateDatabase.py +++ b/direct/src/ffi/FFIInterrogateDatabase.py @@ -733,7 +733,7 @@ class FFIInterrogateDatabase: file = open(init, 'w') file.close() - def squeezeGeneratedCode(self, outputDir): + def squeezeGeneratedCode(self, outputDir, deleteSource=True): # Since we will be squeezing the importModuleName file, rename # the original to something we can import from within the @@ -762,9 +762,10 @@ class FFIInterrogateDatabase: pandaSqueezeTool.squeeze(squeezedName, unsqueezedName, files, outputDir) - # Remove the now-squeezed source files. - for file in files: - os.remove(file) + if( deleteSource ): + # Remove the now-squeezed source files. + for file in files: + os.remove(file) def generateCodeLib(self, codeDir, extensionsDir, CModuleName): diff --git a/dtool/pptempl/Template.nmake.pp b/dtool/pptempl/Template.nmake.pp index bdc26ccf85..c2284cbe2c 100644 --- a/dtool/pptempl/Template.nmake.pp +++ b/dtool/pptempl/Template.nmake.pp @@ -39,7 +39,7 @@ // All of the Sources.pp files in the current source hierarchy // $DTOOL/pptempl/Global.pp // $DTOOL/pptempl/Global.nmake.pp -// $DTOOL/pptempl/Depends.pp, once for each Sources.pp filem +// $DTOOL/pptempl/Depends.pp, once for each Sources.pp file // Template.nmake.pp (this file), once for each Sources.pp file #if $[ne $[CTPROJS],] @@ -106,6 +106,14 @@ #define lxx_st_sources $[sort $[lxx_sources(metalib_target lib_target noinst_lib_target static_lib_target ss_lib_target bin_target noinst_bin_target test_bin_target test_lib_target)]] #define dep_sources_1 $[sort $[get_sources(metalib_target lib_target noinst_lib_target static_lib_target ss_lib_target bin_target noinst_bin_target test_bin_target test_lib_target)]] + // If there is an __init__.py in the directory, then all Python + // files in the directory just get installed without having to be + // named. + #if $[and $[INSTALL_PYTHON_SOURCE],$[wildcard $[TOPDIR]/$[DIRPREFIX]__init__.py]] + #define py_sources $[wildcard $[TOPDIR]/$[DIRPREFIX]*.py] + #endif + #define install_py $[py_sources:$[TOPDIR]/$[DIRPREFIX]%=%] + // These are the source files that our dependency cache file will // depend on. If it's an empty list, we won't bother writing rules to // freshen the cache file. @@ -171,6 +179,7 @@ $[if $[install_data],$[install_data_dir]] \ $[if $[install_config],$[install_config_dir]] \ $[if $[install_igatedb],$[install_igatedb_dir]] \ + $[if $[install_py],$[install_py_dir] $[install_py_package_dir]] \ ] // Similarly, we need to ensure that $[ODIR] exists. Trying to make @@ -285,7 +294,8 @@ $[TAB] if exist $[file] del /f $[file] $[INSTALL_HEADERS:%=$[install_headers_dir]/%] \ $[INSTALL_PARSER_INC:%=$[install_parser_inc_dir]/%] \ $[INSTALL_DATA:%=$[install_data_dir]/%] \ - $[INSTALL_CONFIG:%=$[install_config_dir]/%] + $[INSTALL_CONFIG:%=$[install_config_dir]/%] \ + $[if $[install_py],$[install_py:%=$[install_py_dir]/%] $[install_py_package_dir]/__init__.py] #define installed_igate_files \ $[get_igatedb(metalib_target lib_target ss_lib_target):$[ODIR]/%=$[install_igatedb_dir]/%] @@ -923,6 +933,18 @@ $[osfilename $[install_config_dir]/$[file]] : $[patsubst %,$[osfilename %],$[fil $[TAB] xcopy /I/Y $[osfilename $[local]] $[osfilename $[dest]] #end file +#foreach file $[install_py] +$[osfilename $[install_py_dir]/$[file]] : $[patsubst %,$[osfilename %],$[file]] +#define local $[file] +#define dest $[install_py_dir] +$[TAB] xcopy /I/Y $[osfilename $[local]] $[osfilename $[dest]] +#end file + +#if $[install_py] +$[osfilename $[install_py_package_dir]/__init__.py] : +$[TAB] echo. > $[osfilename $[install_py_package_dir]/__init__.py] +#endif + // Finally, all the special targets. These are commands that just need // to be invoked; we don't pretend to know what they are. #forscopes special_target diff --git a/panda/src/audiotraits/fmodAudioManager.cxx b/panda/src/audiotraits/fmodAudioManager.cxx index 8a1be0f7e3..7037d76262 100644 --- a/panda/src/audiotraits/fmodAudioManager.cxx +++ b/panda/src/audiotraits/fmodAudioManager.cxx @@ -66,6 +66,17 @@ FmodAudioManager() { _cache_limit = audio_cache_limit; _concurrent_sound_limit = 0; + // RobCode + // Fill list of supported types + // Order of this list (first is most important) determines + // the search order for sound files without an extension. + _supported_types.push_back("wav"); + _supported_types.push_back("ogg"); + _supported_types.push_back("mp3"); + _supported_types.push_back("mid"); + _supported_types.push_back("midi"); + _supported_types.push_back("rmi"); + // Initialize FMOD, if this is the first manager created. _is_valid = true; if (_active_managers == 0) { @@ -168,11 +179,55 @@ get_sound(const string &file_name, bool positional) { nassertr(is_valid(), NULL); Filename path = file_name; - if (use_vfs) { - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - vfs->resolve_filename(path, get_sound_path()); - } else { - path.resolve_filename(get_sound_path()); + // RobCode + // test for an invalid suffix type + string suffix = downcase(path.get_extension()); + if (!suffix.empty()) { + SupportedTypes::iterator type_i=find(_supported_types.begin(), _supported_types.end(), suffix); + // if suffix not found in list of supported types + if (type_i == _supported_types.end()) { + // print error and return + audio_error("FmodAudioManager::get_sound: \""<resolve_filename(path, get_sound_path()); + } else { + path.resolve_filename(get_sound_path()); + } + } + } else { // no suffix given. Search for supported file types of the same name. + audio_debug("FmodAudioManager::get_sound: \""<resolve_filename(path, get_sound_path())) { + break; // break out of loop with a valid type_i value and path with correct extension + } + } else { // check regular file system + if (path.resolve_filename(get_sound_path())) { + break; // break out of loop with a valid type_i value and path with correct extension + } + } + } // end for loop + // if no valid file found + if (type_i == _supported_types.end() ) { + // just print a warning for now + audio_debug("FmodAudioManager::get_sound: \""< LRU; LRU _lru; + // RobCode + // List of supported sound formats + typedef pvector SupportedTypes; + SupportedTypes _supported_types; + void release_sound(FmodAudioSound *audioSound); int _cache_limit; diff --git a/panda/src/putil/buttonHandle.I b/panda/src/putil/buttonHandle.I index 8574a8d13d..ff4a1ccdb4 100644 --- a/panda/src/putil/buttonHandle.I +++ b/panda/src/putil/buttonHandle.I @@ -92,6 +92,23 @@ get_ascii_equivalent() const { return has_ascii_equivalent() ? (char)_index : '\0'; } +//////////////////////////////////////////////////////////////////// +// Function: ButtonHandle::matches +// Access: Published +// Description: Returns true if this ButtonHandle is the same as the +// other one, or if the other one is an alias for this +// one. (Does not return true if this button is an +// alias for the other one, however.) +// +// This is a more general comparison than operator ==. +//////////////////////////////////////////////////////////////////// +INLINE bool ButtonHandle:: +matches(const ButtonHandle &other) const { + return ((*this) == other || + (other != ButtonHandle::none() && + get_alias() == other)); +} + //////////////////////////////////////////////////////////////////// // Function: ButtonHandle::get_index // Access: Published diff --git a/panda/src/putil/buttonHandle.cxx b/panda/src/putil/buttonHandle.cxx index 26217b27c7..972521a154 100644 --- a/panda/src/putil/buttonHandle.cxx +++ b/panda/src/putil/buttonHandle.cxx @@ -36,3 +36,25 @@ get_name() const { return ButtonRegistry::ptr()->get_name(*this); } } + +//////////////////////////////////////////////////////////////////// +// Function: ButtonHandle::get_alias +// Access: Published +// Description: Returns the alias (alternate name) associated with +// the button, if any, or ButtonHandle::none() if the +// button has no alias. +// +// Each button is allowed to have one alias, and +// multiple different buttons can refer to the same +// alias. The alias should be the more general name for +// the button, for instance, shift is an alias for +// lshift, but not vice-versa. +//////////////////////////////////////////////////////////////////// +ButtonHandle ButtonHandle:: +get_alias() const { + if ((*this) == ButtonHandle::none()) { + return ButtonHandle::none(); + } else { + return ButtonRegistry::ptr()->get_alias(*this); + } +} diff --git a/panda/src/putil/buttonHandle.h b/panda/src/putil/buttonHandle.h index ffd67091ed..d55aeab633 100644 --- a/panda/src/putil/buttonHandle.h +++ b/panda/src/putil/buttonHandle.h @@ -43,6 +43,10 @@ PUBLISHED: INLINE bool has_ascii_equivalent() const; INLINE char get_ascii_equivalent() const; + ButtonHandle get_alias() const; + + INLINE bool matches(const ButtonHandle &other) const; + INLINE int get_index() const; INLINE void output(ostream &out) const; INLINE static ButtonHandle none(); diff --git a/panda/src/putil/buttonRegistry.I b/panda/src/putil/buttonRegistry.I index 8954a45328..b91d7ce71b 100644 --- a/panda/src/putil/buttonRegistry.I +++ b/panda/src/putil/buttonRegistry.I @@ -24,13 +24,14 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE ButtonRegistry::RegistryNode:: -RegistryNode(ButtonHandle handle, const string &name) : - _handle(handle), _name(name) { +RegistryNode(ButtonHandle handle, ButtonHandle alias, const string &name) : + _handle(handle), _alias(alias), _name(name) +{ } //////////////////////////////////////////////////////////////////// // Function: ButtonRegistry::ptr -// Access: Public, Static +// Access: Published, Static // Description: Returns the pointer to the global ButtonRegistry // object. //////////////////////////////////////////////////////////////////// @@ -53,3 +54,17 @@ get_name(ButtonHandle button) const { nassertr(rnode != (RegistryNode *)NULL, ""); return rnode->_name; } + +//////////////////////////////////////////////////////////////////// +// Function: ButtonRegistry::get_alias +// Access: Public +// Description: Returns the alias for the indicated button, or +// ButtonHandle::none() if the button has no specified +// alias. +//////////////////////////////////////////////////////////////////// +INLINE ButtonHandle ButtonRegistry:: +get_alias(ButtonHandle button) const { + RegistryNode *rnode = look_up(button); + nassertr(rnode != (RegistryNode *)NULL, ButtonHandle::none()); + return rnode->_alias; +} diff --git a/panda/src/putil/buttonRegistry.cxx b/panda/src/putil/buttonRegistry.cxx index 0b7b3d0f09..8c46a10786 100644 --- a/panda/src/putil/buttonRegistry.cxx +++ b/panda/src/putil/buttonRegistry.cxx @@ -38,13 +38,21 @@ ButtonRegistry *ButtonRegistry::_global_pointer = NULL; // it was already registered; in either case, the new // ButtonHandle is loaded into the first parameter. // +// If the alias is not ButtonHandle::none(), it +// indicates an alias (alternate name) for the same +// button. Each button is allowed to have one alias, +// and multiple different buttons can refer to the same +// alias. The alias should be the more general name for +// the button, for instance, shift is an alias for +// lshift, but not vice-versa. +// // This defines a new kind of button matching the // indicated name. The ButtonHandle can then be passed // around to devices as a button in its own right. //////////////////////////////////////////////////////////////////// bool ButtonRegistry:: register_button(ButtonHandle &button_handle, const string &name, - char ascii_equivalent) { + ButtonHandle alias, char ascii_equivalent) { NameRegistry::iterator ri; ri = _name_registry.find(name); @@ -81,7 +89,7 @@ register_button(ButtonHandle &button_handle, const string &name, ButtonHandle new_handle; new_handle._index = index; - RegistryNode *rnode = new RegistryNode(new_handle, name); + RegistryNode *rnode = new RegistryNode(new_handle, alias, name); _handle_registry[index] = rnode; _name_registry[name] = rnode; @@ -108,7 +116,7 @@ register_button(ButtonHandle &button_handle, const string &name, //////////////////////////////////////////////////////////////////// // Function: ButtonRegistry::get_button -// Access: Public +// Access: Published // Description: Finds a ButtonHandle in the registry matching the // indicated name. If there is no such ButtonHandle, // registers a new one and returns it. @@ -129,7 +137,7 @@ get_button(const string &name) { //////////////////////////////////////////////////////////////////// // Function: ButtonRegistry::find_ascii_button -// Access: Public +// Access: Published // Description: Finds a ButtonHandle in the registry matching the // indicated ASCII equivalent character. If there is no // such ButtonHandle, returns ButtonHandle::none(). @@ -142,10 +150,9 @@ find_ascii_button(char ascii_equivalent) const { return _handle_registry[ascii_equivalent]->_handle; } - //////////////////////////////////////////////////////////////////// // Function: ButtonRegistry::write -// Access: Public +// Access: Published // Description: //////////////////////////////////////////////////////////////////// void ButtonRegistry:: @@ -165,11 +172,16 @@ write(ostream &out) const { NameRegistry::const_iterator ri; for (ri = _name_registry.begin(); ri != _name_registry.end(); ++ri) { if (!(*ri).second->_handle.has_ascii_equivalent()) { - out << " " << (*ri).second->_name << "\n"; + out << " " << (*ri).second->_name; + if ((*ri).second->_alias != ButtonHandle::none()) { + out << " (alias " << (*ri).second->_alias << ")"; + } + out << "\n"; } } } + //////////////////////////////////////////////////////////////////// // Function: ButtonRegistry::Constructor // Access: Private diff --git a/panda/src/putil/buttonRegistry.h b/panda/src/putil/buttonRegistry.h index 8664b0fd3c..2723017bab 100644 --- a/panda/src/putil/buttonRegistry.h +++ b/panda/src/putil/buttonRegistry.h @@ -37,27 +37,31 @@ class EXPCL_PANDA ButtonRegistry { protected: class EXPCL_PANDA RegistryNode { public: - INLINE RegistryNode(ButtonHandle handle, const string &name); + INLINE RegistryNode(ButtonHandle handle, ButtonHandle alias, + const string &name); ButtonHandle _handle; + ButtonHandle _alias; string _name; }; public: bool register_button(ButtonHandle &button_handle, const string &name, + ButtonHandle alias = ButtonHandle::none(), char ascii_equivalent = '\0'); PUBLISHED: ButtonHandle get_button(const string &name); ButtonHandle find_ascii_button(char ascii_equivalent) const; + void write(ostream &out) const; + // ptr() returns the pointer to the global ButtonRegistry object. INLINE static ButtonRegistry *ptr(); public: INLINE string get_name(ButtonHandle button) const; - - void write(ostream &out) const; + INLINE ButtonHandle get_alias(ButtonHandle button) const; private: // The ButtonRegistry class should never be constructed by user code. diff --git a/panda/src/putil/keyboardButton.cxx b/panda/src/putil/keyboardButton.cxx index 7b766f7d09..bcccd3b6c3 100644 --- a/panda/src/putil/keyboardButton.cxx +++ b/panda/src/putil/keyboardButton.cxx @@ -91,6 +91,12 @@ DEFINE_KEYBD_BUTTON_HANDLE(print_screen) DEFINE_KEYBD_BUTTON_HANDLE(shift) DEFINE_KEYBD_BUTTON_HANDLE(control) DEFINE_KEYBD_BUTTON_HANDLE(alt) +DEFINE_KEYBD_BUTTON_HANDLE(lshift) +DEFINE_KEYBD_BUTTON_HANDLE(rshift) +DEFINE_KEYBD_BUTTON_HANDLE(lcontrol) +DEFINE_KEYBD_BUTTON_HANDLE(rcontrol) +DEFINE_KEYBD_BUTTON_HANDLE(lalt) +DEFINE_KEYBD_BUTTON_HANDLE(ralt) //////////////////////////////////////////////////////////////////// @@ -101,12 +107,18 @@ DEFINE_KEYBD_BUTTON_HANDLE(alt) //////////////////////////////////////////////////////////////////// void KeyboardButton:: init_keyboard_buttons() { - ButtonRegistry::ptr()->register_button(_space, "space", ' '); - ButtonRegistry::ptr()->register_button(_backspace, "backspace", '\x08'); - ButtonRegistry::ptr()->register_button(_tab, "tab", '\x09'); - ButtonRegistry::ptr()->register_button(_enter, "enter", '\x0d'); - ButtonRegistry::ptr()->register_button(_escape, "escape", '\x1b'); - ButtonRegistry::ptr()->register_button(_del, "delete", '\x7f'); + ButtonRegistry::ptr()->register_button(_space, "space", + ButtonHandle::none(), ' '); + ButtonRegistry::ptr()->register_button(_backspace, "backspace", + ButtonHandle::none(), '\x08'); + ButtonRegistry::ptr()->register_button(_tab, "tab", + ButtonHandle::none(), '\x09'); + ButtonRegistry::ptr()->register_button(_enter, "enter", + ButtonHandle::none(), '\x0d'); + ButtonRegistry::ptr()->register_button(_escape, "escape", + ButtonHandle::none(), '\x1b'); + ButtonRegistry::ptr()->register_button(_del, "delete", + ButtonHandle::none(), '\x7f'); ButtonRegistry::ptr()->register_button(_f1, "f1"); ButtonRegistry::ptr()->register_button(_f2, "f2"); @@ -141,11 +153,19 @@ init_keyboard_buttons() { ButtonRegistry::ptr()->register_button(_scroll_lock, "scroll_lock"); ButtonRegistry::ptr()->register_button(_print_screen, "print_screen"); + ButtonRegistry::ptr()->register_button(_lshift, "lshift", _shift); + ButtonRegistry::ptr()->register_button(_rshift, "rshift", _shift); + ButtonRegistry::ptr()->register_button(_lcontrol, "lcontrol", _control); + ButtonRegistry::ptr()->register_button(_rcontrol, "rcontrol", _control); + ButtonRegistry::ptr()->register_button(_lalt, "lalt", _alt); + ButtonRegistry::ptr()->register_button(_ralt, "ralt", _alt); + // Also register all of the visible ASCII characters. for (int i = 32; i < 127; i++) { if (isgraph(i)) { ButtonHandle key; - ButtonRegistry::ptr()->register_button(key, string(1, (char)i), i); + ButtonRegistry::ptr()->register_button(key, string(1, (char)i), + ButtonHandle::none(), i); } } } diff --git a/panda/src/putil/keyboardButton.h b/panda/src/putil/keyboardButton.h index 9aa018d601..55dd598f1f 100644 --- a/panda/src/putil/keyboardButton.h +++ b/panda/src/putil/keyboardButton.h @@ -74,6 +74,13 @@ PUBLISHED: static ButtonHandle scroll_lock(); static ButtonHandle print_screen(); + static ButtonHandle lshift(); + static ButtonHandle rshift(); + static ButtonHandle lcontrol(); + static ButtonHandle rcontrol(); + static ButtonHandle lalt(); + static ButtonHandle ralt(); + public: static void init_keyboard_buttons(); }; diff --git a/panda/src/putil/modifierButtons.cxx b/panda/src/putil/modifierButtons.cxx index 1cbdf72777..d3dd37adc7 100644 --- a/panda/src/putil/modifierButtons.cxx +++ b/panda/src/putil/modifierButtons.cxx @@ -235,7 +235,7 @@ bool ModifierButtons:: has_button(ButtonHandle button) const { PTA(ButtonHandle)::const_iterator bi; for (bi = _button_list.begin(); bi != _button_list.end(); ++bi) { - if (button == (*bi)) { + if (button.matches(*bi)) { return true; } } @@ -250,6 +250,10 @@ has_button(ButtonHandle button) const { // being monitored. Returns true if the button was // removed, false if it was not being monitored in the // first place. +// +// Unlike the other methods, you cannot remove a button +// by removing its alias; you have to remove exactly the +// button itself. //////////////////////////////////////////////////////////////////// bool ModifierButtons:: remove_button(ButtonHandle button) { @@ -289,7 +293,7 @@ remove_button(ButtonHandle button) { bool ModifierButtons:: button_down(ButtonHandle button) { for (int i = 0; i < (int)_button_list.size(); i++) { - if (button == _button_list[i]) { + if (button.matches(_button_list[i])) { _state |= ((BitmaskType)1 << i); return true; } @@ -311,7 +315,7 @@ button_down(ButtonHandle button) { bool ModifierButtons:: button_up(ButtonHandle button) { for (int i = 0; i < (int)_button_list.size(); i++) { - if (button == _button_list[i]) { + if (button.matches(_button_list[i])) { _state &= ~((BitmaskType)1 << i); return true; } @@ -330,7 +334,7 @@ button_up(ButtonHandle button) { bool ModifierButtons:: is_down(ButtonHandle button) const { for (int i = 0; i < (int)_button_list.size(); i++) { - if (button == _button_list[i]) { + if (button.matches(_button_list[i])) { return ((_state & ((BitmaskType)1 << i)) != 0); } } diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index 04de6a74f8..138fd8ec00 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -93,6 +93,12 @@ WinGraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, _cursor = 0; memset(_keyboard_state, 0, sizeof(BYTE) * num_virtual_keys); _lost_keypresses = false; + _lshift_down = false; + _rshift_down = false; + _lcontrol_down = false; + _rcontrol_down = false; + _lalt_down = false; + _ralt_down = false; } //////////////////////////////////////////////////////////////////// @@ -1406,6 +1412,27 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { ScreenToClient(hwnd, &point); handle_keypress(lookup_key(wparam), point.x, point.y, get_message_time()); + + // wparam does not contain left/right information for SHIFT, + // CONTROL, or ALT, so we have to track their status and do + // the right thing. We'll send the left/right specific key + // event along with the general key event. + // + // Key repeating is not being handled consistently for LALT + // and RALT, but from comments below, it's only being handled + // the way it is for backspace, so we'll leave it as is. + if (wparam == VK_MENU) { + if ((GetKeyState(VK_LMENU) & 0x8000) != 0 && ! _lalt_down) { + handle_keypress(KeyboardButton::lalt(), point.x, point.y, + get_message_time()); + _lalt_down = true; + } + if ((GetKeyState(VK_RMENU) & 0x8000) != 0 && ! _ralt_down) { + handle_keypress(KeyboardButton::ralt(), point.x, point.y, + get_message_time()); + _ralt_down = true; + } + } if (wparam == VK_F10) { // bypass default windproc F10 behavior (it activates the main // menu, but we have none) @@ -1446,7 +1473,35 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { ScreenToClient(hwnd, &point); handle_keypress(lookup_key(wparam), point.x, point.y, get_message_time()); - + + // wparam does not contain left/right information for SHIFT, + // CONTROL, or ALT, so we have to track their status and do + // the right thing. We'll send the left/right specific key + // event along with the general key event. + if (wparam == VK_SHIFT) { + if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0 && ! _lshift_down) { + handle_keypress(KeyboardButton::lshift(), point.x, point.y, + get_message_time()); + _lshift_down = true; + } + if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0 && ! _rshift_down) { + handle_keypress(KeyboardButton::rshift(), point.x, point.y, + get_message_time()); + _rshift_down = true; + } + } else if(wparam == VK_CONTROL) { + if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0 && ! _lcontrol_down) { + handle_keypress(KeyboardButton::lcontrol(), point.x, point.y, + get_message_time()); + _lcontrol_down = true; + } + if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0 && ! _rcontrol_down) { + handle_keypress(KeyboardButton::rcontrol(), point.x, point.y, + get_message_time()); + _rcontrol_down = true; + } + } + // Handle Cntrl-V paste from clipboard. Is there a better way // to detect this hotkey? if ((wparam=='V') && (GetKeyState(VK_CONTROL) < 0) && @@ -1471,7 +1526,6 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { CloseClipboard(); } } - } else { // Actually, for now we'll respect the repeat anyway, just // so we support backspace properly. Rethink later. @@ -1480,6 +1534,58 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { ScreenToClient(hwnd, &point); handle_keypress(lookup_key(wparam), point.x, point.y, get_message_time()); + + // wparam does not contain left/right information for SHIFT, + // CONTROL, or ALT, so we have to track their status and do + // the right thing. We'll send the left/right specific key + // event along with the general key event. + // + // If the user presses LSHIFT and then RSHIFT, the RSHIFT event + // will come in with the keyrepeat flag on (i.e. it will end up + // in this block). The logic below should detect this correctly + // and only send the RSHIFT event. Note that the CONTROL event + // will be sent twice, once for each keypress. Since keyrepeats + // are currently being sent simply as additional keypress events, + // that should be okay for now. + if (wparam == VK_SHIFT) { + if (((GetKeyState(VK_LSHIFT) & 0x8000) != 0) && ! _lshift_down ) { + handle_keypress(KeyboardButton::lshift(), point.x, point.y, + get_message_time()); + _lshift_down = true; + } else if (((GetKeyState(VK_RSHIFT) & 0x8000) != 0) && ! _rshift_down ) { + handle_keypress(KeyboardButton::rshift(), point.x, point.y, + get_message_time()); + _rshift_down = true; + } else { + if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0) { + handle_keypress(KeyboardButton::lshift(), point.x, point.y, + get_message_time()); + } + if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0) { + handle_keypress(KeyboardButton::rshift(), point.x, point.y, + get_message_time()); + } + } + } else if(wparam == VK_CONTROL) { + if (((GetKeyState(VK_LCONTROL) & 0x8000) != 0) && ! _lcontrol_down ) { + handle_keypress(KeyboardButton::lcontrol(), point.x, point.y, + get_message_time()); + _lcontrol_down = true; + } else if (((GetKeyState(VK_RCONTROL) & 0x8000) != 0) && ! _rcontrol_down ) { + handle_keypress(KeyboardButton::rcontrol(), point.x, point.y, + get_message_time()); + _rcontrol_down = true; + } else { + if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0) { + handle_keypress(KeyboardButton::lcontrol(), point.x, point.y, + get_message_time()); + } + if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0) { + handle_keypress(KeyboardButton::rcontrol(), point.x, point.y, + get_message_time()); + } + } + } } break; @@ -1493,6 +1599,39 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { << "keyup: " << wparam << " (" << lookup_key(wparam) << ")\n"; } handle_keyrelease(lookup_key(wparam), get_message_time()); + + // wparam does not contain left/right information for SHIFT, + // CONTROL, or ALT, so we have to track their status and do + // the right thing. We'll send the left/right specific key + // event along with the general key event. + if (wparam == VK_SHIFT) { + if ((GetKeyState(VK_LSHIFT) & 0x8000) == 0 && _lshift_down) { + handle_keyrelease(KeyboardButton::lshift(), get_message_time()); + _lshift_down = false; + } + if ((GetKeyState(VK_RSHIFT) & 0x8000) == 0 && _rshift_down) { + handle_keyrelease(KeyboardButton::rshift(), get_message_time()); + _rshift_down = false; + } + } else if(wparam == VK_CONTROL) { + if ((GetKeyState(VK_LCONTROL) & 0x8000) == 0 && _lcontrol_down) { + handle_keyrelease(KeyboardButton::lcontrol(), get_message_time()); + _lcontrol_down = false; + } + if ((GetKeyState(VK_RCONTROL) & 0x8000) == 0 && _rcontrol_down) { + handle_keyrelease(KeyboardButton::rcontrol(), get_message_time()); + _rcontrol_down = false; + } + } else if(wparam == VK_MENU) { + if ((GetKeyState(VK_LMENU) & 0x8000) == 0 && _lalt_down) { + handle_keyrelease(KeyboardButton::lalt(), get_message_time()); + _lalt_down = false; + } + if ((GetKeyState(VK_RMENU) & 0x8000) == 0 && _ralt_down) { + handle_keyrelease(KeyboardButton::ralt(), get_message_time()); + _ralt_down = false; + } + } break; case WM_KILLFOCUS: @@ -1870,20 +2009,17 @@ lookup_key(WPARAM wparam) const { case VK_SCROLL: return KeyboardButton::scroll_lock(); case VK_SNAPSHOT: return KeyboardButton::print_screen(); - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - return KeyboardButton::shift(); + case VK_SHIFT: return KeyboardButton::shift(); + case VK_LSHIFT: return KeyboardButton::lshift(); + case VK_RSHIFT: return KeyboardButton::rshift(); - case VK_CONTROL: - case VK_LCONTROL: - case VK_RCONTROL: - return KeyboardButton::control(); + case VK_CONTROL: return KeyboardButton::control(); + case VK_LCONTROL: return KeyboardButton::lcontrol(); + case VK_RCONTROL: return KeyboardButton::rcontrol(); - case VK_MENU: - case VK_LMENU: - case VK_RMENU: - return KeyboardButton::alt(); + case VK_MENU: return KeyboardButton::alt(); + case VK_LMENU: return KeyboardButton::lalt(); + case VK_RMENU: return KeyboardButton::ralt(); default: int key = MapVirtualKey(wparam, 2); diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index 0fa390a448..6bb3baf960 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -139,6 +139,18 @@ private: BYTE _keyboard_state[num_virtual_keys]; bool _lost_keypresses; + // These are used to store the status of the individual left and right + // shift, control, and alt keys. Keyboard events are not sent for + // these individual keys, but for each pair as a whole. The status + // of each key must be checked as keypress and keyrelease events are + // received. + bool _lshift_down; + bool _rshift_down; + bool _lcontrol_down; + bool _rcontrol_down; + bool _lalt_down; + bool _ralt_down; + private: // We need this map to support per-window calls to window_proc(). typedef map WindowHandles;