void gameplay_help_blit_control_line(int x, int y, int id)
{
	int			has_key=0, has_joy=0;
	char			buf[256];
	config_item	*ci;

	ci = &Control_config[id];

	buf[0] = 0;

	if ( ci->key_id >= 0 ) {
		strcpy_s(buf, textify_scancode(ci->key_id));
		has_key=1;
	}

	if ( ci->joy_id >= 0 ) {
		if ( has_key ) {
			strcat_s(buf, XSTR( ", ", 129));
		}
		strcat_s(buf, Joy_button_text[ci->joy_id]);
		has_joy=1;
	}

	if ( !has_key && !has_joy ) {
		strcpy_s(buf, XSTR( "no binding", 130));
	}

	gr_string(x,y,buf,GR_RESIZE_MENU);

//	gr_string(x+KEY_DESCRIPTION_OFFSET,y,ci->text,GR_RESIZE_MENU);
	gr_string(x+KEY_DESCRIPTION_OFFSET, y, XSTR(ci->text, CONTROL_CONFIG_XSTR + id), GR_RESIZE_MENU);
}
// generate a line for the on-line help for a control item with specified id
// input:	id		=>	index for control item within Control_config[]
//				buf	=> buffer with enough space to hold ouput string
char *gameplay_help_control_text(int id, char *buf)
{
	int			has_key=0, has_joy=0;
	config_item	*ci;

	ci = &Control_config[id];

	if ( ci->key_id >= 0 ) {
		strcpy(buf, textify_scancode(ci->key_id));
		has_key=1;
	}

	if ( ci->joy_id >= 0 ) {
		if ( has_key ) {
			strcat(buf, XSTR( ", ", 129));
		}
		strcat(buf, Joy_button_text[ci->joy_id]);
		has_joy=1;
	}

	if ( !has_key && !has_joy ) {
		strcpy(buf, XSTR( "no binding", 130));
	}

	strcat(buf, XSTR( " - ", 131));
	strcat(buf, ci->text);

	return buf;
}
/*! Given the system default key 'key', return the current key that is bound to that function.
* Both are 'key' and the return value are descriptive strings that can be displayed
* directly to the user.  If 'key' isn't a real key, is not normally bound to anything,
* or there is no key currently bound to the function, NULL is returned.
*/
char *translate_key(char *key)
{
	int index = -1, key_code = -1, joy_code = -1;
	const char *key_text = NULL;
	const char *joy_text = NULL;

	static char text[40] = {"None"};

	index = translate_key_to_index(key, false);
	if (index < 0) {
		return NULL;
	}

	key_code = Control_config[index].key_id;
	joy_code = Control_config[index].joy_id;

	Failed_key_index = index;

	if (key_code >= 0) {
		key_text = textify_scancode(key_code);
	}

	if (joy_code >= 0) {
		joy_text = Joy_button_text[joy_code];
	}

	// both key and joystick button are mapped to this control
	if ((key_code >= 0 ) && (joy_code >= 0) ) {
		strcpy_s(text, key_text);
		strcat_s(text, " or ");
		strcat_s(text, joy_text);
	}
	// if we only have one
	else if (key_code >= 0 ) {
		strcpy_s(text, key_text);
	}
	else if (joy_code >= 0) {
		strcpy_s(text, joy_text);
	}
	else {
		strcpy_s(text, "None");
	}

	return text;
}
// Given the system default key 'key', return the current key that is bound to the function
// Both are 'key' and the return value are descriptive strings that can be displayed
// directly to the user.  If 'key' isn't a real key or not normally bound to anything,
// or there is no key current bound to the function, NULL is returned.
char *translate_key(char *key)
{
	int index = -1, code = -1;

	index = translate_key_to_index(key);
	if (index < 0)
		return NULL;

	code = Control_config[index].key_id;
	Failed_key_index = index;
	if (code < 0) {
		code = Control_config[index].joy_id;
		if (code >= 0)
			return Joy_button_text[code];
	}

	return textify_scancode(code);
}
Beispiel #5
0
bool ConditionedHook::ConditionsValid(int action, object* objp)
{
	uint i;

	//Return false if any conditions are not met
	script_condition* scp;
	ship_info* sip;
	for (i = 0; i < MAX_HOOK_CONDITIONS; i++)
	{
		scp = &Conditions[i];
		switch (scp->condition_type)
		{
		case CHC_STATE:
			if (gameseq_get_depth() < 0)
				return false;
			if (stricmp(GS_state_text[gameseq_get_state(0)], scp->data.name))
				return false;
			break;
		case CHC_SHIPTYPE:
			if (objp == NULL || objp->type != OBJ_SHIP)
				return false;
			sip = &Ship_info[Ships[objp->instance].ship_info_index];
			if (sip->class_type < 0)
				return false;
			if (stricmp(Ship_types[sip->class_type].name, scp->data.name))
				return false;
		case CHC_SHIPCLASS:
			if (objp == NULL || objp->type != OBJ_SHIP)
				return false;
			if (stricmp(Ship_info[Ships[objp->instance].ship_info_index].name, scp->data.name))
				return false;
			break;
		case CHC_SHIP:
			if (objp == NULL || objp->type != OBJ_SHIP)
				return false;
			if (stricmp(Ships[objp->instance].ship_name, scp->data.name))
				return false;
			break;
		case CHC_MISSION:
			{
				//WMC - Get mission filename with Mission_filename
				//I don't use Game_current_mission_filename, because
				//Mission_filename is valid in both fs2_open and FRED
				size_t len = strlen(Mission_filename);
				if (!len)
					return false;
				if (len > 4 && !stricmp(&Mission_filename[len - 4], ".fs2"))
					len -= 4;
				if (strnicmp(scp->data.name, Mission_filename, len))
					return false;
				break;
			}
		case CHC_CAMPAIGN:
			{
				size_t len = strlen(Campaign.filename);
				if (!len)
					return false;
				if (len > 4 && !stricmp(&Mission_filename[len - 4], ".fc2"))
					len -= 4;
				if (strnicmp(scp->data.name, Mission_filename, len))
					return false;
				break;
			}
		case CHC_WEAPONCLASS:
			if (objp == NULL || objp->type != OBJ_WEAPON)
				return false;
			if (stricmp(Weapon_info[Weapons[objp->instance].weapon_info_index].name, scp->data.name))
				return false;
			break;
		case CHC_OBJECTTYPE:
			if (objp == NULL)
				return false;
			if (stricmp(Object_type_names[objp->type], scp->data.name))
				return false;
			break;
		case CHC_KEYPRESS:
			{
				extern int Current_key_down;
				if (gameseq_get_depth() < 0)
					return false;
				if (Current_key_down == 0)
					return false;
				//WMC - could be more efficient, but whatever.
				if (stricmp(textify_scancode(Current_key_down), scp->data.name))
					return false;
				break;
			}
		case CHC_VERSION:
			{
				// Goober5000: I'm going to assume scripting doesn't care about SVN revision
				char buf[32];
				sprintf(buf, "%i.%i.%i", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD);
				if (stricmp(buf, scp->data.name))
				{
					//In case some people are lazy and say "3.7" instead of "3.7.0" or something
					if (FS_VERSION_BUILD == 0)
					{
						sprintf(buf, "%i.%i", FS_VERSION_MAJOR, FS_VERSION_MINOR);
						if (stricmp(buf, scp->data.name))
							return false;
					}
					else
					{
						return false;
					}
				}
				break;
			}
		case CHC_APPLICATION:
			{
				if (Fred_running)
				{
					if (stricmp("FRED2_Open", scp->data.name) && stricmp("FRED2_Open", scp->data.name) &&
						stricmp("FRED 2", scp->data.name) && stricmp("FRED", scp->data.name))
						return false;
				}
				else
				{
					if (stricmp("FS2_Open", scp->data.name) && stricmp("FS2Open", scp->data.name) &&
						stricmp("Freespace 2", scp->data.name) && stricmp("Freespace", scp->data.name))
						return false;
				}
			}
		default:
			break;
		}
	}

	return true;
}
Beispiel #6
0
//	Add a key up or down code to the key buffer.  state=1 -> down, state=0 -> up
// latency => time difference in ms between when key was actually pressed and now
//void key_mark( uint code, int state )
void key_mark( uint code, int state, uint latency )
{
	uint scancode, breakbit, temp, event_time;
	ushort keycode;	

	if ( !key_inited ) return;

	ENTER_CRITICAL_SECTION( key_lock );		

	// If running in the UK, need to translate their wacky slash scancode to ours
	if ( code == KEY_SLASH_UK ) {
		code = KEY_SLASH;
	}

#ifndef SCP_UNIX

	if ( (code == 0xc5) && !Key_running_NT ) {
		key_turn_off_numlock();
	}
#endif

	Assert( code < NUM_KEYS );	

	event_time = timer_get_milliseconds() - latency;
	// event_time = timeGetTime() - latency;

	// Read in scancode
	scancode = code & (NUM_KEYS-1);
	breakbit = !state;
	
	if (breakbit) {
		// Key going up
		keyd_last_released = scancode;
		keyd_pressed[scancode] = 0;
		key_data.NumUps[scancode]++;

		// What is the point of this code?  "temp" is never used!
		temp = 0;
		temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
		temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
		temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
		temp |= keyd_pressed[KEY_DEBUG_KEY];
	
		if (event_time < key_data.TimeKeyWentDown[scancode]) {
			key_data.TimeKeyHeldDown[scancode] = 0;
		} else {
			key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];
		}

		Current_key_down = scancode;
		if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
			Current_key_down |= KEY_SHIFTED;
		}

		if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
			Current_key_down |= KEY_ALTED;
		}

		if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
			Current_key_down |= KEY_CTRLED;
		}

		Script_system.SetHookVar("Key", 's', textify_scancode(Current_key_down));
		Script_system.RunCondition(CHA_KEYRELEASED);
		Script_system.RemHookVar("Key");
	} else {
		// Key going down
		keyd_last_pressed = scancode;
		keyd_time_when_last_pressed = event_time;
		if (!keyd_pressed[scancode]) {
			// First time down
			key_data.TimeKeyWentDown[scancode] = event_time;
			keyd_pressed[scancode] = 1;
			key_data.NumDowns[scancode]++;
			key_data.down_check[scancode]++;

			//WMC - For scripting
			Current_key_down = scancode;
			if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
				Current_key_down |= KEY_SHIFTED;
			}

			if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
				Current_key_down |= KEY_ALTED;
			}

			if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
				Current_key_down |= KEY_CTRLED;
			}

			Script_system.SetHookVar("Key", 's', textify_scancode(Current_key_down));
			Script_system.RunCondition(CHA_KEYPRESSED);
			Script_system.RemHookVar("Key");
		} else if (!keyd_repeat) {
			// Don't buffer repeating key if repeat mode is off
			scancode = 0xAA;		
		} 

		if ( scancode!=0xAA ) {
			keycode = (unsigned short)scancode;

			if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
				keycode |= KEY_SHIFTED;
			}

			if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
				keycode |= KEY_ALTED;
			}

			if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
				keycode |= KEY_CTRLED;
			}

#ifndef NDEBUG
			if ( keyd_pressed[KEY_DEBUG_KEY] ) {
				keycode |= KEY_DEBUGGED;
			}
#else
			if ( keyd_pressed[KEY_DEBUG_KEY] ) {
				mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
				if (Cheats_enabled && Key_normal_game) {
					keycode |= KEY_DEBUGGED1;
				}
			}

#endif

			if ( keycode ) {
				temp = key_data.keytail+1;
				if ( temp >= KEY_BUFFER_SIZE ) temp=0;

				if (temp!=key_data.keyhead) {
					key_data.keybuffer[key_data.keytail] = keycode;
					key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
					key_data.keytail = temp;
				}
			}
		}
	}

	LEAVE_CRITICAL_SECTION( key_lock );
}
bool ConditionedHook::ConditionsValid(int action, object *objp, int more_data)
{
	uint i;

	//Return false if any conditions are not met
	script_condition *scp;
	ship_info *sip;
	for(i = 0; i < MAX_HOOK_CONDITIONS; i++)
	{
		scp = &Conditions[i];
		switch(scp->condition_type)
		{
			case CHC_STATE:
				if(gameseq_get_depth() < 0)
					return false;
				if(stricmp(GS_state_text[gameseq_get_state(0)], scp->data.name))
					return false;
				break;
			case CHC_SHIPTYPE:
				if(objp == NULL || objp->type != OBJ_SHIP)
					return false;
				sip = &Ship_info[Ships[objp->instance].ship_info_index];
				if(sip->class_type < 0)
					return false;
				if(stricmp(Ship_types[sip->class_type].name, scp->data.name))
					return false;
			case CHC_SHIPCLASS:
				if(objp == NULL || objp->type != OBJ_SHIP)
					return false;
				if(stricmp(Ship_info[Ships[objp->instance].ship_info_index].name, scp->data.name))
					return false;
				break;
			case CHC_SHIP:
				if(objp == NULL || objp->type != OBJ_SHIP)
					return false;
				if(stricmp(Ships[objp->instance].ship_name, scp->data.name))
					return false;
				break;
			case CHC_MISSION:
				{
					//WMC - Get mission filename with Mission_filename
					//I don't use Game_current_mission_filename, because
					//Mission_filename is valid in both fs2_open and FRED
					size_t len = strlen(Mission_filename);
					if(!len)
						return false;
					if(len > 4 && !stricmp(&Mission_filename[len-4], ".fs2"))
						len -= 4;
					if(strnicmp(scp->data.name, Mission_filename, len))
						return false;
					break;
				}
			case CHC_CAMPAIGN:
				{
					size_t len = strlen(Campaign.filename);
					if(!len)
						return false;
					if(len > 4 && !stricmp(&Mission_filename[len-4], ".fc2"))
						len -= 4;
					if(strnicmp(scp->data.name, Mission_filename, len))
						return false;
					break;
				}
			case CHC_WEAPONCLASS:
				{
					if (action == CHA_COLLIDEWEAPON) {
						if (stricmp(Weapon_info[more_data].name, scp->data.name) != 0)
							return false;
					} else if (!(action == CHA_ONWPSELECTED || action == CHA_ONWPDESELECTED || action == CHA_ONWPEQUIPPED || action == CHA_ONWPFIRED || action == CHA_ONTURRETFIRED )) {
						if(objp == NULL || (objp->type != OBJ_WEAPON && objp->type != OBJ_BEAM))
							return false;
						else if (( objp->type == OBJ_WEAPON) && (stricmp(Weapon_info[Weapons[objp->instance].weapon_info_index].name, scp->data.name) != 0 ))
							return false;
						else if (( objp->type == OBJ_BEAM) && (stricmp(Weapon_info[Beams[objp->instance].weapon_info_index].name, scp->data.name) != 0 ))
							return false;
					} else if(objp == NULL || objp->type != OBJ_SHIP) {
						return false;
					} else {

						// Okay, if we're still here, then objp is both valid and a ship
						ship* shipp = &Ships[objp->instance];
						bool primary = false, secondary = false, prev_primary = false, prev_secondary = false;
						switch (action) {
							case CHA_ONWPSELECTED:
								primary = stricmp(Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name, scp->data.name) == 0;
								secondary = stricmp(Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name, scp->data.name) == 0;
								
								if (!(primary || secondary))
									return false;

								if ((shipp->flags[Ship::Ship_Flags::Primary_linked]) && primary && (Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].wi_flags[Weapon::Info_Flags::Nolink]))
									return false;
								
								break;
							case CHA_ONWPDESELECTED:
								primary = stricmp(Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name, scp->data.name) == 0;
								prev_primary = stricmp(Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.previous_primary_bank]].name, scp->data.name) == 0;
								secondary = stricmp(Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name, scp->data.name) == 0;
								prev_secondary = stricmp(Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.previous_secondary_bank]].name, scp->data.name) == 0;

								if ((shipp->flags[Ship::Ship_Flags::Primary_linked]) && prev_primary && (Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.previous_primary_bank]].wi_flags[Weapon::Info_Flags::Nolink]))
									return true;

								if ( !prev_secondary && ! secondary && !prev_primary && !primary )
									return false;

								if ( (!prev_secondary && !secondary) && (prev_primary && primary) ) 
									return false;

								if ( (!prev_secondary && !secondary) && (!prev_primary && primary) ) 
									return false;

								if ( (!prev_primary && !primary) && (prev_secondary && secondary) )
									return false;

								if ( (!prev_primary && !primary) && (!prev_secondary && secondary) )
									return false;

								break;
							case CHA_ONWPEQUIPPED: {
								bool equipped = false;
								for(int j = 0; j < MAX_SHIP_PRIMARY_BANKS; j++) {
									if (!equipped && (shipp->weapons.primary_bank_weapons[j] >= 0) && (shipp->weapons.primary_bank_weapons[j] < MAX_WEAPON_TYPES) ) {
										if ( !stricmp(Weapon_info[shipp->weapons.primary_bank_weapons[j]].name, scp->data.name) ) {
											equipped = true;
											break;
										}
									}
								}
							
								if (!equipped) {
									for(int j = 0; j < MAX_SHIP_SECONDARY_BANKS; j++) {
										if (!equipped && (shipp->weapons.secondary_bank_weapons[j] >= 0) && (shipp->weapons.secondary_bank_weapons[j] < MAX_WEAPON_TYPES) ) {
											if ( !stricmp(Weapon_info[shipp->weapons.secondary_bank_weapons[j]].name, scp->data.name) ) {
												equipped = true;
												break;
											}
										}
									}
								}

								if (!equipped)
									return false;
							
								break;
							}
							case CHA_ONWPFIRED: {
								if (more_data == 1) {
									primary = stricmp(Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name, scp->data.name) == 0;
									secondary = false;
								} else {
									primary = false;
									secondary = stricmp(Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name, scp->data.name) == 0;
								}

								if ((shipp->flags[Ship::Ship_Flags::Primary_linked]) && primary && (Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].wi_flags[Weapon::Info_Flags::Nolink]))
								 	return false;

								return more_data == 1 ? primary : secondary;

								break;
							}
							case CHA_ONTURRETFIRED: {
								if (! (stricmp(Weapon_info[shipp->last_fired_turret->last_fired_weapon_info_index].name, scp->data.name) == 0))
									return false;
								break;
							}
							case CHA_PRIMARYFIRE: {
								if (stricmp(Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name, scp->data.name))
									return false;
								break;
							}
							case CHA_SECONDARYFIRE: {
								if (stricmp(Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name, scp->data.name))
									return false;
								break;
							}
							case CHA_BEAMFIRE: {
								if (!(stricmp(Weapon_info[more_data].name, scp->data.name) == 0))
									return false;
								break;
							}

						}
					} // case CHC_WEAPONCLASS
					break;
				}
			case CHC_OBJECTTYPE:
				if(objp == NULL)
					return false;
				if(stricmp(Object_type_names[objp->type], scp->data.name))
					return false;
				break;
			case CHC_KEYPRESS:
				{
					extern int Current_key_down;
					if(gameseq_get_depth() < 0)
						return false;
					if(Current_key_down == 0)
						return false;
					//WMC - could be more efficient, but whatever.
					if(stricmp(textify_scancode(Current_key_down), scp->data.name))
						return false;
					break;
				}
			case CHC_ACTION:
				{
					if(gameseq_get_depth() < 0)
						return false;

					int action_index = more_data;

					if (action_index <= 0 || stricmp(scp->data.name, Control_config[action_index].text))
						return false;
					break;
				}
			case CHC_VERSION:
				{
					// Goober5000: I'm going to assume scripting doesn't care about SVN revision
					char buf[32];
					sprintf(buf, "%i.%i.%i", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD);
					if(stricmp(buf, scp->data.name))
					{
						//In case some people are lazy and say "3.7" instead of "3.7.0" or something
						if(FS_VERSION_BUILD == 0)
						{
							sprintf(buf, "%i.%i", FS_VERSION_MAJOR, FS_VERSION_MINOR);
							if(stricmp(buf, scp->data.name))
								return false;
						}
						else
						{
							return false;
						}
					}
					break;
				}
			case CHC_APPLICATION:
				{
					if(Fred_running)
					{
						if(stricmp("FRED2_Open", scp->data.name) && stricmp("FRED2Open", scp->data.name) && stricmp("FRED 2", scp->data.name) && stricmp("FRED", scp->data.name))
							return false;
					}
					else
					{
						if(stricmp("FS2_Open", scp->data.name) && stricmp("FS2Open", scp->data.name) && stricmp("Freespace 2", scp->data.name) && stricmp("Freespace", scp->data.name))
							return false;
					}
				}
			default:
				break;
		}
	}

	return true;
}
Beispiel #8
0
//	Add a key up or down code to the key buffer.  state=1 -> down, state=0 -> up
// latency => time difference in ms between when key was actually pressed and now
//void key_mark( uint code, int state )
void key_mark(uint code, int state, uint latency)
{
	uint scancode, breakbit, temp, event_time;
	ushort keycode;

	if (!key_inited)
		return;

	ENTER_CRITICAL_SECTION(key_lock);

	// If running in the UK, need to translate their wacky slash scancode to ours
	//if ( code == KEY_SLASH_UK ) {
	//	code = KEY_SLASH;
	//}

	if (Lcl_fr)
	{
		switch (code)
		{
		case KEY_A:
			code = KEY_Q;
			break;

		case KEY_M:
			code = KEY_COMMA;
			break;

		case KEY_Q:
			code = KEY_A;
			break;

		case KEY_W:
			code = KEY_Z;
			break;

		case KEY_Z:
			code = KEY_W;
			break;

		case KEY_SEMICOL:
			code = KEY_M;
			break;

		case KEY_COMMA:
			code = KEY_SEMICOL;
			break;
		}
#if defined(SCP_UNIX) && !defined(__APPLE__)
	} else if(Lcl_gr){
		switch (code) {
		case KEY_Y:
			code = KEY_Z;
			break;

		case KEY_Z:
			code = KEY_Y;
			break;
		}
#endif
	}

	if ((code == 0xc5) && !Key_running_NT)
	{
		key_turn_off_numlock();
	}

	Assert(code < NUM_KEYS);

	event_time = timer_get_milliseconds() - latency;
	// event_time = timeGetTime() - latency;

	// Read in scancode
	scancode = code & (NUM_KEYS - 1);
	breakbit = !state;

	if (breakbit)
	{
		// Key going up
		keyd_last_released = scancode;
		keyd_pressed[scancode] = 0;
		key_data.NumUps[scancode]++;

		//	What is the point of this code?  "temp" is never used!
		temp = 0;
		temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
		temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
		temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
		//#ifndef NDEBUG
		temp |= keyd_pressed[KEY_DEBUG_KEY];
		//#endif	
		if (event_time < key_data.TimeKeyWentDown[scancode])
			key_data.TimeKeyHeldDown[scancode] = 0;
		else
			key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];

		Current_key_down = scancode;
		if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT])
			Current_key_down |= KEY_SHIFTED;

		if (keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT])
			Current_key_down |= KEY_ALTED;

		if (keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL])
			Current_key_down |= KEY_CTRLED;
		Script_system.SetHookVar("Key", 's', textify_scancode(Current_key_down));
		Script_system.RunCondition(CHA_KEYRELEASED);
		Script_system.RemHookVar("Key");
	}
	else
	{
		// Key going down
		keyd_last_pressed = scancode;
		keyd_time_when_last_pressed = event_time;
		if (!keyd_pressed[scancode])
		{
			// First time down
			key_data.TimeKeyWentDown[scancode] = event_time;
			keyd_pressed[scancode] = 1;
			key_data.NumDowns[scancode]++;
			key_data.down_check[scancode]++;

			//			mprintf(( "Scancode = %x\n", scancode ));

			//			if ( scancode == KEY_BREAK )
			//				Int3();


			//WMC - For scripting
			Current_key_down = scancode;
			if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT])
				Current_key_down |= KEY_SHIFTED;

			if (keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT])
				Current_key_down |= KEY_ALTED;

			if (keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL])
				Current_key_down |= KEY_CTRLED;
			Script_system.SetHookVar("Key", 's', textify_scancode(Current_key_down));
			Script_system.RunCondition(CHA_KEYPRESSED);
			Script_system.RemHookVar("Key");
		}
		else if (!keyd_repeat)
		{
			// Don't buffer repeating key if repeat mode is off
			scancode = 0xAA;
		}

		if (scancode != 0xAA)
		{
			keycode = (unsigned short)scancode;

			if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT])
				keycode |= KEY_SHIFTED;

			if (keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT])
				keycode |= KEY_ALTED;

			if (keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL])
				keycode |= KEY_CTRLED;

#ifndef NDEBUG
			if (keyd_pressed[KEY_DEBUG_KEY])
				keycode |= KEY_DEBUGGED;
#else
			if ( keyd_pressed[KEY_DEBUG_KEY] ) {
				mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
				if (Cheats_enabled && Key_normal_game) {
					keycode |= KEY_DEBUGGED1;
				}
			}

#endif

			if (keycode)
			{
				temp = key_data.keytail + 1;
				if (temp >= KEY_BUFFER_SIZE)
					temp = 0;

				if (temp != key_data.keyhead)
				{
					int i, accept_key = 1;
					// Num_filter_keys will only be non-zero when a key filter has
					// been explicity set up via key_set_filter()
					for (i = 0; i < Num_filter_keys; i++)
					{
						accept_key = 0;
						if (Key_filter[i] == keycode)
						{
							accept_key = 1;
							break;
						}
					}

					if (accept_key)
					{
						key_data.keybuffer[key_data.keytail] = keycode;
						key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
						key_data.keytail = temp;
					}
				}
			}
		}
	}

	LEAVE_CRITICAL_SECTION(key_lock);
}