com.agateau.ui.GamepadInputMapper.java Source code

Java tutorial

Introduction

Here is the source code for com.agateau.ui.GamepadInputMapper.java

Source

/*
 * Copyright 2018 Aurlien Gteau <mail@agateau.com>
 *
 * This file is part of Pixel Wheels.
 *
 * Tiny Wheels is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.agateau.ui;

import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.ControllerAdapter;
import com.badlogic.gdx.controllers.PovDirection;

import java.lang.ref.WeakReference;
import java.util.HashMap;

/**
 * An implementation of InputMapper for gamepads
 */
public class GamepadInputMapper extends ControllerAdapter implements InputMapper {
    private static final String TRIGGER_BUTTON_PREF = "trigger";
    private static final String BACK_BUTTON_PREF = "back";

    private enum AxisValue {
        LESS, ZERO, MORE
    }

    private enum KeyState {
        RELEASED, PRESSED, JUST_PRESSED
    }

    public enum GamepadButton {
        TRIGGER, BACK
    }

    public interface Listener {
        /**
         * Returns true if the event has been handled. In this case the internal state of the input mapper won't be updated
         */
        boolean onButtonPressed(int buttonCode, boolean pressed);
    }

    private Controller mController;

    private final HashMap<VirtualKey, KeyState> mPressedKeys = new HashMap<VirtualKey, KeyState>();

    private final HashMap<GamepadButton, Integer> mButtonCodes = new HashMap<GamepadButton, Integer>();

    private WeakReference<Listener> mListenerRef;

    public static GamepadInputMapper[] getInstances() {
        return GamepadInputMappers.getInstance().getMappers();
    }

    public static GamepadInputMapper getInstance(int idx) {
        return GamepadInputMappers.getInstance().getMappers()[idx];
    }

    GamepadInputMapper(Controller controller) {
        mButtonCodes.put(GamepadButton.TRIGGER, 1);
        mButtonCodes.put(GamepadButton.BACK, 2);
        setController(controller);
    }

    Controller getController() {
        return mController;
    }

    void setController(Controller controller) {
        mController = controller;
        if (controller != null) {
            mController.addListener(this);
        }
    }

    public int getButtonCode(GamepadButton button) {
        return mButtonCodes.get(button);
    }

    public void setButtonCode(GamepadButton button, int code) {
        mButtonCodes.put(button, code);
    }

    public void setListener(Listener listener) {
        mListenerRef = new WeakReference<Listener>(listener);
    }

    @Override
    public boolean isKeyPressed(VirtualKey key) {
        KeyState state = mPressedKeys.get(key);
        return state != null && state != KeyState.RELEASED;
    }

    @Override
    public boolean isKeyJustPressed(VirtualKey key) {
        KeyState state = mPressedKeys.get(key);
        if (state == KeyState.JUST_PRESSED) {
            mPressedKeys.put(key, KeyState.PRESSED);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void loadConfig(Preferences preferences, String prefix) {
        mButtonCodes.put(GamepadButton.TRIGGER, preferences.getInteger(prefix + TRIGGER_BUTTON_PREF, 1));
        mButtonCodes.put(GamepadButton.BACK, preferences.getInteger(prefix + BACK_BUTTON_PREF, 2));
    }

    @Override
    public void saveConfig(Preferences preferences, String prefix) {
        preferences.putInteger(prefix + TRIGGER_BUTTON_PREF, mButtonCodes.get(GamepadButton.TRIGGER));
        preferences.putInteger(prefix + BACK_BUTTON_PREF, mButtonCodes.get(GamepadButton.BACK));
    }

    @Override
    public boolean isAvailable() {
        return mController != null;
    }

    @Override
    public boolean buttonDown(Controller controller, int buttonCode) {
        onButtonPressed(buttonCode, true);
        return false;
    }

    @Override
    public boolean buttonUp(Controller controller, int buttonCode) {
        onButtonPressed(buttonCode, false);
        return false;
    }

    @Override
    public boolean povMoved(Controller controller, int povCode, PovDirection value) {
        boolean up = false;
        boolean down = false;
        boolean left = false;
        boolean right = false;
        switch (value) {
        case center:
            break;
        case north:
            up = true;
            break;
        case south:
            down = true;
            break;
        case east:
            right = true;
            break;
        case west:
            left = true;
            break;
        case northEast:
            up = true;
            right = true;
            break;
        case southEast:
            down = true;
            right = true;
            break;
        case northWest:
            up = true;
            left = true;
            break;
        case southWest:
            down = true;
            left = true;
            break;
        }
        setKeyJustPressed(VirtualKey.UP, up);
        setKeyJustPressed(VirtualKey.DOWN, down);
        setKeyJustPressed(VirtualKey.LEFT, left);
        setKeyJustPressed(VirtualKey.RIGHT, right);
        return false;
    }

    @Override
    public boolean axisMoved(Controller controller, int axisCode, float fvalue) {
        AxisValue value = normalizeAxisValue(fvalue);
        if ((axisCode & 1) == 0) {
            setKeyJustPressed(VirtualKey.LEFT, value == AxisValue.LESS);
            setKeyJustPressed(VirtualKey.RIGHT, value == AxisValue.MORE);
        } else {
            setKeyJustPressed(VirtualKey.UP, value == AxisValue.LESS);
            setKeyJustPressed(VirtualKey.DOWN, value == AxisValue.MORE);
        }
        return false;
    }

    private void setKeyJustPressed(VirtualKey key, boolean justPressed) {
        mPressedKeys.put(key, justPressed ? KeyState.JUST_PRESSED : KeyState.RELEASED);
    }

    private static AxisValue normalizeAxisValue(float value) {
        if (value < -0.5f) {
            return AxisValue.LESS;
        } else if (value > 0.5f) {
            return AxisValue.MORE;
        } else {
            return AxisValue.ZERO;
        }
    }

    private void onButtonPressed(int buttonCode, boolean pressed) {
        Listener listener = mListenerRef != null ? mListenerRef.get() : null;
        if (listener != null) {
            if (listener.onButtonPressed(buttonCode, pressed)) {
                return;
            }
        }
        if (buttonCode == mButtonCodes.get(GamepadButton.TRIGGER)) {
            setKeyJustPressed(VirtualKey.TRIGGER, pressed);
        } else if (buttonCode == mButtonCodes.get(GamepadButton.BACK)) {
            setKeyJustPressed(VirtualKey.BACK, pressed);
        }
    }
}