mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 01:05:48 +01:00 
			
		
		
		
	Initial Gamepad support
Adds initial ingame gamepad support to minetest. Full Formspec support is not implemented yet and can be added by a later change.
This commit is contained in:
		@@ -104,6 +104,17 @@ random_input (Random input) bool false
 | 
			
		||||
#    Continuous forward movement (only used for testing).
 | 
			
		||||
continuous_forward (Continuous forward) bool false
 | 
			
		||||
 | 
			
		||||
#    Enable Joysticks
 | 
			
		||||
enable_joysticks (Enable Joysticks) bool true
 | 
			
		||||
 | 
			
		||||
#    The time in seconds it takes between repeated events
 | 
			
		||||
#    when holding down a joystick button combination.
 | 
			
		||||
repeat_joystick_button_time (Joystick button repetition invterval) float 0.17
 | 
			
		||||
 | 
			
		||||
#    The sensitivity of the joystick axes for moving the
 | 
			
		||||
#    ingame view frustum around.
 | 
			
		||||
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170
 | 
			
		||||
 | 
			
		||||
#    Key for moving the player forward.
 | 
			
		||||
#    See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
 | 
			
		||||
keymap_forward (Forward key) key KEY_KEY_W
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
set(client_SRCS
 | 
			
		||||
	${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
 | 
			
		||||
	${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
 | 
			
		||||
	${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp
 | 
			
		||||
	PARENT_SCOPE
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "guiEngine.h"
 | 
			
		||||
#include "player.h"
 | 
			
		||||
#include "fontengine.h"
 | 
			
		||||
#include "joystick_controller.h"
 | 
			
		||||
#include "clientlauncher.h"
 | 
			
		||||
 | 
			
		||||
/* mainmenumanager.h
 | 
			
		||||
@@ -499,7 +500,8 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* show main menu */
 | 
			
		||||
	GUIEngine mymenu(device, guiroot, &g_menumgr, smgr, menudata, *kill);
 | 
			
		||||
	GUIEngine mymenu(device, &input->joystick, guiroot,
 | 
			
		||||
		&g_menumgr, smgr, menudata, *kill);
 | 
			
		||||
 | 
			
		||||
	smgr->clear();	/* leave scene manager in a clean state */
 | 
			
		||||
}
 | 
			
		||||
@@ -558,6 +560,22 @@ bool ClientLauncher::create_engine_device()
 | 
			
		||||
	device = createDeviceEx(params);
 | 
			
		||||
 | 
			
		||||
	if (device) {
 | 
			
		||||
		if (g_settings->getBool("enable_joysticks")) {
 | 
			
		||||
			irr::core::array<irr::SJoystickInfo> infos;
 | 
			
		||||
			std::vector<irr::SJoystickInfo> joystick_infos;
 | 
			
		||||
			// Make sure this is called maximum once per
 | 
			
		||||
			// irrlicht device, otherwise it will give you
 | 
			
		||||
			// multiple events for the same joystick.
 | 
			
		||||
			if (device->activateJoysticks(infos)) {
 | 
			
		||||
				infostream << "Joystick support enabled" << std::endl;
 | 
			
		||||
				joystick_infos.reserve(infos.size());
 | 
			
		||||
				for (u32 i = 0; i < infos.size(); i++) {
 | 
			
		||||
					joystick_infos.push_back(infos[i]);
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				errorstream << "Could not activate joystick support." << std::endl;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		porting::initIrrlicht(device);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#define INPUT_HANDLER_H
 | 
			
		||||
 | 
			
		||||
#include "irrlichttypes_extrabloated.h"
 | 
			
		||||
#include "joystick_controller.h"
 | 
			
		||||
 | 
			
		||||
class MyEventReceiver : public IEventReceiver
 | 
			
		||||
{
 | 
			
		||||
@@ -62,6 +63,14 @@ public:
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
 | 
			
		||||
			/* TODO add a check like:
 | 
			
		||||
			if (event.JoystickEvent != joystick_we_listen_for)
 | 
			
		||||
				return false;
 | 
			
		||||
			*/
 | 
			
		||||
			return joystick->handleEvent(event.JoystickEvent);
 | 
			
		||||
		}
 | 
			
		||||
		// handle mouse events
 | 
			
		||||
		if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
 | 
			
		||||
			if (noMenuActive() == false) {
 | 
			
		||||
@@ -172,6 +181,8 @@ public:
 | 
			
		||||
 | 
			
		||||
	s32 mouse_wheel;
 | 
			
		||||
 | 
			
		||||
	JoystickController *joystick;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_TOUCHSCREENGUI
 | 
			
		||||
	TouchScreenGUI* m_touchscreengui;
 | 
			
		||||
#endif
 | 
			
		||||
@@ -202,6 +213,7 @@ public:
 | 
			
		||||
		m_receiver(receiver),
 | 
			
		||||
		m_mousepos(0,0)
 | 
			
		||||
	{
 | 
			
		||||
		m_receiver->joystick = &joystick;
 | 
			
		||||
	}
 | 
			
		||||
	virtual bool isKeyDown(const KeyPress &keyCode)
 | 
			
		||||
	{
 | 
			
		||||
@@ -288,6 +300,7 @@ public:
 | 
			
		||||
 | 
			
		||||
	void clear()
 | 
			
		||||
	{
 | 
			
		||||
		joystick.clear();
 | 
			
		||||
		m_receiver->clearInput();
 | 
			
		||||
	}
 | 
			
		||||
private:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										179
									
								
								src/client/joystick_controller.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								src/client/joystick_controller.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
			
		||||
/*
 | 
			
		||||
Minetest
 | 
			
		||||
Copyright (C) 2016 est31, <MTest31@outlook.com>
 | 
			
		||||
 | 
			
		||||
This program is free software; you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU Lesser General Public License along
 | 
			
		||||
with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "joystick_controller.h"
 | 
			
		||||
#include "irrlichttypes_extrabloated.h"
 | 
			
		||||
#include "keys.h"
 | 
			
		||||
#include "settings.h"
 | 
			
		||||
#include "gettime.h"
 | 
			
		||||
 | 
			
		||||
bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
 | 
			
		||||
{
 | 
			
		||||
	u32 buttons = ev.ButtonStates;
 | 
			
		||||
 | 
			
		||||
	buttons &= filter_mask;
 | 
			
		||||
	return buttons == compare_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
 | 
			
		||||
{
 | 
			
		||||
	s16 ax_val = ev.Axis[axis_to_compare];
 | 
			
		||||
 | 
			
		||||
	return (ax_val * direction < 0) && (thresh * direction > ax_val * direction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// spares many characters
 | 
			
		||||
#define JLO_B_PB(A, B, C)    jlo.button_keys.push_back(JoystickButtonCmb(A, B, C))
 | 
			
		||||
#define JLO_A_PB(A, B, C, D) jlo.axis_keys.push_back(JoystickAxisCmb(A, B, C, D))
 | 
			
		||||
 | 
			
		||||
static JoystickLayout create_default_layout()
 | 
			
		||||
{
 | 
			
		||||
	JoystickLayout jlo;
 | 
			
		||||
 | 
			
		||||
	jlo.axes_dead_border = 1024;
 | 
			
		||||
 | 
			
		||||
	const JoystickAxisLayout axes[JA_COUNT] = {
 | 
			
		||||
		{0, 1}, // JA_SIDEWARD_MOVE
 | 
			
		||||
		{1, 1}, // JA_FORWARD_MOVE
 | 
			
		||||
		{3, 1}, // JA_FRUSTUM_HORIZONTAL
 | 
			
		||||
		{4, 1}, // JA_FRUSTUM_VERTICAL
 | 
			
		||||
	};
 | 
			
		||||
	memcpy(jlo.axes, axes, sizeof(jlo.axes));
 | 
			
		||||
 | 
			
		||||
	u32 sb = 1 << 7; // START button mask
 | 
			
		||||
	u32 fb = 1 << 3; // FOUR button mask
 | 
			
		||||
	u32 bm = sb | fb; // Mask for Both Modifiers
 | 
			
		||||
 | 
			
		||||
	// The back button means "ESC".
 | 
			
		||||
	JLO_B_PB(KeyType::ESC,        1 << 6,      1 << 6);
 | 
			
		||||
 | 
			
		||||
	// The start button counts as modifier as well as use key.
 | 
			
		||||
	// JLO_B_PB(KeyType::USE,        sb,          sb));
 | 
			
		||||
 | 
			
		||||
	// Accessible without start modifier button pressed
 | 
			
		||||
	// regardless whether four is pressed or not
 | 
			
		||||
	JLO_B_PB(KeyType::SNEAK,      sb | 1 << 2, 1 << 2);
 | 
			
		||||
 | 
			
		||||
	// Accessible without four modifier button pressed
 | 
			
		||||
	// regardless whether start is pressed or not
 | 
			
		||||
	JLO_B_PB(KeyType::MOUSE_L,    fb | 1 << 4, 1 << 4);
 | 
			
		||||
	JLO_B_PB(KeyType::MOUSE_R,    fb | 1 << 5, 1 << 5);
 | 
			
		||||
 | 
			
		||||
	// Accessible without any modifier pressed
 | 
			
		||||
	JLO_B_PB(KeyType::JUMP,       bm | 1 << 0, 1 << 0);
 | 
			
		||||
	JLO_B_PB(KeyType::SPECIAL1,   bm | 1 << 1, 1 << 1);
 | 
			
		||||
 | 
			
		||||
	// Accessible with start button not pressed, but four pressed
 | 
			
		||||
	// TODO find usage for button 0
 | 
			
		||||
	JLO_B_PB(KeyType::DROP,       bm | 1 << 1, fb | 1 << 1);
 | 
			
		||||
	JLO_B_PB(KeyType::SCROLL_UP,  bm | 1 << 4, fb | 1 << 4);
 | 
			
		||||
	JLO_B_PB(KeyType::SCROLL_DOWN,bm | 1 << 5, fb | 1 << 5);
 | 
			
		||||
 | 
			
		||||
	// Accessible with start button and four pressed
 | 
			
		||||
	// TODO find usage for buttons 0, 1 and 4, 5
 | 
			
		||||
 | 
			
		||||
	// Now about the buttons simulated by the axes
 | 
			
		||||
 | 
			
		||||
	// Movement buttons, important for vessels
 | 
			
		||||
	JLO_A_PB(KeyType::FORWARD,  1,  1, 1024);
 | 
			
		||||
	JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024);
 | 
			
		||||
	JLO_A_PB(KeyType::LEFT,     0,  1, 1024);
 | 
			
		||||
	JLO_A_PB(KeyType::RIGHT,    0, -1, 1024);
 | 
			
		||||
 | 
			
		||||
	// Scroll buttons
 | 
			
		||||
	JLO_A_PB(KeyType::SCROLL_UP,   2, -1, 1024);
 | 
			
		||||
	JLO_A_PB(KeyType::SCROLL_DOWN, 5, -1, 1024);
 | 
			
		||||
 | 
			
		||||
	return jlo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const JoystickLayout default_layout = create_default_layout();
 | 
			
		||||
 | 
			
		||||
JoystickController::JoystickController()
 | 
			
		||||
{
 | 
			
		||||
	m_layout = &default_layout;
 | 
			
		||||
	doubling_dtime = g_settings->getFloat("repeat_joystick_button_time");
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
 | 
			
		||||
		m_past_pressed_time[i] = 0;
 | 
			
		||||
	}
 | 
			
		||||
	clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
 | 
			
		||||
{
 | 
			
		||||
	m_internal_time = getTimeMs() / 1000.f;
 | 
			
		||||
 | 
			
		||||
	std::bitset<KeyType::INTERNAL_ENUM_COUNT> keys_pressed;
 | 
			
		||||
 | 
			
		||||
	// First generate a list of keys pressed
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < m_layout->button_keys.size(); i++) {
 | 
			
		||||
		if (m_layout->button_keys[i].isTriggered(ev)) {
 | 
			
		||||
			keys_pressed.set(m_layout->button_keys[i].key);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < m_layout->axis_keys.size(); i++) {
 | 
			
		||||
		if (m_layout->axis_keys[i].isTriggered(ev)) {
 | 
			
		||||
			keys_pressed.set(m_layout->axis_keys[i].key);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Then update the values
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
 | 
			
		||||
		if (keys_pressed[i]) {
 | 
			
		||||
			if (!m_past_pressed_keys[i] &&
 | 
			
		||||
					m_past_pressed_time[i] < m_internal_time - doubling_dtime) {
 | 
			
		||||
				m_past_pressed_keys[i] = true;
 | 
			
		||||
				m_past_pressed_time[i] = m_internal_time;
 | 
			
		||||
			}
 | 
			
		||||
		} else if (m_pressed_keys[i]) {
 | 
			
		||||
			m_past_released_keys[i] = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m_pressed_keys[i] = keys_pressed[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < JA_COUNT; i++) {
 | 
			
		||||
		const JoystickAxisLayout &ax_la = m_layout->axes[i];
 | 
			
		||||
		m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void JoystickController::clear()
 | 
			
		||||
{
 | 
			
		||||
	m_pressed_keys.reset();
 | 
			
		||||
	m_past_pressed_keys.reset();
 | 
			
		||||
	m_past_released_keys.reset();
 | 
			
		||||
	memset(m_axes_vals, 0, sizeof(m_axes_vals));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
 | 
			
		||||
{
 | 
			
		||||
	s16 v = m_axes_vals[axis];
 | 
			
		||||
	if (((v > 0) && (v < m_layout->axes_dead_border)) ||
 | 
			
		||||
			((v < 0) && (v > -m_layout->axes_dead_border)))
 | 
			
		||||
		return 0;
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										163
									
								
								src/client/joystick_controller.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/client/joystick_controller.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
			
		||||
/*
 | 
			
		||||
Minetest
 | 
			
		||||
Copyright (C) 2016 est31, <MTest31@outlook.com>
 | 
			
		||||
 | 
			
		||||
This program is free software; you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU Lesser General Public License along
 | 
			
		||||
with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef JOYSTICK_HEADER
 | 
			
		||||
#define JOYSTICK_HEADER
 | 
			
		||||
 | 
			
		||||
#include "irrlichttypes_extrabloated.h"
 | 
			
		||||
#include "keys.h"
 | 
			
		||||
#include <bitset>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
enum JoystickAxis {
 | 
			
		||||
	JA_SIDEWARD_MOVE,
 | 
			
		||||
	JA_FORWARD_MOVE,
 | 
			
		||||
 | 
			
		||||
	JA_FRUSTUM_HORIZONTAL,
 | 
			
		||||
	JA_FRUSTUM_VERTICAL,
 | 
			
		||||
 | 
			
		||||
	// To know the count of enum values
 | 
			
		||||
	JA_COUNT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct JoystickAxisLayout {
 | 
			
		||||
	u16 axis_id;
 | 
			
		||||
	// -1 if to invert, 1 if to keep it.
 | 
			
		||||
	int invert;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct JoystickCombination {
 | 
			
		||||
 | 
			
		||||
	virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const=0;
 | 
			
		||||
 | 
			
		||||
	GameKeyType key;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct JoystickButtonCmb : public JoystickCombination {
 | 
			
		||||
 | 
			
		||||
	JoystickButtonCmb() {}
 | 
			
		||||
	JoystickButtonCmb(GameKeyType key, u32 filter_mask, u32 compare_mask) :
 | 
			
		||||
		filter_mask(filter_mask),
 | 
			
		||||
		compare_mask(compare_mask)
 | 
			
		||||
	{
 | 
			
		||||
		this->key = key;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const;
 | 
			
		||||
 | 
			
		||||
	u32 filter_mask;
 | 
			
		||||
	u32 compare_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct JoystickAxisCmb : public JoystickCombination {
 | 
			
		||||
 | 
			
		||||
	JoystickAxisCmb() {}
 | 
			
		||||
	JoystickAxisCmb(GameKeyType key, u16 axis_to_compare, int direction, s16 thresh) :
 | 
			
		||||
		axis_to_compare(axis_to_compare),
 | 
			
		||||
		direction(direction),
 | 
			
		||||
		thresh(thresh)
 | 
			
		||||
	{
 | 
			
		||||
		this->key = key;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const;
 | 
			
		||||
 | 
			
		||||
	u16 axis_to_compare;
 | 
			
		||||
 | 
			
		||||
	// if -1, thresh must be smaller than the axis value in order to trigger
 | 
			
		||||
	// if  1, thresh must be bigger  than the axis value in order to trigger
 | 
			
		||||
	int direction;
 | 
			
		||||
	s16 thresh;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct JoystickLayout {
 | 
			
		||||
	std::vector<JoystickButtonCmb> button_keys;
 | 
			
		||||
	std::vector<JoystickAxisCmb> axis_keys;
 | 
			
		||||
	JoystickAxisLayout axes[JA_COUNT];
 | 
			
		||||
	s16 axes_dead_border;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class JoystickController {
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	JoystickController();
 | 
			
		||||
	bool handleEvent(const irr::SEvent::SJoystickEvent &ev);
 | 
			
		||||
	void clear();
 | 
			
		||||
 | 
			
		||||
	bool wasKeyDown(GameKeyType b)
 | 
			
		||||
	{
 | 
			
		||||
		bool r = m_past_pressed_keys[b];
 | 
			
		||||
		m_past_pressed_keys[b] = false;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
	bool getWasKeyDown(GameKeyType b)
 | 
			
		||||
	{
 | 
			
		||||
		return m_past_pressed_keys[b];
 | 
			
		||||
	}
 | 
			
		||||
	void clearWasKeyDown(GameKeyType b)
 | 
			
		||||
	{
 | 
			
		||||
		m_past_pressed_keys[b] = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool wasKeyReleased(GameKeyType b)
 | 
			
		||||
	{
 | 
			
		||||
		bool r = m_past_released_keys[b];
 | 
			
		||||
		m_past_released_keys[b] = false;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
	bool getWasKeyReleased(GameKeyType b)
 | 
			
		||||
	{
 | 
			
		||||
		return m_past_pressed_keys[b];
 | 
			
		||||
	}
 | 
			
		||||
	void clearWasKeyReleased(GameKeyType b)
 | 
			
		||||
	{
 | 
			
		||||
		m_past_pressed_keys[b] = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool isKeyDown(GameKeyType b)
 | 
			
		||||
	{
 | 
			
		||||
		return m_pressed_keys[b];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s16 getAxis(JoystickAxis axis)
 | 
			
		||||
	{
 | 
			
		||||
		return m_axes_vals[axis];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s16 getAxisWithoutDead(JoystickAxis axis);
 | 
			
		||||
 | 
			
		||||
	f32 doubling_dtime;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	const JoystickLayout *m_layout;
 | 
			
		||||
 | 
			
		||||
	s16 m_axes_vals[JA_COUNT];
 | 
			
		||||
 | 
			
		||||
	std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_pressed_keys;
 | 
			
		||||
 | 
			
		||||
	f32 m_internal_time;
 | 
			
		||||
 | 
			
		||||
	f32 m_past_pressed_time[KeyType::INTERNAL_ENUM_COUNT];
 | 
			
		||||
 | 
			
		||||
	std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_pressed_keys;
 | 
			
		||||
	std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_released_keys;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -67,6 +67,12 @@ public:
 | 
			
		||||
 | 
			
		||||
		DEBUG_STACKS,
 | 
			
		||||
 | 
			
		||||
		// joystick specific keys
 | 
			
		||||
		MOUSE_L,
 | 
			
		||||
		MOUSE_R,
 | 
			
		||||
		SCROLL_UP,
 | 
			
		||||
		SCROLL_DOWN,
 | 
			
		||||
 | 
			
		||||
		// Fake keycode for array size and internal checks
 | 
			
		||||
		INTERNAL_ENUM_COUNT
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1056,7 +1056,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
 | 
			
		||||
			PlayerControl controls = player->getPlayerControl();
 | 
			
		||||
 | 
			
		||||
			bool walking = false;
 | 
			
		||||
			if(controls.up || controls.down || controls.left || controls.right)
 | 
			
		||||
			if (controls.up || controls.down || controls.left || controls.right ||
 | 
			
		||||
					controls.forw_move_joystick_axis != 0.f ||
 | 
			
		||||
					controls.sidew_move_joystick_axis != 0.f)
 | 
			
		||||
				walking = true;
 | 
			
		||||
 | 
			
		||||
			f32 new_speed = player->local_animation_speed;
 | 
			
		||||
 
 | 
			
		||||
@@ -116,6 +116,9 @@ void set_default_settings(Settings *settings)
 | 
			
		||||
	settings->setDefault("free_move", "false");
 | 
			
		||||
	settings->setDefault("noclip", "false");
 | 
			
		||||
	settings->setDefault("continuous_forward", "false");
 | 
			
		||||
	settings->setDefault("enable_joysticks", "true");
 | 
			
		||||
	settings->setDefault("repeat_joystick_button_time", "0.17");
 | 
			
		||||
	settings->setDefault("joystick_frustum_sensitivity", "170");
 | 
			
		||||
	settings->setDefault("cinematic", "false");
 | 
			
		||||
	settings->setDefault("camera_smoothing", "0");
 | 
			
		||||
	settings->setDefault("cinematic_camera_smoothing", "0.7");
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										167
									
								
								src/game.cpp
									
									
									
									
									
								
							
							
						
						
									
										167
									
								
								src/game.cpp
									
									
									
									
									
								
							@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "client.h"
 | 
			
		||||
#include "client/tile.h"     // For TextureSource
 | 
			
		||||
#include "client/keys.h"
 | 
			
		||||
#include "client/joystick_controller.h"
 | 
			
		||||
#include "clientmap.h"
 | 
			
		||||
#include "clouds.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
@@ -1108,12 +1109,14 @@ bool nodePlacementPrediction(Client &client,
 | 
			
		||||
static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
 | 
			
		||||
		InventoryManager *invmgr, IGameDef *gamedef,
 | 
			
		||||
		IWritableTextureSource *tsrc, IrrlichtDevice *device,
 | 
			
		||||
		JoystickController *joystick,
 | 
			
		||||
		IFormSource *fs_src, TextDest *txt_dest, Client *client)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	if (*cur_formspec == 0) {
 | 
			
		||||
		*cur_formspec = new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr,
 | 
			
		||||
						    invmgr, gamedef, tsrc, fs_src, txt_dest, client);
 | 
			
		||||
		*cur_formspec = new GUIFormSpecMenu(device, joystick,
 | 
			
		||||
			guiroot, -1, &g_menumgr, invmgr, gamedef, tsrc,
 | 
			
		||||
			fs_src, txt_dest, client);
 | 
			
		||||
		(*cur_formspec)->doPause = false;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
@@ -1138,7 +1141,8 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
 | 
			
		||||
 | 
			
		||||
static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
 | 
			
		||||
		InventoryManager *invmgr, IGameDef *gamedef,
 | 
			
		||||
		IWritableTextureSource *tsrc, IrrlichtDevice *device, Client *client)
 | 
			
		||||
		IWritableTextureSource *tsrc, IrrlichtDevice *device,
 | 
			
		||||
		JoystickController *joystick, Client *client)
 | 
			
		||||
{
 | 
			
		||||
	std::string formspec =
 | 
			
		||||
		std::string(FORMSPEC_VERSION_STRING) +
 | 
			
		||||
@@ -1154,14 +1158,15 @@ static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
 | 
			
		||||
	FormspecFormSource *fs_src = new FormspecFormSource(formspec);
 | 
			
		||||
	LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
 | 
			
		||||
 | 
			
		||||
	create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,  fs_src, txt_dst, NULL);
 | 
			
		||||
	create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,
 | 
			
		||||
		joystick, fs_src, txt_dst, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************/
 | 
			
		||||
static void show_pause_menu(GUIFormSpecMenu **cur_formspec,
 | 
			
		||||
		InventoryManager *invmgr, IGameDef *gamedef,
 | 
			
		||||
		IWritableTextureSource *tsrc, IrrlichtDevice *device,
 | 
			
		||||
		bool singleplayermode)
 | 
			
		||||
		JoystickController *joystick, bool singleplayermode)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
	std::string control_text = strgettext("Default Controls:\n"
 | 
			
		||||
@@ -1226,7 +1231,8 @@ static void show_pause_menu(GUIFormSpecMenu **cur_formspec,
 | 
			
		||||
	FormspecFormSource *fs_src = new FormspecFormSource(os.str());
 | 
			
		||||
	LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
 | 
			
		||||
 | 
			
		||||
	create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,  fs_src, txt_dst, NULL);
 | 
			
		||||
	create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,
 | 
			
		||||
		joystick, fs_src, txt_dst, NULL);
 | 
			
		||||
	std::string con("btn_continue");
 | 
			
		||||
	(*cur_formspec)->setFocus(con);
 | 
			
		||||
	(*cur_formspec)->doPause = true;
 | 
			
		||||
@@ -1574,9 +1580,10 @@ protected:
 | 
			
		||||
	void decreaseViewRange(float *statustext_time);
 | 
			
		||||
	void toggleFullViewRange(float *statustext_time);
 | 
			
		||||
 | 
			
		||||
	void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags);
 | 
			
		||||
	void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags,
 | 
			
		||||
		float dtime);
 | 
			
		||||
	void updateCameraOrientation(CameraOrientation *cam,
 | 
			
		||||
			const VolatileRunFlags &flags);
 | 
			
		||||
		const VolatileRunFlags &flags, float dtime);
 | 
			
		||||
	void updatePlayerControl(const CameraOrientation &cam);
 | 
			
		||||
	void step(f32 *dtime);
 | 
			
		||||
	void processClientEvents(CameraOrientation *cam, float *damage_flash);
 | 
			
		||||
@@ -1611,34 +1618,39 @@ protected:
 | 
			
		||||
	static void settingChangedCallback(const std::string &setting_name, void *data);
 | 
			
		||||
	void readSettings();
 | 
			
		||||
 | 
			
		||||
	bool getLeftClicked()
 | 
			
		||||
	inline bool getLeftClicked()
 | 
			
		||||
	{
 | 
			
		||||
		return input->getLeftClicked();
 | 
			
		||||
		return input->getLeftClicked() ||
 | 
			
		||||
			input->joystick.getWasKeyDown(KeyType::MOUSE_L);
 | 
			
		||||
	}
 | 
			
		||||
	bool getRightClicked()
 | 
			
		||||
	inline bool getRightClicked()
 | 
			
		||||
	{
 | 
			
		||||
		return input->getRightClicked();
 | 
			
		||||
		return input->getRightClicked() ||
 | 
			
		||||
			input->joystick.getWasKeyDown(KeyType::MOUSE_R);
 | 
			
		||||
	}
 | 
			
		||||
	bool isLeftPressed()
 | 
			
		||||
	inline bool isLeftPressed()
 | 
			
		||||
	{
 | 
			
		||||
		return input->getLeftState();
 | 
			
		||||
		return input->getLeftState() ||
 | 
			
		||||
			input->joystick.isKeyDown(KeyType::MOUSE_L);
 | 
			
		||||
	}
 | 
			
		||||
	bool isRightPressed()
 | 
			
		||||
	inline bool isRightPressed()
 | 
			
		||||
	{
 | 
			
		||||
		return input->getRightState();
 | 
			
		||||
		return input->getRightState() ||
 | 
			
		||||
			input->joystick.isKeyDown(KeyType::MOUSE_R);
 | 
			
		||||
	}
 | 
			
		||||
	bool getLeftReleased()
 | 
			
		||||
	inline bool getLeftReleased()
 | 
			
		||||
	{
 | 
			
		||||
		return input->getLeftReleased();
 | 
			
		||||
		return input->getLeftReleased() ||
 | 
			
		||||
			input->joystick.wasKeyReleased(KeyType::MOUSE_L);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool isKeyDown(GameKeyType k)
 | 
			
		||||
	inline bool isKeyDown(GameKeyType k)
 | 
			
		||||
	{
 | 
			
		||||
		return input->isKeyDown(keycache.key[k]);
 | 
			
		||||
		return input->isKeyDown(keycache.key[k]) || input->joystick.isKeyDown(k);
 | 
			
		||||
	}
 | 
			
		||||
	bool wasKeyDown(GameKeyType k)
 | 
			
		||||
	inline bool wasKeyDown(GameKeyType k)
 | 
			
		||||
	{
 | 
			
		||||
		return input->wasKeyDown(keycache.key[k]);
 | 
			
		||||
		return input->wasKeyDown(keycache.key[k]) || input->joystick.wasKeyDown(k);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
@@ -1724,9 +1736,11 @@ private:
 | 
			
		||||
	 */
 | 
			
		||||
	bool m_cache_doubletap_jump;
 | 
			
		||||
	bool m_cache_enable_clouds;
 | 
			
		||||
	bool m_cache_enable_joysticks;
 | 
			
		||||
	bool m_cache_enable_particles;
 | 
			
		||||
	bool m_cache_enable_fog;
 | 
			
		||||
	f32  m_cache_mouse_sensitivity;
 | 
			
		||||
	f32  m_cache_joystick_frustum_sensitivity;
 | 
			
		||||
	f32  m_repeat_right_click_time;
 | 
			
		||||
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
@@ -1762,12 +1776,16 @@ Game::Game() :
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
	g_settings->registerChangedCallback("enable_clouds",
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
	g_settings->registerChangedCallback("doubletap_joysticks",
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
	g_settings->registerChangedCallback("enable_particles",
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
	g_settings->registerChangedCallback("enable_fog",
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
	g_settings->registerChangedCallback("mouse_sensitivity",
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
	g_settings->registerChangedCallback("joystick_frustum_sensitivity",
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
	g_settings->registerChangedCallback("repeat_rightclick_time",
 | 
			
		||||
		&settingChangedCallback, this);
 | 
			
		||||
 | 
			
		||||
@@ -1930,7 +1948,7 @@ void Game::run()
 | 
			
		||||
		updateProfilers(runData, stats, draw_times, dtime);
 | 
			
		||||
		processUserInput(&flags, &runData, dtime);
 | 
			
		||||
		// Update camera before player movement to avoid camera lag of one frame
 | 
			
		||||
		updateCameraDirection(&cam_view_target, &flags);
 | 
			
		||||
		updateCameraDirection(&cam_view_target, &flags, dtime);
 | 
			
		||||
		float cam_smoothing = 0;
 | 
			
		||||
		if (g_settings->getBool("cinematic"))
 | 
			
		||||
			cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing");
 | 
			
		||||
@@ -2727,7 +2745,8 @@ void Game::processKeyInput(VolatileRunFlags *flags,
 | 
			
		||||
	} else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) {
 | 
			
		||||
		if (!gui_chat_console->isOpenInhibited()) {
 | 
			
		||||
			show_pause_menu(¤t_formspec, client, gamedef,
 | 
			
		||||
					texture_src, device, simple_singleplayer_mode);
 | 
			
		||||
				texture_src, device, &input->joystick,
 | 
			
		||||
				simple_singleplayer_mode);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (wasKeyDown(KeyType::CHAT)) {
 | 
			
		||||
		openConsole(0.2, L"");
 | 
			
		||||
@@ -2813,12 +2832,21 @@ void Game::processItemSelection(u16 *new_playeritem)
 | 
			
		||||
	u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1,
 | 
			
		||||
		                 player->hud_hotbar_itemcount - 1);
 | 
			
		||||
 | 
			
		||||
	if (wheel < 0)
 | 
			
		||||
		*new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0;
 | 
			
		||||
	else if (wheel > 0)
 | 
			
		||||
		*new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item;
 | 
			
		||||
	// else wheel == 0
 | 
			
		||||
	s32 dir = wheel;
 | 
			
		||||
 | 
			
		||||
	if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN)) {
 | 
			
		||||
		dir = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (input->joystick.wasKeyDown(KeyType::SCROLL_UP)) {
 | 
			
		||||
		dir = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dir < 0)
 | 
			
		||||
		*new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0;
 | 
			
		||||
	else if (dir > 0)
 | 
			
		||||
		*new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item;
 | 
			
		||||
	// else dir == 0
 | 
			
		||||
 | 
			
		||||
	/* Item selection using keyboard
 | 
			
		||||
	 */
 | 
			
		||||
@@ -2868,7 +2896,7 @@ void Game::openInventory()
 | 
			
		||||
	TextDest *txt_dst = new TextDestPlayerInventory(client);
 | 
			
		||||
 | 
			
		||||
	create_formspec_menu(¤t_formspec, client, gamedef, texture_src,
 | 
			
		||||
			device, fs_src, txt_dst, client);
 | 
			
		||||
			device, &input->joystick, fs_src, txt_dst, client);
 | 
			
		||||
 | 
			
		||||
	InventoryLocation inventoryloc;
 | 
			
		||||
	inventoryloc.setCurrentPlayer();
 | 
			
		||||
@@ -3154,7 +3182,7 @@ void Game::toggleFullViewRange(float *statustext_time)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Game::updateCameraDirection(CameraOrientation *cam,
 | 
			
		||||
		VolatileRunFlags *flags)
 | 
			
		||||
		VolatileRunFlags *flags, float dtime)
 | 
			
		||||
{
 | 
			
		||||
	if ((device->isWindowActive() && noMenuActive()) || random_input) {
 | 
			
		||||
 | 
			
		||||
@@ -3169,7 +3197,7 @@ void Game::updateCameraDirection(CameraOrientation *cam,
 | 
			
		||||
		if (flags->first_loop_after_window_activation)
 | 
			
		||||
			flags->first_loop_after_window_activation = false;
 | 
			
		||||
		else
 | 
			
		||||
			updateCameraOrientation(cam, *flags);
 | 
			
		||||
			updateCameraOrientation(cam, *flags, dtime);
 | 
			
		||||
 | 
			
		||||
		input->setMousePos((driver->getScreenSize().Width / 2),
 | 
			
		||||
				(driver->getScreenSize().Height / 2));
 | 
			
		||||
@@ -3187,9 +3215,8 @@ void Game::updateCameraDirection(CameraOrientation *cam,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Game::updateCameraOrientation(CameraOrientation *cam,
 | 
			
		||||
		const VolatileRunFlags &flags)
 | 
			
		||||
		const VolatileRunFlags &flags, float dtime)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_TOUCHSCREENGUI
 | 
			
		||||
	if (g_touchscreengui) {
 | 
			
		||||
@@ -3197,6 +3224,7 @@ void Game::updateCameraOrientation(CameraOrientation *cam,
 | 
			
		||||
		cam->camera_pitch = g_touchscreengui->getPitch();
 | 
			
		||||
	} else {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		s32 dx = input->getMousePos().X - (driver->getScreenSize().Width / 2);
 | 
			
		||||
		s32 dy = input->getMousePos().Y - (driver->getScreenSize().Height / 2);
 | 
			
		||||
 | 
			
		||||
@@ -3212,6 +3240,14 @@ void Game::updateCameraOrientation(CameraOrientation *cam,
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (m_cache_enable_joysticks) {
 | 
			
		||||
		f32 c = m_cache_joystick_frustum_sensitivity * (1.f / 32767.f) * dtime;
 | 
			
		||||
		cam->camera_yaw -= input->joystick.getAxisWithoutDead(JA_FRUSTUM_HORIZONTAL) *
 | 
			
		||||
			c;
 | 
			
		||||
		cam->camera_pitch += input->joystick.getAxisWithoutDead(JA_FRUSTUM_VERTICAL) *
 | 
			
		||||
			c;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cam->camera_pitch = rangelim(cam->camera_pitch, -89.5, 89.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3220,30 +3256,36 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
 | 
			
		||||
{
 | 
			
		||||
	//TimeTaker tt("update player control", NULL, PRECISION_NANO);
 | 
			
		||||
 | 
			
		||||
	// DO NOT use the isKeyDown method for the forward, backward, left, right
 | 
			
		||||
	// buttons, as the code that uses the controls needs to be able to
 | 
			
		||||
	// distinguish between the two in order to know when to use joysticks.
 | 
			
		||||
 | 
			
		||||
	PlayerControl control(
 | 
			
		||||
		input->isKeyDown(keycache.key[KeyType::FORWARD]),
 | 
			
		||||
		input->isKeyDown(keycache.key[KeyType::BACKWARD]),
 | 
			
		||||
		input->isKeyDown(keycache.key[KeyType::LEFT]),
 | 
			
		||||
		input->isKeyDown(keycache.key[KeyType::RIGHT]),
 | 
			
		||||
		input->isKeyDown(keycache.key[KeyType::JUMP]),
 | 
			
		||||
		input->isKeyDown(keycache.key[KeyType::SPECIAL1]),
 | 
			
		||||
		input->isKeyDown(keycache.key[KeyType::SNEAK]),
 | 
			
		||||
		input->getLeftState(),
 | 
			
		||||
		input->getRightState(),
 | 
			
		||||
		isKeyDown(KeyType::JUMP),
 | 
			
		||||
		isKeyDown(KeyType::SPECIAL1),
 | 
			
		||||
		isKeyDown(KeyType::SNEAK),
 | 
			
		||||
		isLeftPressed(),
 | 
			
		||||
		isRightPressed(),
 | 
			
		||||
		cam.camera_pitch,
 | 
			
		||||
		cam.camera_yaw
 | 
			
		||||
		cam.camera_yaw,
 | 
			
		||||
		input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE),
 | 
			
		||||
		input->joystick.getAxisWithoutDead(JA_FORWARD_MOVE)
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	u32 keypress_bits =
 | 
			
		||||
			( (u32)(input->isKeyDown(keycache.key[KeyType::FORWARD])  & 0x1) << 0) |
 | 
			
		||||
			( (u32)(input->isKeyDown(keycache.key[KeyType::BACKWARD]) & 0x1) << 1) |
 | 
			
		||||
			( (u32)(input->isKeyDown(keycache.key[KeyType::LEFT])     & 0x1) << 2) |
 | 
			
		||||
			( (u32)(input->isKeyDown(keycache.key[KeyType::RIGHT])    & 0x1) << 3) |
 | 
			
		||||
			( (u32)(input->isKeyDown(keycache.key[KeyType::JUMP])     & 0x1) << 4) |
 | 
			
		||||
			( (u32)(input->isKeyDown(keycache.key[KeyType::SPECIAL1]) & 0x1) << 5) |
 | 
			
		||||
			( (u32)(input->isKeyDown(keycache.key[KeyType::SNEAK])    & 0x1) << 6) |
 | 
			
		||||
			( (u32)(input->getLeftState()                                        & 0x1) << 7) |
 | 
			
		||||
			( (u32)(input->getRightState()                                       & 0x1) << 8
 | 
			
		||||
			( (u32)(isKeyDown(KeyType::FORWARD)                       & 0x1) << 0) |
 | 
			
		||||
			( (u32)(isKeyDown(KeyType::BACKWARD)                      & 0x1) << 1) |
 | 
			
		||||
			( (u32)(isKeyDown(KeyType::LEFT)                          & 0x1) << 2) |
 | 
			
		||||
			( (u32)(isKeyDown(KeyType::RIGHT)                         & 0x1) << 3) |
 | 
			
		||||
			( (u32)(isKeyDown(KeyType::JUMP)                          & 0x1) << 4) |
 | 
			
		||||
			( (u32)(isKeyDown(KeyType::SPECIAL1)                      & 0x1) << 5) |
 | 
			
		||||
			( (u32)(isKeyDown(KeyType::SNEAK)                         & 0x1) << 6) |
 | 
			
		||||
			( (u32)(isLeftPressed()                                   & 0x1) << 7) |
 | 
			
		||||
			( (u32)(isRightPressed()                                  & 0x1) << 8
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
#ifdef ANDROID
 | 
			
		||||
@@ -3312,7 +3354,7 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
 | 
			
		||||
			cam->camera_pitch = event.player_force_move.pitch;
 | 
			
		||||
		} else if (event.type == CE_DEATHSCREEN) {
 | 
			
		||||
			show_deathscreen(¤t_formspec, client, gamedef, texture_src,
 | 
			
		||||
					 device, client);
 | 
			
		||||
				device, &input->joystick, client);
 | 
			
		||||
 | 
			
		||||
			chat_backend->addMessage(L"", L"You died.");
 | 
			
		||||
 | 
			
		||||
@@ -3328,7 +3370,8 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
 | 
			
		||||
				new TextDestPlayerInventory(client, *(event.show_formspec.formname));
 | 
			
		||||
 | 
			
		||||
			create_formspec_menu(¤t_formspec, client, gamedef,
 | 
			
		||||
					     texture_src, device, fs_src, txt_dst, client);
 | 
			
		||||
				texture_src, device, &input->joystick,
 | 
			
		||||
				fs_src, txt_dst, client);
 | 
			
		||||
 | 
			
		||||
			delete(event.show_formspec.formspec);
 | 
			
		||||
			delete(event.show_formspec.formname);
 | 
			
		||||
@@ -3723,8 +3766,14 @@ void Game::processPlayerInteraction(GameRunData *runData,
 | 
			
		||||
	input->resetLeftClicked();
 | 
			
		||||
	input->resetRightClicked();
 | 
			
		||||
 | 
			
		||||
	input->joystick.clearWasKeyDown(KeyType::MOUSE_L);
 | 
			
		||||
	input->joystick.clearWasKeyDown(KeyType::MOUSE_R);
 | 
			
		||||
 | 
			
		||||
	input->resetLeftReleased();
 | 
			
		||||
	input->resetRightReleased();
 | 
			
		||||
 | 
			
		||||
	input->joystick.clearWasKeyReleased(KeyType::MOUSE_L);
 | 
			
		||||
	input->joystick.clearWasKeyReleased(KeyType::MOUSE_R);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -3785,7 +3834,7 @@ void Game::handlePointingAtNode(GameRunData *runData,
 | 
			
		||||
			TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
 | 
			
		||||
 | 
			
		||||
			create_formspec_menu(¤t_formspec, client, gamedef,
 | 
			
		||||
					     texture_src, device, fs_src, txt_dst, client);
 | 
			
		||||
				texture_src, device, &input->joystick, fs_src, txt_dst, client);
 | 
			
		||||
 | 
			
		||||
			current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
 | 
			
		||||
		} else {
 | 
			
		||||
@@ -4468,12 +4517,14 @@ void Game::settingChangedCallback(const std::string &setting_name, void *data)
 | 
			
		||||
 | 
			
		||||
void Game::readSettings()
 | 
			
		||||
{
 | 
			
		||||
	m_cache_doubletap_jump            = g_settings->getBool("doubletap_jump");
 | 
			
		||||
	m_cache_enable_clouds             = g_settings->getBool("enable_clouds");
 | 
			
		||||
	m_cache_enable_particles          = g_settings->getBool("enable_particles");
 | 
			
		||||
	m_cache_enable_fog                = g_settings->getBool("enable_fog");
 | 
			
		||||
	m_cache_mouse_sensitivity         = g_settings->getFloat("mouse_sensitivity");
 | 
			
		||||
	m_repeat_right_click_time         = g_settings->getFloat("repeat_rightclick_time");
 | 
			
		||||
	m_cache_doubletap_jump               = g_settings->getBool("doubletap_jump");
 | 
			
		||||
	m_cache_enable_clouds                = g_settings->getBool("enable_clouds");
 | 
			
		||||
	m_cache_enable_joysticks             = g_settings->getBool("enable_joysticks");
 | 
			
		||||
	m_cache_enable_particles             = g_settings->getBool("enable_particles");
 | 
			
		||||
	m_cache_enable_fog                   = g_settings->getBool("enable_fog");
 | 
			
		||||
	m_cache_mouse_sensitivity            = g_settings->getFloat("mouse_sensitivity");
 | 
			
		||||
	m_cache_joystick_frustum_sensitivity = g_settings->getFloat("joystick_frustum_sensitivity");
 | 
			
		||||
	m_repeat_right_click_time            = g_settings->getFloat("repeat_rightclick_time");
 | 
			
		||||
 | 
			
		||||
	m_cache_mouse_sensitivity = rangelim(m_cache_mouse_sensitivity, 0.001, 100.0);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "irrlichttypes_extrabloated.h"
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "client/keys.h"
 | 
			
		||||
#include "client/joystick_controller.h"
 | 
			
		||||
#include "keycode.h"
 | 
			
		||||
#include <list>
 | 
			
		||||
 | 
			
		||||
@@ -135,6 +136,8 @@ public:
 | 
			
		||||
	virtual void step(float dtime) {}
 | 
			
		||||
 | 
			
		||||
	virtual void clear() {}
 | 
			
		||||
 | 
			
		||||
	JoystickController joystick;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ChatBackend;  /* to avoid having to include chat.h */
 | 
			
		||||
 
 | 
			
		||||
@@ -131,6 +131,7 @@ void MenuMusicFetcher::fetchSounds(const std::string &name,
 | 
			
		||||
/** GUIEngine                                                                 */
 | 
			
		||||
/******************************************************************************/
 | 
			
		||||
GUIEngine::GUIEngine(	irr::IrrlichtDevice* dev,
 | 
			
		||||
						JoystickController *joystick,
 | 
			
		||||
						gui::IGUIElement* parent,
 | 
			
		||||
						IMenuManager *menumgr,
 | 
			
		||||
						scene::ISceneManager* smgr,
 | 
			
		||||
@@ -189,6 +190,7 @@ GUIEngine::GUIEngine(	irr::IrrlichtDevice* dev,
 | 
			
		||||
 | 
			
		||||
	/* Create menu */
 | 
			
		||||
	m_menu = new GUIFormSpecMenu(m_device,
 | 
			
		||||
			joystick,
 | 
			
		||||
			m_parent,
 | 
			
		||||
			-1,
 | 
			
		||||
			m_menumanager,
 | 
			
		||||
 
 | 
			
		||||
@@ -149,7 +149,8 @@ public:
 | 
			
		||||
	 * @param smgr scene manager to add scene elements to
 | 
			
		||||
	 * @param data struct to transfer data to main game handling
 | 
			
		||||
	 */
 | 
			
		||||
	GUIEngine(	irr::IrrlichtDevice* dev,
 | 
			
		||||
	GUIEngine(irr::IrrlichtDevice* dev,
 | 
			
		||||
			JoystickController *joystick,
 | 
			
		||||
			gui::IGUIElement* parent,
 | 
			
		||||
			IMenuManager *menumgr,
 | 
			
		||||
			scene::ISceneManager* smgr,
 | 
			
		||||
 
 | 
			
		||||
@@ -79,6 +79,7 @@ static unsigned int font_line_height(gui::IGUIFont *font)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
 | 
			
		||||
		JoystickController *joystick,
 | 
			
		||||
		gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
 | 
			
		||||
		InventoryManager *invmgr, IGameDef *gamedef,
 | 
			
		||||
		ISimpleTextureSource *tsrc, IFormSource* fsrc, TextDest* tdst,
 | 
			
		||||
@@ -102,6 +103,7 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
 | 
			
		||||
	m_text_dst(tdst),
 | 
			
		||||
	m_formspec_version(0),
 | 
			
		||||
	m_focused_element(""),
 | 
			
		||||
	m_joystick(joystick),
 | 
			
		||||
	m_font(NULL),
 | 
			
		||||
	m_remap_dbl_click(remap_dbl_click)
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
@@ -2459,7 +2461,7 @@ void GUIFormSpecMenu::drawMenu()
 | 
			
		||||
		Draw static text elements
 | 
			
		||||
	*/
 | 
			
		||||
	for (u32 i = 0; i < m_static_texts.size(); i++) {
 | 
			
		||||
		const StaticTextSpec &spec = m_static_texts[i];	
 | 
			
		||||
		const StaticTextSpec &spec = m_static_texts[i];
 | 
			
		||||
		core::rect<s32> rect = spec.rect;
 | 
			
		||||
		if (spec.parent_button && spec.parent_button->isPressed()) {
 | 
			
		||||
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
 | 
			
		||||
@@ -3024,6 +3026,25 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
 | 
			
		||||
	}
 | 
			
		||||
	#endif
 | 
			
		||||
 | 
			
		||||
	if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
 | 
			
		||||
		/* TODO add a check like:
 | 
			
		||||
		if (event.JoystickEvent != joystick_we_listen_for)
 | 
			
		||||
			return false;
 | 
			
		||||
		*/
 | 
			
		||||
		bool handled = m_joystick->handleEvent(event.JoystickEvent);
 | 
			
		||||
		if (handled) {
 | 
			
		||||
			if (m_joystick->wasKeyDown(KeyType::ESC)) {
 | 
			
		||||
				tryClose();
 | 
			
		||||
			} else if (m_joystick->wasKeyDown(KeyType::JUMP)) {
 | 
			
		||||
				if (m_allowclose) {
 | 
			
		||||
					acceptInput(quit_mode_accept);
 | 
			
		||||
					quitMenu();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return handled;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3085,19 +3106,24 @@ bool GUIFormSpecMenu::DoubleClickDetection(const SEvent event)
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIFormSpecMenu::tryClose()
 | 
			
		||||
{
 | 
			
		||||
	if (m_allowclose) {
 | 
			
		||||
		doPause = false;
 | 
			
		||||
		acceptInput(quit_mode_cancel);
 | 
			
		||||
		quitMenu();
 | 
			
		||||
	} else {
 | 
			
		||||
		m_text_dst->gotText(L"MenuQuit");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GUIFormSpecMenu::OnEvent(const SEvent& event)
 | 
			
		||||
{
 | 
			
		||||
	if (event.EventType==EET_KEY_INPUT_EVENT) {
 | 
			
		||||
		KeyPress kp(event.KeyInput);
 | 
			
		||||
		if (event.KeyInput.PressedDown && ( (kp == EscapeKey) ||
 | 
			
		||||
				(kp == getKeySetting("keymap_inventory")) || (kp == CancelKey))) {
 | 
			
		||||
			if (m_allowclose) {
 | 
			
		||||
				doPause = false;
 | 
			
		||||
				acceptInput(quit_mode_cancel);
 | 
			
		||||
				quitMenu();
 | 
			
		||||
			} else {
 | 
			
		||||
				m_text_dst->gotText(L"MenuQuit");
 | 
			
		||||
			}
 | 
			
		||||
			tryClose();
 | 
			
		||||
			return true;
 | 
			
		||||
		} else if (m_client != NULL && event.KeyInput.PressedDown &&
 | 
			
		||||
				(kp == getKeySetting("keymap_screenshot"))) {
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "modalMenu.h"
 | 
			
		||||
#include "guiTable.h"
 | 
			
		||||
#include "network/networkprotocol.h"
 | 
			
		||||
#include "client/joystick_controller.h"
 | 
			
		||||
#include "util/string.h"
 | 
			
		||||
#include "util/enriched_string.h"
 | 
			
		||||
 | 
			
		||||
@@ -278,6 +279,7 @@ class GUIFormSpecMenu : public GUIModalMenu
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	GUIFormSpecMenu(irr::IrrlichtDevice* dev,
 | 
			
		||||
			JoystickController *joystick,
 | 
			
		||||
			gui::IGUIElement* parent, s32 id,
 | 
			
		||||
			IMenuManager *menumgr,
 | 
			
		||||
			InventoryManager *invmgr,
 | 
			
		||||
@@ -433,10 +435,11 @@ protected:
 | 
			
		||||
	video::SColor m_default_tooltip_color;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	IFormSource      *m_form_src;
 | 
			
		||||
	TextDest         *m_text_dst;
 | 
			
		||||
	unsigned int      m_formspec_version;
 | 
			
		||||
	std::string       m_focused_element;
 | 
			
		||||
	IFormSource        *m_form_src;
 | 
			
		||||
	TextDest           *m_text_dst;
 | 
			
		||||
	unsigned int        m_formspec_version;
 | 
			
		||||
	std::string         m_focused_element;
 | 
			
		||||
	JoystickController *m_joystick;
 | 
			
		||||
 | 
			
		||||
	typedef struct {
 | 
			
		||||
		bool explicit_size;
 | 
			
		||||
@@ -494,6 +497,8 @@ private:
 | 
			
		||||
	bool parseSizeDirect(parserData* data, std::string element);
 | 
			
		||||
	void parseScrollBar(parserData* data, std::string element);
 | 
			
		||||
 | 
			
		||||
	void tryClose();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * check if event is part of a double click
 | 
			
		||||
	 * @param event event to evaluate
 | 
			
		||||
 
 | 
			
		||||
@@ -528,18 +528,23 @@ void LocalPlayer::applyControl(float dtime)
 | 
			
		||||
			speedH += move_direction;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(control.down)
 | 
			
		||||
	{
 | 
			
		||||
	if (control.down) {
 | 
			
		||||
		speedH -= move_direction;
 | 
			
		||||
	}
 | 
			
		||||
	if(control.left)
 | 
			
		||||
	{
 | 
			
		||||
	if (!control.up && !control.down) {
 | 
			
		||||
		speedH -= move_direction *
 | 
			
		||||
			(control.forw_move_joystick_axis / 32767.f);
 | 
			
		||||
	}
 | 
			
		||||
	if (control.left) {
 | 
			
		||||
		speedH += move_direction.crossProduct(v3f(0,1,0));
 | 
			
		||||
	}
 | 
			
		||||
	if(control.right)
 | 
			
		||||
	{
 | 
			
		||||
	if (control.right) {
 | 
			
		||||
		speedH += move_direction.crossProduct(v3f(0,-1,0));
 | 
			
		||||
	}
 | 
			
		||||
	if (!control.left && !control.right) {
 | 
			
		||||
		speedH -= move_direction.crossProduct(v3f(0,1,0)) *
 | 
			
		||||
			(control.sidew_move_joystick_axis / 32767.f);
 | 
			
		||||
	}
 | 
			
		||||
	if(control.jump)
 | 
			
		||||
	{
 | 
			
		||||
		if (free_move) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								src/player.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/player.h
									
									
									
									
									
								
							@@ -46,6 +46,8 @@ struct PlayerControl
 | 
			
		||||
		RMB = false;
 | 
			
		||||
		pitch = 0;
 | 
			
		||||
		yaw = 0;
 | 
			
		||||
		sidew_move_joystick_axis = .0f;
 | 
			
		||||
		forw_move_joystick_axis = .0f;
 | 
			
		||||
	}
 | 
			
		||||
	PlayerControl(
 | 
			
		||||
		bool a_up,
 | 
			
		||||
@@ -58,7 +60,9 @@ struct PlayerControl
 | 
			
		||||
		bool a_LMB,
 | 
			
		||||
		bool a_RMB,
 | 
			
		||||
		float a_pitch,
 | 
			
		||||
		float a_yaw
 | 
			
		||||
		float a_yaw,
 | 
			
		||||
		float a_sidew_move_joystick_axis,
 | 
			
		||||
		float a_forw_move_joystick_axis
 | 
			
		||||
	)
 | 
			
		||||
	{
 | 
			
		||||
		up = a_up;
 | 
			
		||||
@@ -72,6 +76,8 @@ struct PlayerControl
 | 
			
		||||
		RMB = a_RMB;
 | 
			
		||||
		pitch = a_pitch;
 | 
			
		||||
		yaw = a_yaw;
 | 
			
		||||
		sidew_move_joystick_axis = a_sidew_move_joystick_axis;
 | 
			
		||||
		forw_move_joystick_axis = a_forw_move_joystick_axis;
 | 
			
		||||
	}
 | 
			
		||||
	bool up;
 | 
			
		||||
	bool down;
 | 
			
		||||
@@ -84,6 +90,8 @@ struct PlayerControl
 | 
			
		||||
	bool RMB;
 | 
			
		||||
	float pitch;
 | 
			
		||||
	float yaw;
 | 
			
		||||
	float sidew_move_joystick_axis;
 | 
			
		||||
	float forw_move_joystick_axis;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Map;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user