static bool InputHandler_HandleCoreKey(Key key) {
	struct Screen* active = Gui_GetActiveScreen();

	if (key == KeyBinds[KEYBIND_HIDE_FPS]) {
		Gui_ShowFPS = !Gui_ShowFPS;
	} else if (key == KeyBinds[KEYBIND_FULLSCREEN]) {
		int state = Window_GetWindowState();
		if (state != WINDOW_STATE_MINIMISED) {
			bool fullscreen = state == WINDOW_STATE_FULLSCREEN;
			Window_SetWindowState(fullscreen ? WINDOW_STATE_NORMAL : WINDOW_STATE_FULLSCREEN);
		}
	} else if (key == KeyBinds[KEYBIND_FOG]) {
		short* viewDists = Gui_ClassicMenu ? classicViewDists : normViewDists;
		int count = Gui_ClassicMenu ? Array_Elems(classicViewDists) : Array_Elems(normViewDists);

		if (Key_IsShiftPressed()) {
			InputHandler_CycleDistanceBackwards(viewDists, count);
		} else {
			InputHandler_CycleDistanceForwards(viewDists, count);
		}
	} else if (key == KeyBinds[KEYBIND_INVENTORY] && active == Gui_HUD) {
		Gui_FreeActive();
		Gui_SetActive(InventoryScreen_MakeInstance());
	} else if (key == KEY_F5 && Game_ClassicMode) {
		int weather = Env.Weather == WEATHER_SUNNY ? WEATHER_RAINY : WEATHER_SUNNY;
		Env_SetWeather(weather);
	} else {
		if (Game_ClassicMode) return false;
		return InputHandler_HandleNonClassicKey(key);
	}
	return true;
}
static void InputHandler_MouseUp(void* obj, int button) {
	struct Screen* active = Gui_GetActiveScreen();
	if (!Elem_HandlesMouseUp(active, Mouse_X, Mouse_Y, button)) {
		if (Server.SupportsPlayerClick && button <= MOUSE_MIDDLE) {
			input_pickingId = -1;
			InputHandler_ButtonStateChanged(button, false);
		}
	}
}
static void InputHandler_KeyDown(void* obj, int key, bool was) {
	struct Screen* active;
	int idx;
	struct HotkeyData* hkey;
	String text;

	if (!was && InputHandler_SimulateMouse(key, true)) return;
	active = Gui_GetActiveScreen();

#ifndef CC_BUILD_WEB
	if (key == KEY_ESCAPE && active->Closable) {
		/* Don't want holding down escape to go in and out of pause menu */
		if (!was) Gui_Close(active); 
		return;
	}
#endif

	if (InputHandler_IsShutdown(key)) {
		/* TODO: Do we need a separate exit function in Game class? */
		Window_Close(); return;
	} else if (key == KeyBinds[KEYBIND_SCREENSHOT] && !was) {
		Game_ScreenshotRequested = true; return;
	} else if (Elem_HandlesKeyDown(active, key, was)) {
		return;
	} else if ((key == KEY_ESCAPE || key == KEY_PAUSE) && !active->HandlesAllInput) {
#ifdef CC_BUILD_WEB
		/* Can't do this in KeyUp, because pressing escape without having */
		/* explicitly disabled mouse lock means a KeyUp event isn't sent. */
		/* But switching to pause screen disables mouse lock, causing a KeyUp */
		/* event to be sent, triggering the active->Closable case which immediately
		/* closes the pause screen. Hence why the next KeyUp must be supressed. */
		suppressEscape = true;
#endif
		Gui_FreeActive();
		Gui_SetActive(PauseScreen_MakeInstance()); return;
	}

	/* These should not be triggered multiple times when holding down */
	if (was) return;
	if (InputHandler_HandleCoreKey(key)) {
	} else if (LocalPlayer_HandlesKey(key)) {
	} else {
		idx = Hotkeys_FindPartial(key);
		if (idx == -1) return;

		hkey = &HotkeysList[idx];
		text = StringsBuffer_UNSAFE_Get(&HotkeysText, hkey->TextIndex);

		if (!hkey->StaysOpen) {
			Chat_Send(&text, false);
		} else if (!Gui_Active) {
			HUDScreen_OpenInput(Gui_HUD, &text);
		}
	}
}
static void InputHandler_MouseDown(void* obj, int button) {
	struct Screen* active = Gui_GetActiveScreen();
	if (!Elem_HandlesMouseDown(active, Mouse_X, Mouse_Y, button)) {
		bool left   = button == MOUSE_LEFT;
		bool middle = button == MOUSE_MIDDLE;
		bool right  = button == MOUSE_RIGHT;
		InputHandler_PickBlocks(false, left, middle, right);
	} else {
		input_lastClick = DateTime_CurrentUTC_MS();
	}
}
static void InputHandler_MouseWheel(void* obj, float delta) {
	struct Screen* active = Gui_GetActiveScreen();
	struct Widget* widget;
	bool hotbar;
	if (Elem_HandlesMouseScroll(active, delta)) return;

	hotbar = Key_IsAltPressed() || Key_IsControlPressed() || Key_IsShiftPressed();
	if (!hotbar && Camera.Active->Zoom(delta)) return;
	if (InputHandler_DoFovZoom(delta) || !Inventory.CanChangeSelected) return;

	widget = HUDScreen_GetHotbar(Gui_HUD);
	Elem_HandlesMouseScroll(widget, delta);
}
Example #6
0
bool GameMode_HandlesKeyDown(Key key) {
	Screen* activeScreen = Gui_GetActiveScreen();
	if (key == KeyBind_Get(KeyBind_Inventory) && activeScreen == Gui_HUD) {
		Gui_ReplaceActive(InventoryScreen_MakeInstance());
		return true;
	} else if (key == KeyBind_Get(KeyBind_DropBlock) && !Game_ClassicMode) {
		if (Inventory_CanChangeSelected() && Inventory_SelectedBlock != BLOCK_AIR) {
			/* Don't assign SelectedIndex directly, because we don't want held block
			   switching positions if they already have air in their inventory hotbar. */
			Inventory_Set(Inventory_SelectedIndex, BLOCK_AIR);
			Event_RaiseVoid(&UserEvents_HeldBlockChanged);
		}
		return true;
	}
	return false;
}
static void InputHandler_KeyUp(void* obj, int key) {
	struct Screen* active;
	if (InputHandler_SimulateMouse(key, false)) return;

	if (key == KeyBinds[KEYBIND_ZOOM_SCROLL]) Game_SetFov(Game_DefaultFov);
	active = Gui_GetActiveScreen();

#ifdef CC_BUILD_WEB
	/* When closing menus (which reacquires mouse focus) in key down, */
	/* this still leaves the cursor visible. But if this is instead */
	/* done in key up, the cursor disappears as expected. */
	if (key == KEY_ESCAPE && active->Closable) {
		if (suppressEscape) { suppressEscape = false; return; }
		Gui_Close(active); return;
	}
#endif
	Elem_HandlesKeyUp(active, key);
}
static void InputHandler_KeyPress(void* obj, int keyChar) {
	struct Screen* active = Gui_GetActiveScreen();
	Elem_HandlesKeyPress(active, keyChar);
}
static void InputHandler_MouseMove(void* obj, int xDelta, int yDelta) {
	struct Screen* active = Gui_GetActiveScreen();
	Elem_HandlesMouseMove(active, Mouse_X, Mouse_Y);
}
void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right) {
	TimeMS now = DateTime_CurrentUTC_MS();
	int delta  = (int)(now - input_lastClick);

	Vector3I pos;
	BlockID old, cur, block;
	int i;

	if (cooldown && delta < 250) return; /* 4 times per second */
	input_lastClick = now;

	if (Server.SupportsPlayerClick && !Gui_GetActiveScreen()->HandlesAllInput) {
		input_pickingId = -1;
		InputHandler_ButtonStateChanged(MOUSE_LEFT,   left);
		InputHandler_ButtonStateChanged(MOUSE_RIGHT,  right);
		InputHandler_ButtonStateChanged(MOUSE_MIDDLE, middle);
	}

	if (Gui_GetActiveScreen()->HandlesAllInput) return;

	if (left) {
		/* always play delete animations, even if we aren't picking a block */
		HeldBlockRenderer_ClickAnim(true);

		pos = Game_SelectedPos.BlockPos;
		if (!Game_SelectedPos.Valid || !World_Contains(pos.X, pos.Y, pos.Z)) return;

		old = World_GetBlock(pos.X, pos.Y, pos.Z);
		if (Blocks.Draw[old] == DRAW_GAS || !Blocks.CanDelete[old]) return;

		Game_ChangeBlock(pos.X, pos.Y, pos.Z, BLOCK_AIR);
		Event_RaiseBlock(&UserEvents.BlockChanged, pos, old, BLOCK_AIR);
	} else if (right) {
		pos = Game_SelectedPos.TranslatedPos;
		if (!Game_SelectedPos.Valid || !World_Contains(pos.X, pos.Y, pos.Z)) return;

		old   = World_GetBlock(pos.X, pos.Y, pos.Z);
		block = Inventory_SelectedBlock;
		if (AutoRotate_Enabled) block = AutoRotate_RotateBlock(block);

		if (Game_CanPick(old) || !Blocks.CanPlace[block]) return;
		/* air-ish blocks can only replace over other air-ish blocks */
		if (Blocks.Draw[block] == DRAW_GAS && Blocks.Draw[old] != DRAW_GAS) return;
		if (!InputHandler_CheckIsFree(block)) return;

		Game_ChangeBlock(pos.X, pos.Y, pos.Z, block);
		Event_RaiseBlock(&UserEvents.BlockChanged, pos, old, block);
	} else if (middle) {
		pos = Game_SelectedPos.BlockPos;
		if (!World_Contains(pos.X, pos.Y, pos.Z)) return;

		cur = World_GetBlock(pos.X, pos.Y, pos.Z);
		if (Blocks.Draw[cur] == DRAW_GAS) return;
		if (!(Blocks.CanPlace[cur] || Blocks.CanDelete[cur])) return;
		if (!Inventory_CheckChangeSelected() || Inventory_SelectedBlock == cur) return;

		/* Is the currently selected block an empty slot? */
		if (Inventory_SelectedBlock == BLOCK_AIR) {
			Inventory_SetSelectedBlock(cur); return;
		}

		/* Try to replace same block */
		for (i = 0; i < INVENTORY_BLOCKS_PER_HOTBAR; i++) {
			if (Inventory_Get(i) != cur) continue;
			Inventory_SetSelectedIndex(i); return;
		}

		/* Try to replace empty slots */
		for (i = 0; i < INVENTORY_BLOCKS_PER_HOTBAR; i++) {
			if (Inventory_Get(i) != BLOCK_AIR) continue;
			Inventory_Set(i, cur);
			Inventory_SetSelectedIndex(i); return;
		}

		/* Finally, replace the currently selected block */
		Inventory_SetSelectedBlock(cur);
	}
}