about summary refs log tree commit diff
path: root/src/game/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/client')
-rw-r--r--src/game/client/gc_client.cpp107
-rw-r--r--src/game/client/gc_client.h13
-rw-r--r--src/game/client/gc_console.cpp374
-rw-r--r--src/game/client/gc_hooks.cpp59
-rw-r--r--src/game/client/gc_menu.cpp109
5 files changed, 461 insertions, 201 deletions
diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp
index eae9f52f..fa4e8ca2 100644
--- a/src/game/client/gc_client.cpp
+++ b/src/game/client/gc_client.cpp
@@ -33,7 +33,9 @@ int input_target_lock = 0;
 int chat_mode = CHATMODE_NONE;
 bool menu_active = false;
 bool menu_game_active = false;
-static bool emoticon_selector_active = false;
+int emoticon_selector_active = 0;
+int scoreboard_active = 0;
+static int emoticon_selected_emote = -1;
 
 tuning_params tuning;
 
@@ -438,12 +440,7 @@ static void draw_circle(float x, float y, float r, int segments)
 
 static vec2 emoticon_selector_mouse;
 
-void emoticon_selector_reset()
-{
-	emoticon_selector_mouse = vec2(0, 0);
-}
-
-int emoticon_selector_render()
+void emoticon_selector_render()
 {
 	int x, y;
 	inp_mouse_relative(&x, &y);
@@ -458,17 +455,8 @@ int emoticon_selector_render()
 	if (selected_angle < 0)
 		selected_angle += 2*pi;
 
-	bool return_now = false;
-	int selected_emoticon = -1;
-
 	if (length(emoticon_selector_mouse) > 100)
-		selected_emoticon = (int)(selected_angle / (2*pi) * 12.0f);
-
-	if(!inp_key_pressed(config.key_emoticon))
-	{
-		return_now = true;
-		emoticon_selector_active = false;
-	}
+		emoticon_selected_emote = (int)(selected_angle / (2*pi) * 12.0f);
 
     RECT screen = *ui_screen();
 
@@ -491,7 +479,7 @@ int emoticon_selector_render()
 		if (angle > pi)
 			angle -= 2*pi;
 
-		bool selected = selected_emoticon == i;
+		bool selected = emoticon_selected_emote == i;
 
 		float size = selected ? 96 : 64;
 
@@ -508,8 +496,6 @@ int emoticon_selector_render()
     gfx_setcolor(1,1,1,1);
     gfx_quads_drawTL(emoticon_selector_mouse.x+screen.w/2,emoticon_selector_mouse.y+screen.h/2,24,24);
     gfx_quads_end();
-
-	return return_now ? selected_emoticon : -1;
 }
 
 void render_goals(float x, float y, float w)
@@ -715,7 +701,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title)
 		y += 50.0f;
 	}
 }
-
+/*
 static int do_input(int *v, int key)
 {
 	*v += inp_key_presses(key) + inp_key_releases(key);
@@ -724,6 +710,27 @@ static int do_input(int *v, int key)
 	*v &= INPUT_STATE_MASK;
 	
 	return (*v&1);
+}*/
+
+void chat_say(int team, const char *line)
+{
+	// send chat message
+	msg_pack_start(MSG_SAY, MSGFLAG_VITAL);
+	msg_pack_int(team);
+	msg_pack_string(line, 512);
+	msg_pack_end();
+	client_send_msg();
+}
+
+void chat_enable_mode(int team)
+{
+	if(team)
+		chat_mode = CHATMODE_TEAM;
+	else
+		chat_mode = CHATMODE_ALL;
+		
+	mem_zero(chat_input, sizeof(chat_input));
+	chat_input_len = 0;
 }
 
 void render_game()
@@ -792,17 +799,7 @@ void render_game()
 			{
 				// send message
 				if(chat_input_len)
-				{
-					// send chat message
-					msg_pack_start(MSG_SAY, MSGFLAG_VITAL);
-					if(chat_mode == CHATMODE_ALL)
-						msg_pack_int(0);
-					else
-						msg_pack_int(1);
-					msg_pack_string(chat_input, 512);
-					msg_pack_end();
-					client_send_msg();
-				}
+					chat_say(chat_mode == CHATMODE_ALL ? 0 : 1, chat_input);
 
 				chat_mode = CHATMODE_NONE;
 			}
@@ -831,23 +828,6 @@ void render_game()
 				}
 			}
 		}
-		else
-		{
-			if(chat_mode == CHATMODE_NONE)
-			{
-				if(inp_key_down(config.key_chat))
-					chat_mode = CHATMODE_ALL;
-
-				if(inp_key_down(config.key_teamchat))
-					chat_mode = CHATMODE_TEAM;
-				
-				if(chat_mode != CHATMODE_NONE)
-				{
-					mem_zero(chat_input, sizeof(chat_input));
-					chat_input_len = 0;
-				}
-			}
-		}
 	}
 
 	if (!menu_active)
@@ -889,6 +869,7 @@ void render_game()
 	// update some input
 	if(!menu_active && chat_mode == CHATMODE_NONE)
 	{
+		/*
 		bool do_direct = false;
 		
 		if(!emoticon_selector_active)
@@ -933,7 +914,7 @@ void render_game()
 		}
 		
 		if(do_direct) // do direct input if wanted
-			client_direct_input((int *)&input_data, sizeof(input_data));
+			client_direct_input((int *)&input_data, sizeof(input_data));*/
 	}
 
 
@@ -1402,27 +1383,21 @@ void render_game()
 		return;
 	}
 
-	if(chat_mode == CHATMODE_NONE && !menu_active && !spectate)
-	{
-		if(!emoticon_selector_active && inp_key_pressed(config.key_emoticon))
-		{
-			emoticon_selector_active = true;
-			emoticon_selector_reset();
-		}
-	}
-	else
-		emoticon_selector_active = false;
-
+	// do emoticon
 	if(emoticon_selector_active)
+		emoticon_selector_render();
+	else
 	{
-		int emoticon = emoticon_selector_render();
-		if (emoticon != -1)
+		emoticon_selector_mouse = vec2(0,0);	
+	
+		if(emoticon_selected_emote != -1)
 		{
-			send_emoticon(emoticon);
-			emoticon_selector_active = false;
+			send_emoticon(emoticon_selected_emote);
+			emoticon_selected_emote = -1;
 		}
 	}
 	
+	// render debug stuff
 	if(config.debug && netobjects.local_character && netobjects.local_prev_character)
 	{
 		gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300);
@@ -1436,7 +1411,7 @@ void render_game()
 	}
 
 	// render score board
-	if(inp_key_pressed(KEY_TAB) || // user requested
+	if(scoreboard_active || // user requested
 		(!spectate && (!netobjects.local_character || netobjects.local_character->health < 0)) || // not spectating and is dead
 		(netobjects.gameobj && netobjects.gameobj->game_over) // game over
 		)
diff --git a/src/game/client/gc_client.h b/src/game/client/gc_client.h
index 0b76e38c..48313765 100644
--- a/src/game/client/gc_client.h
+++ b/src/game/client/gc_client.h
@@ -82,6 +82,9 @@ extern int chat_mode;
 void chat_add_line(int client_id, int team, const char *line);
 void chat_reset();
 
+extern int emoticon_selector_active; // TODO: ugly
+extern int scoreboard_active; // TODO: ugly
+
 // client data
 struct client_data
 {
@@ -125,6 +128,11 @@ void process_events(int snaptype);
 void clear_object_pointers();
 void reset_projectile_particles();
 void send_info(bool start);
+void send_emoticon(int emoticon);
+
+void chat_say(int team, const char *line);
+void chat_enable_mode(int team);
+
 inline vec2 random_dir() { return normalize(vec2(frandom()-0.5f, frandom()-0.5f)); }
 
 
@@ -202,3 +210,8 @@ void flow_dbg_render();
 void flow_init();
 void flow_update();
 
+//
+void binds_save();
+void binds_set(int keyid, const char *str);
+const char *binds_get(int keyid);
+
diff --git a/src/game/client/gc_console.cpp b/src/game/client/gc_console.cpp
index 21e3bc34..dd8b7e4d 100644
--- a/src/game/client/gc_console.cpp
+++ b/src/game/client/gc_console.cpp
@@ -84,74 +84,77 @@ public:
 			}
 		}
 
-		if(e.key == KEY_BACKSPACE)
+		if(e.flags&INPFLAG_PRESS)
 		{
-			if(input_len > 0)
+			if(e.key == KEY_BACKSPACE)
 			{
-				input[input_len-1] = 0;
-				input_len--;
+				if(input_len > 0)
+				{
+					input[input_len-1] = 0;
+					input_len--;
 
-				history_entry = 0x0;
+					history_entry = 0x0;
+				}
 			}
-		}
-		else if(e.key == KEY_ENTER || e.key == KEY_KP_ENTER)
-		{
-			if (input_len)
+			else if(e.key == KEY_ENTER || e.key == KEY_KP_ENTER)
 			{
-				char *entry = (char *)ringbuf_allocate(history, input_len+1);
-				mem_copy(entry, input, input_len+1);
-				
-				execute_line(input);
-				input[0] = 0;
-				input_len = 0;
-
-				history_entry = 0x0;
+				if (input_len)
+				{
+					char *entry = (char *)ringbuf_allocate(history, input_len+1);
+					mem_copy(entry, input, input_len+1);
+					
+					execute_line(input);
+					input[0] = 0;
+					input_len = 0;
+
+					history_entry = 0x0;
+				}
 			}
-		}
-		else if (e.key == KEY_UP)
-		{
-			if (history_entry)
+			else if (e.key == KEY_UP)
 			{
-				char *test = (char *)ringbuf_prev(history, history_entry);
+				if (history_entry)
+				{
+					char *test = (char *)ringbuf_prev(history, history_entry);
 
-				if (test)
-					history_entry = test;
-			}
-			else
-				history_entry = (char *)ringbuf_last(history);
+					if (test)
+						history_entry = test;
+				}
+				else
+					history_entry = (char *)ringbuf_last(history);
 
-			if (history_entry)
-			{
-				unsigned int len = strlen(history_entry);
-				if (len < sizeof(input) - 1)
+				if (history_entry)
 				{
-					mem_copy(input, history_entry, len+1);
-					input_len = len;
+					unsigned int len = strlen(history_entry);
+					if (len < sizeof(input) - 1)
+					{
+						mem_copy(input, history_entry, len+1);
+						input_len = len;
+					}
 				}
-			}
-
-		}
-		else if (e.key == KEY_DOWN)
-		{
-			if (history_entry)
-				history_entry = (char *)ringbuf_next(history, history_entry);
 
-			if (history_entry)
+			}
+			else if (e.key == KEY_DOWN)
 			{
-				unsigned int len = strlen(history_entry);
-				if (len < sizeof(input) - 1)
+				if (history_entry)
+					history_entry = (char *)ringbuf_next(history, history_entry);
+
+				if (history_entry)
 				{
-					mem_copy(input, history_entry, len+1);
+					unsigned int len = strlen(history_entry);
+					if (len < sizeof(input) - 1)
+					{
+						mem_copy(input, history_entry, len+1);
 
-					input_len = len;
+						input_len = len;
+					}
+				}
+				else
+				{
+					input[0] = 0;
+					input_len = 0;
 				}
 			}
-			else
-			{
-				input[0] = 0;
-				input_len = 0;
-			}
-		}		
+		}
 	}
 	
 	void print_line(const char *line)
@@ -204,18 +207,19 @@ static void con_team(void *result, void *user_data)
 	send_switch_team(new_team);
 }
 
-/*
-static void con_history(void *result, void *user_data)
+static void con_say(void *result, void *user_data)
 {
-	char *entry = (char *)ringbuf_first(console_history);
-
-	while (entry)
-	{
-		dbg_msg("console/history", entry);
+	const char *str;
+	console_result_string(result, 1, &str);
+	chat_say(0, str);
+}
 
-		entry = (char *)ringbuf_next(console_history, entry);
-	}
-}*/
+static void con_sayteam(void *result, void *user_data)
+{
+	const char *str;
+	console_result_string(result, 1, &str);
+	chat_say(1, str);
+}
 
 void send_kill(int client_id);
 
@@ -224,12 +228,219 @@ static void con_kill(void *result, void *user_data)
 	send_kill(-1);
 }
 
+static char keybindings[KEY_LAST][128] = {{0}};
+
+const char *binds_get(int keyid)
+{
+	if(keyid > 0 && keyid < KEY_LAST)
+		return keybindings[keyid];
+	return "";
+}
+
+void binds_set(int keyid, const char *str)
+{
+	if(keyid < 0 && keyid >= KEY_LAST)
+		return;
+		
+	str_copy(keybindings[keyid], str, sizeof(keybindings[keyid]));
+	if(!keybindings[keyid][0])
+		dbg_msg("binds", "unbound %s (%d)", inp_key_name(keyid), keyid);
+	else
+		dbg_msg("binds", "bound %s (%d) = %s", inp_key_name(keyid), keyid, keybindings[keyid]);
+}
+
+static int get_key_id(const char *key_name)
+{
+	int i = atoi(key_name);
+	if(i > 0 && i < KEY_LAST)
+		return i; // numeric
+		
+	// search for key
+	for(int i = 0; i < KEY_LAST; i++)
+	{
+		if(strcmp(key_name, inp_key_name(i)) == 0)
+			return i;
+	}
+	
+	return 0;
+}
+
+static void con_binds_set(void *result, void *user_data)
+{
+	const char *key_name;
+	const char *bind_str;
+	console_result_string(result, 1, &key_name);
+	console_result_string(result, 2, &bind_str);
+	int id = get_key_id(key_name);
+	
+	if(!id)
+	{
+		dbg_msg("binds", "key %s not found", key_name);
+		return;
+	}
+	
+	binds_set(id, bind_str);
+}
+
+
+static void con_binds_remove(void *result, void *user_data)
+{
+	const char *key_name;
+	console_result_string(result, 1, &key_name);
+	int id = get_key_id(key_name);
+	
+	if(!id)
+	{
+		dbg_msg("binds", "key %s not found", key_name);
+		return;
+	}
+	
+	binds_set(id, "");
+}
+
+static void con_binds_dump(void *result, void *user_data)
+{
+	for(int i = 0; i < KEY_LAST; i++)
+	{
+		if(keybindings[i][0] == 0)
+			continue;
+		dbg_msg("binds", "%s (%d) = %s", inp_key_name(i), i, keybindings[i]);
+	}
+}
+
+void binds_save()
+{
+	char buffer[256];
+	for(int i = 0; i < KEY_LAST; i++)
+	{
+		if(keybindings[i][0] == 0)
+			continue;
+		str_format(buffer, sizeof(buffer), "binds_set %s \"%s\"", inp_key_name(i), keybindings[i]);
+		client_save_line(buffer);
+	}
+}
+
+static void con_key_input_state(void *result, void *user_data)
+{
+	int i;
+	console_result_int(result, 1, &i);
+	((int *)user_data)[0] = i;
+}
+
+static void con_key_input_counter(void *result, void *user_data)
+{
+	int stroke;
+	int *v = (int *)user_data;
+	console_result_int(result, 1, &stroke);
+	if(((*v)&1) != stroke)
+		(*v)++;
+	*v &= INPUT_STATE_MASK;
+}
+
+static void con_key_input_weapon(void *result, void *user_data)
+{
+	int w = (char *)user_data - (char *)0;
+	int stroke;
+	console_result_int(result, 1, &stroke);
+	if(stroke)
+		input_data.wanted_weapon = w;
+}
+
+static void con_chat(void *result, void *user_data)
+{
+	const char *mode;
+	console_result_string(result, 1, &mode);
+	if(strcmp(mode, "all") == 0)
+		chat_enable_mode(0);
+	else if(strcmp(mode, "team") == 0)
+		chat_enable_mode(1);
+	else
+		dbg_msg("console", "expected all or team as mode");
+}
+
+static void con_toggle_local_console(void *result, void *user_data)
+{
+	console_toggle(0);
+}
+
+static void con_toggle_remote_console(void *result, void *user_data)
+{
+	console_toggle(1);
+}
+
+
+static void con_emote(void *result, void *user_data)
+{
+	int emote;
+	console_result_int(result, 1, &emote);
+	send_emoticon(emote);
+}
+
 void client_console_init()
 {
 	console_register_print_callback(client_console_print);
+
+	//
+	MACRO_REGISTER_COMMAND("toggle_local_console", "", con_toggle_local_console, 0x0);
+	MACRO_REGISTER_COMMAND("toggle_remote_console", "", con_toggle_remote_console, 0x0);
+
+	//
 	MACRO_REGISTER_COMMAND("team", "i", con_team, 0x0);
-	//MACRO_REGISTER_COMMAND("history", "", con_history, 0x0);
 	MACRO_REGISTER_COMMAND("kill", "", con_kill, 0x0);
+	
+	// bindings
+	MACRO_REGISTER_COMMAND("binds_set", "ss", con_binds_set, 0x0);
+	MACRO_REGISTER_COMMAND("binds_remove", "s", con_binds_remove, 0x0);
+	MACRO_REGISTER_COMMAND("binds_dump", "", con_binds_dump, 0x0);
+
+	// chatting
+	MACRO_REGISTER_COMMAND("say", "s", con_say, 0x0);
+	MACRO_REGISTER_COMMAND("say_team", "s", con_sayteam, 0x0);
+	MACRO_REGISTER_COMMAND("chat", "s", con_chat, 0x0);
+	MACRO_REGISTER_COMMAND("emote", "i", con_emote, 0);
+
+	// game commands
+	MACRO_REGISTER_COMMAND("+left", "i", con_key_input_state, &input_data.left);
+	MACRO_REGISTER_COMMAND("+right", "i", con_key_input_state, &input_data.right);
+	MACRO_REGISTER_COMMAND("+jump", "i", con_key_input_state, &input_data.jump);
+	MACRO_REGISTER_COMMAND("+hook", "i", con_key_input_state, &input_data.hook);
+	MACRO_REGISTER_COMMAND("+fire", "i", con_key_input_counter, &input_data.fire);
+	MACRO_REGISTER_COMMAND("+weapon1", "i", con_key_input_weapon, (void *)1);
+	MACRO_REGISTER_COMMAND("+weapon2", "i", con_key_input_weapon, (void *)2);
+	MACRO_REGISTER_COMMAND("+weapon3", "i", con_key_input_weapon, (void *)3);
+	MACRO_REGISTER_COMMAND("+weapon4", "i", con_key_input_weapon, (void *)4);
+	MACRO_REGISTER_COMMAND("+weapon5", "i", con_key_input_weapon, (void *)5);
+
+	MACRO_REGISTER_COMMAND("+nextweapon", "i", con_key_input_counter, &input_data.next_weapon);
+	MACRO_REGISTER_COMMAND("+prevweapon", "i", con_key_input_counter, &input_data.prev_weapon);
+	
+	MACRO_REGISTER_COMMAND("+emote", "i", con_key_input_state, &emoticon_selector_active);
+	MACRO_REGISTER_COMMAND("+scoreboard", "i", con_key_input_state, &scoreboard_active);
+	
+	// set default key bindings
+	binds_set(KEY_F1, "toggle_local_console");
+	binds_set(KEY_F2, "toggle_remote_console");
+	binds_set(KEY_TAB, "+scoreboard");
+	binds_set(KEY_F10, "screenshot");
+	
+	binds_set('A', "+left");
+	binds_set('D', "+right");
+	binds_set(KEY_SPACE, "+jump");
+	binds_set(KEY_MOUSE_1, "+fire");
+	binds_set(KEY_MOUSE_2, "+hook");
+	binds_set(KEY_LSHIFT, "+emote");
+
+	binds_set('1', "+weapon1");
+	binds_set('2', "+weapon2");
+	binds_set('3', "+weapon3");
+	binds_set('4', "+weapon4");
+	binds_set('5', "+weapon5");
+	
+	binds_set(KEY_MOUSE_WHEEL_UP, "+prevweapon");
+	binds_set(KEY_MOUSE_WHEEL_DOWN, "+nextweapon");
+	
+	binds_set('T', "chat all");
+	binds_set('Y', "chat team");
 }
 
 void console_handle_input()
@@ -239,16 +450,27 @@ void console_handle_input()
 	for(int i = 0; i < inp_num_events(); i++)
 	{
 		INPUT_EVENT e = inp_get_event(i);
-
-		if (e.key == config.key_toggleconsole)
-			console_toggle(0);
-		else if (e.key == config.key_toggleconsole+1)
-			console_toggle(1);
-		else if(console_active())
-			current_console()->handle_event(e);
+		
+		if(console_active())
+		{
+			if(e.key == KEY_ESC && e.flags&INPFLAG_PRESS)
+				console_toggle(console_type);
+			else
+				current_console()->handle_event(e);
+		}
+		else
+		{
+			if(e.key > 0 && e.key < KEY_LAST && keybindings[e.key][0] != 0)
+			{
+				int stroke = 0;
+				if(e.flags&INPFLAG_PRESS)
+					stroke = 1;
+				console_execute_line_stroked(stroke, keybindings[e.key]);
+			}
+		}
 	}
 
-	if (was_active || console_active())
+	if(was_active || console_active())
 	{
 		inp_clear_events();
 		inp_clear_key_states();
@@ -325,7 +547,7 @@ void console_render()
 
 	gfx_mapscreen(screen.x, screen.y, screen.w, screen.h);
 
-	// do shadow
+	// do console shadow
 	gfx_texture_set(-1);
     gfx_quads_begin();
     gfx_setcolorvertex(0, 0,0,0, 0.5f);
@@ -345,6 +567,16 @@ void console_render()
     gfx_quads_drawTL(0,0,screen.w,console_height);
     gfx_quads_end();
 
+	// do small bar shadow
+	gfx_texture_set(-1);
+    gfx_quads_begin();
+    gfx_setcolorvertex(0, 0,0,0, 0.0f);
+    gfx_setcolorvertex(1, 0,0,0, 0.0f);
+    gfx_setcolorvertex(2, 0,0,0, 0.25f);
+    gfx_setcolorvertex(3, 0,0,0, 0.25f);
+    gfx_quads_drawTL(0,console_height-20,screen.w,10);
+    gfx_quads_end();
+
 	// do the lower bar
 	gfx_texture_set(data->images[IMAGE_CONSOLE_BAR].id);
     gfx_quads_begin();
diff --git a/src/game/client/gc_hooks.cpp b/src/game/client/gc_hooks.cpp
index d8863be7..e85a7e7f 100644
--- a/src/game/client/gc_hooks.cpp
+++ b/src/game/client/gc_hooks.cpp
@@ -31,6 +31,8 @@ extern "C" void modc_console_init()
 	client_console_init();
 }
 
+//binds_save()
+
 static void load_sounds_thread(void *)
 {
 	// load sounds
@@ -112,6 +114,11 @@ extern "C" void modc_init()
 	dbg_msg("", "%f.2ms", ((end-start)*1000)/(float)time_freq());
 }
 
+extern "C" void modc_save_config()
+{
+	binds_save();
+}
+
 extern "C" void modc_entergame()
 {
 }
@@ -355,6 +362,31 @@ extern "C" void modc_rcon_line(const char *line)
 
 extern "C" int modc_snap_input(int *data)
 {
+	static NETOBJ_PLAYER_INPUT last_data = {0};
+	
+	// update player state
+	if(chat_mode != CHATMODE_NONE)
+		input_data.player_state = PLAYERSTATE_CHATTING;
+	else if(menu_active)
+		input_data.player_state = PLAYERSTATE_IN_MENU;
+	else
+		input_data.player_state = PLAYERSTATE_PLAYING;
+	last_data.player_state = input_data.player_state;
+	
+	// we freeze the input if chat or menu is activated
+	if(menu_active || chat_mode != CHATMODE_NONE || console_active())
+	{
+		last_data.left = 0;
+		last_data.right = 0;
+		last_data.hook = 0;
+		last_data.jump = 0;
+		
+		input_data = last_data;
+			
+		mem_copy(data, &input_data, sizeof(input_data));
+		return sizeof(input_data);
+	}
+	
 	picked_up_weapon = -1;
 
 	if(!input_target_lock)
@@ -365,32 +397,8 @@ extern "C" int modc_snap_input(int *data)
 		if(!input_data.target_x && !input_data.target_y)
 			input_data.target_y = 1;
 	}
-	input_target_lock = 0;
-
-	if(chat_mode != CHATMODE_NONE)
-		input_data.player_state = PLAYERSTATE_CHATTING;
-	else if(menu_active)
-		input_data.player_state = PLAYERSTATE_IN_MENU;
-	else
-	{
-		input_data.player_state = PLAYERSTATE_PLAYING;
 
-		// TODO: this doesn't feel too pretty... look into it?
-		if (console_active())
-		{
-			input_data.left = 0;
-			input_data.right = 0;
-			input_data.hook = 0;
-			input_data.jump = 0;
-		}
-		else
-		{
-			input_data.left = inp_key_state(config.key_move_left);
-			input_data.right = inp_key_state(config.key_move_right);
-			input_data.hook = inp_key_state(config.key_hook);
-			input_data.jump  = inp_key_state(config.key_jump);
-		}
-	}
+	input_target_lock = 0;
 
 	// stress testing
 	if(config.dbg_stress)
@@ -409,6 +417,7 @@ extern "C" int modc_snap_input(int *data)
 	}
 
 	// copy and return size	
+	last_data = input_data;
 	mem_copy(data, &input_data, sizeof(input_data));
 	return sizeof(input_data);
 }
diff --git a/src/game/client/gc_menu.cpp b/src/game/client/gc_menu.cpp
index 96b4a9f1..fe2d1c73 100644
--- a/src/game/client/gc_menu.cpp
+++ b/src/game/client/gc_menu.cpp
@@ -224,24 +224,27 @@ int ui_do_edit_box(void *id, const RECT *rect, char *str, int str_size, float fo
 					at_index++;
 				}
 			}
-
-			if (k == KEY_BACKSPACE && at_index > 0)
+			
+			if(e.flags&INPFLAG_PRESS)
 			{
-				memmove(str + at_index - 1, str + at_index, len - at_index + 1);
-				at_index--;
+				if (k == KEY_BACKSPACE && at_index > 0)
+				{
+					memmove(str + at_index - 1, str + at_index, len - at_index + 1);
+					at_index--;
+				}
+				else if (k == KEY_DEL && at_index < len)
+					memmove(str + at_index, str + at_index + 1, len - at_index);
+				else if (k == KEY_ENTER)
+					ui_clear_last_active_item();
+				else if (k == KEY_LEFT && at_index > 0)
+					at_index--;
+				else if (k == KEY_RIGHT && at_index < len)
+					at_index++;
+				else if (k == KEY_HOME)
+					at_index = 0;
+				else if (k == KEY_END)
+					at_index = len;
 			}
-			else if (k == KEY_DEL && at_index < len)
-				memmove(str + at_index, str + at_index + 1, len - at_index);
-			else if (k == KEY_ENTER)
-				ui_clear_last_active_item();
-			else if (k == KEY_LEFT && at_index > 0)
-				at_index--;
-			else if (k == KEY_RIGHT && at_index < len)
-				at_index++;
-			else if (k == KEY_HOME)
-				at_index = 0;
-			else if (k == KEY_END)
-				at_index = len;
 		}
 		
 		r = 1;
@@ -421,7 +424,7 @@ int ui_do_key_reader(void *id, const RECT *rect, int key)
 		for(int i = 0; i < inp_num_events(); i++)
 		{
 			INPUT_EVENT e = inp_get_event(i);
-			if(e.key && e.key != KEY_ESC)
+			if(e.flags&INPFLAG_PRESS && e.key && e.key != KEY_ESC)
 			{
 				new_key = e.key;
 				ui_set_active_item(0);
@@ -444,7 +447,12 @@ int ui_do_key_reader(void *id, const RECT *rect, int key)
 	if (ui_active_item() == id)
 		ui_draw_keyselect_button(id, "???", 0, rect, 0);
 	else
-		ui_draw_keyselect_button(id, inp_key_name(key), 0, rect, 0);
+	{
+		if(key == 0)
+			ui_draw_keyselect_button(id, "", 0, rect, 0);
+		else
+			ui_draw_keyselect_button(id, inp_key_name(key), 0, rect, 0);
+	}
 	return new_key;
 }
 
@@ -1296,33 +1304,50 @@ static void menu2_render_settings_controls(RECT main_view)
 	
 	typedef struct 
 	{
-		char name[32];
-		int *key;
+		char *name;
+		char *command;
+		int keyid;
 	} KEYINFO;
 
-	const KEYINFO keys[] = 
+	KEYINFO keys[] = 
 	{
-		{ "Move Left:", &config.key_move_left },
-		{ "Move Right:", &config.key_move_right },
-		{ "Jump:", &config.key_jump },
-		{ "Fire:", &config.key_fire },
-		{ "Hook:", &config.key_hook },
-		{ "Hammer:", &config.key_weapon1 },
-		{ "Pistol:", &config.key_weapon2 },
-		{ "Shotgun:", &config.key_weapon3 },
-		{ "Grenade:", &config.key_weapon4 },
-		{ "Rifle:", &config.key_weapon5 },
-		{ "Next Weapon:", &config.key_next_weapon },
-		{ "Prev. Weapon:", &config.key_prev_weapon },
-		{ "Emoticon:", &config.key_emoticon },
-		{ "Chat:", &config.key_chat },
-		{ "Team Chat:", &config.key_teamchat },
-		{ "Toggle Console:", &config.key_toggleconsole },
-		{ "Screenshot:", &config.key_screenshot },
+		{ "Move Left:", "+left", 0},
+		{ "Move Right:", "+right", 0 },
+		{ "Jump:", "+jump", 0 },
+		{ "Fire:", "+fire", 0 },
+		{ "Hook:", "+hook", 0 },
+		{ "Hammer:", "+weapon1", 0 },
+		{ "Pistol:", "+weapon2", 0 },
+		{ "Shotgun:", "+weapon3", 0 },
+		{ "Grenade:", "+weapon4", 0 },
+		{ "Rifle:", "+weapon5", 0 },
+		{ "Next Weapon:", "+nextweapon", 0 },
+		{ "Prev. Weapon:", "+prevweapon", 0 },
+		{ "Emoticon:", "+emote", 0 },
+		{ "Chat:", "chat all", 0 },
+		{ "Team Chat:", "chat team", 0 },
+		{ "Console:", "toggle_local_console", 0 },
+		{ "RemoteConsole:", "toggle_remote_console", 0 },
+		{ "Screenshot:", "screenshot", 0 },
 	};
 
 	const int key_count = sizeof(keys) / sizeof(KEYINFO);
 	
+	// this is kinda slow, but whatever
+	for(int keyid = 0; keyid < KEY_LAST; keyid++)
+	{
+		const char *bind = binds_get(keyid);
+		if(!bind[0])
+			continue;
+			
+		for(int i = 0; i < key_count; i++)
+			if(strcmp(bind, keys[i].command) == 0)
+			{
+				keys[i].keyid = keyid;
+				break;
+			}
+	}
+	
 	for (int i = 0; i < key_count; i++)
     {
 		KEYINFO key = keys[i];
@@ -1331,7 +1356,13 @@ static void menu2_render_settings_controls(RECT main_view)
     	ui_vsplit_l(&button, 110.0f, &label, &button);
     	
 		ui_do_label(&label, key.name, 14.0f, -1);
-		*key.key = ui_do_key_reader(key.key, &button, *key.key);
+		int oldid = key.keyid;
+		int newid = ui_do_key_reader(keys[i].name, &button, oldid);
+		if(newid != oldid)
+		{
+			binds_set(oldid, "");
+			binds_set(newid, keys[i].command);
+		}
     	ui_hsplit_t(&main_view, 5.0f, 0, &main_view);
     }	
 }