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