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
-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)

View File

@ -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,6 +762,7 @@ class FFIInterrogateDatabase:
pandaSqueezeTool.squeeze(squeezedName, unsqueezedName,
files, outputDir)
if( deleteSource ):
# Remove the now-squeezed source files.
for file in files:
os.remove(file)

View File

@ -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

View File

@ -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,12 +179,56 @@ get_sound(const string &file_name, bool positional) {
nassertr(is_valid(), NULL);
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) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
vfs->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: \""<<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<<"'");
@ -241,7 +296,7 @@ get_sound(const string &file_name, bool positional) {
}
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") {
stream = FSOUND_Stream_Open(os_path.c_str(), 0, 0, 0);

View File

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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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

View File

@ -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.

View File

@ -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);
}
}
}

View File

@ -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();
};

View File

@ -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);
}
}

View File

@ -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)
@ -1447,6 +1474,34 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
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);

View File

@ -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<HWND, WinGraphicsWindow *> WindowHandles;