latest merges from Schell Games

This commit is contained in:
David Rose 2005-02-04 05:24:47 +00:00
parent 7f97f4ed46
commit 28d62c55ef
16 changed files with 395 additions and 54 deletions

View File

@ -38,6 +38,7 @@ Options:
-r remove the default library list; instrument only named libraries -r remove the default library list; instrument only named libraries
-O no C++ comments or assertion statements -O no C++ comments or assertion statements
-n Don't use squeezeTool to squeeze the result into one .pyz file -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 Any additional names listed on the command line are taken to be names
of libraries that are to be instrumented. of libraries that are to be instrumented.
@ -50,7 +51,8 @@ extensionsDir = ''
interrogateLib = '' interrogateLib = ''
codeLibs = [] codeLibs = []
etcPath = [] etcPath = []
doSqueeze = 1 doSqueeze = True
deleteSourceAfterSqueeze = True
def doGetopts(): def doGetopts():
global outputDir global outputDir
@ -58,6 +60,7 @@ def doGetopts():
global interrogateLib global interrogateLib
global codeLibs global codeLibs
global doSqueeze global doSqueeze
global deleteSourceAfterSqueeze
global etcPath global etcPath
# These options are allowed but are flagged as warnings (they are # These options are allowed but are flagged as warnings (they are
@ -73,7 +76,7 @@ def doGetopts():
# Extract the args the user passed in # Extract the args the user passed in
try: 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: except Exception, e:
# User passed in a bad option, print the error and the help, then exit # User passed in a bad option, print the error and the help, then exit
print e print e
@ -105,7 +108,9 @@ def doGetopts():
FFIConstants.wantComments = 0 FFIConstants.wantComments = 0
FFIConstants.wantTypeChecking = 0 FFIConstants.wantTypeChecking = 0
elif (flag == '-n'): elif (flag == '-n'):
doSqueeze = 0 doSqueeze = False
elif (flag == '-s'):
deleteSourceAfterSqueeze = False
elif (flag in ['-g', '-t', '-p', '-o']): elif (flag in ['-g', '-t', '-p', '-o']):
FFIConstants.notify.warning("option is deprecated: %s" % (flag)) FFIConstants.notify.warning("option is deprecated: %s" % (flag))
@ -191,4 +196,4 @@ def run():
db.generateCode(outputDir, extensionsDir) db.generateCode(outputDir, extensionsDir)
if doSqueeze: if doSqueeze:
db.squeezeGeneratedCode(outputDir) db.squeezeGeneratedCode(outputDir, deleteSourceAfterSqueeze)

View File

@ -733,7 +733,7 @@ class FFIInterrogateDatabase:
file = open(init, 'w') file = open(init, 'w')
file.close() file.close()
def squeezeGeneratedCode(self, outputDir): def squeezeGeneratedCode(self, outputDir, deleteSource=True):
# Since we will be squeezing the importModuleName file, rename # Since we will be squeezing the importModuleName file, rename
# the original to something we can import from within the # the original to something we can import from within the
@ -762,6 +762,7 @@ class FFIInterrogateDatabase:
pandaSqueezeTool.squeeze(squeezedName, unsqueezedName, pandaSqueezeTool.squeeze(squeezedName, unsqueezedName,
files, outputDir) files, outputDir)
if( deleteSource ):
# Remove the now-squeezed source files. # Remove the now-squeezed source files.
for file in files: for file in files:
os.remove(file) os.remove(file)

View File

@ -39,7 +39,7 @@
// All of the Sources.pp files in the current source hierarchy // All of the Sources.pp files in the current source hierarchy
// $DTOOL/pptempl/Global.pp // $DTOOL/pptempl/Global.pp
// $DTOOL/pptempl/Global.nmake.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 // Template.nmake.pp (this file), once for each Sources.pp file
#if $[ne $[CTPROJS],] #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 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)]] #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 // 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 // depend on. If it's an empty list, we won't bother writing rules to
// freshen the cache file. // freshen the cache file.
@ -171,6 +179,7 @@
$[if $[install_data],$[install_data_dir]] \ $[if $[install_data],$[install_data_dir]] \
$[if $[install_config],$[install_config_dir]] \ $[if $[install_config],$[install_config_dir]] \
$[if $[install_igatedb],$[install_igatedb_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 // 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_HEADERS:%=$[install_headers_dir]/%] \
$[INSTALL_PARSER_INC:%=$[install_parser_inc_dir]/%] \ $[INSTALL_PARSER_INC:%=$[install_parser_inc_dir]/%] \
$[INSTALL_DATA:%=$[install_data_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 \ #define installed_igate_files \
$[get_igatedb(metalib_target lib_target ss_lib_target):$[ODIR]/%=$[install_igatedb_dir]/%] $[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]] $[TAB] xcopy /I/Y $[osfilename $[local]] $[osfilename $[dest]]
#end file #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 // Finally, all the special targets. These are commands that just need
// to be invoked; we don't pretend to know what they are. // to be invoked; we don't pretend to know what they are.
#forscopes special_target #forscopes special_target

View File

@ -66,6 +66,17 @@ FmodAudioManager() {
_cache_limit = audio_cache_limit; _cache_limit = audio_cache_limit;
_concurrent_sound_limit = 0; _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. // Initialize FMOD, if this is the first manager created.
_is_valid = true; _is_valid = true;
if (_active_managers == 0) { if (_active_managers == 0) {
@ -168,12 +179,56 @@ get_sound(const string &file_name, bool positional) {
nassertr(is_valid(), NULL); nassertr(is_valid(), NULL);
Filename path = file_name; Filename path = file_name;
// 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: \""<<path<<"\" is not a supported sound file format.");
audio_error("Supported formats are: WAV, OGG, MP3, MID, MIDI, RMI");
return get_null_sound();
} else { // the suffix is of a supported type
audio_debug("FmodAudioManager::get_sound: \""<<path<<"\" is a supported sound file format.");
// resolve the path normally
if (use_vfs) { if (use_vfs) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
vfs->resolve_filename(path, get_sound_path()); vfs->resolve_filename(path, get_sound_path());
} else { } else {
path.resolve_filename(get_sound_path()); path.resolve_filename(get_sound_path());
} }
}
} else { // no suffix given. Search for supported file types of the same name.
audio_debug("FmodAudioManager::get_sound: \""<<path<<"\" has no extension. Searching for supported files with the same name.");
// look for each type of file
SupportedTypes::const_iterator type_i;
for (type_i = _supported_types.begin(); type_i != _supported_types.end(); ++type_i) {
path.set_extension(*type_i); // set extension as supported type
if (use_vfs) { // check virtual file system
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (vfs->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: \""<<file_name<<"\" does not exist, even with default sound extensions.");
// reset path to no extension
path.set_extension("");
} else {
audio_debug("FmodAudioManager::get_sound: \""<<path<<"\" found using default sound extensions.");
suffix = downcase(path.get_extension()); // update suffix (used below when loading file)
}
}
audio_debug(" resolved file_name is '"<<path<<"'"); audio_debug(" resolved file_name is '"<<path<<"'");
@ -241,7 +296,7 @@ get_sound(const string &file_name, bool positional) {
} }
string os_path = path.to_os_specific(); string os_path = path.to_os_specific();
string suffix = downcase(path.get_extension()); //string suffix = downcase(path.get_extension()); // declared above by RobCode
if (suffix == "mid" || suffix == "rmi" || suffix == "midi") { if (suffix == "mid" || suffix == "rmi" || suffix == "midi") {
stream = FSOUND_Stream_Open(os_path.c_str(), 0, 0, 0); stream = FSOUND_Stream_Open(os_path.c_str(), 0, 0, 0);

View File

@ -136,6 +136,11 @@ private:
typedef pdeque<string> LRU; typedef pdeque<string> LRU;
LRU _lru; LRU _lru;
// RobCode
// List of supported sound formats
typedef pvector<string> SupportedTypes;
SupportedTypes _supported_types;
void release_sound(FmodAudioSound *audioSound); void release_sound(FmodAudioSound *audioSound);
int _cache_limit; int _cache_limit;

View File

@ -92,6 +92,23 @@ get_ascii_equivalent() const {
return has_ascii_equivalent() ? (char)_index : '\0'; 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 // Function: ButtonHandle::get_index
// Access: Published // Access: Published

View File

@ -36,3 +36,25 @@ get_name() const {
return ButtonRegistry::ptr()->get_name(*this); 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);
}
}

View File

@ -43,6 +43,10 @@ PUBLISHED:
INLINE bool has_ascii_equivalent() const; INLINE bool has_ascii_equivalent() const;
INLINE char get_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 int get_index() const;
INLINE void output(ostream &out) const; INLINE void output(ostream &out) const;
INLINE static ButtonHandle none(); INLINE static ButtonHandle none();

View File

@ -24,13 +24,14 @@
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE ButtonRegistry::RegistryNode:: INLINE ButtonRegistry::RegistryNode::
RegistryNode(ButtonHandle handle, const string &name) : RegistryNode(ButtonHandle handle, ButtonHandle alias, const string &name) :
_handle(handle), _name(name) { _handle(handle), _alias(alias), _name(name)
{
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: ButtonRegistry::ptr // Function: ButtonRegistry::ptr
// Access: Public, Static // Access: Published, Static
// Description: Returns the pointer to the global ButtonRegistry // Description: Returns the pointer to the global ButtonRegistry
// object. // object.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -53,3 +54,17 @@ get_name(ButtonHandle button) const {
nassertr(rnode != (RegistryNode *)NULL, ""); nassertr(rnode != (RegistryNode *)NULL, "");
return rnode->_name; 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;
}

View File

@ -38,13 +38,21 @@ ButtonRegistry *ButtonRegistry::_global_pointer = NULL;
// it was already registered; in either case, the new // it was already registered; in either case, the new
// ButtonHandle is loaded into the first parameter. // 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 // This defines a new kind of button matching the
// indicated name. The ButtonHandle can then be passed // indicated name. The ButtonHandle can then be passed
// around to devices as a button in its own right. // around to devices as a button in its own right.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool ButtonRegistry:: bool ButtonRegistry::
register_button(ButtonHandle &button_handle, const string &name, register_button(ButtonHandle &button_handle, const string &name,
char ascii_equivalent) { ButtonHandle alias, char ascii_equivalent) {
NameRegistry::iterator ri; NameRegistry::iterator ri;
ri = _name_registry.find(name); ri = _name_registry.find(name);
@ -81,7 +89,7 @@ register_button(ButtonHandle &button_handle, const string &name,
ButtonHandle new_handle; ButtonHandle new_handle;
new_handle._index = index; new_handle._index = index;
RegistryNode *rnode = new RegistryNode(new_handle, name); RegistryNode *rnode = new RegistryNode(new_handle, alias, name);
_handle_registry[index] = rnode; _handle_registry[index] = rnode;
_name_registry[name] = rnode; _name_registry[name] = rnode;
@ -108,7 +116,7 @@ register_button(ButtonHandle &button_handle, const string &name,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: ButtonRegistry::get_button // Function: ButtonRegistry::get_button
// Access: Public // Access: Published
// Description: Finds a ButtonHandle in the registry matching the // Description: Finds a ButtonHandle in the registry matching the
// indicated name. If there is no such ButtonHandle, // indicated name. If there is no such ButtonHandle,
// registers a new one and returns it. // registers a new one and returns it.
@ -129,7 +137,7 @@ get_button(const string &name) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: ButtonRegistry::find_ascii_button // Function: ButtonRegistry::find_ascii_button
// Access: Public // Access: Published
// Description: Finds a ButtonHandle in the registry matching the // Description: Finds a ButtonHandle in the registry matching the
// indicated ASCII equivalent character. If there is no // indicated ASCII equivalent character. If there is no
// such ButtonHandle, returns ButtonHandle::none(). // such ButtonHandle, returns ButtonHandle::none().
@ -142,10 +150,9 @@ find_ascii_button(char ascii_equivalent) const {
return _handle_registry[ascii_equivalent]->_handle; return _handle_registry[ascii_equivalent]->_handle;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: ButtonRegistry::write // Function: ButtonRegistry::write
// Access: Public // Access: Published
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void ButtonRegistry:: void ButtonRegistry::
@ -165,11 +172,16 @@ write(ostream &out) const {
NameRegistry::const_iterator ri; NameRegistry::const_iterator ri;
for (ri = _name_registry.begin(); ri != _name_registry.end(); ++ri) { for (ri = _name_registry.begin(); ri != _name_registry.end(); ++ri) {
if (!(*ri).second->_handle.has_ascii_equivalent()) { 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 // Function: ButtonRegistry::Constructor
// Access: Private // Access: Private

View File

@ -37,27 +37,31 @@ class EXPCL_PANDA ButtonRegistry {
protected: protected:
class EXPCL_PANDA RegistryNode { class EXPCL_PANDA RegistryNode {
public: public:
INLINE RegistryNode(ButtonHandle handle, const string &name); INLINE RegistryNode(ButtonHandle handle, ButtonHandle alias,
const string &name);
ButtonHandle _handle; ButtonHandle _handle;
ButtonHandle _alias;
string _name; string _name;
}; };
public: public:
bool register_button(ButtonHandle &button_handle, const string &name, bool register_button(ButtonHandle &button_handle, const string &name,
ButtonHandle alias = ButtonHandle::none(),
char ascii_equivalent = '\0'); char ascii_equivalent = '\0');
PUBLISHED: PUBLISHED:
ButtonHandle get_button(const string &name); ButtonHandle get_button(const string &name);
ButtonHandle find_ascii_button(char ascii_equivalent) const; ButtonHandle find_ascii_button(char ascii_equivalent) const;
void write(ostream &out) const;
// ptr() returns the pointer to the global ButtonRegistry object. // ptr() returns the pointer to the global ButtonRegistry object.
INLINE static ButtonRegistry *ptr(); INLINE static ButtonRegistry *ptr();
public: public:
INLINE string get_name(ButtonHandle button) const; INLINE string get_name(ButtonHandle button) const;
INLINE ButtonHandle get_alias(ButtonHandle button) const;
void write(ostream &out) const;
private: private:
// The ButtonRegistry class should never be constructed by user code. // The ButtonRegistry class should never be constructed by user code.

View File

@ -91,6 +91,12 @@ DEFINE_KEYBD_BUTTON_HANDLE(print_screen)
DEFINE_KEYBD_BUTTON_HANDLE(shift) DEFINE_KEYBD_BUTTON_HANDLE(shift)
DEFINE_KEYBD_BUTTON_HANDLE(control) DEFINE_KEYBD_BUTTON_HANDLE(control)
DEFINE_KEYBD_BUTTON_HANDLE(alt) 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:: void KeyboardButton::
init_keyboard_buttons() { init_keyboard_buttons() {
ButtonRegistry::ptr()->register_button(_space, "space", ' '); ButtonRegistry::ptr()->register_button(_space, "space",
ButtonRegistry::ptr()->register_button(_backspace, "backspace", '\x08'); ButtonHandle::none(), ' ');
ButtonRegistry::ptr()->register_button(_tab, "tab", '\x09'); ButtonRegistry::ptr()->register_button(_backspace, "backspace",
ButtonRegistry::ptr()->register_button(_enter, "enter", '\x0d'); ButtonHandle::none(), '\x08');
ButtonRegistry::ptr()->register_button(_escape, "escape", '\x1b'); ButtonRegistry::ptr()->register_button(_tab, "tab",
ButtonRegistry::ptr()->register_button(_del, "delete", '\x7f'); 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(_f1, "f1");
ButtonRegistry::ptr()->register_button(_f2, "f2"); 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(_scroll_lock, "scroll_lock");
ButtonRegistry::ptr()->register_button(_print_screen, "print_screen"); 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. // Also register all of the visible ASCII characters.
for (int i = 32; i < 127; i++) { for (int i = 32; i < 127; i++) {
if (isgraph(i)) { if (isgraph(i)) {
ButtonHandle key; ButtonHandle key;
ButtonRegistry::ptr()->register_button(key, string(1, (char)i), i); ButtonRegistry::ptr()->register_button(key, string(1, (char)i),
ButtonHandle::none(), i);
} }
} }
} }

View File

@ -74,6 +74,13 @@ PUBLISHED:
static ButtonHandle scroll_lock(); static ButtonHandle scroll_lock();
static ButtonHandle print_screen(); static ButtonHandle print_screen();
static ButtonHandle lshift();
static ButtonHandle rshift();
static ButtonHandle lcontrol();
static ButtonHandle rcontrol();
static ButtonHandle lalt();
static ButtonHandle ralt();
public: public:
static void init_keyboard_buttons(); static void init_keyboard_buttons();
}; };

View File

@ -235,7 +235,7 @@ bool ModifierButtons::
has_button(ButtonHandle button) const { has_button(ButtonHandle button) const {
PTA(ButtonHandle)::const_iterator bi; PTA(ButtonHandle)::const_iterator bi;
for (bi = _button_list.begin(); bi != _button_list.end(); ++bi) { for (bi = _button_list.begin(); bi != _button_list.end(); ++bi) {
if (button == (*bi)) { if (button.matches(*bi)) {
return true; return true;
} }
} }
@ -250,6 +250,10 @@ has_button(ButtonHandle button) const {
// being monitored. Returns true if the button was // being monitored. Returns true if the button was
// removed, false if it was not being monitored in the // removed, false if it was not being monitored in the
// first place. // 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:: bool ModifierButtons::
remove_button(ButtonHandle button) { remove_button(ButtonHandle button) {
@ -289,7 +293,7 @@ remove_button(ButtonHandle button) {
bool ModifierButtons:: bool ModifierButtons::
button_down(ButtonHandle button) { button_down(ButtonHandle button) {
for (int i = 0; i < (int)_button_list.size(); i++) { 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); _state |= ((BitmaskType)1 << i);
return true; return true;
} }
@ -311,7 +315,7 @@ button_down(ButtonHandle button) {
bool ModifierButtons:: bool ModifierButtons::
button_up(ButtonHandle button) { button_up(ButtonHandle button) {
for (int i = 0; i < (int)_button_list.size(); i++) { 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); _state &= ~((BitmaskType)1 << i);
return true; return true;
} }
@ -330,7 +334,7 @@ button_up(ButtonHandle button) {
bool ModifierButtons:: bool ModifierButtons::
is_down(ButtonHandle button) const { is_down(ButtonHandle button) const {
for (int i = 0; i < (int)_button_list.size(); i++) { 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); return ((_state & ((BitmaskType)1 << i)) != 0);
} }
} }

View File

@ -93,6 +93,12 @@ WinGraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
_cursor = 0; _cursor = 0;
memset(_keyboard_state, 0, sizeof(BYTE) * num_virtual_keys); memset(_keyboard_state, 0, sizeof(BYTE) * num_virtual_keys);
_lost_keypresses = false; _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); ScreenToClient(hwnd, &point);
handle_keypress(lookup_key(wparam), point.x, point.y, handle_keypress(lookup_key(wparam), point.x, point.y,
get_message_time()); 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) { if (wparam == VK_F10) {
// bypass default windproc F10 behavior (it activates the main // bypass default windproc F10 behavior (it activates the main
// menu, but we have none) // menu, but we have none)
@ -1447,6 +1474,34 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
handle_keypress(lookup_key(wparam), point.x, point.y, handle_keypress(lookup_key(wparam), point.x, point.y,
get_message_time()); 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 // Handle Cntrl-V paste from clipboard. Is there a better way
// to detect this hotkey? // to detect this hotkey?
if ((wparam=='V') && (GetKeyState(VK_CONTROL) < 0) && if ((wparam=='V') && (GetKeyState(VK_CONTROL) < 0) &&
@ -1471,7 +1526,6 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
CloseClipboard(); CloseClipboard();
} }
} }
} else { } else {
// Actually, for now we'll respect the repeat anyway, just // Actually, for now we'll respect the repeat anyway, just
// so we support backspace properly. Rethink later. // so we support backspace properly. Rethink later.
@ -1480,6 +1534,58 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
ScreenToClient(hwnd, &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()); 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; break;
@ -1493,6 +1599,39 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
<< "keyup: " << wparam << " (" << lookup_key(wparam) << ")\n"; << "keyup: " << wparam << " (" << lookup_key(wparam) << ")\n";
} }
handle_keyrelease(lookup_key(wparam), get_message_time()); 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; break;
case WM_KILLFOCUS: case WM_KILLFOCUS:
@ -1870,20 +2009,17 @@ lookup_key(WPARAM wparam) const {
case VK_SCROLL: return KeyboardButton::scroll_lock(); case VK_SCROLL: return KeyboardButton::scroll_lock();
case VK_SNAPSHOT: return KeyboardButton::print_screen(); case VK_SNAPSHOT: return KeyboardButton::print_screen();
case VK_SHIFT: case VK_SHIFT: return KeyboardButton::shift();
case VK_LSHIFT: case VK_LSHIFT: return KeyboardButton::lshift();
case VK_RSHIFT: case VK_RSHIFT: return KeyboardButton::rshift();
return KeyboardButton::shift();
case VK_CONTROL: case VK_CONTROL: return KeyboardButton::control();
case VK_LCONTROL: case VK_LCONTROL: return KeyboardButton::lcontrol();
case VK_RCONTROL: case VK_RCONTROL: return KeyboardButton::rcontrol();
return KeyboardButton::control();
case VK_MENU: case VK_MENU: return KeyboardButton::alt();
case VK_LMENU: case VK_LMENU: return KeyboardButton::lalt();
case VK_RMENU: case VK_RMENU: return KeyboardButton::ralt();
return KeyboardButton::alt();
default: default:
int key = MapVirtualKey(wparam, 2); int key = MapVirtualKey(wparam, 2);

View File

@ -139,6 +139,18 @@ private:
BYTE _keyboard_state[num_virtual_keys]; BYTE _keyboard_state[num_virtual_keys];
bool _lost_keypresses; 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: private:
// We need this map to support per-window calls to window_proc(). // We need this map to support per-window calls to window_proc().
typedef map<HWND, WinGraphicsWindow *> WindowHandles; typedef map<HWND, WinGraphicsWindow *> WindowHandles;