/* * Copyright 2015 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.input.lwjgl; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import net.java.games.input.Component; import net.java.games.input.Component.Identifier; import net.java.games.input.Component.Identifier.Button; import net.java.games.input.Controller; import net.java.games.input.Controller.Type; import net.java.games.input.ControllerEnvironment; import net.java.games.input.ControllerEvent; import net.java.games.input.ControllerListener; import net.java.games.input.Event; import net.java.games.input.EventQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.config.ControllerConfig; import org.terasology.config.ControllerConfig.ControllerInfo; import org.terasology.input.ButtonState; import org.terasology.input.ControllerDevice; import org.terasology.input.ControllerId; import org.terasology.input.Input; import org.terasology.input.InputType; import org.terasology.input.device.ControllerAction; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; /** * Retrieves information on connected controllers through JInput. */ public class JInputControllerDevice implements ControllerDevice { private static final Logger logger = LoggerFactory.getLogger(JInputControllerDevice.class); private final Set<Type> filter = ImmutableSet.of(Type.KEYBOARD, Type.MOUSE, Type.UNKNOWN); private final Map<Identifier, Integer> buttonMap = ImmutableMap.<Identifier, Integer>builder() .put(Button._0, ControllerId.ZERO) .put(Button._1, ControllerId.ONE) .put(Button._2, ControllerId.TWO) .put(Button._3, ControllerId.THREE) .put(Button._4, ControllerId.FOUR) .put(Button._5, ControllerId.FIVE) .put(Button._6, ControllerId.SIX) .put(Button._7, ControllerId.SEVEN) .put(Button._8, ControllerId.EIGHT) .put(Button._9, ControllerId.NINE) .put(Button._10, ControllerId.TEN) .put(Button._11, ControllerId.ELEVEN) .build(); private ControllerConfig config; private final List<Controller> controllers = new ArrayList<>(); public JInputControllerDevice(ControllerConfig config) { this.config = config; ControllerEnvironment env = ControllerEnvironment.getDefaultEnvironment(); // Unfortunately, no existing implementation env.addControllerListener(new ControllerListener() { @Override public void controllerRemoved(ControllerEvent ev) { Controller controller = ev.getController(); logger.info("Controller disconnected: " + controller.getName()); removeController(controller); } @Override public void controllerAdded(ControllerEvent ev) { Controller controller = ev.getController(); logger.info("Controller connected: " + controller.getName()); addController(controller); } }); for (Controller c : env.getControllers()) { addController(c); } } @Override public List<String> getControllers() { List<String> ids = new ArrayList<>(); for (Controller controller : controllers) { ids.add(controller.getName()); } return ids; } @Override public Queue<ControllerAction> getInputQueue() { Queue<ControllerAction> result = new ArrayDeque<>(); Event event = new Event(); Iterator<Controller> it = controllers.iterator(); while (it.hasNext()) { Controller c = it.next(); if (c.poll()) { EventQueue queue = c.getEventQueue(); while (queue.getNextEvent(event)) { ControllerAction action = convertEvent(c, event); if (action != null) { result.add(action); } } } else { removeController(c); } } return result; } private ControllerAction convertEvent(Controller c, Event event) { Component comp = event.getComponent(); Identifier id = comp.getIdentifier(); float axisValue = comp.getPollData(); Input input; ButtonState state = ButtonState.UP; if (id instanceof Identifier.Button) { state = event.getValue() != 0 ? ButtonState.DOWN : ButtonState.UP; Integer buttonId = buttonMap.get(id); if (buttonId == null) { return null; //button not registered } input = InputType.CONTROLLER_BUTTON.getInput(buttonId); } else if (id instanceof Identifier.Axis) { ControllerInfo info = config.getController(c.getName()); if (id.equals(Identifier.Axis.X)) { if (Math.abs(axisValue) < info.getMovementDeadZone()) { axisValue = 0; } input = InputType.CONTROLLER_AXIS.getInput(ControllerId.X_AXIS); } else if (id.equals(Identifier.Axis.Y)) { if (Math.abs(axisValue) < info.getMovementDeadZone()) { axisValue = 0; } input = InputType.CONTROLLER_AXIS.getInput(ControllerId.Y_AXIS); } else if (id.equals(Identifier.Axis.Z)) { if (Math.abs(axisValue) < info.getMovementDeadZone()) { axisValue = 0; } input = InputType.CONTROLLER_AXIS.getInput(ControllerId.Z_AXIS); } else if (id.equals(Identifier.Axis.RX)) { if (Math.abs(axisValue) < info.getRotationDeadZone()) { axisValue = 0; } input = InputType.CONTROLLER_AXIS.getInput(ControllerId.RX_AXIS); } else if (id.equals(Identifier.Axis.RY)) { if (Math.abs(axisValue) < info.getRotationDeadZone()) { axisValue = 0; } input = InputType.CONTROLLER_AXIS.getInput(ControllerId.RY_AXIS); } else if (id.equals(Identifier.Axis.POV)) { // the poll data float value is actually an ID in this case boolean isX = (axisValue == Component.POV.LEFT) || (axisValue == Component.POV.RIGHT); boolean isY = (axisValue == Component.POV.UP) || (axisValue == Component.POV.DOWN); if (isX || isY) { input = InputType.CONTROLLER_AXIS.getInput(isX ? ControllerId.POVX_AXIS : ControllerId.POVY_AXIS); if ((axisValue == Component.POV.UP) || (axisValue == Component.POV.LEFT)) { axisValue = -1; } if ((axisValue == Component.POV.DOWN) || (axisValue == Component.POV.RIGHT)) { axisValue = 1; } } else { return null; // TODO: handle 8-button POVs } } else { return null; // unrecognized axis } } else { return null; // unrecognized id (e.g. Identifier.Key) } return new ControllerAction(input, c.getName(), state, axisValue); } /** * Removes a controller. Also works while iterating over the list. * @param controller the controller to remove */ private void removeController(Controller controller) { controllers.remove(controller.getName()); logger.info("Removed controller: " + controller.getName()); } private void addController(Controller c) { if (filter.contains(c.getType())) { logger.debug("Ignoring controller: " + c.getName()); return; } if (c.getControllers().length == 0) { controllers.add(c); logger.info("Registered controller: " + c.getName()); } else { for (Controller sub : c.getControllers()) { addController(sub); } } } }