/* * Copyright (c) 2012. HappyDroids LLC, All rights reserved. */ package com.happydroids.droidtowers.input; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.InputAdapter; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.input.GestureDetector; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.utils.Array; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.eventbus.EventBus; import com.happydroids.droidtowers.entities.GameLayer; import com.happydroids.droidtowers.events.SafeEventBus; import com.happydroids.droidtowers.events.SwitchToolEvent; import com.happydroids.droidtowers.scenes.components.SceneManager; import javax.annotation.Nullable; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import static com.badlogic.gdx.input.GestureDetector.GestureListener; public class InputSystem extends InputAdapter { private static final String TAG = InputSystem.class.getSimpleName(); private Array<InputProcessorEntry> inputProcessors; private HashMap<Integer, Array<InputCallback>> keyBindings; private OrthographicCamera camera; private CameraController cameraController; private GestureDetector gestureDetector; private GestureDelegater gestureDelegater; private static InputSystem instance; private List<GameLayer> gameLayers; private EventBus eventBus; private float timeUntilProcessorCleanup; private float timeSinceDrag; public static InputSystem instance() { if (instance == null) { instance = new InputSystem(); } return instance; } public InputSystem() { inputProcessors = new Array<InputProcessorEntry>(4); keyBindings = Maps.newHashMap(); eventBus = new SafeEventBus(InputSystem.class.getSimpleName()); } public void addInputProcessor(InputProcessor inputProcessor, int priority) { inputProcessors.add(new InputProcessorEntry(inputProcessor, priority)); inputProcessors.sort(); } public void removeInputProcessor(InputProcessor inputProcessor) { for (InputProcessorEntry processorEntry : inputProcessors) { if (processorEntry.getInputProcessor() == inputProcessor) { processorEntry.markForRemoval(); } } } public void switchTool(GestureTool selectedTool, Runnable switchToolRunnable) { if (gestureDelegater != null) { gestureDelegater.switchTool(SceneManager.activeScene() .getCamera(), gestureDelegater.getGameLayers(), selectedTool, switchToolRunnable); } eventBus.post(new SwitchToolEvent(selectedTool)); } public GestureListener getCurrentTool() { return gestureDelegater != null ? gestureDelegater.getCurrentTool() : null; } public void bind(int keyCode, InputCallback inputCallback) { Array<InputCallback> inputCallbacks = getBindingsForKeyCode(keyCode); if (inputCallbacks != null) { inputCallback.addBoundKey(keyCode); inputCallbacks.insert(0, inputCallback); } } public void bind(int[] keyCodes, InputCallback inputCallback) { for (int i = 0, keyCodesLength = keyCodes.length; i < keyCodesLength; i++) { int keyCode = keyCodes[i]; bind(keyCode, inputCallback); } } public void listen(int keyCode, InputCallback inputCallback) { getBindingsForKeyCode(keyCode).add(inputCallback); } private Array<InputCallback> getBindingsForKeyCode(int keyCode) { Array<InputCallback> inputCallbacks; if (keyBindings == null) { keyBindings = Maps.newHashMap(); } if (!keyBindings.containsKey(keyCode)) { inputCallbacks = new Array<InputCallback>(); keyBindings.put(keyCode, inputCallbacks); } else { inputCallbacks = keyBindings.get(keyCode); } return inputCallbacks; } @SuppressWarnings("WhileLoopReplaceableByForEach") public boolean keyDown(int keycode) { if (keyBindings != null && keyBindings.containsKey(keycode)) { float deltaTime = Gdx.graphics.getDeltaTime(); Array<InputCallback> actionsForKeyCode = keyBindings.get(keycode); for (int i = 0, actionsForKeyCodeSize = actionsForKeyCode.size; i < actionsForKeyCodeSize; i++) { InputCallback inputCallback = actionsForKeyCode.get(i); if (inputCallback.run(deltaTime)) { return true; } } } if (inputProcessors != null) { for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (!entry.isMarkedForRemoval() && entry.getInputProcessor().keyDown(keycode)) { return true; } } } return false; } @Override public boolean keyTyped(char character) { if (inputProcessors != null) { for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (!entry.isMarkedForRemoval() && entry.getInputProcessor().keyTyped(character)) { return true; } } } return false; } @Override public boolean keyUp(int keycode) { if (inputProcessors != null) { for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (!entry.isMarkedForRemoval() && entry.getInputProcessor().keyUp(keycode)) { return true; } } } return false; } public boolean touchDown(int x, int y, int pointer, int button) { if (inputProcessors != null) { for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (!entry.isMarkedForRemoval() && entry.getInputProcessor().touchDown(x, y, pointer, button)) { return true; } } } return false; } public boolean touchUp(int x, int y, int pointer, int button) { if (inputProcessors != null) { for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (!entry.isMarkedForRemoval() && entry.getInputProcessor().touchUp(x, y, pointer, button)) { return true; } } } return false; } public boolean touchDragged(int x, int y, int pointer) { timeSinceDrag = 0f; if (inputProcessors != null) { for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (!entry.isMarkedForRemoval() && entry.getInputProcessor().touchDragged(x, y, pointer)) { return true; } } } return false; } public boolean scrolled(int amount) { if (inputProcessors != null) { for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (!entry.isMarkedForRemoval() && entry.getInputProcessor().scrolled(amount)) { return true; } } } return gestureDelegater != null && gestureDelegater.scrolled(amount); } public void update(float deltaTime) { timeSinceDrag += deltaTime; timeUntilProcessorCleanup -= deltaTime; if (timeUntilProcessorCleanup <= 0) { timeUntilProcessorCleanup = 3f; Iterables.removeIf(inputProcessors, INPUT_PROCESSOR_CLEANER); } if (gestureDelegater != null) { gestureDelegater.update(deltaTime); } } public void unbind(int keyCode, InputCallback inputCallbackToRemove) { if (keyBindings == null || !keyBindings.containsKey(keyCode)) { return; } Iterator<InputCallback> iterator = keyBindings.get(keyCode).iterator(); while (iterator.hasNext()) { InputCallback inputCallback = iterator.next(); if (inputCallback == inputCallbackToRemove) { iterator.remove(); } } } public void unbind(int[] keyCodes, InputCallback inputCallback) { for (int i = 0, keyCodesLength = keyCodes.length; i < keyCodesLength; i++) { int keyCode = keyCodes[i]; unbind(keyCode, inputCallback); } } public void setGestureDelegate(GestureDelegater gestureDelegate) { this.gestureDelegater = gestureDelegate; } public void unfocusAll() { Gdx.app.debug(TAG, "unfocusAll()"); if (gestureDetector != null) { gestureDetector.reset(); } for (int i = 0, inputProcessorsSize = inputProcessors.size; i < inputProcessorsSize; i++) { InputProcessorEntry entry = inputProcessors.get(i); if (entry.getInputProcessor() instanceof Stage) { ((Stage) entry.getInputProcessor()).unfocusAll(); } } } public void unbind(InputCallback... callbacks) { if (callbacks == null || callbacks.length == 0) { return; } for (Map.Entry<Integer, Array<InputCallback>> entry : keyBindings.entrySet()) { for (InputCallback callback : callbacks) { entry.getValue().removeValue(callback, false); } } } public EventBus events() { return eventBus; } public boolean wasDragging() { Gdx.app.log(TAG, "timeSinceDrag: " + timeSinceDrag); return timeSinceDrag < 0.5f; } public static class Keys extends Input.Keys { } public static final Predicate<InputProcessorEntry> INPUT_PROCESSOR_CLEANER = new Predicate<InputProcessorEntry>() { @Override public boolean apply(@Nullable InputProcessorEntry input) { return input.isMarkedForRemoval(); } }; }