Squashed 'external/gainput/' content from commit 2be0a50
git-subtree-dir: external/gainput git-subtree-split: 2be0a50089eafcc6fccb66142180082e48f27f4c
15
.appveyor.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
|
||||||
|
configuration:
|
||||||
|
- Debug
|
||||||
|
- Release
|
||||||
|
|
||||||
|
before_build:
|
||||||
|
- md build
|
||||||
|
- cd build
|
||||||
|
- cmake -G "Visual Studio 14 2015 Win64" ..
|
||||||
|
|
||||||
|
build:
|
||||||
|
project: build\Project.sln
|
||||||
22
.gitignore
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
*.[doa]
|
||||||
|
*.swp
|
||||||
|
*.mk
|
||||||
|
*.pyc
|
||||||
|
.lock-*
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
build/
|
||||||
|
__pycache__/
|
||||||
|
.depproj/
|
||||||
|
gainput_2008.*
|
||||||
|
docs/
|
||||||
|
gainput.sdf
|
||||||
|
gainput.sln
|
||||||
|
gainput.unsuccessfulbuild
|
||||||
|
*.opensdf
|
||||||
|
cmakebuild*/
|
||||||
|
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
.externalNativeBuild
|
||||||
|
gradle
|
||||||
10
.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
language: cpp
|
||||||
|
compiler:
|
||||||
|
- gcc
|
||||||
|
- clang
|
||||||
|
sudo: false
|
||||||
|
script: mkdir build_debug && cd build_debug/ && cmake -DCMAKE_BUILD_TYPE=Debug .. && make && test/gainputtest && cd .. && mkdir build_release && cd build_release/ && cmake -DCMAKE_BUILD_TYPE=Release .. && make && test/gainputtest
|
||||||
|
|
||||||
35
CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
set(GAINPUT_MAJOR_VERSION 1)
|
||||||
|
set(GAINPUT_MINOR_VERSION 0)
|
||||||
|
set(GAINPUT_PATCH_VERSION 0)
|
||||||
|
set(GAINPUT_VERSION ${GAINPUT_MAJOR_VERSION}.${GAINPUT_MINOR_VERSION}.${GAINPUT_PATCH_VERSION})
|
||||||
|
|
||||||
|
option(GAINPUT_SAMPLES "Build Samples for Gainput" ON)
|
||||||
|
option(GAINPUT_TESTS "Build Tests for Gainput" ON)
|
||||||
|
option(GAINPUT_BUILD_SHARED "BUILD_SHARED" ON)
|
||||||
|
option(GAINPUT_BUILD_STATIC "BUILD_STATIC" ON)
|
||||||
|
|
||||||
|
if(!WIN32)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra")
|
||||||
|
else()
|
||||||
|
set(XINPUT "Xinput9_1_0")
|
||||||
|
if ( ${CMAKE_SYSTEM_VERSION} LESS 6.1 )
|
||||||
|
set(XINPUT, "xinput")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
include(extern/cmake/AndroidNdkModules.cmake)
|
||||||
|
android_ndk_import_module_native_app_glue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(lib)
|
||||||
|
|
||||||
|
if(GAINPUT_SAMPLES)
|
||||||
|
add_subdirectory(samples)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(GAINPUT_TESTS)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
||||||
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Copyright (c) 2013-2017 Johannes Kuhlmann
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
115
README.md
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
This project is archived. It's neither maintained nor developed anymore.
|
||||||
|
=======
|
||||||
|
|
||||||
|
Gainput [](https://travis-ci.org/jkuhlmann/gainput) [](./LICENSE)
|
||||||
|
=======
|
||||||
|
|
||||||
|
Gainput is the awesome C++ input library for your game:
|
||||||
|
|
||||||
|
- handles your input needs from low-level device reading to high-level mapping of user-defined buttons
|
||||||
|
- well-documented, clean, lightweight, and easy to use
|
||||||
|
- a unified interface on all supported platforms: **Android NDK, iOS/tvOS, Linux, macOS, Windows**
|
||||||
|
- supported devices: keyboard, mouse, gamepad, multi-touch, device built-in sensors
|
||||||
|
- [Open Source (MIT license)](https://github.com/jkuhlmann/gainput/blob/master/LICENSE)
|
||||||
|
- [complete list of features](#features)
|
||||||
|
- [API documentation](http://gainput.johanneskuhlmann.de/api/)
|
||||||
|
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
enum Button
|
||||||
|
{
|
||||||
|
ButtonConfirm
|
||||||
|
};
|
||||||
|
|
||||||
|
gainput::InputManager manager;
|
||||||
|
manager.SetDisplaySize(displayWidth, displayHeight);
|
||||||
|
const gainput::DeviceId keyboardId = manager.CreateDevice<gainput::InputDeviceKeyboard>();
|
||||||
|
const gainput::DeviceId mouseId = manager.CreateDevice<gainput::InputDeviceMouse>();
|
||||||
|
const gainput::DeviceId padId = manager.CreateDevice<gainput::InputDevicePad>();
|
||||||
|
const gainput::DeviceId touchId = manager.CreateDevice<gainput::InputDeviceTouch>();
|
||||||
|
|
||||||
|
gainput::InputMap map(manager);
|
||||||
|
map.MapBool(ButtonConfirm, keyboardId, gainput::KeyReturn);
|
||||||
|
map.MapBool(ButtonConfirm, mouseId, gainput::MouseButtonLeft);
|
||||||
|
map.MapBool(ButtonConfirm, padId, gainput::PadButtonA);
|
||||||
|
map.MapBool(ButtonConfirm, touchId, gainput::Touch0Down);
|
||||||
|
|
||||||
|
while (running)
|
||||||
|
{
|
||||||
|
manager.Update();
|
||||||
|
|
||||||
|
// May need some platform-specific message handling here
|
||||||
|
|
||||||
|
if (map.GetBoolWasDown(ButtonConfirm))
|
||||||
|
{
|
||||||
|
// Confirmed!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Offers a **unified interface** on all supported platforms. (Some minor changes are necessary to setup the library.)
|
||||||
|
- Provides a low-level and high-level interface: Query the state of input devices buttons directly or map device buttons to a user button. That way it's easy to support alternative inputs or change the **input mappings** around later.
|
||||||
|
- Supports **recording and playback** of input sequences.
|
||||||
|
- Features a **network server** to obtain information on devices and mappings from.
|
||||||
|
- Two Gainput instances can **sync device states over the network**. It's also possible to receive **multi-touch inputs from a smartphone**'s regular browser.
|
||||||
|
- Completely written in portable **C++**.
|
||||||
|
- **No STL** is used. **No exceptions** are thrown. **No RTTI** is used. **No C++11**, and **no boost**.
|
||||||
|
- **No weird external dependencies** are used. Relies on the existing platform SDKs.
|
||||||
|
- **Easily set up and built** using your favorite IDE/build tool.
|
||||||
|
- **Listeners** can be installed both for devices buttons as well as user buttons. That way you are notified when a button state changes.
|
||||||
|
- **Gestures** allow for more complex input patterns to be detected, for example double-clicking, pinch/rotation gestures, or holding several buttons simultaneously.
|
||||||
|
- An **external allocator** can be supplied to the library so that all memory management is done the way you want it.
|
||||||
|
- Supports **raw input** on Linux and Windows.
|
||||||
|
- Gamepad rumbling is supported where available.
|
||||||
|
- It's easy to check for all pressed buttons so that offering a way to the players to remap their buttons is easy to implement. Similarly it's easy to save and load mappings.
|
||||||
|
- Possibly unnecessary features, like gestures or the network server, are easily disabled.
|
||||||
|
- **Dead zones** can be set up for any float-value button.
|
||||||
|
- **State changes**, i.e. if a button is newly down or just released, can be checked for.
|
||||||
|
|
||||||
|
|
||||||
|
Building
|
||||||
|
--------
|
||||||
|
|
||||||
|
By default, Gainput is built using [CMake](http://www.cmake.org/).
|
||||||
|
|
||||||
|
1. Run `mkdir build`
|
||||||
|
1. Run `cmake ..`
|
||||||
|
1. Run `make`
|
||||||
|
1. The library can be found in `lib/`, the executables in `samples/`.
|
||||||
|
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
------------
|
||||||
|
|
||||||
|
Everyone is welcome to contribute to the library. If you find any problems, you can submit them using [GitHub's issue system](https://github.com/jkuhlmann/gainput/issues). If you want to contribute code, you should fork the project and then send a pull request.
|
||||||
|
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
Gainput has a minimal number of external dependencies to make it as self-contained as possible. It uses the platforms' default ways of getting inputs and doesn't use the STL.
|
||||||
|
|
||||||
|
|
||||||
|
Testing
|
||||||
|
-------
|
||||||
|
|
||||||
|
Generally, testing should be done by building and running Gainput on all supported platforms. The samples in the `samples/` folder should be used in order to determine if the library is functional.
|
||||||
|
|
||||||
|
The unit tests in the `test/` folder are built by the normal CMake build. The executable can be found in the `test/` folder. All build configurations and unit tests are built and run by Travis CI whenever something is pushed into the repository.
|
||||||
|
|
||||||
|
|
||||||
|
Alternatives
|
||||||
|
------------
|
||||||
|
|
||||||
|
- [OIS](https://github.com/wgois/Object-oriented-Input-System--OIS-)
|
||||||
|
- [SDL](http://www.libsdl.org/)
|
||||||
|
|
||||||
64
build.gradle
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:2.3.2'
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 25
|
||||||
|
buildToolsVersion "25.0.2"
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.example.gainput.gainput"
|
||||||
|
minSdkVersion 21
|
||||||
|
targetSdkVersion 25
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path "CMakeLists.txt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
manifest.srcFile 'extern/android/AndroidManifest.xml'
|
||||||
|
res.srcDirs = ['extern/android/res/']
|
||||||
|
java.srcDirs = ['lib/java/']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||||
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
|
})
|
||||||
|
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
|
}
|
||||||
24
extern/android/AndroidManifest.xml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
|
||||||
|
package="com.example.gainput.gainput">
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".BasicActivity"
|
||||||
|
android:label="@string/app_name">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
BIN
extern/android/res/mipmap-hdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
extern/android/res/mipmap-hdpi/ic_launcher_round.png
vendored
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
extern/android/res/mipmap-mdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
extern/android/res/mipmap-mdpi/ic_launcher_round.png
vendored
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
extern/android/res/mipmap-xhdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
extern/android/res/mipmap-xhdpi/ic_launcher_round.png
vendored
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
extern/android/res/mipmap-xxhdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
extern/android/res/mipmap-xxhdpi/ic_launcher_round.png
vendored
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
extern/android/res/mipmap-xxxhdpi/ic_launcher.png
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
extern/android/res/mipmap-xxxhdpi/ic_launcher_round.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
6
extern/android/res/values/colors.xml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#3F51B5</color>
|
||||||
|
<color name="colorPrimaryDark">#303F9F</color>
|
||||||
|
<color name="colorAccent">#FF4081</color>
|
||||||
|
</resources>
|
||||||
3
extern/android/res/values/strings.xml
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Gainput</string>
|
||||||
|
</resources>
|
||||||
11
extern/android/res/values/styles.xml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
||||||
9427
extern/catch/catch.hpp
vendored
Normal file
59
extern/cmake/AndroidNdkModules.cmake
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# Copyright (c) 2014, Pavel Rojtberg
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
macro(android_ndk_import_module_cpufeatures)
|
||||||
|
if(ANDROID)
|
||||||
|
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
|
||||||
|
add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
|
||||||
|
target_link_libraries(cpufeatures dl)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(android_ndk_import_module_native_app_glue)
|
||||||
|
if(ANDROID)
|
||||||
|
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
|
||||||
|
#include_directories(${ANDROID_NDK}/platforms/android-21/arch-arm/usr/include/)
|
||||||
|
add_library(native_app_glue ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
|
||||||
|
target_link_libraries(native_app_glue log)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(android_ndk_import_module_ndk_helper)
|
||||||
|
if(ANDROID)
|
||||||
|
android_ndk_import_module_cpufeatures()
|
||||||
|
android_ndk_import_module_native_app_glue()
|
||||||
|
|
||||||
|
include_directories(${ANDROID_NDK}/sources/android/ndk_helper)
|
||||||
|
file(GLOB _NDK_HELPER_SRCS ${ANDROID_NDK}/sources/android/ndk_helper/*.cpp ${ANDROID_NDK}/sources/android/ndk_helper/gl3stub.c)
|
||||||
|
add_library(ndk_helper ${_NDK_HELPER_SRCS})
|
||||||
|
target_link_libraries(ndk_helper log android EGL GLESv2 cpufeatures native_app_glue)
|
||||||
|
|
||||||
|
unset(_NDK_HELPER_SRCS)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
1688
extern/cmake/android.toolchain.cmake
vendored
Normal file
200
extern/cmake/iOS.cmake
vendored
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
|
||||||
|
# files which are included with CMake 2.8.4
|
||||||
|
# It has been altered for iOS development
|
||||||
|
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
# IOS_PLATFORM = OS (default) or SIMULATOR
|
||||||
|
# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
|
||||||
|
# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
|
||||||
|
# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
|
||||||
|
#
|
||||||
|
# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
|
||||||
|
# By default this location is automatcially chosen based on the IOS_PLATFORM value above.
|
||||||
|
# If set manually, it will override the default location and force the user of a particular Developer Platform
|
||||||
|
#
|
||||||
|
# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
|
||||||
|
# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
|
||||||
|
# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
|
||||||
|
# If set manually, this will force the use of a specific SDK version
|
||||||
|
|
||||||
|
# Macros:
|
||||||
|
#
|
||||||
|
# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
|
||||||
|
# A convenience macro for setting xcode specific properties on targets
|
||||||
|
# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
|
||||||
|
#
|
||||||
|
# find_host_package (PROGRAM ARGS)
|
||||||
|
# A macro used to find executable programs on the host system, not within the iOS environment.
|
||||||
|
# Thanks to the android-cmake project for providing the command
|
||||||
|
|
||||||
|
# Standard settings
|
||||||
|
set (CMAKE_SYSTEM_NAME Darwin)
|
||||||
|
set (CMAKE_SYSTEM_VERSION 1)
|
||||||
|
set (UNIX True)
|
||||||
|
set (APPLE True)
|
||||||
|
set (IOS True)
|
||||||
|
|
||||||
|
# Required as of cmake 2.8.10
|
||||||
|
set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
|
||||||
|
|
||||||
|
# Determine the cmake host system version so we know where to find the iOS SDKs
|
||||||
|
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
|
||||||
|
if (CMAKE_UNAME)
|
||||||
|
exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
|
||||||
|
string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
|
||||||
|
endif (CMAKE_UNAME)
|
||||||
|
|
||||||
|
# Force the compilers to gcc for iOS
|
||||||
|
include (CMakeForceCompiler)
|
||||||
|
CMAKE_FORCE_C_COMPILER (/usr/bin/clang AppleClang)
|
||||||
|
CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ AppleClang)
|
||||||
|
set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
|
||||||
|
|
||||||
|
# Skip the platform compiler checks for cross compiling
|
||||||
|
set (CMAKE_CXX_COMPILER_WORKS TRUE)
|
||||||
|
set (CMAKE_C_COMPILER_WORKS TRUE)
|
||||||
|
|
||||||
|
# All iOS/Darwin specific settings - some may be redundant
|
||||||
|
set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
|
||||||
|
set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
|
||||||
|
set (CMAKE_SHARED_MODULE_PREFIX "lib")
|
||||||
|
set (CMAKE_SHARED_MODULE_SUFFIX ".so")
|
||||||
|
set (CMAKE_MODULE_EXISTS 1)
|
||||||
|
set (CMAKE_DL_LIBS "")
|
||||||
|
|
||||||
|
set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
|
||||||
|
set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
|
||||||
|
set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
|
||||||
|
set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
|
||||||
|
|
||||||
|
# Hidden visibilty is required for cxx on iOS
|
||||||
|
set (CMAKE_C_FLAGS_INIT "")
|
||||||
|
set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}")
|
||||||
|
|
||||||
|
set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
|
||||||
|
set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
|
||||||
|
|
||||||
|
set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
|
||||||
|
set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
|
||||||
|
set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
|
||||||
|
set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
|
||||||
|
set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
|
||||||
|
set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
|
||||||
|
|
||||||
|
# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
|
||||||
|
# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
|
||||||
|
# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
|
||||||
|
# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
|
||||||
|
if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||||
|
find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
|
||||||
|
endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||||
|
|
||||||
|
# Setup iOS platform unless specified manually with IOS_PLATFORM
|
||||||
|
if (NOT DEFINED IOS_PLATFORM)
|
||||||
|
set (IOS_PLATFORM "OS")
|
||||||
|
endif (NOT DEFINED IOS_PLATFORM)
|
||||||
|
set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
|
||||||
|
|
||||||
|
# Check the platform selection and setup for developer root
|
||||||
|
if (${IOS_PLATFORM} STREQUAL "OS")
|
||||||
|
set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
|
||||||
|
|
||||||
|
# This causes the installers to properly locate the output libraries
|
||||||
|
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
|
||||||
|
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
|
||||||
|
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
|
||||||
|
|
||||||
|
# This causes the installers to properly locate the output libraries
|
||||||
|
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
|
||||||
|
else (${IOS_PLATFORM} STREQUAL "OS")
|
||||||
|
message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
|
||||||
|
endif (${IOS_PLATFORM} STREQUAL "OS")
|
||||||
|
|
||||||
|
# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
|
||||||
|
# Note Xcode 4.3 changed the installation location, choose the most recent one available
|
||||||
|
execute_process(
|
||||||
|
COMMAND "xcode-select" "-p"
|
||||||
|
OUTPUT_VARIABLE "XCODE_PATH"
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE )
|
||||||
|
set (XCODE_POST_43_ROOT "${XCODE_PATH}/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||||
|
set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||||
|
if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||||
|
if (EXISTS ${XCODE_POST_43_ROOT})
|
||||||
|
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
|
||||||
|
elseif(EXISTS ${XCODE_PRE_43_ROOT})
|
||||||
|
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
|
||||||
|
endif (EXISTS ${XCODE_POST_43_ROOT})
|
||||||
|
endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||||
|
set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
|
||||||
|
|
||||||
|
# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
|
||||||
|
if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||||
|
file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
|
||||||
|
if (_CMAKE_IOS_SDKS)
|
||||||
|
list (SORT _CMAKE_IOS_SDKS)
|
||||||
|
list (REVERSE _CMAKE_IOS_SDKS)
|
||||||
|
list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
|
||||||
|
else (_CMAKE_IOS_SDKS)
|
||||||
|
message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
|
||||||
|
endif (_CMAKE_IOS_SDKS)
|
||||||
|
message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
|
||||||
|
endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||||
|
set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
|
||||||
|
|
||||||
|
# Set the sysroot default to the most recent SDK
|
||||||
|
set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
|
||||||
|
|
||||||
|
# set the architecture for iOS
|
||||||
|
# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually
|
||||||
|
if (${IOS_PLATFORM} STREQUAL "OS")
|
||||||
|
set (IOS_ARCH arm64)
|
||||||
|
else (${IOS_PLATFORM} STREQUAL "OS")
|
||||||
|
set (IOS_ARCH i386)
|
||||||
|
endif (${IOS_PLATFORM} STREQUAL "OS")
|
||||||
|
|
||||||
|
set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS")
|
||||||
|
|
||||||
|
# Set the find root to the iOS developer roots and to user defined paths
|
||||||
|
set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root")
|
||||||
|
|
||||||
|
# default to searching for frameworks first
|
||||||
|
set (CMAKE_FIND_FRAMEWORK FIRST)
|
||||||
|
|
||||||
|
# set up the default search directories for frameworks
|
||||||
|
set (CMAKE_SYSTEM_FRAMEWORK_PATH
|
||||||
|
${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
|
||||||
|
${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
|
||||||
|
${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
|
||||||
|
)
|
||||||
|
|
||||||
|
# only search the iOS sdks, not the remainder of the host filesystem
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
|
||||||
|
set( CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "8.0" )
|
||||||
|
set( CMAKE_XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" )
|
||||||
|
set( CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE NO )
|
||||||
|
|
||||||
|
# This little macro lets you set any XCode specific property
|
||||||
|
macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
|
||||||
|
set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
|
||||||
|
endmacro (set_xcode_property)
|
||||||
|
|
||||||
|
|
||||||
|
# This macro lets you find executable programs on the host system
|
||||||
|
macro (find_host_package)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
|
||||||
|
set (IOS FALSE)
|
||||||
|
|
||||||
|
find_package(${ARGN})
|
||||||
|
|
||||||
|
set (IOS TRUE)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
endmacro (find_host_package)
|
||||||
|
|
||||||
49
extern/ios/Info.plist
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.example.gainput.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${PRODUCT_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>Launch Screen</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UIStatusBarHidden</key>
|
||||||
|
<true/>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
53
extern/ios/Launch Screen.storyboard
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<device id="retina4_7" orientation="portrait">
|
||||||
|
<adaptation id="fullscreen"/>
|
||||||
|
</device>
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||||
|
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
|
||||||
|
<rect key="frame" x="20" y="647" width="335" height="0.0"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Project" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
|
||||||
|
<rect key="frame" x="20" y="202" width="335" height="43"/>
|
||||||
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||||
|
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
|
||||||
|
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
|
||||||
|
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
|
||||||
|
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
79
lib/CMakeLists.txt
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
project(gainput)
|
||||||
|
message(STATUS "GAINPUT version ${GAINPUT_VERSION}")
|
||||||
|
|
||||||
|
set(CMAKE_MACOSX_RPATH 1)
|
||||||
|
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98 -Wall -Wextra -pedantic -Wshadow -Wno-variadic-macros")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories (include/)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE sources source/*.cpp source/*.h include/*.h)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
file(GLOB_RECURSE mmsources source/*.mm)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
## build STATIC *or* SHARED
|
||||||
|
if (GAINPUT_BUILD_SHARED)
|
||||||
|
message(STATUS "..Building shared libraries (-DGAINPUT_BUILD_SHARED=OFF to disable)")
|
||||||
|
add_library(gainput SHARED ${sources} ${mmsources})
|
||||||
|
set_target_properties(gainput PROPERTIES
|
||||||
|
OUTPUT_NAME gainput
|
||||||
|
DEBUG_POSTFIX -d
|
||||||
|
VERSION ${GAINPUT_VERSION}
|
||||||
|
SOVERSION ${GAINPUT_MAJOR_VERSION}
|
||||||
|
FOLDER gainput
|
||||||
|
)
|
||||||
|
set(install_libs ${install_libs} gainput)
|
||||||
|
endif (GAINPUT_BUILD_SHARED)
|
||||||
|
|
||||||
|
if (GAINPUT_BUILD_STATIC)
|
||||||
|
message(STATUS "..Building static libraries (-DGAINPUT_BUILD_STATIC=OFF to disable)")
|
||||||
|
add_library(gainputstatic STATIC ${sources} ${mmsources})
|
||||||
|
set_target_properties(gainputstatic PROPERTIES DEBUG_POSTFIX -d FOLDER gainput)
|
||||||
|
set(install_libs ${install_libs} gainputstatic)
|
||||||
|
endif (GAINPUT_BUILD_STATIC)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(gainput ${XINPUT} ws2_32)
|
||||||
|
target_link_libraries(gainputstatic ${XINPUT} ws2_32)
|
||||||
|
add_definitions(-DGAINPUT_LIB_DYNAMIC=1)
|
||||||
|
elseif(ANDROID)
|
||||||
|
target_link_libraries(gainputstatic native_app_glue log android)
|
||||||
|
target_link_libraries(gainput native_app_glue log android)
|
||||||
|
elseif(APPLE)
|
||||||
|
find_library(FOUNDATION Foundation)
|
||||||
|
find_library(IOKIT IOKit)
|
||||||
|
find_library(GAME_CONTROLLER GameController)
|
||||||
|
target_link_libraries(gainput ${FOUNDATION} ${IOKIT} ${GAME_CONTROLLER})
|
||||||
|
if(IOS)
|
||||||
|
find_library(UIKIT UIKit)
|
||||||
|
find_library(COREMOTION CoreMotion)
|
||||||
|
find_library(QUARTZCORE QuartzCore)
|
||||||
|
target_link_libraries(gainput ${UIKIT} ${COREMOTION})
|
||||||
|
else()
|
||||||
|
find_library(APPKIT AppKit)
|
||||||
|
target_link_libraries(gainput ${APPKIT})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Library installation directory
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||||
|
set(CMAKE_INSTALL_LIBDIR lib)
|
||||||
|
endif(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||||
|
set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY "include/gainput"
|
||||||
|
DESTINATION "include"
|
||||||
|
FILES_MATCHING PATTERN "*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS ${install_libs}
|
||||||
|
LIBRARY DESTINATION "${libdir}"
|
||||||
|
ARCHIVE DESTINATION "${libdir}"
|
||||||
|
RUNTIME DESTINATION "bin"
|
||||||
|
)
|
||||||
228
lib/include/gainput/GainputAllocator.h
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTALLOCATOR_H_
|
||||||
|
#define GAINPUTALLOCATOR_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Interface used to pass custom allocators to the library.
|
||||||
|
/**
|
||||||
|
* If you want the library to use your custom allocator you should implement this interface.
|
||||||
|
* Specifically, you should provide implementations for the Allocate() and Deallocate()
|
||||||
|
* functions. All other (template) member functions are simply based on those two functions.
|
||||||
|
*
|
||||||
|
* \sa DefaultAllocator
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT Allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum { DefaultAlign = 0 };
|
||||||
|
|
||||||
|
/// Allocates a number of bytes and returns a pointer to the allocated memory.
|
||||||
|
/**
|
||||||
|
* \param size The number of bytes to allocate.
|
||||||
|
* \return A memory block encompassing at least size bytes.
|
||||||
|
*/
|
||||||
|
virtual void* Allocate(size_t size, size_t align = DefaultAlign) = 0;
|
||||||
|
/// Deallocates the given memory.
|
||||||
|
/**
|
||||||
|
* \param ptr The memory block to deallocate.
|
||||||
|
*/
|
||||||
|
virtual void Deallocate(void* ptr) = 0;
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
T* New()
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with one parameter.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0>
|
||||||
|
T* New(P0& p0)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with one parameter.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0>
|
||||||
|
T* New(const P0& p0)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with two parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1>
|
||||||
|
T* New(P0& p0, P1& p1)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with two parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1>
|
||||||
|
T* New(const P0& p0, P1& p1)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with two parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1>
|
||||||
|
T* New(P0& p0, const P1& p1)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1, class P2>
|
||||||
|
T* New(P0& p0, const P1& p1, const P2& p2)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1, class P2>
|
||||||
|
T* New(P0& p0, const P1& p1, P2& p2)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1, class P2, class P3>
|
||||||
|
T* New(P0& p0, P1& p1, P2& p2, P3& p3)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1, class P2, class P3>
|
||||||
|
T* New(P0& p0, const P1& p1, P2& p2, P3& p3)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1, class P2, class P3, class P4>
|
||||||
|
T* New(P0& p0, P1& p1, P2& p2, P3& p3, P4& p4)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3, p4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
|
||||||
|
/**
|
||||||
|
* \return A pointer to an initialized instance of T.
|
||||||
|
*/
|
||||||
|
template <class T, class P0, class P1, class P2, class P3, class P4>
|
||||||
|
T* New(P0& p0, const P1& p1, P2& p2, P3& p3, P4& p4)
|
||||||
|
{
|
||||||
|
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3, p4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An operator delete-like function that calls ptr's constructor and deallocates the memory.
|
||||||
|
/**
|
||||||
|
* \param ptr The object to destruct and deallocate.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
void Delete(T* ptr)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
ptr->~T();
|
||||||
|
Deallocate(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The default allocator used by the library.
|
||||||
|
/**
|
||||||
|
* Any allocation/deallocation calls are simply forwarded to \c malloc and \c free. Any
|
||||||
|
* requested alignment is ignored.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT DefaultAllocator : public Allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void* Allocate(size_t size, size_t /*align*/)
|
||||||
|
{
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deallocate(void* ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns the default instance of the default allocator.
|
||||||
|
/**
|
||||||
|
* \sa DefaultAllocator
|
||||||
|
*/
|
||||||
|
GAINPUT_LIBEXPORT DefaultAllocator& GetDefaultAllocator();
|
||||||
|
|
||||||
|
template<class K, class V>
|
||||||
|
class GAINPUT_LIBEXPORT HashMap;
|
||||||
|
|
||||||
|
/// An allocator that tracks an allocations that were done
|
||||||
|
/**
|
||||||
|
* Any allocation/deallocation calls are simply forwarded to \c malloc and \c free. Any
|
||||||
|
* requested alignment is ignored.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT TrackingAllocator : public Allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TrackingAllocator(Allocator& backingAllocator, Allocator& internalAllocator = GetDefaultAllocator());
|
||||||
|
~TrackingAllocator();
|
||||||
|
|
||||||
|
void* Allocate(size_t size, size_t align = DefaultAlign);
|
||||||
|
void Deallocate(void* ptr);
|
||||||
|
|
||||||
|
size_t GetAllocateCount() const { return allocateCount_; }
|
||||||
|
size_t GetDeallocateCount() const { return deallocateCount_; }
|
||||||
|
size_t GetAllocatedMemory() const { return allocatedMemory_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator& backingAllocator_;
|
||||||
|
Allocator& internalAllocator_;
|
||||||
|
HashMap<void*, size_t>* allocations_;
|
||||||
|
size_t allocateCount_;
|
||||||
|
size_t deallocateCount_;
|
||||||
|
size_t allocatedMemory_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
508
lib/include/gainput/GainputContainers.h
Normal file
@@ -0,0 +1,508 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTCONTAINERS_H_
|
||||||
|
#define GAINPUTCONTAINERS_H_
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// -- MurmurHash3 begin --
|
||||||
|
// http://code.google.com/p/smhasher/wiki/MurmurHash3
|
||||||
|
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||||
|
// domain. The author hereby disclaims copyright to this source code.
|
||||||
|
|
||||||
|
inline uint32_t rotl32(uint32_t x, int8_t r)
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (32 - r));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t getblock(const uint32_t * p, int i)
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline uint32_t fmix(uint32_t h)
|
||||||
|
{
|
||||||
|
h ^= h >> 16;
|
||||||
|
h *= 0x85ebca6b;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 0xc2b2ae35;
|
||||||
|
h ^= h >> 16;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates MurmurHash3 for the given key.
|
||||||
|
/**
|
||||||
|
* \param key The key to calculate the hash of.
|
||||||
|
* \param len Length of the key in bytes.
|
||||||
|
* \param seed Seed for the hash.
|
||||||
|
* \param[out] out The hash value, a uint32_t in this case.
|
||||||
|
*/
|
||||||
|
inline void MurmurHash3_x86_32(const void * key, int len, uint32_t seed, void * out)
|
||||||
|
{
|
||||||
|
const uint8_t * data = (const uint8_t*)key;
|
||||||
|
const int nblocks = len / 4;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0xcc9e2d51;
|
||||||
|
const uint32_t c2 = 0x1b873593;
|
||||||
|
|
||||||
|
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
|
||||||
|
|
||||||
|
for(int i = -nblocks; i; i++)
|
||||||
|
{
|
||||||
|
uint32_t k1 = getblock(blocks,i);
|
||||||
|
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = rotl32(k1,15);
|
||||||
|
k1 *= c2;
|
||||||
|
|
||||||
|
h1 ^= k1;
|
||||||
|
h1 = rotl32(h1,13);
|
||||||
|
h1 = h1*5+0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
|
switch(len & 3)
|
||||||
|
{
|
||||||
|
case 3: k1 ^= tail[2] << 16;
|
||||||
|
case 2: k1 ^= tail[1] << 8;
|
||||||
|
case 1: k1 ^= tail[0];
|
||||||
|
k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
h1 ^= len;
|
||||||
|
|
||||||
|
h1 = fmix(h1);
|
||||||
|
|
||||||
|
*(uint32_t*)out = h1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- MurmurHash3 end --
|
||||||
|
|
||||||
|
|
||||||
|
/// A std::vector-like data container for POD-types.
|
||||||
|
/**
|
||||||
|
* \tparam T A POD-type to hold in this container.
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
class GAINPUT_LIBEXPORT Array
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const size_t DefaultCapacity = 8;
|
||||||
|
|
||||||
|
typedef T* iterator;
|
||||||
|
typedef const T* const_iterator;
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
Array(Allocator& allocator, size_t capacity = DefaultCapacity) :
|
||||||
|
allocator_(allocator),
|
||||||
|
size_(0),
|
||||||
|
capacity_(capacity)
|
||||||
|
{
|
||||||
|
data_ = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity_));
|
||||||
|
}
|
||||||
|
|
||||||
|
~Array()
|
||||||
|
{
|
||||||
|
allocator_.Delete(data_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() { return data_; }
|
||||||
|
const_iterator begin() const { return data_; }
|
||||||
|
iterator end() { return data_ + size_; }
|
||||||
|
const_iterator end() const { return data_ + size_; }
|
||||||
|
|
||||||
|
T& operator[] (size_t i)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(i < size_);
|
||||||
|
return data_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& operator[] (size_t i) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(i < size_);
|
||||||
|
return data_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(const value_type& val)
|
||||||
|
{
|
||||||
|
if (size_ + 1 > capacity_)
|
||||||
|
{
|
||||||
|
reserve(size_ + 1);
|
||||||
|
}
|
||||||
|
data_[size_++] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
if (size_ > 0)
|
||||||
|
--size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_t capacity)
|
||||||
|
{
|
||||||
|
if (capacity <= capacity_)
|
||||||
|
return;
|
||||||
|
capacity = (capacity_*2) < capacity ? capacity : (capacity_*2);
|
||||||
|
T* newData = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity));
|
||||||
|
memcpy(newData, data_, sizeof(T)*capacity_);
|
||||||
|
allocator_.Deallocate(data_);
|
||||||
|
data_ = newData;
|
||||||
|
capacity_ = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(Array<T>& x)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(&allocator_ == &x.allocator_);
|
||||||
|
|
||||||
|
const size_t thisSize = size_;
|
||||||
|
const size_t capacity = capacity_;
|
||||||
|
T* data = data_;
|
||||||
|
|
||||||
|
size_ = x.size_;
|
||||||
|
capacity_ = x.capacity_;
|
||||||
|
data_ = x.data_;
|
||||||
|
|
||||||
|
x.size_ = thisSize;
|
||||||
|
x.capacity_ = capacity;
|
||||||
|
x.data_ = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(iterator pos)
|
||||||
|
{
|
||||||
|
if (size_ == 0)
|
||||||
|
return end();
|
||||||
|
GAINPUT_ASSERT(pos >= begin() && pos < end());
|
||||||
|
memcpy(pos, pos+1, sizeof(T)*(end()-(pos+1)));
|
||||||
|
--size_;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() { size_ = 0; }
|
||||||
|
|
||||||
|
bool empty() const { return size_ == 0; }
|
||||||
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
|
iterator find(const value_type& val)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size_; ++i)
|
||||||
|
{
|
||||||
|
if (data_[i] == val)
|
||||||
|
{
|
||||||
|
return data_ + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator find(const value_type& val) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size_; ++i)
|
||||||
|
{
|
||||||
|
if (data_[i] == val)
|
||||||
|
{
|
||||||
|
return data_ + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator& allocator_;
|
||||||
|
size_t size_;
|
||||||
|
size_t capacity_;
|
||||||
|
T* data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// A hash table mapping keys to POD-type values.
|
||||||
|
/**
|
||||||
|
* \tparam K The key pointing to a value.
|
||||||
|
* \tparam V POD-type being stored in the table.
|
||||||
|
*/
|
||||||
|
template<class K, class V>
|
||||||
|
class GAINPUT_LIBEXPORT HashMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const unsigned Seed = 329856235;
|
||||||
|
enum { InvalidKey = unsigned(-1) };
|
||||||
|
|
||||||
|
/// An element of the hash table.
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
K first; ///< The element's key.
|
||||||
|
V second; ///< The element's value.
|
||||||
|
uint32_t next; ///< The index of the next element with the same (wrapped) hash; Do not use.
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Node* iterator;
|
||||||
|
typedef const Node* const_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
HashMap(Allocator& allocator = GetDefaultAllocator()) :
|
||||||
|
allocator_(allocator),
|
||||||
|
keys_(allocator_),
|
||||||
|
values_(allocator_),
|
||||||
|
size_(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
iterator begin() { return values_.begin(); }
|
||||||
|
const_iterator begin() const { return values_.begin(); }
|
||||||
|
iterator end() { return values_.begin() + values_.size(); }
|
||||||
|
const_iterator end() const { return values_.begin() + values_.size(); }
|
||||||
|
|
||||||
|
size_t size() const { return size_; }
|
||||||
|
bool empty() const { return size_ == 0; }
|
||||||
|
|
||||||
|
size_t count(const K& k) const
|
||||||
|
{
|
||||||
|
return find(k) != end() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(const K& k)
|
||||||
|
{
|
||||||
|
if (keys_.empty() || values_.empty())
|
||||||
|
return end();
|
||||||
|
uint32_t h;
|
||||||
|
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||||
|
const uint32_t ha = h % keys_.size();
|
||||||
|
volatile uint32_t vi = keys_[ha];
|
||||||
|
while (vi != InvalidKey)
|
||||||
|
{
|
||||||
|
if (values_[vi].first == k)
|
||||||
|
{
|
||||||
|
return &values_[vi];
|
||||||
|
}
|
||||||
|
vi = values_[vi].next;
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator find(const K& k) const
|
||||||
|
{
|
||||||
|
if (keys_.empty() || values_.empty())
|
||||||
|
return end();
|
||||||
|
uint32_t h;
|
||||||
|
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||||
|
const uint32_t ha = h % keys_.size();
|
||||||
|
volatile uint32_t vi = keys_[ha];
|
||||||
|
while (vi != InvalidKey)
|
||||||
|
{
|
||||||
|
if (values_[vi].first == k)
|
||||||
|
{
|
||||||
|
return &values_[vi];
|
||||||
|
}
|
||||||
|
vi = values_[vi].next;
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator insert(const K& k, const V& v)
|
||||||
|
{
|
||||||
|
if (values_.size() >= 0.6f*keys_.size())
|
||||||
|
{
|
||||||
|
Rehash(values_.size()*2 + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t h;
|
||||||
|
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||||
|
const uint32_t ha = h % keys_.size();
|
||||||
|
uint32_t vi = keys_[ha];
|
||||||
|
|
||||||
|
if (vi == InvalidKey)
|
||||||
|
{
|
||||||
|
keys_[ha] = values_.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (values_[vi].next == InvalidKey)
|
||||||
|
{
|
||||||
|
values_[vi].next = values_.size();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vi = values_[vi].next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node node;
|
||||||
|
node.first = k;
|
||||||
|
node.second = v;
|
||||||
|
node.next = InvalidKey;
|
||||||
|
values_.push_back(node);
|
||||||
|
|
||||||
|
++size_;
|
||||||
|
|
||||||
|
return &values_[values_.size()-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
V& operator[] (const K& k)
|
||||||
|
{
|
||||||
|
iterator it = find(k);
|
||||||
|
if (it == end())
|
||||||
|
{
|
||||||
|
return insert(k, V())->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t erase(const K& k)
|
||||||
|
{
|
||||||
|
if (keys_.empty())
|
||||||
|
return 0;
|
||||||
|
uint32_t h;
|
||||||
|
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
|
||||||
|
const uint32_t ha = h % keys_.size();
|
||||||
|
uint32_t vi = keys_[ha];
|
||||||
|
uint32_t prevVi = InvalidKey;
|
||||||
|
while (vi != InvalidKey)
|
||||||
|
{
|
||||||
|
if (values_[vi].first == k)
|
||||||
|
{
|
||||||
|
if (prevVi == InvalidKey)
|
||||||
|
{
|
||||||
|
keys_[ha] = values_[vi].next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
values_[prevVi].next = values_[vi].next;
|
||||||
|
}
|
||||||
|
|
||||||
|
--size_;
|
||||||
|
if (vi == values_.size() - 1)
|
||||||
|
{
|
||||||
|
values_.pop_back();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t lastVi = values_.size()-1;
|
||||||
|
values_[vi] = values_[lastVi];
|
||||||
|
values_.pop_back();
|
||||||
|
|
||||||
|
for (typename Array<uint32_t>::iterator it = keys_.begin(); it != keys_.end(); ++it)
|
||||||
|
{
|
||||||
|
if (*it == lastVi)
|
||||||
|
{
|
||||||
|
*it = vi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (typename Array<Node>::iterator it = values_.begin(); it != values_.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->next == lastVi)
|
||||||
|
{
|
||||||
|
it->next = vi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevVi = vi;
|
||||||
|
vi = values_[vi].next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
keys_.clear();
|
||||||
|
values_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator& allocator_;
|
||||||
|
Array<uint32_t> keys_;
|
||||||
|
Array<Node> values_;
|
||||||
|
size_t size_;
|
||||||
|
|
||||||
|
void Rehash(size_t newSize)
|
||||||
|
{
|
||||||
|
Array<uint32_t> keys(allocator_, newSize);
|
||||||
|
Array<Node> values(allocator_, values_.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < newSize; ++i)
|
||||||
|
keys.push_back(InvalidKey);
|
||||||
|
|
||||||
|
keys_.swap(keys);
|
||||||
|
values_.swap(values);
|
||||||
|
size_ = 0;
|
||||||
|
|
||||||
|
for (typename Array<Node>::const_iterator it = values.begin();
|
||||||
|
it != values.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
insert(it->first, it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// A ring buffer.
|
||||||
|
/**
|
||||||
|
* \tparam N The number of elements that can be stored in the ring buffer.
|
||||||
|
* \tparam T Type of the elements stored in the ring buffer.
|
||||||
|
*/
|
||||||
|
template<int N, class T>
|
||||||
|
class GAINPUT_LIBEXPORT RingBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RingBuffer() :
|
||||||
|
nextRead_(0),
|
||||||
|
nextWrite_(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
bool CanGet() const
|
||||||
|
{
|
||||||
|
return nextRead_ < nextWrite_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetCount() const
|
||||||
|
{
|
||||||
|
const size_t d = nextWrite_ - nextRead_;
|
||||||
|
return d > N ? N : d;
|
||||||
|
}
|
||||||
|
|
||||||
|
T Get()
|
||||||
|
{
|
||||||
|
return buf_[(nextRead_++) % N];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(T d)
|
||||||
|
{
|
||||||
|
buf_[(nextWrite_++) % N] = d;
|
||||||
|
while (nextRead_ + N < nextWrite_)
|
||||||
|
++nextRead_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T buf_[N];
|
||||||
|
size_t nextRead_;
|
||||||
|
size_t nextWrite_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
34
lib/include/gainput/GainputDebugRenderer.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTDEBUGRENDERER_H_
|
||||||
|
#define GAINPUTDEBUGRENDERER_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Interface for debug rendering of input device states.
|
||||||
|
/**
|
||||||
|
* Coordinates and other measures passed to the interface's functions are in the
|
||||||
|
* range of 0.0f to 1.0f.
|
||||||
|
*
|
||||||
|
* The functions are called as part InputManager::Update().
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT DebugRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Empty virtual destructor.
|
||||||
|
virtual ~DebugRenderer() { }
|
||||||
|
|
||||||
|
/// Called to draw a circle with the given radius.
|
||||||
|
virtual void DrawCircle(float x, float y, float radius) = 0;
|
||||||
|
|
||||||
|
/// Called to draw a line between the two given points.
|
||||||
|
virtual void DrawLine(float x1, float y1, float x2, float y2) = 0;
|
||||||
|
|
||||||
|
/// Called to draw some text at the given position.
|
||||||
|
virtual void DrawText(float x, float y, const char* const text) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
71
lib/include/gainput/GainputHelpers.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTHELPERS_H_
|
||||||
|
#define GAINPUTHELPERS_H_
|
||||||
|
|
||||||
|
#include <gainput/GainputLog.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
inline void HandleButton(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, bool value)
|
||||||
|
{
|
||||||
|
#ifdef GAINPUT_DEBUG
|
||||||
|
if (value != state.GetBool(buttonId))
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("Button changed: %d, %i\n", buttonId, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (delta)
|
||||||
|
{
|
||||||
|
const bool oldValue = state.GetBool(buttonId);
|
||||||
|
if (value != oldValue)
|
||||||
|
{
|
||||||
|
delta->AddChange(device.GetDeviceId(), buttonId, oldValue, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Set(buttonId, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void HandleAxis(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, float value)
|
||||||
|
{
|
||||||
|
const float deadZone = device.GetDeadZone(buttonId);
|
||||||
|
if (deadZone > 0.0f)
|
||||||
|
{
|
||||||
|
const float absValue = Abs(value);
|
||||||
|
const float sign = value < 0.0f ? -1.0f : 1.0f;
|
||||||
|
if (absValue < deadZone)
|
||||||
|
{
|
||||||
|
value = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value -= sign*deadZone;
|
||||||
|
value *= 1.0f / (1.0f - deadZone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef GAINPUT_DEBUG
|
||||||
|
if (value != state.GetFloat(buttonId))
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("Axis changed: %d, %f\n", buttonId, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (delta)
|
||||||
|
{
|
||||||
|
const float oldValue = state.GetFloat(buttonId);
|
||||||
|
if (value != oldValue)
|
||||||
|
{
|
||||||
|
delta->AddChange(device.GetDeviceId(), buttonId, oldValue, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Set(buttonId, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
59
lib/include/gainput/GainputInputDeltaState.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDELTASTATE_H_
|
||||||
|
#define GAINPUTINPUTDELTASTATE_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Stores a list of input state changes.
|
||||||
|
class GAINPUT_LIBEXPORT InputDeltaState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputDeltaState(Allocator& allocator);
|
||||||
|
|
||||||
|
/// Add a state change for a bool-type button.
|
||||||
|
/**
|
||||||
|
* \param device The input device the change occurred on.
|
||||||
|
* \param deviceButton The input button that was changed.
|
||||||
|
* \param oldValue The old button state.
|
||||||
|
* \param newValue The new button state.
|
||||||
|
*/
|
||||||
|
void AddChange(DeviceId device, DeviceButtonId deviceButton, bool oldValue, bool newValue);
|
||||||
|
/// Add a state change for a float-type button.
|
||||||
|
/**
|
||||||
|
* \param device The input device the change occurred on.
|
||||||
|
* \param deviceButton The input button that was changed.
|
||||||
|
* \param oldValue The old button state.
|
||||||
|
* \param newValue The new button state.
|
||||||
|
*/
|
||||||
|
void AddChange(DeviceId device, DeviceButtonId deviceButton, float oldValue, float newValue);
|
||||||
|
|
||||||
|
/// Clear list of state changes.
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
/// Notifies all input listeners of the previously recorded state changes.
|
||||||
|
/**
|
||||||
|
* \param listeners A list of input listeners to notify.
|
||||||
|
*/
|
||||||
|
void NotifyListeners(Array<InputListener*>& listeners) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Change
|
||||||
|
{
|
||||||
|
DeviceId device;
|
||||||
|
DeviceButtonId deviceButton;
|
||||||
|
ButtonType type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
float f;
|
||||||
|
} oldValue, newValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array<Change> changes_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
271
lib/include/gainput/GainputInputDevice.h
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICE_H_
|
||||||
|
#define GAINPUTINPUTDEVICE_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// Type of an input device button.
|
||||||
|
enum ButtonType
|
||||||
|
{
|
||||||
|
BT_BOOL, ///< A boolean value button, either down (true) or up (false).
|
||||||
|
BT_FLOAT, ///< A floating-point value button, between -1.0f and 1.0f or 0.0f and 1.0f.
|
||||||
|
BT_COUNT ///< The number of different button types.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Interface for anything that provides device inputs.
|
||||||
|
/**
|
||||||
|
* An InputDevice can be anything from a physical device, like a mouse or keyboard, to the more abstract
|
||||||
|
* concept of gestures that in turn themselves depend on other InputDevices. What they have in common is
|
||||||
|
* that they provide a number of device buttons (identified by a DeviceButtonId) which can be queried for
|
||||||
|
* their state.
|
||||||
|
*
|
||||||
|
* Note that you may not instantiate an InputDevice (or any derived implementation) directly. Instead you
|
||||||
|
* have to call InputManager::CreateDevice() or InputManager::CreateAndGetDevice() with the device you want
|
||||||
|
* to instantiate as the template parameter. That way the device will be properly registered with the
|
||||||
|
* InputManager and continuously updated.
|
||||||
|
*
|
||||||
|
* Normally, you won't interact with an InputDevice directly, but instead use its device ID and its device
|
||||||
|
* buttons' IDs to map the device buttons to user buttons (see InputMap).
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Type of an input device.
|
||||||
|
enum DeviceType
|
||||||
|
{
|
||||||
|
DT_MOUSE, ///< A mouse/cursor input device featuring one pointer.
|
||||||
|
DT_KEYBOARD, ///< A keyboard input device.
|
||||||
|
DT_PAD, ///< A joypad/gamepad input device.
|
||||||
|
DT_TOUCH, ///< A touch-sensitive input device supporting multiple simultaneous pointers.
|
||||||
|
DT_BUILTIN, ///< Any controls directly built into the device that also contains the screen.
|
||||||
|
DT_REMOTE, ///< A generic networked input device.
|
||||||
|
DT_GESTURE, ///< A gesture input device, building on top of other input devices.
|
||||||
|
DT_CUSTOM, ///< A custom, user-created input device.
|
||||||
|
DT_COUNT ///< The count of input device types.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Variant of an input device type.
|
||||||
|
enum DeviceVariant
|
||||||
|
{
|
||||||
|
DV_STANDARD, ///< The standard implementation of the given device type.
|
||||||
|
DV_RAW, ///< The raw input implementation of the given device type.
|
||||||
|
DV_NULL ///< The null/empty implementation of the given device type.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// State of an input device.
|
||||||
|
enum DeviceState
|
||||||
|
{
|
||||||
|
DS_OK, ///< Everything is okay.
|
||||||
|
DS_LOW_BATTERY, ///< The input device is low on battery.
|
||||||
|
DS_UNAVAILABLE ///< The input device is currently not available.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned AutoIndex = unsigned(-1);
|
||||||
|
|
||||||
|
/// Initializes the input device.
|
||||||
|
/**
|
||||||
|
* Do not instantiate any input device directly. Call InputManager::CreateDevice() instead.
|
||||||
|
*/
|
||||||
|
InputDevice(InputManager& manager, DeviceId device, unsigned index);
|
||||||
|
|
||||||
|
/// Empty virtual destructor.
|
||||||
|
virtual ~InputDevice();
|
||||||
|
|
||||||
|
/// Update this device, internally called by InputManager.
|
||||||
|
/**
|
||||||
|
* \param delta The delta state to add changes to. May be 0.
|
||||||
|
*/
|
||||||
|
void Update(InputDeltaState* delta);
|
||||||
|
|
||||||
|
/// Returns this device's ID.
|
||||||
|
DeviceId GetDeviceId() const { return deviceId_; }
|
||||||
|
/// Returns the device's index among devices of the same type.
|
||||||
|
unsigned GetIndex() const { return index_; }
|
||||||
|
|
||||||
|
/// Returns the device type.
|
||||||
|
virtual DeviceType GetType() const = 0;
|
||||||
|
/// Returns the device variant.
|
||||||
|
virtual DeviceVariant GetVariant() const { return DV_STANDARD; }
|
||||||
|
/// Returns the device type's name.
|
||||||
|
virtual const char* GetTypeName() const = 0;
|
||||||
|
/// Returns if this device should be updated after other devices.
|
||||||
|
virtual bool IsLateUpdate() const { return false; }
|
||||||
|
/// Returns the device state.
|
||||||
|
DeviceState GetState() const;
|
||||||
|
/// Returns if this device is available.
|
||||||
|
virtual bool IsAvailable() const { return GetState() == DS_OK || GetState() == DS_LOW_BATTERY; }
|
||||||
|
|
||||||
|
/// Returns if the given button is valid for this device.
|
||||||
|
virtual bool IsValidButtonId(DeviceButtonId deviceButton) const = 0;
|
||||||
|
|
||||||
|
/// Returns the current state of the given button.
|
||||||
|
bool GetBool(DeviceButtonId deviceButton) const;
|
||||||
|
/// Returns the previous state of the given button.
|
||||||
|
bool GetBoolPrevious(DeviceButtonId deviceButton) const;
|
||||||
|
/// Returns the current state of the given button.
|
||||||
|
float GetFloat(DeviceButtonId deviceButton) const;
|
||||||
|
/// Returns the previous state of the given button.
|
||||||
|
float GetFloatPrevious(DeviceButtonId deviceButton) const;
|
||||||
|
|
||||||
|
/// Checks if any button on this device is down.
|
||||||
|
/**
|
||||||
|
* \param[out] outButtons An array with maxButtonCount fields to receive the device buttons that are down.
|
||||||
|
* \param maxButtonCount The number of fields in outButtons.
|
||||||
|
* \return The number of device buttons written to outButtons.
|
||||||
|
*/
|
||||||
|
virtual size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const { GAINPUT_UNUSED(outButtons); GAINPUT_UNUSED(maxButtonCount); return 0; }
|
||||||
|
|
||||||
|
/// Gets the name of the given button.
|
||||||
|
/**
|
||||||
|
* \param deviceButton ID of the button.
|
||||||
|
* \param buffer A char-buffer to receive the button name.
|
||||||
|
* \param bufferLength Length of the buffer receiving the button name in bytes.
|
||||||
|
* \return The number of bytes written to buffer (includes the trailing \0).
|
||||||
|
*/
|
||||||
|
virtual size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const { GAINPUT_UNUSED(deviceButton); GAINPUT_UNUSED(buffer); GAINPUT_UNUSED(bufferLength); return 0; }
|
||||||
|
/// Returns the type of the given button.
|
||||||
|
virtual ButtonType GetButtonType(DeviceButtonId deviceButton) const = 0;
|
||||||
|
|
||||||
|
/// Returns the button's ID if the name is of this device's buttons.
|
||||||
|
/**
|
||||||
|
* \param name Name of the device button to look for.
|
||||||
|
* \return The device button ID.
|
||||||
|
*/
|
||||||
|
virtual DeviceButtonId GetButtonByName(const char* name) const { GAINPUT_UNUSED(name); return InvalidDeviceButtonId; }
|
||||||
|
|
||||||
|
/// Returns the device's state, probably best if only used internally.
|
||||||
|
InputState* GetInputState() { return state_; }
|
||||||
|
/// Returns the device's state, probably best if only used internally.
|
||||||
|
const InputState* GetInputState() const { return state_; }
|
||||||
|
/// Returns the device's previous state, probably best if only used internally.
|
||||||
|
InputState* GetPreviousInputState() { return previousState_; }
|
||||||
|
/// Returns the device's state that is currently being determined, may be 0 if not available.
|
||||||
|
virtual InputState* GetNextInputState() { return 0; }
|
||||||
|
|
||||||
|
/// Returns the previously set dead zone for the given button or 0.0f if none was set yet.
|
||||||
|
float GetDeadZone(DeviceButtonId buttonId) const;
|
||||||
|
/// Sets the dead zone for the given button.
|
||||||
|
void SetDeadZone(DeviceButtonId buttonId, float value);
|
||||||
|
|
||||||
|
/// Enable/disable debug rendering of this device.
|
||||||
|
void SetDebugRenderingEnabled(bool enabled);
|
||||||
|
/// Returns true if debug rendering is enabled, false otherwise.
|
||||||
|
bool IsDebugRenderingEnabled() const { return debugRenderingEnabled_; }
|
||||||
|
|
||||||
|
#if defined(GAINPUT_DEV) || defined(GAINPUT_ENABLE_RECORDER)
|
||||||
|
/// Returns true if this device is being controlled by a remote device
|
||||||
|
/// or a recorded input sequence, false otherwise.
|
||||||
|
bool IsSynced() const { return synced_; }
|
||||||
|
/// Sets if this device is being controlled remotely or from a recording.
|
||||||
|
/**
|
||||||
|
* \sa IsSynced()
|
||||||
|
*/
|
||||||
|
void SetSynced(bool synced) { synced_ = synced; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// The manager this device belongs to.
|
||||||
|
InputManager& manager_;
|
||||||
|
|
||||||
|
/// The ID of this device.
|
||||||
|
DeviceId deviceId_;
|
||||||
|
|
||||||
|
/// Index of this device among devices of the same type.
|
||||||
|
unsigned index_;
|
||||||
|
|
||||||
|
/// The current state of this device.
|
||||||
|
InputState* state_;
|
||||||
|
/// The previous state of this device.
|
||||||
|
InputState* previousState_;
|
||||||
|
|
||||||
|
float* deadZones_;
|
||||||
|
|
||||||
|
/// Specifies if this device is currently rendering debug information.
|
||||||
|
bool debugRenderingEnabled_;
|
||||||
|
|
||||||
|
#if defined(GAINPUT_DEV) || defined(GAINPUT_ENABLE_RECORDER)
|
||||||
|
/// Specifies if this device's state is actually set from a device
|
||||||
|
/// or manually set by some other system.
|
||||||
|
bool synced_;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Implementation of the device's Update function.
|
||||||
|
/**
|
||||||
|
* \param delta The delta state to add changes to. May be 0.
|
||||||
|
*/
|
||||||
|
virtual void InternalUpdate(InputDeltaState* delta) = 0;
|
||||||
|
|
||||||
|
/// Implementation of the device's GetState function.
|
||||||
|
/**
|
||||||
|
* \return The device's state.
|
||||||
|
*/
|
||||||
|
virtual DeviceState InternalGetState() const = 0;
|
||||||
|
|
||||||
|
/// Checks which buttons are down.
|
||||||
|
/**
|
||||||
|
* This function is normally used by GetAnyButtonDown implementations internally.
|
||||||
|
* \param outButtons An array to write buttons that are down to.
|
||||||
|
* \param maxButtonCount The size of outButtons.
|
||||||
|
* \param start The lowest device button ID to check.
|
||||||
|
* \param end The biggest device button ID to check.
|
||||||
|
* \return The number of buttons written to outButtons.
|
||||||
|
*/
|
||||||
|
size_t CheckAllButtonsDown(DeviceButtonSpec* outButtons, size_t maxButtonCount, unsigned start, unsigned end) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
InputDevice::GetBool(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
if (!IsAvailable())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
return state_->GetBool(deviceButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
InputDevice::GetBoolPrevious(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
if (!IsAvailable())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
return previousState_->GetBool(deviceButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
float
|
||||||
|
InputDevice::GetFloat(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
if (!IsAvailable())
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
return state_->GetFloat(deviceButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
float
|
||||||
|
InputDevice::GetFloatPrevious(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
if (!IsAvailable())
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
return previousState_->GetFloat(deviceButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
68
lib/include/gainput/GainputInputDeviceBuiltIn.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEBUILTIN_H_
|
||||||
|
#define GAINPUTINPUTDEVICEBUILTIN_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// All valid device buttons for InputDeviceBuiltIn.
|
||||||
|
enum BuiltInButton
|
||||||
|
{
|
||||||
|
BuiltInButtonAccelerationX,
|
||||||
|
BuiltInButtonAccelerationY,
|
||||||
|
BuiltInButtonAccelerationZ,
|
||||||
|
BuiltInButtonGravityX,
|
||||||
|
BuiltInButtonGravityY,
|
||||||
|
BuiltInButtonGravityZ,
|
||||||
|
BuiltInButtonGyroscopeX,
|
||||||
|
BuiltInButtonGyroscopeY,
|
||||||
|
BuiltInButtonGyroscopeZ,
|
||||||
|
BuiltInButtonMagneticFieldX,
|
||||||
|
BuiltInButtonMagneticFieldY,
|
||||||
|
BuiltInButtonMagneticFieldZ,
|
||||||
|
BuiltInButtonCount_
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputDeviceBuiltInImpl;
|
||||||
|
|
||||||
|
/// An input device for inputs that are directly built into the executing device (for example, sensors in a phone).
|
||||||
|
class GAINPUT_LIBEXPORT InputDeviceBuiltIn : public InputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the device.
|
||||||
|
/**
|
||||||
|
* Instantiate the device using InputManager::CreateDevice().
|
||||||
|
*
|
||||||
|
* \param manager The input manager this device is managed by.
|
||||||
|
* \param device The ID of this device.
|
||||||
|
*/
|
||||||
|
InputDeviceBuiltIn(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Shuts down the device.
|
||||||
|
~InputDeviceBuiltIn();
|
||||||
|
|
||||||
|
/// Returns DT_BUILTIN.
|
||||||
|
DeviceType GetType() const { return DT_BUILTIN; }
|
||||||
|
DeviceVariant GetVariant() const;
|
||||||
|
const char* GetTypeName() const { return "builtin"; }
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const;
|
||||||
|
|
||||||
|
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
|
||||||
|
|
||||||
|
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
|
||||||
|
DeviceButtonId GetButtonByName(const char* name) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
DeviceState InternalGetState() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputDeviceBuiltInImpl* impl_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
267
lib/include/gainput/GainputInputDeviceKeyboard.h
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEKEYBOARD_H_
|
||||||
|
#define GAINPUTINPUTDEVICEKEYBOARD_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// All valid device buttons for InputDeviceKeyboard.
|
||||||
|
enum Key
|
||||||
|
{
|
||||||
|
KeyEscape,
|
||||||
|
KeyF1,
|
||||||
|
KeyF2,
|
||||||
|
KeyF3,
|
||||||
|
KeyF4,
|
||||||
|
KeyF5,
|
||||||
|
KeyF6,
|
||||||
|
KeyF7,
|
||||||
|
KeyF8,
|
||||||
|
KeyF9,
|
||||||
|
KeyF10,
|
||||||
|
KeyF11,
|
||||||
|
KeyF12,
|
||||||
|
KeyF13,
|
||||||
|
KeyF14,
|
||||||
|
KeyF15,
|
||||||
|
KeyF16,
|
||||||
|
KeyF17,
|
||||||
|
KeyF18,
|
||||||
|
KeyF19,
|
||||||
|
KeyPrint,
|
||||||
|
KeyScrollLock,
|
||||||
|
KeyBreak,
|
||||||
|
|
||||||
|
KeySpace = 0x0020,
|
||||||
|
|
||||||
|
KeyApostrophe = 0x0027,
|
||||||
|
KeyComma = 0x002c,
|
||||||
|
KeyMinus = 0x002d,
|
||||||
|
KeyPeriod = 0x002e,
|
||||||
|
KeySlash = 0x002f,
|
||||||
|
|
||||||
|
Key0 = 0x0030,
|
||||||
|
Key1 = 0x0031,
|
||||||
|
Key2 = 0x0032,
|
||||||
|
Key3 = 0x0033,
|
||||||
|
Key4 = 0x0034,
|
||||||
|
Key5 = 0x0035,
|
||||||
|
Key6 = 0x0036,
|
||||||
|
Key7 = 0x0037,
|
||||||
|
Key8 = 0x0038,
|
||||||
|
Key9 = 0x0039,
|
||||||
|
|
||||||
|
KeySemicolon = 0x003b,
|
||||||
|
KeyLess = 0x003c,
|
||||||
|
KeyEqual = 0x003d,
|
||||||
|
|
||||||
|
KeyA = 0x0041,
|
||||||
|
KeyB = 0x0042,
|
||||||
|
KeyC = 0x0043,
|
||||||
|
KeyD = 0x0044,
|
||||||
|
KeyE = 0x0045,
|
||||||
|
KeyF = 0x0046,
|
||||||
|
KeyG = 0x0047,
|
||||||
|
KeyH = 0x0048,
|
||||||
|
KeyI = 0x0049,
|
||||||
|
KeyJ = 0x004a,
|
||||||
|
KeyK = 0x004b,
|
||||||
|
KeyL = 0x004c,
|
||||||
|
KeyM = 0x004d,
|
||||||
|
KeyN = 0x004e,
|
||||||
|
KeyO = 0x004f,
|
||||||
|
KeyP = 0x0050,
|
||||||
|
KeyQ = 0x0051,
|
||||||
|
KeyR = 0x0052,
|
||||||
|
KeyS = 0x0053,
|
||||||
|
KeyT = 0x0054,
|
||||||
|
KeyU = 0x0055,
|
||||||
|
KeyV = 0x0056,
|
||||||
|
KeyW = 0x0057,
|
||||||
|
KeyX = 0x0058,
|
||||||
|
KeyY = 0x0059,
|
||||||
|
KeyZ = 0x005a,
|
||||||
|
|
||||||
|
KeyBracketLeft = 0x005b,
|
||||||
|
KeyBackslash = 0x005c,
|
||||||
|
KeyBracketRight = 0x005d,
|
||||||
|
|
||||||
|
KeyGrave = 0x0060,
|
||||||
|
|
||||||
|
KeyLeft,
|
||||||
|
KeyRight,
|
||||||
|
KeyUp,
|
||||||
|
KeyDown,
|
||||||
|
KeyInsert,
|
||||||
|
KeyHome,
|
||||||
|
KeyDelete,
|
||||||
|
KeyEnd,
|
||||||
|
KeyPageUp,
|
||||||
|
KeyPageDown,
|
||||||
|
|
||||||
|
KeyNumLock,
|
||||||
|
KeyKpEqual,
|
||||||
|
KeyKpDivide,
|
||||||
|
KeyKpMultiply,
|
||||||
|
KeyKpSubtract,
|
||||||
|
KeyKpAdd,
|
||||||
|
KeyKpEnter,
|
||||||
|
KeyKpInsert, // 0
|
||||||
|
KeyKpEnd, // 1
|
||||||
|
KeyKpDown, // 2
|
||||||
|
KeyKpPageDown, // 3
|
||||||
|
KeyKpLeft, // 4
|
||||||
|
KeyKpBegin, // 5
|
||||||
|
KeyKpRight, // 6
|
||||||
|
KeyKpHome, // 7
|
||||||
|
KeyKpUp, // 8
|
||||||
|
KeyKpPageUp, // 9
|
||||||
|
KeyKpDelete, // ,
|
||||||
|
|
||||||
|
KeyBackSpace,
|
||||||
|
KeyTab,
|
||||||
|
KeyReturn,
|
||||||
|
KeyCapsLock,
|
||||||
|
KeyShiftL,
|
||||||
|
KeyCtrlL,
|
||||||
|
KeySuperL,
|
||||||
|
KeyAltL,
|
||||||
|
KeyAltR,
|
||||||
|
KeySuperR,
|
||||||
|
KeyMenu,
|
||||||
|
KeyCtrlR,
|
||||||
|
KeyShiftR,
|
||||||
|
|
||||||
|
KeyBack,
|
||||||
|
KeySoftLeft,
|
||||||
|
KeySoftRight,
|
||||||
|
KeyCall,
|
||||||
|
KeyEndcall,
|
||||||
|
KeyStar,
|
||||||
|
KeyPound,
|
||||||
|
KeyDpadCenter,
|
||||||
|
KeyVolumeUp,
|
||||||
|
KeyVolumeDown,
|
||||||
|
KeyPower,
|
||||||
|
KeyCamera,
|
||||||
|
KeyClear,
|
||||||
|
KeySymbol,
|
||||||
|
KeyExplorer,
|
||||||
|
KeyEnvelope,
|
||||||
|
KeyEquals,
|
||||||
|
KeyAt,
|
||||||
|
KeyHeadsethook,
|
||||||
|
KeyFocus,
|
||||||
|
KeyPlus,
|
||||||
|
KeyNotification,
|
||||||
|
KeySearch,
|
||||||
|
KeyMediaPlayPause,
|
||||||
|
KeyMediaStop,
|
||||||
|
KeyMediaNext,
|
||||||
|
KeyMediaPrevious,
|
||||||
|
KeyMediaRewind,
|
||||||
|
KeyMediaFastForward,
|
||||||
|
KeyMute,
|
||||||
|
KeyPictsymbols,
|
||||||
|
KeySwitchCharset,
|
||||||
|
|
||||||
|
KeyForward,
|
||||||
|
KeyExtra1,
|
||||||
|
KeyExtra2,
|
||||||
|
KeyExtra3,
|
||||||
|
KeyExtra4,
|
||||||
|
KeyExtra5,
|
||||||
|
KeyExtra6,
|
||||||
|
KeyFn,
|
||||||
|
|
||||||
|
KeyCircumflex,
|
||||||
|
KeySsharp,
|
||||||
|
KeyAcute,
|
||||||
|
KeyAltGr,
|
||||||
|
KeyNumbersign,
|
||||||
|
KeyUdiaeresis,
|
||||||
|
KeyAdiaeresis,
|
||||||
|
KeyOdiaeresis,
|
||||||
|
KeySection,
|
||||||
|
KeyAring,
|
||||||
|
KeyDiaeresis,
|
||||||
|
KeyTwosuperior,
|
||||||
|
KeyRightParenthesis,
|
||||||
|
KeyDollar,
|
||||||
|
KeyUgrave,
|
||||||
|
KeyAsterisk,
|
||||||
|
KeyColon,
|
||||||
|
KeyExclam,
|
||||||
|
|
||||||
|
KeyBraceLeft,
|
||||||
|
KeyBraceRight,
|
||||||
|
KeySysRq,
|
||||||
|
|
||||||
|
KeyCount_
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class InputDeviceKeyboardImpl;
|
||||||
|
|
||||||
|
/// A keyboard input device.
|
||||||
|
/**
|
||||||
|
* This input device provides support for standard keyboard devices. The valid device buttons are defined
|
||||||
|
* in the ::Key enum.
|
||||||
|
*
|
||||||
|
* This device is implemented on Android NDK, Linux, and Windows. Note that no support for
|
||||||
|
* virtual keyboards (on-screen) is present.
|
||||||
|
*
|
||||||
|
* The raw variants (InputDevice::DV_RAW) of this device do not support text input.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputDeviceKeyboard : public InputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the device.
|
||||||
|
/**
|
||||||
|
* Instantiate the device using InputManager::CreateDevice().
|
||||||
|
*
|
||||||
|
* \param manager The input manager this device is managed by.
|
||||||
|
* \param device The ID of this device.
|
||||||
|
*/
|
||||||
|
InputDeviceKeyboard(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Shuts down the device.
|
||||||
|
~InputDeviceKeyboard();
|
||||||
|
|
||||||
|
/// Returns DT_KEYBOARD.
|
||||||
|
DeviceType GetType() const { return DT_KEYBOARD; }
|
||||||
|
DeviceVariant GetVariant() const;
|
||||||
|
const char* GetTypeName() const { return "keyboard"; }
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton < KeyCount_; }
|
||||||
|
|
||||||
|
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
|
||||||
|
|
||||||
|
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
|
||||||
|
DeviceButtonId GetButtonByName(const char* name) const;
|
||||||
|
|
||||||
|
InputState* GetNextInputState();
|
||||||
|
|
||||||
|
/// Returns if text input is enabled.
|
||||||
|
bool IsTextInputEnabled() const;
|
||||||
|
/// Sets if text input is enabled and therefore if calling GetNextCharacter() make sense.
|
||||||
|
void SetTextInputEnabled(bool enabled);
|
||||||
|
/// Returns the next pending input character if text input is enabled.
|
||||||
|
char GetNextCharacter();
|
||||||
|
|
||||||
|
/// Returns the platform-specific implementation of this device (internal use only).
|
||||||
|
InputDeviceKeyboardImpl* GetPimpl() { return impl_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
DeviceState InternalGetState() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputDeviceKeyboardImpl* impl_;
|
||||||
|
|
||||||
|
HashMap<Key, const char*> keyNames_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
101
lib/include/gainput/GainputInputDeviceMouse.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEMOUSE_H_
|
||||||
|
#define GAINPUTINPUTDEVICEMOUSE_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// All valid device buttons for InputDeviceMouse.
|
||||||
|
enum MouseButton
|
||||||
|
{
|
||||||
|
MouseButton0 = 0,
|
||||||
|
MouseButtonLeft = MouseButton0,
|
||||||
|
MouseButton1,
|
||||||
|
MouseButtonMiddle = MouseButton1,
|
||||||
|
MouseButton2,
|
||||||
|
MouseButtonRight = MouseButton2,
|
||||||
|
MouseButton3,
|
||||||
|
MouseButtonWheelUp = MouseButton3,
|
||||||
|
MouseButton4,
|
||||||
|
MouseButtonWheelDown = MouseButton4,
|
||||||
|
MouseButton5,
|
||||||
|
MouseButton6,
|
||||||
|
MouseButton7,
|
||||||
|
MouseButton8,
|
||||||
|
MouseButton9,
|
||||||
|
MouseButton10,
|
||||||
|
MouseButton11,
|
||||||
|
MouseButton12,
|
||||||
|
MouseButton13,
|
||||||
|
MouseButton14,
|
||||||
|
MouseButton15,
|
||||||
|
MouseButton16,
|
||||||
|
MouseButton17,
|
||||||
|
MouseButton18,
|
||||||
|
MouseButton19,
|
||||||
|
MouseButton20,
|
||||||
|
MouseButtonMax = MouseButton20,
|
||||||
|
MouseButtonCount,
|
||||||
|
MouseAxisX = MouseButtonCount,
|
||||||
|
MouseAxisY,
|
||||||
|
MouseButtonCount_,
|
||||||
|
MouseAxisCount = MouseButtonCount_ - MouseAxisX
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class InputDeviceMouseImpl;
|
||||||
|
|
||||||
|
/// A mouse input device.
|
||||||
|
/**
|
||||||
|
* This input device provides support for standard mouse devices. The valid device buttons are defined
|
||||||
|
* in the ::MouseButton enum.
|
||||||
|
*
|
||||||
|
* This device is implemented on Linux and Windows.
|
||||||
|
*
|
||||||
|
* The raw variants (InputDevice::DV_RAW) of this device do not offer normalized absolute axis values.
|
||||||
|
* That means that the values of MouseAxisX and MouseAxisY don't have defined mininum or maximum
|
||||||
|
* values. Therefore only the delta (InputMap::GetFloatDelta()) should be used with raw mouse devices.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputDeviceMouse : public InputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the device.
|
||||||
|
/**
|
||||||
|
* Instantiate the device using InputManager::CreateDevice().
|
||||||
|
*
|
||||||
|
* \param manager The input manager this device is managed by.
|
||||||
|
* \param device The ID of this device.
|
||||||
|
*/
|
||||||
|
InputDeviceMouse(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Shuts down the device.
|
||||||
|
~InputDeviceMouse();
|
||||||
|
|
||||||
|
/// Returns DT_MOUSE.
|
||||||
|
DeviceType GetType() const { return DT_MOUSE; }
|
||||||
|
DeviceVariant GetVariant() const;
|
||||||
|
const char* GetTypeName() const { return "mouse"; }
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton < MouseButtonCount_; }
|
||||||
|
|
||||||
|
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
|
||||||
|
|
||||||
|
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
|
||||||
|
DeviceButtonId GetButtonByName(const char* name) const;
|
||||||
|
|
||||||
|
/// Returns the platform-specific implementation of this device (internal use only).
|
||||||
|
InputDeviceMouseImpl* GetPimpl() { return impl_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
DeviceState InternalGetState() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputDeviceMouseImpl* impl_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
163
lib/include/gainput/GainputInputDevicePad.h
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEPAD_H_
|
||||||
|
#define GAINPUTINPUTDEVICEPAD_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// The maximum number of pads supported.
|
||||||
|
enum { MaxPadCount = 10 };
|
||||||
|
|
||||||
|
/// All valid device buttons for InputDevicePad.
|
||||||
|
enum PadButton
|
||||||
|
{
|
||||||
|
PadButtonLeftStickX,
|
||||||
|
PadButtonLeftStickY,
|
||||||
|
PadButtonRightStickX,
|
||||||
|
PadButtonRightStickY,
|
||||||
|
PadButtonAxis4, // L2/Left trigger
|
||||||
|
PadButtonAxis5, // R2/Right trigger
|
||||||
|
PadButtonAxis6,
|
||||||
|
PadButtonAxis7,
|
||||||
|
PadButtonAxis8,
|
||||||
|
PadButtonAxis9,
|
||||||
|
PadButtonAxis10,
|
||||||
|
PadButtonAxis11,
|
||||||
|
PadButtonAxis12,
|
||||||
|
PadButtonAxis13,
|
||||||
|
PadButtonAxis14,
|
||||||
|
PadButtonAxis15,
|
||||||
|
PadButtonAxis16,
|
||||||
|
PadButtonAxis17,
|
||||||
|
PadButtonAxis18,
|
||||||
|
PadButtonAxis19,
|
||||||
|
PadButtonAxis20,
|
||||||
|
PadButtonAxis21,
|
||||||
|
PadButtonAxis22,
|
||||||
|
PadButtonAxis23,
|
||||||
|
PadButtonAxis24,
|
||||||
|
PadButtonAxis25,
|
||||||
|
PadButtonAxis26,
|
||||||
|
PadButtonAxis27,
|
||||||
|
PadButtonAxis28,
|
||||||
|
PadButtonAxis29,
|
||||||
|
PadButtonAxis30,
|
||||||
|
PadButtonAxis31,
|
||||||
|
PadButtonAccelerationX,
|
||||||
|
PadButtonAccelerationY,
|
||||||
|
PadButtonAccelerationZ,
|
||||||
|
PadButtonGravityX,
|
||||||
|
PadButtonGravityY,
|
||||||
|
PadButtonGravityZ,
|
||||||
|
PadButtonGyroscopeX,
|
||||||
|
PadButtonGyroscopeY,
|
||||||
|
PadButtonGyroscopeZ,
|
||||||
|
PadButtonMagneticFieldX,
|
||||||
|
PadButtonMagneticFieldY,
|
||||||
|
PadButtonMagneticFieldZ,
|
||||||
|
PadButtonStart,
|
||||||
|
PadButtonAxisCount_ = PadButtonStart,
|
||||||
|
PadButtonSelect,
|
||||||
|
PadButtonLeft,
|
||||||
|
PadButtonRight,
|
||||||
|
PadButtonUp,
|
||||||
|
PadButtonDown,
|
||||||
|
PadButtonA, // Cross
|
||||||
|
PadButtonB, // Circle
|
||||||
|
PadButtonX, // Square
|
||||||
|
PadButtonY, // Triangle
|
||||||
|
PadButtonL1,
|
||||||
|
PadButtonR1,
|
||||||
|
PadButtonL2,
|
||||||
|
PadButtonR2,
|
||||||
|
PadButtonL3, // Left thumb
|
||||||
|
PadButtonR3, // Right thumb
|
||||||
|
PadButtonHome, // PS button
|
||||||
|
PadButton17,
|
||||||
|
PadButton18,
|
||||||
|
PadButton19,
|
||||||
|
PadButton20,
|
||||||
|
PadButton21,
|
||||||
|
PadButton22,
|
||||||
|
PadButton23,
|
||||||
|
PadButton24,
|
||||||
|
PadButton25,
|
||||||
|
PadButton26,
|
||||||
|
PadButton27,
|
||||||
|
PadButton28,
|
||||||
|
PadButton29,
|
||||||
|
PadButton30,
|
||||||
|
PadButton31,
|
||||||
|
PadButtonMax_,
|
||||||
|
PadButtonCount_ = PadButtonMax_ - PadButtonAxisCount_
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputDevicePadImpl;
|
||||||
|
|
||||||
|
/// A pad input device.
|
||||||
|
/**
|
||||||
|
* This input device provides support for gamepad devices. The valid device buttons are defined
|
||||||
|
* in the ::PadButton enum.
|
||||||
|
*
|
||||||
|
* This device is implemented on Android NDK, Linux and Windows.
|
||||||
|
*
|
||||||
|
* Note that the Android implementation does not support any external pads, but only internal
|
||||||
|
* sensors (acceleration, gyroscope, magnetic field).
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputDevicePad : public InputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// The operating system device IDs for all possible pads.
|
||||||
|
static const char* PadDeviceIds[MaxPadCount];
|
||||||
|
// TODO SetPadDeviceId(padIndex, const char* id);
|
||||||
|
|
||||||
|
/// Initializes the device.
|
||||||
|
/**
|
||||||
|
* Instantiate the device using InputManager::CreateDevice().
|
||||||
|
*
|
||||||
|
* \param manager The input manager this device is managed by.
|
||||||
|
* \param device The ID of this device.
|
||||||
|
*/
|
||||||
|
InputDevicePad(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Shuts down the device.
|
||||||
|
~InputDevicePad();
|
||||||
|
|
||||||
|
/// Returns DT_PAD.
|
||||||
|
DeviceType GetType() const { return DT_PAD; }
|
||||||
|
DeviceVariant GetVariant() const;
|
||||||
|
const char* GetTypeName() const { return "pad"; }
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const;
|
||||||
|
|
||||||
|
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
|
||||||
|
|
||||||
|
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
|
||||||
|
DeviceButtonId GetButtonByName(const char* name) const;
|
||||||
|
|
||||||
|
InputState* GetNextInputState();
|
||||||
|
|
||||||
|
/// Enables the rumble feature of the pad.
|
||||||
|
/**
|
||||||
|
* \param leftMotor Speed of the left motor, between 0.0 and 1.0.
|
||||||
|
* \param rightMotor Speed of the right motor, between 0.0 and 1.0.
|
||||||
|
* \return true if rumble was enabled successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
bool Vibrate(float leftMotor, float rightMotor);
|
||||||
|
|
||||||
|
/// Returns the platform-specific implementation of this device.
|
||||||
|
InputDevicePadImpl* GetPimpl() { return impl_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
DeviceState InternalGetState() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputDevicePadImpl* impl_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
107
lib/include/gainput/GainputInputDeviceTouch.h
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICETOUCH_H_
|
||||||
|
#define GAINPUTINPUTDEVICETOUCH_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// All valid device inputs for InputDeviceTouch.
|
||||||
|
enum TouchButton
|
||||||
|
{
|
||||||
|
Touch0Down,
|
||||||
|
Touch0X,
|
||||||
|
Touch0Y,
|
||||||
|
Touch0Pressure,
|
||||||
|
Touch1Down,
|
||||||
|
Touch1X,
|
||||||
|
Touch1Y,
|
||||||
|
Touch1Pressure,
|
||||||
|
Touch2Down,
|
||||||
|
Touch2X,
|
||||||
|
Touch2Y,
|
||||||
|
Touch2Pressure,
|
||||||
|
Touch3Down,
|
||||||
|
Touch3X,
|
||||||
|
Touch3Y,
|
||||||
|
Touch3Pressure,
|
||||||
|
Touch4Down,
|
||||||
|
Touch4X,
|
||||||
|
Touch4Y,
|
||||||
|
Touch4Pressure,
|
||||||
|
Touch5Down,
|
||||||
|
Touch5X,
|
||||||
|
Touch5Y,
|
||||||
|
Touch5Pressure,
|
||||||
|
Touch6Down,
|
||||||
|
Touch6X,
|
||||||
|
Touch6Y,
|
||||||
|
Touch6Pressure,
|
||||||
|
Touch7Down,
|
||||||
|
Touch7X,
|
||||||
|
Touch7Y,
|
||||||
|
Touch7Pressure,
|
||||||
|
TouchCount_
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class InputDeviceTouchImpl;
|
||||||
|
|
||||||
|
/// A touch input device.
|
||||||
|
/**
|
||||||
|
* This input device provides support for touch screen/surface devices. The valid device buttons are defined
|
||||||
|
* in the ::TouchButton enum. For each touch point, there is a boolean input (Touch*Down) showing if the
|
||||||
|
* touch point is active, two float inputs (Touch*X, Touch*Y) showing the touch point's position, and a
|
||||||
|
* float input (Touch*Pressure) showing the touch's pressure.
|
||||||
|
*
|
||||||
|
* Not all touch points must be numbered consecutively, i.e. point #2 may be down even though #0 and #1 are not.
|
||||||
|
*
|
||||||
|
* The number of simultaneously possible touch points is implementaion-dependent.
|
||||||
|
*
|
||||||
|
* This device is implemented on Android NDK.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputDeviceTouch : public InputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the device.
|
||||||
|
/**
|
||||||
|
* Instantiate the device using InputManager::CreateDevice().
|
||||||
|
*
|
||||||
|
* \param manager The input manager this device is managed by.
|
||||||
|
* \param device The ID of this device.
|
||||||
|
*/
|
||||||
|
InputDeviceTouch(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Shuts down the device.
|
||||||
|
~InputDeviceTouch();
|
||||||
|
|
||||||
|
/// Returns DT_TOUCH.
|
||||||
|
DeviceType GetType() const { return DT_TOUCH; }
|
||||||
|
DeviceVariant GetVariant() const;
|
||||||
|
const char* GetTypeName() const { return "touch"; }
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const;
|
||||||
|
|
||||||
|
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
|
||||||
|
|
||||||
|
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
|
||||||
|
DeviceButtonId GetButtonByName(const char* name) const;
|
||||||
|
|
||||||
|
InputState* GetNextInputState();
|
||||||
|
|
||||||
|
/// Returns the platform-specific implementation of this device.
|
||||||
|
InputDeviceTouchImpl* GetPimpl() { return impl_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
DeviceState InternalGetState() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputDeviceTouchImpl* impl_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
77
lib/include/gainput/GainputInputListener.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTLISTENER_H_
|
||||||
|
#define GAINPUTINPUTLISTENER_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Listener interface that allows to receive notifications when device button states change.
|
||||||
|
class GAINPUT_LIBEXPORT InputListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~InputListener() { }
|
||||||
|
|
||||||
|
/// Called when a bool-type button state changes.
|
||||||
|
/**
|
||||||
|
* \param device The input device's ID the state change occurred on.
|
||||||
|
* \param deviceButton The ID of the device button that changed.
|
||||||
|
* \param oldValue Previous state of the button.
|
||||||
|
* \param newValue New state of the button.
|
||||||
|
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool OnDeviceButtonBool(DeviceId device, DeviceButtonId deviceButton, bool oldValue, bool newValue) { GAINPUT_UNUSED(device); GAINPUT_UNUSED(deviceButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
|
||||||
|
|
||||||
|
/// Called when a float-type button state changes.
|
||||||
|
/**
|
||||||
|
* \param device The input device's ID the state change occurred on.
|
||||||
|
* \param deviceButton The ID of the device button that changed.
|
||||||
|
* \param oldValue Previous state of the button.
|
||||||
|
* \param newValue New state of the button.
|
||||||
|
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool OnDeviceButtonFloat(DeviceId device, DeviceButtonId deviceButton, float oldValue, float newValue) { GAINPUT_UNUSED(device); GAINPUT_UNUSED(deviceButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
|
||||||
|
|
||||||
|
/// Returns the priority which influences the order in which listeners are called by InputManager.
|
||||||
|
/**
|
||||||
|
* \sa InputManager::ReorderListeners()
|
||||||
|
*/
|
||||||
|
virtual int GetPriority() const { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Listener interface that allows to receive notifications when user button states change.
|
||||||
|
class GAINPUT_LIBEXPORT MappedInputListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MappedInputListener() { }
|
||||||
|
|
||||||
|
/// Called when a bool-type button state changes.
|
||||||
|
/**
|
||||||
|
* \param userButton The user button's ID.
|
||||||
|
* \param oldValue Previous state of the button.
|
||||||
|
* \param newValue New state of the button.
|
||||||
|
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool OnUserButtonBool(UserButtonId userButton, bool oldValue, bool newValue) { GAINPUT_UNUSED(userButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
|
||||||
|
|
||||||
|
/// Called when a float-type button state changes.
|
||||||
|
/**
|
||||||
|
* \param userButton The user button's ID.
|
||||||
|
* \param oldValue Previous state of the button.
|
||||||
|
* \param newValue New state of the button.
|
||||||
|
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool OnUserButtonFloat(UserButtonId userButton, float oldValue, float newValue) { GAINPUT_UNUSED(userButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
|
||||||
|
|
||||||
|
/// Returns the priority which influences the order in which listeners are called by InputMap.
|
||||||
|
/**
|
||||||
|
* \sa InputMap::ReorderListeners()
|
||||||
|
*/
|
||||||
|
virtual int GetPriority() const { return 0; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
331
lib/include/gainput/GainputInputManager.h
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTMANAGER_H_
|
||||||
|
#define GAINPUTINPUTMANAGER_H_
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Manages all input devices and some other helpful stuff.
|
||||||
|
/**
|
||||||
|
* This manager takes care of all device-related things. Normally, you should only need one that contains
|
||||||
|
* all your input devices.
|
||||||
|
*
|
||||||
|
* After instantiating an InputManager, you have to call SetDisplaySize(). You should also create some
|
||||||
|
* input devices using the template function CreateDevice() which returns the device ID that is needed
|
||||||
|
* to do anything further with the device (for example, see InputMap).
|
||||||
|
*
|
||||||
|
* The manager has to be updated every frame by calling Update(). Depending on the platform,
|
||||||
|
* you may have to call another function as part of your message handling code (see HandleMessage(), HandleInput()).
|
||||||
|
*
|
||||||
|
* Note that destruction of an InputManager invalidates all input maps based on it and all devices created
|
||||||
|
* through it.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the manager.
|
||||||
|
/**
|
||||||
|
* Further initialization is typically necessary.
|
||||||
|
* \param useSystemTime Specifies if the GetTime() function uses system time or the time
|
||||||
|
* supplied to Update(uint64_t).
|
||||||
|
* \param allocator The memory allocator to be used for all allocations.
|
||||||
|
* \see SetDisplaySize
|
||||||
|
* \see GetTime
|
||||||
|
*/
|
||||||
|
InputManager(bool useSystemTime = true, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
|
||||||
|
/// Destructs the manager.
|
||||||
|
~InputManager();
|
||||||
|
|
||||||
|
/// Sets the window resolution.
|
||||||
|
/**
|
||||||
|
* Informs the InputManager and its devices of the size of the window that is used for
|
||||||
|
* receiving inputs. For example, the size is used to to normalize mouse inputs.
|
||||||
|
*/
|
||||||
|
void SetDisplaySize(int width, int height) { displayWidth_ = width; displayHeight_ = height; }
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||||
|
/// [LINUX ONLY] Lets the InputManager handle the given X event.
|
||||||
|
/**
|
||||||
|
* Call this function for event types MotionNotify, ButtonPress,
|
||||||
|
* ButtonRelease, KeyPress, KeyRelease.
|
||||||
|
*/
|
||||||
|
void HandleEvent(XEvent& event);
|
||||||
|
#endif
|
||||||
|
#if defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
/// [WINDOWS ONLY] Lets the InputManager handle the given Windows message.
|
||||||
|
/**
|
||||||
|
* Call this function for message types WM_CHAR, WM_KEYDOWN, WM_KEYUP,
|
||||||
|
* WM_SYSKEYDOWN, WM_SYSKEYUP, WM_?BUTTON*, WM_MOUSEMOVE, WM_MOUSEWHEEL.
|
||||||
|
*/
|
||||||
|
void HandleMessage(const MSG& msg);
|
||||||
|
#endif
|
||||||
|
#if defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
/// [ANDROID ONLY] Lets the InputManager handle the given input event.
|
||||||
|
int32_t HandleInput(AInputEvent* event);
|
||||||
|
|
||||||
|
struct DeviceInput
|
||||||
|
{
|
||||||
|
InputDevice::DeviceType deviceType;
|
||||||
|
unsigned deviceIndex;
|
||||||
|
ButtonType buttonType;
|
||||||
|
DeviceButtonId buttonId;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
float f;
|
||||||
|
bool b;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
|
void HandleDeviceInput(DeviceInput const& input);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Updates the input state, call this every frame.
|
||||||
|
/**
|
||||||
|
* If the InputManager was initialized with `useSystemTime` set to `false`, you have to
|
||||||
|
* call Update(uint64_t) instead.
|
||||||
|
* \see GetTime
|
||||||
|
*/
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
/// Updates the input state and the manager's time, call this every frame.
|
||||||
|
/**
|
||||||
|
* Updates the time returned by GetTime() and then calls the regular Update(). This function
|
||||||
|
* should only be called if the InputManager was initialized with `useSystemTime`
|
||||||
|
* set to `false`.
|
||||||
|
* \param deltaTime The provided must be in milliseconds.
|
||||||
|
* \see Update
|
||||||
|
* \see GetTime
|
||||||
|
*/
|
||||||
|
void Update(uint64_t deltaTime);
|
||||||
|
|
||||||
|
/// Returns the allocator to be used for memory allocations.
|
||||||
|
Allocator& GetAllocator() const { return allocator_; }
|
||||||
|
|
||||||
|
/// Returns a monotonic time in milliseconds.
|
||||||
|
uint64_t GetTime() const;
|
||||||
|
|
||||||
|
/// Creates an input device and registers it with the manager.
|
||||||
|
/**
|
||||||
|
* \tparam T The input device class, muste be derived from InputDevice.
|
||||||
|
* \param variant Requests the specified device variant. Note that this is only
|
||||||
|
* a request. Another implementation variant of the device may silently be instantiated
|
||||||
|
* instead. To determine what variant was instantiated, call InputDevice::GetVariant().
|
||||||
|
* \return The ID of the newly created input device.
|
||||||
|
*/
|
||||||
|
template<class T> DeviceId CreateDevice(unsigned index = InputDevice::AutoIndex, InputDevice::DeviceVariant variant = InputDevice::DV_STANDARD);
|
||||||
|
/// Creates an input device, registers it with the manager and returns it.
|
||||||
|
/**
|
||||||
|
* \tparam T The input device class, muste be derived from InputDevice.
|
||||||
|
* \param variant Requests the specified device variant. Note that this is only
|
||||||
|
* a request. Another implementation variant of the device may silently be instantiated
|
||||||
|
* instead. To determine what variant was instantiated, call InputDevice::GetVariant().
|
||||||
|
* \return The newly created input device.
|
||||||
|
*/
|
||||||
|
template<class T> T* CreateAndGetDevice(unsigned index = InputDevice::AutoIndex, InputDevice::DeviceVariant variant = InputDevice::DV_STANDARD);
|
||||||
|
/// Returns the input device with the given ID.
|
||||||
|
/**
|
||||||
|
* \return The input device or 0 if it doesn't exist.
|
||||||
|
*/
|
||||||
|
InputDevice* GetDevice(DeviceId deviceId);
|
||||||
|
/// Returns the input device with the given ID.
|
||||||
|
/**
|
||||||
|
* \return The input device or 0 if it doesn't exist.
|
||||||
|
*/
|
||||||
|
const InputDevice* GetDevice(DeviceId deviceId) const;
|
||||||
|
/// Returns the ID of the device with the given type and index.
|
||||||
|
/**
|
||||||
|
* \param typeName The name of the device type. Should come from InputDevice::GetTypeName().
|
||||||
|
* \param index The index of the device. Should come from InputDevice::GetIndex().
|
||||||
|
* \return The device's ID or InvalidDeviceId if no matching device exists.
|
||||||
|
*/
|
||||||
|
DeviceId FindDeviceId(const char* typeName, unsigned index) const;
|
||||||
|
/// Returns the ID of the device with the given type and index.
|
||||||
|
/**
|
||||||
|
* \param type The device type. Should come from InputDevice::GetType().
|
||||||
|
* \param index The index of the device. Should come from InputDevice::GetIndex().
|
||||||
|
* \return The device's ID or InvalidDeviceId if no matching device exists.
|
||||||
|
*/
|
||||||
|
DeviceId FindDeviceId(InputDevice::DeviceType type, unsigned index) const;
|
||||||
|
|
||||||
|
typedef HashMap<DeviceId, InputDevice*> DeviceMap;
|
||||||
|
/// Iterator over all registered devices.
|
||||||
|
typedef DeviceMap::iterator iterator;
|
||||||
|
/// Const iterator over all registered devices.
|
||||||
|
typedef DeviceMap::const_iterator const_iterator;
|
||||||
|
|
||||||
|
/// Returns the begin iterator over all registered devices.
|
||||||
|
iterator begin() { return devices_.begin(); }
|
||||||
|
/// Returns the end iterator over all registered devices.
|
||||||
|
iterator end() { return devices_.end(); }
|
||||||
|
/// Returns the begin iterator over all registered devices.
|
||||||
|
const_iterator begin() const { return devices_.begin(); }
|
||||||
|
/// Returns the end iterator over all registered devices.
|
||||||
|
const_iterator end() const { return devices_.end(); }
|
||||||
|
|
||||||
|
/// Registers a listener to be notified when a button state changes.
|
||||||
|
/**
|
||||||
|
* If there are listeners registered, all input devices will have to record their state changes. This incurs extra runtime costs.
|
||||||
|
*/
|
||||||
|
ListenerId AddListener(InputListener* listener);
|
||||||
|
/// De-registers the given listener.
|
||||||
|
void RemoveListener(ListenerId listenerId);
|
||||||
|
/// Sorts the list of listeners which controls the order in which listeners are called.
|
||||||
|
/**
|
||||||
|
* The order of listeners may be important as the functions being called to notify a listener of a state change can control if
|
||||||
|
* the state change will be passed to any consequent listeners. Call this function whenever listener priorites have changed. It
|
||||||
|
* is automatically called by AddListener() and RemoveListener().
|
||||||
|
*/
|
||||||
|
void ReorderListeners();
|
||||||
|
|
||||||
|
/// Checks if any button on any device is down.
|
||||||
|
/**
|
||||||
|
* \param[out] outButtons An array with maxButtonCount fields to receive the device buttons that are down.
|
||||||
|
* \param maxButtonCount The number of fields in outButtons.
|
||||||
|
* \return The number of device buttons written to outButtons.
|
||||||
|
*/
|
||||||
|
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
|
||||||
|
|
||||||
|
/// Returns the number of devices with the given type.
|
||||||
|
unsigned GetDeviceCountByType(InputDevice::DeviceType type) const;
|
||||||
|
/// Returns the graphical display's width in pixels.
|
||||||
|
int GetDisplayWidth() const { return displayWidth_; }
|
||||||
|
/// Returns the graphical display's height in pixels.
|
||||||
|
int GetDisplayHeight() const { return displayHeight_; }
|
||||||
|
|
||||||
|
/// Registers a modifier that will be called after devices have been updated.
|
||||||
|
ModifierId AddDeviceStateModifier(DeviceStateModifier* modifier);
|
||||||
|
/// De-registers the given modifier.
|
||||||
|
void RemoveDeviceStateModifier(ModifierId modifierId);
|
||||||
|
|
||||||
|
void EnqueueConcurrentChange(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, bool value);
|
||||||
|
void EnqueueConcurrentChange(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, float value);
|
||||||
|
|
||||||
|
/// [IN dev BUILDS ONLY] Connect to a remote host to send device state changes to.
|
||||||
|
void ConnectForStateSync(const char* ip, unsigned port);
|
||||||
|
/// [IN dev BUILDS ONLY] Initiate sending of device state changes to the given device.
|
||||||
|
void StartDeviceStateSync(DeviceId deviceId);
|
||||||
|
|
||||||
|
/// Enable/disable debug rendering of input devices.
|
||||||
|
void SetDebugRenderingEnabled(bool enabled);
|
||||||
|
/// Returns true if debug rendering is enabled, false otherwise.
|
||||||
|
bool IsDebugRenderingEnabled() const { return debugRenderingEnabled_; }
|
||||||
|
/// Sets the debug renderer to be used if debug rendering is enabled.
|
||||||
|
void SetDebugRenderer(DebugRenderer* debugRenderer);
|
||||||
|
/// Returns the previously set debug renderer.
|
||||||
|
DebugRenderer* GetDebugRenderer() const { return debugRenderer_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator& allocator_;
|
||||||
|
|
||||||
|
DeviceMap devices_;
|
||||||
|
unsigned nextDeviceId_;
|
||||||
|
|
||||||
|
HashMap<ListenerId, InputListener*> listeners_;
|
||||||
|
unsigned nextListenerId_;
|
||||||
|
Array<InputListener*> sortedListeners_;
|
||||||
|
|
||||||
|
HashMap<ModifierId, DeviceStateModifier*> modifiers_;
|
||||||
|
unsigned nextModifierId_;
|
||||||
|
|
||||||
|
InputDeltaState* deltaState_;
|
||||||
|
|
||||||
|
uint64_t currentTime_;
|
||||||
|
struct Change
|
||||||
|
{
|
||||||
|
InputDevice* device;
|
||||||
|
InputState* state;
|
||||||
|
InputDeltaState* delta;
|
||||||
|
DeviceButtonId buttonId;
|
||||||
|
ButtonType type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
float f;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
GAINPUT_CONC_QUEUE(Change) concurrentInputs_;
|
||||||
|
|
||||||
|
int displayWidth_;
|
||||||
|
int displayHeight_;
|
||||||
|
bool useSystemTime_;
|
||||||
|
|
||||||
|
bool debugRenderingEnabled_;
|
||||||
|
DebugRenderer* debugRenderer_;
|
||||||
|
|
||||||
|
void DeviceCreated(InputDevice* device);
|
||||||
|
|
||||||
|
// Do not copy.
|
||||||
|
InputManager(const InputManager &);
|
||||||
|
InputManager& operator=(const InputManager &);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline
|
||||||
|
DeviceId
|
||||||
|
InputManager::CreateDevice(unsigned index, InputDevice::DeviceVariant variant)
|
||||||
|
{
|
||||||
|
T* device = allocator_.New<T>(*this, nextDeviceId_, index, variant);
|
||||||
|
devices_[nextDeviceId_] = device;
|
||||||
|
DeviceCreated(device);
|
||||||
|
return nextDeviceId_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline
|
||||||
|
T*
|
||||||
|
InputManager::CreateAndGetDevice(unsigned index, InputDevice::DeviceVariant variant)
|
||||||
|
{
|
||||||
|
T* device = allocator_.New<T>(*this, nextDeviceId_, index, variant);
|
||||||
|
devices_[nextDeviceId_] = device;
|
||||||
|
++nextDeviceId_;
|
||||||
|
DeviceCreated(device);
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
InputDevice*
|
||||||
|
InputManager::GetDevice(DeviceId deviceId)
|
||||||
|
{
|
||||||
|
DeviceMap::iterator it = devices_.find(deviceId);
|
||||||
|
if (it == devices_.end())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
const InputDevice*
|
||||||
|
InputManager::GetDevice(DeviceId deviceId) const
|
||||||
|
{
|
||||||
|
DeviceMap::const_iterator it = devices_.find(deviceId);
|
||||||
|
if (it == devices_.end())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Interface for modifiers that change device input states after they have been updated.
|
||||||
|
class DeviceStateModifier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Called after non-dependent devices have been updated.
|
||||||
|
/**
|
||||||
|
* This function is called by InputManager::Update() after InputDevice::Update() has been
|
||||||
|
* called on all registered devices that have InputDevice::IsLateUpdate() return \c false.
|
||||||
|
*
|
||||||
|
* \param delta All device state changes should be registered with this delta state, may be 0.
|
||||||
|
*/
|
||||||
|
virtual void Update(InputDeltaState* delta) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
195
lib/include/gainput/GainputInputMap.h
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTMAP_H_
|
||||||
|
#define GAINPUTINPUTMAP_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
class UserButton;
|
||||||
|
|
||||||
|
/// Type for filter functions that can be used to filter mapped float inputs.
|
||||||
|
typedef float (*FilterFunc_T)(float const value, void* userData);
|
||||||
|
|
||||||
|
/// Maps user buttons to device buttons.
|
||||||
|
/**
|
||||||
|
* This is the interface that should be used to get input. You can have several maps that are used
|
||||||
|
* simultaneously or use different ones depending on game state. The user button IDs have to be unique per input map.
|
||||||
|
*
|
||||||
|
* InputMap uses the provided InputManager to get devices inputs and process them into user-mapped inputs. After creating
|
||||||
|
* an InputMap, you should map some device buttons to user buttons (using MapBool() or MapFloat()). User buttons are identified
|
||||||
|
* by an ID provided by you. In order to ensure their uniqueness, it's a good idea to define an enum containing all your user buttons
|
||||||
|
* for any given InputMap. It's of course possible to map multiple different device button to one user button.
|
||||||
|
*
|
||||||
|
* After a user button has been mapped, you can query its state by calling one of the several GetBool* and GetFloat* functions. The
|
||||||
|
* result will depend on the mapped device button(s) and the policy (set using SetUserButtonPolicy()).
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the map.
|
||||||
|
/**
|
||||||
|
* \param manager The input manager used to get device inputs.
|
||||||
|
* \param name The name for the input map (optional). If a name is provided, it is copied to an internal buffer.
|
||||||
|
* \param allocator The allocator to be used for all memory allocations.
|
||||||
|
*/
|
||||||
|
InputMap(InputManager& manager, const char* name = 0, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
/// Unitializes the map.
|
||||||
|
~InputMap();
|
||||||
|
|
||||||
|
/// Clears all mapped inputs.
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
/// Returns the input manager this input map uses.
|
||||||
|
const InputManager& GetManager() const { return manager_; }
|
||||||
|
/// Returns the map's name, if any.
|
||||||
|
/**
|
||||||
|
* \return The map's name or 0 if no name was set.
|
||||||
|
*/
|
||||||
|
const char* GetName() const { return name_; }
|
||||||
|
/// Returns the map's auto-generated ID (that should not be used outside of the library).
|
||||||
|
unsigned GetId() const { return id_; }
|
||||||
|
|
||||||
|
/// Maps a bool-type button.
|
||||||
|
/**
|
||||||
|
* \param userButton The user ID for this mapping.
|
||||||
|
* \param device The device's ID of the device button to be mapped.
|
||||||
|
* \param deviceButton The ID of the device button to be mapped.
|
||||||
|
* \return true if the mapping was created.
|
||||||
|
*/
|
||||||
|
bool MapBool(UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton);
|
||||||
|
/// Maps a float-type button, possibly to a custom range.
|
||||||
|
/**
|
||||||
|
* \param userButton The user ID for this mapping.
|
||||||
|
* \param device The device's ID of the device button to be mapped.
|
||||||
|
* \param deviceButton The ID of the device button to be mapped.
|
||||||
|
* \param min Optional minimum value of the mapped button.
|
||||||
|
* \param max Optional maximum value of the mapped button.
|
||||||
|
* \param filterFunc Optional filter functions that modifies the device button value.
|
||||||
|
* \param filterUserData Optional user data pointer that is passed to filterFunc.
|
||||||
|
* \return true if the mapping was created.
|
||||||
|
*/
|
||||||
|
bool MapFloat(UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton,
|
||||||
|
float min = 0.0f, float max = 1.0f,
|
||||||
|
FilterFunc_T filterFunc = 0, void* filterUserData = 0);
|
||||||
|
/// Removes all mappings for the given user button.
|
||||||
|
void Unmap(UserButtonId userButton);
|
||||||
|
/// Returns if the given user button has any mappings.
|
||||||
|
bool IsMapped(UserButtonId userButton) const;
|
||||||
|
|
||||||
|
/// Gets all device buttons mapped to the given user button.
|
||||||
|
/**
|
||||||
|
* \param userButton The user button ID of the button to return all mappings for.
|
||||||
|
* \param[out] outButtons An array with maxButtonCount fields to receive the device buttons that are mapped.
|
||||||
|
* \param maxButtonCount The number of fields in outButtons.
|
||||||
|
* \return The number of device buttons written to outButtons.
|
||||||
|
*/
|
||||||
|
size_t GetMappings(UserButtonId userButton, DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
|
||||||
|
|
||||||
|
/// Policy for how multiple device buttons are summarized in one user button.
|
||||||
|
enum UserButtonPolicy
|
||||||
|
{
|
||||||
|
UBP_FIRST_DOWN, ///< The first device buttons that is down (or not 0.0f) determines the result.
|
||||||
|
UBP_MAX, ///< The maximum of all device button states is the result.
|
||||||
|
UBP_MIN, ///< The minimum of all device button states is the result.
|
||||||
|
UBP_AVERAGE ///< The average of all device button states is the result.
|
||||||
|
};
|
||||||
|
/// Sets how a user button handles inputs from multiple device buttons.
|
||||||
|
/**
|
||||||
|
* \return true if the policy was set, false otherwise (i.e. the user button doesn't exist).
|
||||||
|
*/
|
||||||
|
bool SetUserButtonPolicy(UserButtonId userButton, UserButtonPolicy policy);
|
||||||
|
|
||||||
|
/// Sets a dead zone for a float-type button.
|
||||||
|
/**
|
||||||
|
* If a dead zone is set for a button anything less or equal to the given value will be treated
|
||||||
|
* as 0.0f. The absolute input value is used in order to determine if the input value falls within the dead
|
||||||
|
* zone (i.e. with a dead zone of 0.2f, both -0.1f and 0.1f will result in 0.0f).
|
||||||
|
*
|
||||||
|
* \param userButton The user button's ID.
|
||||||
|
* \param deadZone The dead zone to be set.
|
||||||
|
* \return true if the dead zone was set, false otherwise (i.e. the user button doesn't exist).
|
||||||
|
*/
|
||||||
|
bool SetDeadZone(UserButtonId userButton, float deadZone);
|
||||||
|
|
||||||
|
/// Returns the bool state of a user button.
|
||||||
|
bool GetBool(UserButtonId userButton) const;
|
||||||
|
/// Returns if the user button is newly down.
|
||||||
|
bool GetBoolIsNew(UserButtonId userButton) const;
|
||||||
|
/// Returns the bool state of a user button from the previous frame.
|
||||||
|
bool GetBoolPrevious(UserButtonId userButton) const;
|
||||||
|
/// Returns if the user button has been released.
|
||||||
|
bool GetBoolWasDown(UserButtonId userButton) const;
|
||||||
|
|
||||||
|
/// Returns the float state of a user button.
|
||||||
|
float GetFloat(UserButtonId userButton) const;
|
||||||
|
/// Returns the float state of a user button from the previous frame.
|
||||||
|
float GetFloatPrevious(UserButtonId userButton) const;
|
||||||
|
/// Returns the delta between the previous and the current frame of the float state of the given user button.
|
||||||
|
float GetFloatDelta(UserButtonId userButton) const;
|
||||||
|
|
||||||
|
/// Gets the name of the device button mapped to the given user button.
|
||||||
|
/**
|
||||||
|
* \param userButton ID of the user button.
|
||||||
|
* \param buffer A char-buffer to receive the button name.
|
||||||
|
* \param bufferLength Length of the buffer receiving the button name in bytes.
|
||||||
|
* \return The number of bytes written to buffer (includes the trailing \0).
|
||||||
|
*/
|
||||||
|
size_t GetUserButtonName(UserButtonId userButton, char* buffer, size_t bufferLength) const;
|
||||||
|
|
||||||
|
/// Returns the user button ID the given device button is mapped to.
|
||||||
|
/**
|
||||||
|
* This function iterates over all mapped buttons and therefore shouldn't be used in a performance critical
|
||||||
|
* situation.
|
||||||
|
*
|
||||||
|
* \param device The device's ID of the device button to be checked.
|
||||||
|
* \param deviceButton The ID of the device button to be checked.
|
||||||
|
* \return The user button ID the device button is mapped to or InvalidDeviceButtonId if the device button is not mapped.
|
||||||
|
*/
|
||||||
|
UserButtonId GetUserButtonId(DeviceId device, DeviceButtonId deviceButton) const;
|
||||||
|
|
||||||
|
/// Registers a listener to be notified when a button state changes.
|
||||||
|
/**
|
||||||
|
* If there are listeners registered, all input devices will have to record their state changes. This incurs extra runtime costs.
|
||||||
|
*/
|
||||||
|
ListenerId AddListener(MappedInputListener* listener);
|
||||||
|
/// De-registers the given listener.
|
||||||
|
void RemoveListener(ListenerId listenerId);
|
||||||
|
/// Sorts the list of listeners which controls the order in which listeners are called.
|
||||||
|
/**
|
||||||
|
* The order of listeners may be important as the functions being called to notify a listener of a state change can control if
|
||||||
|
* the state change will be passed to any consequent listeners. Call this function whenever listener priorites have changed. It
|
||||||
|
* is automatically called by AddListener() and RemoveListener().
|
||||||
|
*/
|
||||||
|
void ReorderListeners();
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputManager& manager_;
|
||||||
|
char* name_;
|
||||||
|
unsigned id_;
|
||||||
|
Allocator& allocator_;
|
||||||
|
|
||||||
|
typedef HashMap<UserButtonId, UserButton*> UserButtonMap;
|
||||||
|
UserButtonMap userButtons_;
|
||||||
|
UserButtonId nextUserButtonId_;
|
||||||
|
|
||||||
|
HashMap<ListenerId, MappedInputListener*> listeners_;
|
||||||
|
Array<MappedInputListener*> sortedListeners_;
|
||||||
|
unsigned nextListenerId_;
|
||||||
|
InputListener* managerListener_;
|
||||||
|
ListenerId managerListenerId_;
|
||||||
|
|
||||||
|
float GetFloatState(UserButtonId userButton, bool previous) const;
|
||||||
|
|
||||||
|
UserButton* GetUserButton(UserButtonId userButton);
|
||||||
|
const UserButton* GetUserButton(UserButtonId userButton) const;
|
||||||
|
|
||||||
|
// Do not copy.
|
||||||
|
InputMap(const InputMap &);
|
||||||
|
InputMap& operator=(const InputMap &);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
60
lib/include/gainput/GainputInputState.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTSTATE_H_
|
||||||
|
#define GAINPUTINPUTSTATE_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// State of an input device.
|
||||||
|
class GAINPUT_LIBEXPORT InputState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the state.
|
||||||
|
/**
|
||||||
|
* \param allocator The allocator to be used for all memory allocations.
|
||||||
|
* \param buttonCount The maximum number of device buttons.
|
||||||
|
*/
|
||||||
|
InputState(Allocator& allocator, unsigned int buttonCount);
|
||||||
|
/// Unitializes the state.
|
||||||
|
~InputState();
|
||||||
|
|
||||||
|
/// Returns the number of buttons in this state.
|
||||||
|
/**
|
||||||
|
* Note that not all buttons may be valid.
|
||||||
|
*
|
||||||
|
* \sa InputDevice::IsValidButtonId()
|
||||||
|
*/
|
||||||
|
unsigned GetButtonCount() const { return buttonCount_; }
|
||||||
|
|
||||||
|
/// Returns the bool state of the given device button.
|
||||||
|
bool GetBool(DeviceButtonId buttonId) const { return buttons_[buttonId].b; }
|
||||||
|
/// Sets the bool state of the given device button.
|
||||||
|
void Set(DeviceButtonId buttonId, bool value) { buttons_[buttonId].b = value; }
|
||||||
|
/// Returns the float state of the given device button.
|
||||||
|
float GetFloat(DeviceButtonId buttonId) const { return buttons_[buttonId].f; }
|
||||||
|
/// Sets the float state of the given device button.
|
||||||
|
void Set(DeviceButtonId buttonId, float value) { buttons_[buttonId].f = value; }
|
||||||
|
|
||||||
|
/// Sets the states of all buttons in this input state to the states of all buttons in the given input state.
|
||||||
|
InputState& operator=(const InputState& other);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator& allocator_;
|
||||||
|
unsigned int buttonCount_;
|
||||||
|
|
||||||
|
struct Button
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
float f;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Button* buttons_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
26
lib/include/gainput/GainputIos.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTIOS_H_
|
||||||
|
#define GAINPUTIOS_H_
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
class InputManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [IOS ONLY] UIKit view that captures touch inputs.
|
||||||
|
/**
|
||||||
|
* In order to enable touch input on iOS devices (i.e. make the InputDeviceTouch work),
|
||||||
|
* an instance of this view has to be attached as a subview to the view of your application.
|
||||||
|
* Note that, for touches to work in portrait and landscape mode, the subview has to be
|
||||||
|
* rotated correctly with its parent.
|
||||||
|
*/
|
||||||
|
@interface GainputView : UIView
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)frame inputManager:(gainput::InputManager&)inputManager;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
39
lib/include/gainput/GainputLog.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUT_LOG_H_
|
||||||
|
#define GAINPUT_LOG_H_
|
||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||||
|
|
||||||
|
#if defined(GAINPUT_DEBUG) || defined(GAINPUT_DEV)
|
||||||
|
#include <stdio.h>
|
||||||
|
#define GAINPUT_LOG(...) printf(__VA_ARGS__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
|
||||||
|
#if defined(GAINPUT_DEBUG) || defined(GAINPUT_DEV)
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#define GAINPUT_LOG(...) { char buf[1024]; sprintf(buf, __VA_ARGS__); OutputDebugStringA(buf); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
|
||||||
|
#if defined(GAINPUT_DEBUG) || defined(GAINPUT_DEV)
|
||||||
|
#include <android/log.h>
|
||||||
|
#define GAINPUT_LOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "gainput", __VA_ARGS__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
#include <stdio.h>
|
||||||
|
#define GAINPUT_LOG(...) printf(__VA_ARGS__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GAINPUT_LOG
|
||||||
|
#define GAINPUT_LOG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
17
lib/include/gainput/GainputMapFilters.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTMAPFILTERS_H_
|
||||||
|
#define GAINPUTMAPFILTERS_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Inverts the given input value in the range [-1.0f, 1.0f].
|
||||||
|
GAINPUT_LIBEXPORT float InvertSymmetricInput(float const value, void*);
|
||||||
|
|
||||||
|
/// Inverts the given input value in the range [0.0f, 1.0f].
|
||||||
|
GAINPUT_LIBEXPORT float InvertInput(float const value, void*);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
193
lib/include/gainput/gainput.h
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/**
|
||||||
|
* Gainput - C++ input library for games.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2017 Johannes Kuhlmann.
|
||||||
|
* Licensed under the MIT license. See LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GAINPUT_H_
|
||||||
|
#define GAINPUT_H_
|
||||||
|
|
||||||
|
#if defined(__ANDROID__) || defined(ANDROID)
|
||||||
|
#define GAINPUT_PLATFORM_ANDROID
|
||||||
|
#define GAINPUT_LIBEXPORT
|
||||||
|
#elif defined(__linux) || defined(__linux__) || defined(linux) || defined(LINUX)
|
||||||
|
#define GAINPUT_PLATFORM_LINUX
|
||||||
|
#define GAINPUT_LIBEXPORT
|
||||||
|
#elif defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER)
|
||||||
|
#define GAINPUT_PLATFORM_WIN
|
||||||
|
#if defined(GAINPUT_LIB_DYNAMIC)
|
||||||
|
#define GAINPUT_LIBEXPORT __declspec(dllexport)
|
||||||
|
#elif defined(GAINPUT_LIB_DYNAMIC_USE)
|
||||||
|
#define GAINPUT_LIBEXPORT __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
#define GAINPUT_LIBEXPORT
|
||||||
|
#endif
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define GAINPUT_LIBEXPORT
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#if TARGET_OS_TV
|
||||||
|
#define GAINPUT_PLATFORM_TVOS
|
||||||
|
#elif TARGET_OS_IPHONE
|
||||||
|
#define GAINPUT_PLATFORM_IOS
|
||||||
|
#elif TARGET_OS_MAC
|
||||||
|
#define GAINPUT_PLATFORM_MAC
|
||||||
|
#else
|
||||||
|
#error Gainput: Unknown/unsupported Apple platform!
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error Gainput: Unknown/unsupported platform!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//#define GAINPUT_DEBUG
|
||||||
|
//#define GAINPUT_DEV
|
||||||
|
#define GAINPUT_ENABLE_ALL_GESTURES
|
||||||
|
#define GAINPUT_ENABLE_RECORDER
|
||||||
|
#define GAINPUT_TEXT_INPUT_QUEUE_LENGTH 32
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_CONCURRENCY
|
||||||
|
#define MOODYCAMEL_EXCEPTIONS_DISABLED
|
||||||
|
#include "concurrentqueue.h"
|
||||||
|
#define GAINPUT_CONC_QUEUE(TYPE) moodycamel::ConcurrentQueue<TYPE>
|
||||||
|
#define GAINPUT_CONC_CONSTRUCT(queue) queue()
|
||||||
|
#define GAINPUT_CONC_ENQUEUE(queue, obj) queue.enqueue(obj)
|
||||||
|
#define GAINPUT_CONC_DEQUEUE(queue, obj) queue.try_dequeue(obj)
|
||||||
|
#else
|
||||||
|
#define GAINPUT_CONC_QUEUE(TYPE) gainput::Array<TYPE>
|
||||||
|
#define GAINPUT_CONC_CONSTRUCT(queue) queue(allocator)
|
||||||
|
#define GAINPUT_CONC_ENQUEUE(queue, obj) queue.push_back(obj)
|
||||||
|
#define GAINPUT_CONC_DEQUEUE(queue, obj) (!queue.empty() ? (obj = queue[queue.size()-1], queue.pop_back(), true) : false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#define GAINPUT_ASSERT assert
|
||||||
|
#define GAINPUT_UNUSED(x) (void)(x)
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
union _XEvent;
|
||||||
|
typedef _XEvent XEvent;
|
||||||
|
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
typedef struct tagMSG MSG;
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef __int8 int8_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
struct AInputEvent;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Contains all Gainput related classes, types, and functions.
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// ID of an input device.
|
||||||
|
typedef unsigned int DeviceId;
|
||||||
|
/// ID of a specific button unique to an input device.
|
||||||
|
typedef unsigned int DeviceButtonId;
|
||||||
|
|
||||||
|
/// Describes a device button on a specific device.
|
||||||
|
struct DeviceButtonSpec
|
||||||
|
{
|
||||||
|
/// ID of the input device.
|
||||||
|
DeviceId deviceId;
|
||||||
|
/// ID of the button on the given input device.
|
||||||
|
DeviceButtonId buttonId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ID of a user-defined, mapped button.
|
||||||
|
typedef unsigned int UserButtonId;
|
||||||
|
/// ID of an input listener.
|
||||||
|
typedef unsigned int ListenerId;
|
||||||
|
/// ID of a device state modifier.
|
||||||
|
typedef unsigned int ModifierId;
|
||||||
|
|
||||||
|
/// An invalid device ID.
|
||||||
|
static const DeviceId InvalidDeviceId = -1;
|
||||||
|
/// An invalid device button ID.
|
||||||
|
static const DeviceButtonId InvalidDeviceButtonId = -1;
|
||||||
|
/// An invalid user button ID.
|
||||||
|
static const UserButtonId InvalidUserButtonId = -1;
|
||||||
|
|
||||||
|
/// Returns the name of the library, should be "Gainput".
|
||||||
|
const char* GetLibName();
|
||||||
|
/// Returns the version number of the library.
|
||||||
|
uint32_t GetLibVersion();
|
||||||
|
/// Returns the version number of the library as a printable string.
|
||||||
|
const char* GetLibVersionString();
|
||||||
|
|
||||||
|
class InputDeltaState;
|
||||||
|
class InputListener;
|
||||||
|
class InputManager;
|
||||||
|
class DebugRenderer;
|
||||||
|
class DeviceStateModifier;
|
||||||
|
|
||||||
|
template <class T> T Abs(T a) { return a < T() ? -a : a; }
|
||||||
|
|
||||||
|
/// Switches the library's internal development server to HTTP mode.
|
||||||
|
/**
|
||||||
|
* When the server is in HTTP mode, it is possible to control touch
|
||||||
|
* input using an external HTML page that connects to the library
|
||||||
|
* via HTTP.
|
||||||
|
*
|
||||||
|
* The HTML page(s) can be found under `tools/html5client/` and should
|
||||||
|
* be placed on an HTTP server that can be reached from the touch device
|
||||||
|
* that should send touch events to the library. The touch device then
|
||||||
|
* in turn connects to the library's internal HTTP server and periodically
|
||||||
|
* sends touch input information.
|
||||||
|
*
|
||||||
|
* The pages can also be found hosted here:
|
||||||
|
* http://gainput.johanneskuhlmann.de/html5client/
|
||||||
|
*/
|
||||||
|
void DevSetHttp(bool enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GAINPUT_VER_MAJOR_SHIFT 16
|
||||||
|
#define GAINPUT_VER_GET_MAJOR(ver) (ver >> GAINPUT_VER_MAJOR_SHIFT)
|
||||||
|
#define GAINPUT_VER_GET_MINOR(ver) (ver & (uint32_t(-1) >> GAINPUT_VER_MAJOR_SHIFT))
|
||||||
|
|
||||||
|
|
||||||
|
#include <gainput/GainputAllocator.h>
|
||||||
|
#include <gainput/GainputContainers.h>
|
||||||
|
#include <gainput/GainputInputState.h>
|
||||||
|
#include <gainput/GainputInputDevice.h>
|
||||||
|
#include <gainput/GainputInputListener.h>
|
||||||
|
#include <gainput/GainputInputManager.h>
|
||||||
|
#include <gainput/GainputInputMap.h>
|
||||||
|
|
||||||
|
#include <gainput/GainputInputDeviceMouse.h>
|
||||||
|
#include <gainput/GainputInputDeviceKeyboard.h>
|
||||||
|
#include <gainput/GainputInputDevicePad.h>
|
||||||
|
#include <gainput/GainputInputDeviceTouch.h>
|
||||||
|
#include <gainput/GainputInputDeviceBuiltIn.h>
|
||||||
|
|
||||||
|
#include <gainput/gestures/GainputGestures.h>
|
||||||
|
|
||||||
|
#include <gainput/recorder/GainputInputRecording.h>
|
||||||
|
#include <gainput/recorder/GainputInputPlayer.h>
|
||||||
|
#include <gainput/recorder/GainputInputRecorder.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
47
lib/include/gainput/gestures/GainputButtonStickGesture.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTBUTTONSTICKGESTURE_H_
|
||||||
|
#define GAINPUTBUTTONSTICKGESTURE_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_BUTTON_STICK_GESTURE
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Buttons provided by the ButtonStickGesture.
|
||||||
|
enum ButtonStickAction
|
||||||
|
{
|
||||||
|
ButtonStickAxis
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class GAINPUT_LIBEXPORT ButtonStickGesture : public InputGesture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the gesture.
|
||||||
|
ButtonStickGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Uninitializes the gesture.
|
||||||
|
~ButtonStickGesture();
|
||||||
|
|
||||||
|
/// Sets up the gesture for operation with the given axes and buttons.
|
||||||
|
void Initialize(DeviceId negativeAxisDevice, DeviceButtonId negativeAxis,
|
||||||
|
DeviceId positiveAxisDevice, DeviceButtonId positiveAxis);
|
||||||
|
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == ButtonStickAxis; }
|
||||||
|
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_FLOAT; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceButtonSpec negativeAxis_;
|
||||||
|
DeviceButtonSpec positiveAxis_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
99
lib/include/gainput/gestures/GainputDoubleClickGesture.h
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTDOUBLECLICKGESTURE_H_
|
||||||
|
#define GAINPUTDOUBLECLICKGESTURE_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_DOUBLE_CLICK_GESTURE
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Buttons provided by the DoubleClickGesture.
|
||||||
|
enum DoubleClickAction
|
||||||
|
{
|
||||||
|
DoubleClickTriggered ///< The button triggered by double-clicking.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A double-click gesture.
|
||||||
|
/**
|
||||||
|
* This gesture implements the classic double-click functionality. Its only device button ::DoubleClickTriggered is
|
||||||
|
* true for one frame after the specified button has been active for a specified number of times in a given
|
||||||
|
* time frame. It's also possible to disallow the pointer from travelling too far between and during clicks.
|
||||||
|
*
|
||||||
|
* After instantiating the gesture like any other input device, call one of the Initialize() functions to properly
|
||||||
|
* set it up.
|
||||||
|
*
|
||||||
|
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
|
||||||
|
* \c GAINPUT_ENABLE_DOUBLE_CLICK_GESTURE defined.
|
||||||
|
*
|
||||||
|
* \sa Initialize
|
||||||
|
* \sa SetClicksTargetCount
|
||||||
|
* \sa InputManager::CreateDevice
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT DoubleClickGesture : public InputGesture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the gesture.
|
||||||
|
DoubleClickGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Uninitializes the gesture.
|
||||||
|
~DoubleClickGesture();
|
||||||
|
|
||||||
|
/// Sets up the gesture for operation without position checking.
|
||||||
|
/**
|
||||||
|
* \param actionButtonDevice ID of the input device containing the action button.
|
||||||
|
* \param actionButton ID of the device button to be used as the action button.
|
||||||
|
* \param timeSpan Allowed time between clicks in milliseconds.
|
||||||
|
*/
|
||||||
|
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, uint64_t timeSpan = 300);
|
||||||
|
/// Sets up the gesture for operation with position checking, i.e. the user may not move the mouse too far between clicks.
|
||||||
|
/**
|
||||||
|
* \param actionButtonDevice ID of the input device containing the action button.
|
||||||
|
* \param actionButton ID of the device button to be used as the action button.
|
||||||
|
* \param xAxisDevice ID of the input device containing the X coordinate of the pointer.
|
||||||
|
* \param xAxis ID of the device button/axis to be used for the X coordinate of the pointer.
|
||||||
|
* \param xTolerance The amount the pointer may travel in the X coordinate to still be valid.
|
||||||
|
* \param yAxisDevice ID of the input device containing the Y coordinate of the pointer.
|
||||||
|
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the pointer.
|
||||||
|
* \param yTolerance The amount the pointer may travel in the Y coordinate to still be valid.
|
||||||
|
* \param timeSpan Allowed time between clicks in milliseconds.
|
||||||
|
*/
|
||||||
|
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis, float xTolerance,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis, float yTolerance,
|
||||||
|
uint64_t timeSpan = 300);
|
||||||
|
|
||||||
|
/// Sets the number of clicks to trigger an action.
|
||||||
|
/**
|
||||||
|
* \param count The number of clicks that will trigger this gesture; the default is 2, i.e. double-click.
|
||||||
|
*/
|
||||||
|
void SetClicksTargetCount(unsigned count) { clicksTargetCount_ = count; }
|
||||||
|
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == DoubleClickTriggered; }
|
||||||
|
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceButtonSpec actionButton_;
|
||||||
|
DeviceButtonSpec xAxis_;
|
||||||
|
float xTolerance_;
|
||||||
|
DeviceButtonSpec yAxis_;
|
||||||
|
float yTolerance_;
|
||||||
|
|
||||||
|
uint64_t timeSpan_;
|
||||||
|
uint64_t firstClickTime_;
|
||||||
|
|
||||||
|
float firstClickX_;
|
||||||
|
float firstClickY_;
|
||||||
|
|
||||||
|
unsigned clicksRegistered_;
|
||||||
|
unsigned clicksTargetCount_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
69
lib/include/gainput/gestures/GainputGestures.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTGESTURES_H_
|
||||||
|
#define GAINPUTGESTURES_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_ALL_GESTURES
|
||||||
|
#define GAINPUT_ENABLE_BUTTON_STICK_GESTURE
|
||||||
|
#define GAINPUT_ENABLE_DOUBLE_CLICK_GESTURE
|
||||||
|
#define GAINPUT_ENABLE_HOLD_GESTURE
|
||||||
|
#define GAINPUT_ENABLE_PINCH_GESTURE
|
||||||
|
#define GAINPUT_ENABLE_ROTATE_GESTURE
|
||||||
|
#define GAINPUT_ENABLE_SIMULTANEOUSLY_DOWN_GESTURE
|
||||||
|
#define GAINPUT_ENABLE_TAP_GESTURE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Base class for all input gestures.
|
||||||
|
/**
|
||||||
|
* Input gestures are a way to process basic input data into more complex input data. For example,
|
||||||
|
* multiple buttons may be interpreted over time to form a new button. A very simple gesture would the
|
||||||
|
* ubiquitous double-click.
|
||||||
|
*
|
||||||
|
* Mainly for consistency and convenience reasons, all gestures should derive from this class though it's not
|
||||||
|
* strictly necessary (deriving from InputDevice would suffice).
|
||||||
|
*
|
||||||
|
* Input gestures are basically just input devices that don't get their data from some hardware device
|
||||||
|
* but from other input devices instead. Therefore gestures must also be created by calling
|
||||||
|
* InputManager::CreateDevice() or InputManager::CreateAndGetDevice(). Most gestures require further
|
||||||
|
* initialization which is done by calling one of their \c Initialize() member functions. After that,
|
||||||
|
* they should be good to go and their buttons can be used like any other input device button, i.e.
|
||||||
|
* they can be mapped to some user button.
|
||||||
|
*
|
||||||
|
* Gestures can be excluded from compilation if they are not required. In order to include all gestures
|
||||||
|
* \c GAINPUT_ENABLE_ALL_GESTURES should be defined in \c gainput.h . This define must be present when
|
||||||
|
* the library is built, otherwise the actual functionality won't be present. Similarly, there is one
|
||||||
|
* define for each gesture. The names of these are documented in the descriptions of the
|
||||||
|
* individual gesture classes. If no such define is defined, no gesture will be included.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputGesture : public InputDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Returns DT_GESTURE.
|
||||||
|
DeviceType GetType() const { return DT_GESTURE; }
|
||||||
|
const char* GetTypeName() const { return "gesture"; }
|
||||||
|
bool IsLateUpdate() const { return true; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Gesture base constructor.
|
||||||
|
InputGesture(InputManager& manager, DeviceId device, unsigned index) : InputDevice(manager, device, index == InputDevice::AutoIndex ? manager.GetDeviceCountByType(DT_GESTURE) : 0) { }
|
||||||
|
|
||||||
|
DeviceState InternalGetState() const { return DS_OK; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <gainput/gestures/GainputButtonStickGesture.h>
|
||||||
|
#include <gainput/gestures/GainputDoubleClickGesture.h>
|
||||||
|
#include <gainput/gestures/GainputHoldGesture.h>
|
||||||
|
#include <gainput/gestures/GainputPinchGesture.h>
|
||||||
|
#include <gainput/gestures/GainputRotateGesture.h>
|
||||||
|
#include <gainput/gestures/GainputSimultaneouslyDownGesture.h>
|
||||||
|
#include <gainput/gestures/GainputTapGesture.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
94
lib/include/gainput/gestures/GainputHoldGesture.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTHOLDGESTURE_H_
|
||||||
|
#define GAINPUTHOLDGESTURE_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_HOLD_GESTURE
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Buttons provided by the HoldGesture.
|
||||||
|
enum HoldAction
|
||||||
|
{
|
||||||
|
HoldTriggered ///< The button that triggers after holding for the given time.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A hold-to-trigger gesture.
|
||||||
|
/**
|
||||||
|
* This gesture, mainly meant for touch devices, triggers after the specified button has been down for at least
|
||||||
|
* the specified amount of time. Its button ::HoldTriggered is then either active for one frame or as long as
|
||||||
|
* the source button is down.
|
||||||
|
*
|
||||||
|
* After instantiating the gesture like any other input device, call one of the Initialize() functions to properly
|
||||||
|
* set it up.
|
||||||
|
*
|
||||||
|
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
|
||||||
|
* \c GAINPUT_ENABLE_HOLD_GESTURE defined.
|
||||||
|
*
|
||||||
|
* \sa Initialize
|
||||||
|
* \sa InputManager::CreateDevice
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT HoldGesture : public InputGesture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the gesture.
|
||||||
|
HoldGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Uninitializes the gesture.
|
||||||
|
~HoldGesture();
|
||||||
|
|
||||||
|
/// Sets up the gesture for operation without position checking.
|
||||||
|
/**
|
||||||
|
* \param actionButtonDevice ID of the input device containing the action button.
|
||||||
|
* \param actionButton ID of the device button to be used as the action button.
|
||||||
|
* \param oneShot Specifies if the gesture triggers only once after the given time or if it triggers as long as the source button is down.
|
||||||
|
* \param timeSpan Time in milliseconds the user needs to hold in order to trigger the gesture.
|
||||||
|
*/
|
||||||
|
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, bool oneShot = true, uint64_t timeSpan = 800);
|
||||||
|
/// Sets up the gesture for operation with position checking, i.e. the user may not move the mouse too far while holding.
|
||||||
|
/**
|
||||||
|
* \param actionButtonDevice ID of the input device containing the action button.
|
||||||
|
* \param actionButton ID of the device button to be used as the action button.
|
||||||
|
* \param xAxisDevice ID of the input device containing the X coordinate of the pointer.
|
||||||
|
* \param xAxis ID of the device button/axis to be used for the X coordinate of the pointer.
|
||||||
|
* \param xTolerance The amount the pointer may travel in the X coordinate to still be valid.
|
||||||
|
* \param yAxisDevice ID of the input device containing the Y coordinate of the pointer.
|
||||||
|
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the pointer.
|
||||||
|
* \param yTolerance The amount the pointer may travel in the Y coordinate to still be valid.
|
||||||
|
* \param oneShot Specifies if the gesture triggers only once after the given time or if it triggers as long as the source button is down.
|
||||||
|
* \param timeSpan Time in milliseconds the user needs to hold in order to trigger the gesture.
|
||||||
|
*/
|
||||||
|
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis, float xTolerance,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis, float yTolerance,
|
||||||
|
bool oneShot = true,
|
||||||
|
uint64_t timeSpan = 800);
|
||||||
|
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == HoldTriggered; }
|
||||||
|
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceButtonSpec actionButton_;
|
||||||
|
DeviceButtonSpec xAxis_;
|
||||||
|
float xTolerance_;
|
||||||
|
DeviceButtonSpec yAxis_;
|
||||||
|
float yTolerance_;
|
||||||
|
|
||||||
|
bool oneShot_;
|
||||||
|
bool oneShotReset_;
|
||||||
|
uint64_t timeSpan_;
|
||||||
|
uint64_t firstDownTime_;
|
||||||
|
|
||||||
|
float firstDownX_;
|
||||||
|
float firstDownY_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
86
lib/include/gainput/gestures/GainputPinchGesture.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTPINCHGESTURE_H_
|
||||||
|
#define GAINPUTPINCHGESTURE_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_PINCH_GESTURE
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Buttons provided by the PinchGesture.
|
||||||
|
enum PinchAction
|
||||||
|
{
|
||||||
|
PinchTriggered, ///< The button that triggers when both pinch buttons are down.
|
||||||
|
PinchScale ///< The current pinch scale value if pinching is active.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A multi-touch pinch-to-scale gesture.
|
||||||
|
/**
|
||||||
|
* This gesture, mainly meant for multi-touch devices, triggers (::PinchTriggered is down) when both specified
|
||||||
|
* source buttons are down. It will then determine the distance between the two 2D touch points and report
|
||||||
|
* any change in distance as a factor of the initial distance using ::PinchScale.
|
||||||
|
*
|
||||||
|
* After instantiating the gesture like any other input device, call Initialize() to properly
|
||||||
|
* set it up.
|
||||||
|
*
|
||||||
|
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
|
||||||
|
* \c GAINPUT_ENABLE_PINCH_GESTURE defined.
|
||||||
|
*
|
||||||
|
* \sa Initialize
|
||||||
|
* \sa InputManager::CreateDevice
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT PinchGesture : public InputGesture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the gesture.
|
||||||
|
PinchGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Uninitializes the gesture.
|
||||||
|
~PinchGesture();
|
||||||
|
|
||||||
|
/// Sets up the gesture for operation with the given axes and buttons.
|
||||||
|
/**
|
||||||
|
* \param downDevice ID of the input device containing the first touch button.
|
||||||
|
* \param downButton ID of the device button to be used as the first touch button.
|
||||||
|
* \param xAxisDevice ID of the input device containing the X coordinate of the first touch point.
|
||||||
|
* \param xAxis ID of the device button/axis to be used for the X coordinate of the first touch point.
|
||||||
|
* \param yAxisDevice ID of the input device containing the Y coordinate of the first touch point.
|
||||||
|
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the first touch point.
|
||||||
|
* \param down2Device ID of the input device containing the second touch button.
|
||||||
|
* \param downButton2 ID of the device button to be used as the second touch button.
|
||||||
|
* \param xAxis2Device ID of the input device containing the X coordinate of the second touch point.
|
||||||
|
* \param xAxis2 ID of the device button/axis to be used for the X coordinate of the second touch point.
|
||||||
|
* \param yAxis2Device ID of the input device containing the Y coordinate of the second touch point.
|
||||||
|
* \param yAxis2 ID of the device button/axis to be used for the Y coordinate of the second touch point.
|
||||||
|
*/
|
||||||
|
void Initialize(DeviceId downDevice, DeviceButtonId downButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis,
|
||||||
|
DeviceId down2Device, DeviceButtonId downButton2,
|
||||||
|
DeviceId xAxis2Device, DeviceButtonId xAxis2,
|
||||||
|
DeviceId yAxis2Device, DeviceButtonId yAxis2);
|
||||||
|
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == PinchTriggered || deviceButton == PinchScale; }
|
||||||
|
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return deviceButton == PinchTriggered ? BT_BOOL : BT_FLOAT; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceButtonSpec downButton_;
|
||||||
|
DeviceButtonSpec xAxis_;
|
||||||
|
DeviceButtonSpec yAxis_;
|
||||||
|
DeviceButtonSpec downButton2_;
|
||||||
|
DeviceButtonSpec xAxis2_;
|
||||||
|
DeviceButtonSpec yAxis2_;
|
||||||
|
|
||||||
|
bool pinching_;
|
||||||
|
float initialDistance_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
87
lib/include/gainput/gestures/GainputRotateGesture.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTROTATEGESTURE_H_
|
||||||
|
#define GAINPUTROTATEGESTURE_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_ROTATE_GESTURE
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Buttons provided by the RotateGesture.
|
||||||
|
enum RotateAction
|
||||||
|
{
|
||||||
|
RotateTriggered, ///< The button that triggers when both rotate buttons are down.
|
||||||
|
RotateAngle ///< The current rotation angle in radians if rotation is triggered (::RotateTriggered).
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A multi-touch rotate gesture.
|
||||||
|
/**
|
||||||
|
* This gesture, mainly meant for multi-touch devices, triggers (::RotateTriggered is down) when both specified
|
||||||
|
* source buttons are down. It then determines the angle between the two specified 2D touch points and reports any
|
||||||
|
* change in angle using ::RotateAngle. The initial angle between the two points is defined as no rotation.
|
||||||
|
*
|
||||||
|
* After instantiating the gesture like any other input device, call Initialize() to properly
|
||||||
|
* set it up.
|
||||||
|
*
|
||||||
|
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
|
||||||
|
* \c GAINPUT_ENABLE_ROTATE_GESTURE defined.
|
||||||
|
*
|
||||||
|
* \sa Initialize
|
||||||
|
* \sa InputManager::CreateDevice
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT RotateGesture : public InputGesture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the gesture.
|
||||||
|
RotateGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Uninitializes the gesture.
|
||||||
|
~RotateGesture();
|
||||||
|
|
||||||
|
/// Sets up the gesture for operation with the given axes and buttons.
|
||||||
|
/**
|
||||||
|
* \param downDevice ID of the input device containing the first touch button.
|
||||||
|
* \param downButton ID of the device button to be used as the first touch button.
|
||||||
|
* \param xAxisDevice ID of the input device containing the X coordinate of the first touch point.
|
||||||
|
* \param xAxis ID of the device button/axis to be used for the X coordinate of the first touch point.
|
||||||
|
* \param yAxisDevice ID of the input device containing the Y coordinate of the first touch point.
|
||||||
|
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the first touch point.
|
||||||
|
* \param down2Device ID of the input device containing the second touch button.
|
||||||
|
* \param downButton2 ID of the device button to be used as the second touch button.
|
||||||
|
* \param xAxis2Device ID of the input device containing the X coordinate of the second touch point.
|
||||||
|
* \param xAxis2 ID of the device button/axis to be used for the X coordinate of the second touch point.
|
||||||
|
* \param yAxis2Device ID of the input device containing the Y coordinate of the second touch point.
|
||||||
|
* \param yAxis2 ID of the device button/axis to be used for the Y coordinate of the second touch point.
|
||||||
|
*/
|
||||||
|
void Initialize(DeviceId downDevice, DeviceButtonId downButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis,
|
||||||
|
DeviceId down2Device, DeviceButtonId downButton2,
|
||||||
|
DeviceId xAxis2Device, DeviceButtonId xAxis2,
|
||||||
|
DeviceId yAxis2Device, DeviceButtonId yAxis2);
|
||||||
|
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == RotateTriggered || deviceButton == RotateAngle; }
|
||||||
|
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return deviceButton == RotateTriggered ? BT_BOOL : BT_FLOAT; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceButtonSpec downButton_;
|
||||||
|
DeviceButtonSpec xAxis_;
|
||||||
|
DeviceButtonSpec yAxis_;
|
||||||
|
DeviceButtonSpec downButton2_;
|
||||||
|
DeviceButtonSpec xAxis2_;
|
||||||
|
DeviceButtonSpec yAxis2_;
|
||||||
|
|
||||||
|
bool rotating_;
|
||||||
|
float initialAngle_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTSIMULTANEOUSLYDOWNGESTURE_H_
|
||||||
|
#define GAINPUTSIMULTANEOUSLYDOWNGESTURE_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_SIMULTANEOUSLY_DOWN_GESTURE
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Buttons provided by the SimultaneouslyDownGesture.
|
||||||
|
enum SimultaneouslyDownAction
|
||||||
|
{
|
||||||
|
SimultaneouslyDownTriggered ///< The button triggered by double-clicking.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A gesture that tracks if a number of buttons is down simultaneously.
|
||||||
|
/**
|
||||||
|
* This gesture can be used to detect if multiple buttons are down at the same time. Its only
|
||||||
|
* device button ::SimultaneouslyDownTriggered is true while all buttons provided through AddButton()
|
||||||
|
* are down.
|
||||||
|
*
|
||||||
|
* After instantiating the gesture like any other input device, call AddButton() as often as necessary
|
||||||
|
* to properly set it up.
|
||||||
|
*
|
||||||
|
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
|
||||||
|
* \c GAINPUT_ENABLE_SIMULTANEOUSLY_DOWN_GESTURE defined.
|
||||||
|
*
|
||||||
|
* \sa AddButton
|
||||||
|
* \sa InputManager::CreateDevice
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT SimultaneouslyDownGesture : public InputGesture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the gesture.
|
||||||
|
SimultaneouslyDownGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Uninitializes the gesture.
|
||||||
|
~SimultaneouslyDownGesture();
|
||||||
|
|
||||||
|
/// Adds the given button as a button to check.
|
||||||
|
/**
|
||||||
|
* \param device ID of the input device containing the button to be checked.
|
||||||
|
* \param button ID of the device button to be checked.
|
||||||
|
*/
|
||||||
|
void AddButton(DeviceId device, DeviceButtonId button);
|
||||||
|
|
||||||
|
/// Removes all buttons previously registered through AddButton().
|
||||||
|
void ClearButtons();
|
||||||
|
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == SimultaneouslyDownTriggered; }
|
||||||
|
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Array<DeviceButtonSpec> buttons_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
66
lib/include/gainput/gestures/GainputTapGesture.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTTAPGESTURE_H_
|
||||||
|
#define GAINPUTTAPGESTURE_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_TAP_GESTURE
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Buttons provided by the TapGesture.
|
||||||
|
enum TapAction
|
||||||
|
{
|
||||||
|
TapTriggered ///< The button that is triggered by tapping.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A tap-to-trigger gesture.
|
||||||
|
/**
|
||||||
|
* This gesture, mainly meant for touch devices, triggers after the specified button has been down and released
|
||||||
|
* during the specified time frame. If the button is down for a longer time, no action is triggered.
|
||||||
|
*
|
||||||
|
* After instantiating the gesture like any other input device, call Initialize() to properly
|
||||||
|
* set it up.
|
||||||
|
*
|
||||||
|
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
|
||||||
|
* \c GAINPUT_ENABLE_TAP_GESTURE defined.
|
||||||
|
*
|
||||||
|
* \sa Initialize
|
||||||
|
* \sa InputManager::CreateDevice
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT TapGesture : public InputGesture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the gesture.
|
||||||
|
TapGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
|
||||||
|
/// Uninitializes the gesture.
|
||||||
|
~TapGesture();
|
||||||
|
|
||||||
|
/// Sets up the gesture.
|
||||||
|
/**
|
||||||
|
* \param actionButtonDevice ID of the input device containing the action button.
|
||||||
|
* \param actionButton ID of the device button to be used as the action button.
|
||||||
|
* \param timeSpan Time in milliseconds the user may hold at most.
|
||||||
|
*/
|
||||||
|
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, uint64_t timeSpan = 500);
|
||||||
|
|
||||||
|
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == TapTriggered; }
|
||||||
|
|
||||||
|
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InternalUpdate(InputDeltaState* delta);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceButtonSpec actionButton_;
|
||||||
|
|
||||||
|
uint64_t timeSpan_;
|
||||||
|
uint64_t firstDownTime_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
65
lib/include/gainput/recorder/GainputInputPlayer.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTPLAYER_H_
|
||||||
|
#define GAINPUTINPUTPLAYER_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_RECORDER
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Plays back a previously recorded sequence of device state changes.
|
||||||
|
/**
|
||||||
|
* In order for input recording to be available, Gainput must have been built with
|
||||||
|
* \c GAINPUT_ENABLE_RECORDER defined.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputPlayer : public DeviceStateModifier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the player.
|
||||||
|
/**
|
||||||
|
* \param manager The manager to receive the device state changes.
|
||||||
|
* \param recording The recording to play, may be 0.
|
||||||
|
*/
|
||||||
|
InputPlayer(InputManager& manager, InputRecording* recording = 0);
|
||||||
|
/// Destructs the player.
|
||||||
|
~InputPlayer();
|
||||||
|
|
||||||
|
/// Updates the player, called internally from InputManager::Update().
|
||||||
|
void Update(InputDeltaState* delta);
|
||||||
|
|
||||||
|
/// Starts the playback.
|
||||||
|
/**
|
||||||
|
* A recording must have been provided before doing this, either through the
|
||||||
|
* constructor or SetRecording().
|
||||||
|
*/
|
||||||
|
void Start();
|
||||||
|
/// Stops the Playback.
|
||||||
|
void Stop();
|
||||||
|
/// Returns if the player is currently playing.
|
||||||
|
bool IsPlaying() const { return isPlaying_; }
|
||||||
|
|
||||||
|
/// Sets the recording to play.
|
||||||
|
void SetRecording(InputRecording* recording);
|
||||||
|
/// Returns the currently set recording.
|
||||||
|
InputRecording* GetRecording() { return recording_; }
|
||||||
|
/// Returns the currently set recording.
|
||||||
|
const InputRecording* GetRecording() const { return recording_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputManager& manager_;
|
||||||
|
|
||||||
|
bool isPlaying_;
|
||||||
|
InputRecording* recording_;
|
||||||
|
uint64_t startTime_;
|
||||||
|
|
||||||
|
Array<DeviceId> devicesToReset_;
|
||||||
|
|
||||||
|
ModifierId playingModifierId_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
73
lib/include/gainput/recorder/GainputInputRecorder.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTRECORDER_H_
|
||||||
|
#define GAINPUTINPUTRECORDER_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_RECORDER
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Records a sequence of button state changes.
|
||||||
|
/**
|
||||||
|
* In order for input recording to be available, Gainput must have been built with
|
||||||
|
* \c GAINPUT_ENABLE_RECORDER defined.
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputRecorder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the recorder.
|
||||||
|
/**
|
||||||
|
* \param manager The InputManager to receive button state changes from.
|
||||||
|
*/
|
||||||
|
InputRecorder(InputManager& manager);
|
||||||
|
/// Destructs the recorder.
|
||||||
|
~InputRecorder();
|
||||||
|
|
||||||
|
/// Starts recording.
|
||||||
|
/**
|
||||||
|
* Also clears the InputRecording that is being recorded to so that it's not possible
|
||||||
|
* to resume recording after stopping to record.
|
||||||
|
*/
|
||||||
|
void Start();
|
||||||
|
/// Stops recording.
|
||||||
|
void Stop();
|
||||||
|
/// Returns if the recorder is currently recording.
|
||||||
|
bool IsRecording() const { return isRecording_; }
|
||||||
|
|
||||||
|
/// Adds a device to record the button state changes of.
|
||||||
|
/**
|
||||||
|
* If no device is set, all devices are recorded.
|
||||||
|
* \param device The ID of the device to record.
|
||||||
|
*/
|
||||||
|
void AddDeviceToRecord(DeviceId device) { recordedDevices_[device] = true; }
|
||||||
|
/// Returns if the given device should be recorded.
|
||||||
|
/**
|
||||||
|
* \param device The ID of the device to check.
|
||||||
|
*/
|
||||||
|
bool IsDeviceToRecord(DeviceId device) { return recordedDevices_.empty() || recordedDevices_.count(device) > 0; }
|
||||||
|
|
||||||
|
/// Returns the recording that is being recorded to, may be 0.
|
||||||
|
InputRecording* GetRecording() { return recording_; }
|
||||||
|
/// Returns the recording that is being recorded to, may be 0.
|
||||||
|
const InputRecording* GetRecording() const { return recording_; }
|
||||||
|
/// Returns the time the recording was started.
|
||||||
|
uint64_t GetStartTime() const { return startTime_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputManager& manager_;
|
||||||
|
|
||||||
|
bool isRecording_;
|
||||||
|
InputListener* recordingListener_;
|
||||||
|
ListenerId recordingListenerId_;
|
||||||
|
InputRecording* recording_;
|
||||||
|
uint64_t startTime_;
|
||||||
|
HashMap<DeviceId, bool> recordedDevices_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
125
lib/include/gainput/recorder/GainputInputRecording.h
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTRECORDING_H_
|
||||||
|
#define GAINPUTINPUTRECORDING_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_RECORDER
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
/// A single recorded change for a device button.
|
||||||
|
struct GAINPUT_LIBEXPORT RecordedDeviceButtonChange
|
||||||
|
{
|
||||||
|
/// The time at which the change occurred.
|
||||||
|
uint64_t time;
|
||||||
|
/// The ID of the device owning the button that changed.
|
||||||
|
DeviceId deviceId;
|
||||||
|
/// The ID of the button that changed.
|
||||||
|
DeviceButtonId buttonId;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
/// If the button's type is ::BT_BOOL, this contains the new value.
|
||||||
|
bool b;
|
||||||
|
/// If the button's type is ::BT_FLOAT, this contains the new value.
|
||||||
|
float f;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A recorded sequence of input changes.
|
||||||
|
/**
|
||||||
|
* The recording can be recorded to, played, or serialized/deserialized.
|
||||||
|
*
|
||||||
|
* In order for input recording to be available, Gainput must have been built with
|
||||||
|
* \c GAINPUT_ENABLE_RECORDER defined.
|
||||||
|
*
|
||||||
|
* \sa InputPlayer
|
||||||
|
* \sa InputRecorder
|
||||||
|
*/
|
||||||
|
class GAINPUT_LIBEXPORT InputRecording
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Initializes the recording in an empty state.
|
||||||
|
/**
|
||||||
|
* \param allocator The allocator to be used for all memory allocations.
|
||||||
|
*/
|
||||||
|
InputRecording(Allocator& allocator = GetDefaultAllocator());
|
||||||
|
/// Initializes the recording from the given serialized data.
|
||||||
|
/**
|
||||||
|
* The recording is reconstructed from a previously serialized recording obtained through
|
||||||
|
* GetSerialized().
|
||||||
|
*
|
||||||
|
* \param manager Used to resolve device and button references in the recording.
|
||||||
|
* \param data The serialized recording as obtained from GetSerialized().
|
||||||
|
* \param size The length of the serialized recording as obtained from GetSerializedSize().
|
||||||
|
* \param allocator The allocator to be used for all memory allocations.
|
||||||
|
*/
|
||||||
|
InputRecording(InputManager& manager, void* data, size_t size, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
|
||||||
|
/// Appends a device button change to the recording.
|
||||||
|
/**
|
||||||
|
* The changes must be added in chronological order, i.e. time must always greater or equal to the time
|
||||||
|
* AddChange() was last called with.
|
||||||
|
*
|
||||||
|
* \param time The time elapsed before the change occurred.
|
||||||
|
* \param deviceId The ID of the device owning the button that changed.
|
||||||
|
* \param buttonId The ID of the button that changed.
|
||||||
|
* \param value The new value of the button.
|
||||||
|
*/
|
||||||
|
void AddChange(uint64_t time, DeviceId deviceId, DeviceButtonId buttonId, bool value);
|
||||||
|
/// Appends a device button change to the recording.
|
||||||
|
/**
|
||||||
|
* The changes must be added in chronological order, i.e. time must always greater or equal to the time
|
||||||
|
* AddChange() was last called with.
|
||||||
|
*
|
||||||
|
* \param time The time elapsed before the change occurred.
|
||||||
|
* \param deviceId The ID of the device owning the button that changed.
|
||||||
|
* \param buttonId The ID of the button that changed.
|
||||||
|
* \param value The new value of the button.
|
||||||
|
*/
|
||||||
|
void AddChange(uint64_t time, DeviceId deviceId, DeviceButtonId buttonId, float value);
|
||||||
|
|
||||||
|
/// Removes all state changes.
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
/// Gets the next button change before and including the given time and returns it.
|
||||||
|
/**
|
||||||
|
* \param time The time up to which to return changes.
|
||||||
|
* \param[out] outChange The change properties will be written to this if this function returns true.
|
||||||
|
* \return true if a change matching the given time was found, false otherwise.
|
||||||
|
*/
|
||||||
|
bool GetNextChange(uint64_t time, RecordedDeviceButtonChange& outChange);
|
||||||
|
/// Resets the playback position.
|
||||||
|
/**
|
||||||
|
* After calling this function, GetNextChange() will return changes from the beginning of the recorded
|
||||||
|
* sequence of changes again.
|
||||||
|
*/
|
||||||
|
void Reset() { position_ = 0; }
|
||||||
|
|
||||||
|
/// Returns what time frame this recording spans.
|
||||||
|
uint64_t GetDuration() const;
|
||||||
|
|
||||||
|
/// Returns the size required to serialize this recording.
|
||||||
|
size_t GetSerializedSize() const;
|
||||||
|
/// Serializes this recording to the given buffer.
|
||||||
|
/**
|
||||||
|
* This function serializes this recording so that it can be saved and read back in and deserialized later.
|
||||||
|
*
|
||||||
|
* \param manager Used to resolve device and button references in the recording.
|
||||||
|
* \param data A buffer of (at least) a size as returned by GetSerializedSize().
|
||||||
|
*/
|
||||||
|
void GetSerialized(InputManager& manager, void* data) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Array<RecordedDeviceButtonChange> changes_;
|
||||||
|
|
||||||
|
/// The position in changes_ for reading.
|
||||||
|
unsigned position_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
85
lib/java/com/example/gainput/gainput/BasicActivity.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package com.example.gainput.gainput;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import de.johanneskuhlmann.gainput.Gainput;
|
||||||
|
|
||||||
|
public class BasicActivity extends Activity
|
||||||
|
{
|
||||||
|
private Gainput gainputHandler;
|
||||||
|
private Timer timer;
|
||||||
|
|
||||||
|
public static native void nativeOnCreate();
|
||||||
|
public static native void nativeOnUpdate();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
System.loadLibrary("basicsample");
|
||||||
|
gainputHandler = new Gainput(getApplicationContext());
|
||||||
|
nativeOnCreate();
|
||||||
|
|
||||||
|
getWindow().getDecorView().findViewById(android.R.id.content).addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||||
|
gainputHandler.viewWidth = v.getWidth();
|
||||||
|
gainputHandler.viewHeight = v.getHeight();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
timer = new Timer();
|
||||||
|
TimerTask t = new TimerTask() {
|
||||||
|
int sec = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
nativeOnUpdate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer.scheduleAtFixedRate(t, 500, 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyDown(int keyCode, KeyEvent event)
|
||||||
|
{
|
||||||
|
gainputHandler.handleKeyEvent(event);
|
||||||
|
return super.onKeyDown(keyCode, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event)
|
||||||
|
{
|
||||||
|
if (gainputHandler.handleTouchEvent(event))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchGenericMotionEvent(MotionEvent event)
|
||||||
|
{
|
||||||
|
if (gainputHandler.handleMotionEvent(event))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onGenericMotionEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchKeyEvent (KeyEvent event)
|
||||||
|
{
|
||||||
|
if (gainputHandler.handleKeyEvent(event))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.dispatchKeyEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
385
lib/java/de/johanneskuhlmann/gainput/Gainput.java
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
package de.johanneskuhlmann.gainput;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.hardware.input.InputManager;
|
||||||
|
import android.view.InputDevice;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Gainput implements InputManager.InputDeviceListener
|
||||||
|
{
|
||||||
|
|
||||||
|
// Must have same order/values as the respective enum in GainputInputDevicePad.h
|
||||||
|
enum PadButton
|
||||||
|
{
|
||||||
|
PadButtonLeftStickX,
|
||||||
|
PadButtonLeftStickY,
|
||||||
|
PadButtonRightStickX,
|
||||||
|
PadButtonRightStickY,
|
||||||
|
PadButtonAxis4, // L2/Left trigger
|
||||||
|
PadButtonAxis5, // R2/Right trigger
|
||||||
|
PadButtonAxis6,
|
||||||
|
PadButtonAxis7,
|
||||||
|
PadButtonAxis8,
|
||||||
|
PadButtonAxis9,
|
||||||
|
PadButtonAxis10,
|
||||||
|
PadButtonAxis11,
|
||||||
|
PadButtonAxis12,
|
||||||
|
PadButtonAxis13,
|
||||||
|
PadButtonAxis14,
|
||||||
|
PadButtonAxis15,
|
||||||
|
PadButtonAxis16,
|
||||||
|
PadButtonAxis17,
|
||||||
|
PadButtonAxis18,
|
||||||
|
PadButtonAxis19,
|
||||||
|
PadButtonAxis20,
|
||||||
|
PadButtonAxis21,
|
||||||
|
PadButtonAxis22,
|
||||||
|
PadButtonAxis23,
|
||||||
|
PadButtonAxis24,
|
||||||
|
PadButtonAxis25,
|
||||||
|
PadButtonAxis26,
|
||||||
|
PadButtonAxis27,
|
||||||
|
PadButtonAxis28,
|
||||||
|
PadButtonAxis29,
|
||||||
|
PadButtonAxis30,
|
||||||
|
PadButtonAxis31,
|
||||||
|
PadButtonAccelerationX,
|
||||||
|
PadButtonAccelerationY,
|
||||||
|
PadButtonAccelerationZ,
|
||||||
|
PadButtonGravityX,
|
||||||
|
PadButtonGravityY,
|
||||||
|
PadButtonGravityZ,
|
||||||
|
PadButtonGyroscopeX,
|
||||||
|
PadButtonGyroscopeY,
|
||||||
|
PadButtonGyroscopeZ,
|
||||||
|
PadButtonMagneticFieldX,
|
||||||
|
PadButtonMagneticFieldY,
|
||||||
|
PadButtonMagneticFieldZ,
|
||||||
|
PadButtonStart,
|
||||||
|
PadButtonSelect,
|
||||||
|
PadButtonLeft,
|
||||||
|
PadButtonRight,
|
||||||
|
PadButtonUp,
|
||||||
|
PadButtonDown,
|
||||||
|
PadButtonA, // Cross
|
||||||
|
PadButtonB, // Circle
|
||||||
|
PadButtonX, // Square
|
||||||
|
PadButtonY, // Triangle
|
||||||
|
PadButtonL1,
|
||||||
|
PadButtonR1,
|
||||||
|
PadButtonL2,
|
||||||
|
PadButtonR2,
|
||||||
|
PadButtonL3, // Left thumb
|
||||||
|
PadButtonR3, // Right thumb
|
||||||
|
PadButtonHome, // PS button
|
||||||
|
PadButton17,
|
||||||
|
PadButton18,
|
||||||
|
PadButton19,
|
||||||
|
PadButton20,
|
||||||
|
PadButton21,
|
||||||
|
PadButton22,
|
||||||
|
PadButton23,
|
||||||
|
PadButton24,
|
||||||
|
PadButton25,
|
||||||
|
PadButton26,
|
||||||
|
PadButton27,
|
||||||
|
PadButton28,
|
||||||
|
PadButton29,
|
||||||
|
PadButton30,
|
||||||
|
PadButton31,
|
||||||
|
PadButtonMax_
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have same order/values as the respective enum in GainputInputDevice.h
|
||||||
|
enum DeviceType
|
||||||
|
{
|
||||||
|
DT_MOUSE, ///< A mouse/cursor input device featuring one pointer.
|
||||||
|
DT_KEYBOARD, ///< A keyboard input device.
|
||||||
|
DT_PAD, ///< A joypad/gamepad input device.
|
||||||
|
DT_TOUCH, ///< A touch-sensitive input device supporting multiple simultaneous pointers.
|
||||||
|
DT_BUILTIN, ///< Any controls directly built into the device that also contains the screen.
|
||||||
|
DT_REMOTE, ///< A generic networked input device.
|
||||||
|
DT_GESTURE, ///< A gesture input device, building on top of other input devices.
|
||||||
|
DT_CUSTOM, ///< A custom, user-created input device.
|
||||||
|
DT_COUNT ///< The count of input device types.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static native void nativeOnInputBool(int deviceType, int deviceIndex, int buttonId, boolean value);
|
||||||
|
public static native void nativeOnInputFloat(int deviceType, int deviceIndex, int buttonId, float value);
|
||||||
|
public static native void nativeOnDeviceChanged(int deviceId, boolean available);
|
||||||
|
|
||||||
|
public float viewWidth = 1.0f;
|
||||||
|
public float viewHeight = 1.0f;
|
||||||
|
|
||||||
|
private float getRealX(float x)
|
||||||
|
{
|
||||||
|
return (x/viewWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getRealY(float y)
|
||||||
|
{
|
||||||
|
return (y/viewHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gainput(Context context)
|
||||||
|
{
|
||||||
|
inputManager_ = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
|
||||||
|
|
||||||
|
if (inputManager_ != null)
|
||||||
|
{
|
||||||
|
inputManager_.registerInputDeviceListener(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] deviceIds = InputDevice.getDeviceIds();
|
||||||
|
for (int deviceId : deviceIds)
|
||||||
|
{
|
||||||
|
InputDevice dev = InputDevice.getDevice(deviceId);
|
||||||
|
int sources = dev.getSources();
|
||||||
|
if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|
||||||
|
|| ((sources & InputDevice.SOURCE_JOYSTICK)
|
||||||
|
== InputDevice.SOURCE_JOYSTICK))
|
||||||
|
{
|
||||||
|
onInputDeviceAdded(deviceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize()
|
||||||
|
{
|
||||||
|
if (inputManager_ != null)
|
||||||
|
{
|
||||||
|
inputManager_.unregisterInputDeviceListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final InputManager inputManager_;
|
||||||
|
private Map<Integer, Integer> deviceIdMappings_ = new HashMap<Integer, Integer>();
|
||||||
|
|
||||||
|
private int translateDeviceIdToIndex(int deviceId)
|
||||||
|
{
|
||||||
|
Integer index = deviceIdMappings_.get(deviceId);
|
||||||
|
if (index != null)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the lowest non-used index.
|
||||||
|
for (int i = 0; i < 1000; ++i)
|
||||||
|
{
|
||||||
|
if (!deviceIdMappings_.containsValue(i))
|
||||||
|
{
|
||||||
|
deviceIdMappings_.put(deviceId, i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputDeviceAdded(int deviceId)
|
||||||
|
{
|
||||||
|
nativeOnDeviceChanged(translateDeviceIdToIndex(deviceId), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputDeviceChanged(int deviceId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInputDeviceRemoved(int deviceId)
|
||||||
|
{
|
||||||
|
int oldDeviceId = translateDeviceIdToIndex(deviceId);
|
||||||
|
deviceIdMappings_.remove(deviceId);
|
||||||
|
nativeOnDeviceChanged(oldDeviceId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleAxis(int deviceId, PadButton button, float value)
|
||||||
|
{
|
||||||
|
boolean isButton = false;
|
||||||
|
if (button == PadButton.PadButtonLeft
|
||||||
|
|| button == PadButton.PadButtonUp)
|
||||||
|
{
|
||||||
|
if (value < -0.5f)
|
||||||
|
value = -1.0f;
|
||||||
|
else
|
||||||
|
value = 0.0f;
|
||||||
|
isButton = true;
|
||||||
|
}
|
||||||
|
else if (button == PadButton.PadButtonRight
|
||||||
|
|| button == PadButton.PadButtonDown)
|
||||||
|
{
|
||||||
|
if (value > 0.5f)
|
||||||
|
value = 1.0f;
|
||||||
|
else
|
||||||
|
value = 0.0f;
|
||||||
|
isButton = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isButton)
|
||||||
|
{
|
||||||
|
nativeOnInputBool(DeviceType.DT_PAD.ordinal(), deviceId, button.ordinal(), value != 0.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nativeOnInputFloat(DeviceType.DT_PAD.ordinal(), deviceId, button.ordinal(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean handleMotionEvent(MotionEvent event)
|
||||||
|
{
|
||||||
|
int source = event.getSource();
|
||||||
|
if ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
|
||||||
|
|| (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|
||||||
|
{
|
||||||
|
int deviceId = translateDeviceIdToIndex(event.getDeviceId());
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonLeftStickX, event.getAxisValue(MotionEvent.AXIS_X));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonLeftStickY, -event.getAxisValue(MotionEvent.AXIS_Y));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonRightStickX, event.getAxisValue(MotionEvent.AXIS_Z));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonRightStickY, -event.getAxisValue(MotionEvent.AXIS_RZ));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonAxis4, event.getAxisValue(MotionEvent.AXIS_LTRIGGER));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonAxis5, event.getAxisValue(MotionEvent.AXIS_RTRIGGER));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonLeft, event.getAxisValue(MotionEvent.AXIS_HAT_X));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonRight, event.getAxisValue(MotionEvent.AXIS_HAT_X));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonUp, event.getAxisValue(MotionEvent.AXIS_HAT_Y));
|
||||||
|
handleAxis(deviceId, PadButton.PadButtonDown, event.getAxisValue(MotionEvent.AXIS_HAT_Y));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getButtonState(KeyEvent event)
|
||||||
|
{
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN)
|
||||||
|
return 1.0f;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleButton(int deviceId, PadButton button, KeyEvent event)
|
||||||
|
{
|
||||||
|
float state = getButtonState(event);
|
||||||
|
nativeOnInputBool(DeviceType.DT_PAD.ordinal(), deviceId, button.ordinal(), state != 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean handleKeyEvent(KeyEvent event)
|
||||||
|
{
|
||||||
|
int keyCode = event.getKeyCode();
|
||||||
|
int source = event.getSource();
|
||||||
|
if ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
|
||||||
|
|| (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|
||||||
|
{
|
||||||
|
int deviceId = translateDeviceIdToIndex(event.getDeviceId());
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_DPAD_UP)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonUp, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonDown, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonLeft, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonRight, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_A)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonA, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_B)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonB, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_X)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonX, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_Y)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonY, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_L1)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonL1, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_R1)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonR1, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBL)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonL3, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBR)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonR3, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_SELECT)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonSelect, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_BUTTON_START)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonStart, event);
|
||||||
|
else if (keyCode == KeyEvent.KEYCODE_HOME)
|
||||||
|
handleButton(deviceId, PadButton.PadButtonHome, event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD)
|
||||||
|
{
|
||||||
|
boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
|
||||||
|
nativeOnInputBool(DeviceType.DT_KEYBOARD.ordinal(), 0, event.getKeyCode(), down);
|
||||||
|
|
||||||
|
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || (keyCode == KeyEvent.KEYCODE_VOLUME_UP))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean handleTouchEvent(MotionEvent event)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final int action = event.getAction() & MotionEvent.ACTION_MASK;
|
||||||
|
final int numberOfPointers = event.getPointerCount();
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
case MotionEvent.ACTION_POINTER_DOWN:
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numberOfPointers; ++i)
|
||||||
|
{
|
||||||
|
final int pointerId = event.getPointerId(i);
|
||||||
|
final float x_move = getRealX(event.getX(i));
|
||||||
|
final float y_move = getRealY(event.getY(i));
|
||||||
|
nativeOnInputBool(DeviceType.DT_TOUCH.ordinal(), 0, 0 + 4 * pointerId, true);
|
||||||
|
nativeOnInputFloat(DeviceType.DT_TOUCH.ordinal(), 0, 1 + 4 * pointerId, x_move);
|
||||||
|
nativeOnInputFloat(DeviceType.DT_TOUCH.ordinal(), 0, 2 + 4 * pointerId, y_move);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numberOfPointers; ++i)
|
||||||
|
{
|
||||||
|
final int pointerId = event.getPointerId(i);
|
||||||
|
final float x_move = getRealX(event.getX(i));
|
||||||
|
final float y_move = getRealY(event.getY(i));
|
||||||
|
nativeOnInputFloat(DeviceType.DT_TOUCH.ordinal(), 0, 1 + 4 * pointerId, x_move);
|
||||||
|
nativeOnInputFloat(DeviceType.DT_TOUCH.ordinal(), 0, 2 + 4 * pointerId, y_move);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_POINTER_UP:
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numberOfPointers; ++i)
|
||||||
|
{
|
||||||
|
final int pointerId = event.getPointerId(i);
|
||||||
|
final float x_move = getRealX(event.getX(i));
|
||||||
|
final float y_move = getRealY(event.getY(i));
|
||||||
|
nativeOnInputBool(DeviceType.DT_TOUCH.ordinal(), 0, 0 + 4 * pointerId, false);
|
||||||
|
nativeOnInputFloat(DeviceType.DT_TOUCH.ordinal(), 0, 1 + 4 * pointerId, x_move);
|
||||||
|
nativeOnInputFloat(DeviceType.DT_TOUCH.ordinal(), 0, 2 + 4 * pointerId, y_move);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (final Exception ex)
|
||||||
|
{
|
||||||
|
ex.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
lib/source/gainput/GainputAllocator.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#include <gainput/GainputLog.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
DefaultAllocator&
|
||||||
|
GetDefaultAllocator()
|
||||||
|
{
|
||||||
|
static DefaultAllocator da;
|
||||||
|
return da;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TrackingAllocator::TrackingAllocator(Allocator& backingAllocator, Allocator& internalAllocator)
|
||||||
|
: backingAllocator_(backingAllocator),
|
||||||
|
internalAllocator_(internalAllocator),
|
||||||
|
allocations_(internalAllocator.New<HashMap<void*, size_t> >(internalAllocator)),
|
||||||
|
allocateCount_(0),
|
||||||
|
deallocateCount_(0),
|
||||||
|
allocatedMemory_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackingAllocator::~TrackingAllocator()
|
||||||
|
{
|
||||||
|
internalAllocator_.Delete(allocations_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* TrackingAllocator::Allocate(size_t size, size_t align)
|
||||||
|
{
|
||||||
|
void* ptr = backingAllocator_.Allocate(size, align);
|
||||||
|
(*allocations_)[ptr] = size;
|
||||||
|
++allocateCount_;
|
||||||
|
allocatedMemory_ += size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackingAllocator::Deallocate(void* ptr)
|
||||||
|
{
|
||||||
|
HashMap<void*, size_t>::iterator it = allocations_->find(ptr);
|
||||||
|
if (it == allocations_->end())
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("Warning: Trying to deallocate unknown memory block: %p\n", ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allocatedMemory_ -= it->second;
|
||||||
|
allocations_->erase(it);
|
||||||
|
}
|
||||||
|
++deallocateCount_;
|
||||||
|
backingAllocator_.Deallocate(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
126
lib/source/gainput/GainputHelpersEvdev.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTHELPERSEVDEV_H_
|
||||||
|
#define GAINPUTHELPERSEVDEV_H_
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/uinput.h>
|
||||||
|
|
||||||
|
#include <gainput/GainputLog.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
static const unsigned EvdevDeviceCount = 10;
|
||||||
|
static const char* EvdevDeviceIds[EvdevDeviceCount] =
|
||||||
|
{
|
||||||
|
"/dev/input/event0",
|
||||||
|
"/dev/input/event1",
|
||||||
|
"/dev/input/event2",
|
||||||
|
"/dev/input/event3",
|
||||||
|
"/dev/input/event4",
|
||||||
|
"/dev/input/event5",
|
||||||
|
"/dev/input/event6",
|
||||||
|
"/dev/input/event7",
|
||||||
|
"/dev/input/event8",
|
||||||
|
"/dev/input/event9",
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef long BitType;
|
||||||
|
|
||||||
|
#define GAINPUT_BITCOUNT (sizeof(BitType)*8)
|
||||||
|
#define GAINPUT_BITS(n) ((n/GAINPUT_BITCOUNT)+1)
|
||||||
|
|
||||||
|
bool IsBitSet(const BitType* bits, unsigned bit)
|
||||||
|
{
|
||||||
|
return bool(bits[bit/GAINPUT_BITCOUNT] & (1ul << (bit % GAINPUT_BITCOUNT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasEventType(const BitType* bits, unsigned type)
|
||||||
|
{
|
||||||
|
return IsBitSet(bits, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasEventCode(const BitType* bits, unsigned code)
|
||||||
|
{
|
||||||
|
return IsBitSet(bits, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class EvdevDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EvdevDevice(int fd) :
|
||||||
|
valid_(false)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
memset(name_, 0, sizeof(name_));
|
||||||
|
rc = ioctl(fd, EVIOCGNAME(sizeof(name_) - 1), name_);
|
||||||
|
if (rc < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GAINPUT_LOG("EVDEV Device name: %s\n", name_);
|
||||||
|
|
||||||
|
rc = ioctl(fd, EVIOCGBIT(0, sizeof(bits_)), bits_);
|
||||||
|
if (rc < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits_)), keyBits_);
|
||||||
|
if (rc < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
valid_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValid() const
|
||||||
|
{
|
||||||
|
return valid_;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceType GetDeviceType() const
|
||||||
|
{
|
||||||
|
if (HasEventType(bits_, EV_REL)
|
||||||
|
&& HasEventType(bits_, EV_KEY)
|
||||||
|
&& HasEventCode(keyBits_, BTN_LEFT))
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("EVDEV Detected as mouse\n");
|
||||||
|
return InputDevice::DT_MOUSE;
|
||||||
|
}
|
||||||
|
else if (HasEventType(bits_, EV_KEY)
|
||||||
|
&& HasEventCode(keyBits_, KEY_A)
|
||||||
|
&& HasEventCode(keyBits_, KEY_Q))
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("EVDEV Detected as keyboard\n");
|
||||||
|
return InputDevice::DT_KEYBOARD;
|
||||||
|
}
|
||||||
|
else if (HasEventType(bits_, EV_ABS)
|
||||||
|
&& HasEventType(bits_, EV_KEY)
|
||||||
|
&& (HasEventCode(keyBits_, BTN_GAMEPAD)
|
||||||
|
|| HasEventCode(keyBits_, BTN_JOYSTICK))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("EVDEV Detected as pad\n");
|
||||||
|
return InputDevice::DT_PAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
GAINPUT_LOG("EVDEV Unknown device type\n");
|
||||||
|
return InputDevice::DT_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool valid_;
|
||||||
|
char name_[255];
|
||||||
|
BitType bits_[GAINPUT_BITS(EV_CNT)];
|
||||||
|
BitType keyBits_[GAINPUT_BITS(KEY_CNT)];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
75
lib/source/gainput/GainputInputDeltaState.cpp
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
InputDeltaState::InputDeltaState(Allocator& allocator) :
|
||||||
|
changes_(allocator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDeltaState::AddChange(DeviceId device, DeviceButtonId deviceButton, bool oldValue, bool newValue)
|
||||||
|
{
|
||||||
|
Change change;
|
||||||
|
change.device = device;
|
||||||
|
change.deviceButton = deviceButton;
|
||||||
|
change.type = BT_BOOL;
|
||||||
|
change.oldValue.b = oldValue;
|
||||||
|
change.newValue.b = newValue;
|
||||||
|
changes_.push_back(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDeltaState::AddChange(DeviceId device, DeviceButtonId deviceButton, float oldValue, float newValue)
|
||||||
|
{
|
||||||
|
Change change;
|
||||||
|
change.device = device;
|
||||||
|
change.deviceButton = deviceButton;
|
||||||
|
change.type = BT_FLOAT;
|
||||||
|
change.oldValue.f = oldValue;
|
||||||
|
change.newValue.f = newValue;
|
||||||
|
changes_.push_back(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDeltaState::Clear()
|
||||||
|
{
|
||||||
|
changes_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDeltaState::NotifyListeners(Array<InputListener*>& listeners) const
|
||||||
|
{
|
||||||
|
for (Array<Change>::const_iterator it = changes_.begin();
|
||||||
|
it != changes_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const Change& change = *it;
|
||||||
|
for (Array<InputListener*>::iterator it2 = listeners.begin();
|
||||||
|
it2 != listeners.end();
|
||||||
|
++it2)
|
||||||
|
{
|
||||||
|
if (change.type == BT_BOOL)
|
||||||
|
{
|
||||||
|
if (!(*it2)->OnDeviceButtonBool(change.device, change.deviceButton, change.oldValue.b, change.newValue.b))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (change.type == BT_FLOAT)
|
||||||
|
{
|
||||||
|
if(!(*it2)->OnDeviceButtonFloat(change.device, change.deviceButton, change.oldValue.f, change.newValue.f))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
97
lib/source/gainput/GainputInputDevice.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
InputDevice::InputDevice(InputManager& manager, DeviceId device, unsigned index) :
|
||||||
|
manager_(manager),
|
||||||
|
deviceId_(device),
|
||||||
|
index_(index),
|
||||||
|
deadZones_(0),
|
||||||
|
debugRenderingEnabled_(false)
|
||||||
|
#if defined(GAINPUT_DEV) || defined(GAINPUT_ENABLE_RECORDER)
|
||||||
|
, synced_(false)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::~InputDevice()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Deallocate(deadZones_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDevice::Update(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
*previousState_ = *state_;
|
||||||
|
#if defined(GAINPUT_DEV)
|
||||||
|
if (synced_)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
InternalUpdate(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceState
|
||||||
|
InputDevice::GetState() const
|
||||||
|
{
|
||||||
|
#if defined(GAINPUT_DEV)
|
||||||
|
if (synced_)
|
||||||
|
{
|
||||||
|
return DS_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return InternalGetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
float InputDevice::GetDeadZone(DeviceButtonId buttonId) const
|
||||||
|
{
|
||||||
|
if (!deadZones_
|
||||||
|
|| !IsValidButtonId(buttonId))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
GAINPUT_ASSERT(buttonId < state_->GetButtonCount());
|
||||||
|
return deadZones_[buttonId];
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputDevice::SetDeadZone(DeviceButtonId buttonId, float value)
|
||||||
|
{
|
||||||
|
if (!deadZones_)
|
||||||
|
{
|
||||||
|
const size_t size = sizeof(float) * state_->GetButtonCount();
|
||||||
|
deadZones_ = reinterpret_cast<float*>(manager_.GetAllocator().Allocate(size));
|
||||||
|
memset(deadZones_, 0, size);
|
||||||
|
}
|
||||||
|
GAINPUT_ASSERT(buttonId < state_->GetButtonCount());
|
||||||
|
deadZones_[buttonId] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDevice::SetDebugRenderingEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
debugRenderingEnabled_ = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputDevice::CheckAllButtonsDown(DeviceButtonSpec* outButtons, size_t maxButtonCount, unsigned start, unsigned end) const
|
||||||
|
{
|
||||||
|
size_t buttonsFound = 0;
|
||||||
|
for (unsigned i = start; i < end && buttonsFound < maxButtonCount; ++i)
|
||||||
|
{
|
||||||
|
DeviceButtonId id(i);
|
||||||
|
if (IsValidButtonId(id) && GetBool(id))
|
||||||
|
{
|
||||||
|
outButtons[buttonsFound].deviceId = deviceId_;
|
||||||
|
outButtons[buttonsFound].buttonId = id;
|
||||||
|
++buttonsFound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buttonsFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
617
lib/source/gainput/GainputInputManager.cpp
Normal file
@@ -0,0 +1,617 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||||
|
#include <time.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include "keyboard/GainputInputDeviceKeyboardLinux.h"
|
||||||
|
#include "mouse/GainputInputDeviceMouseLinux.h"
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
#include "keyboard/GainputInputDeviceKeyboardWin.h"
|
||||||
|
#include "keyboard/GainputInputDeviceKeyboardWinRaw.h"
|
||||||
|
#include "mouse/GainputInputDeviceMouseWin.h"
|
||||||
|
#include "mouse/GainputInputDeviceMouseWinRaw.h"
|
||||||
|
#elif defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
#include <time.h>
|
||||||
|
#include <jni.h>
|
||||||
|
#include "keyboard/GainputInputDeviceKeyboardAndroid.h"
|
||||||
|
#include "pad/GainputInputDevicePadAndroid.h"
|
||||||
|
#include "touch/GainputInputDeviceTouchAndroid.h"
|
||||||
|
static gainput::InputManager* gGainputInputManager;
|
||||||
|
#elif defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#include <mach/clock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "dev/GainputDev.h"
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
InputManager::InputManager(bool useSystemTime, Allocator& allocator) :
|
||||||
|
allocator_(allocator),
|
||||||
|
devices_(allocator_),
|
||||||
|
nextDeviceId_(0),
|
||||||
|
listeners_(allocator_),
|
||||||
|
nextListenerId_(0),
|
||||||
|
sortedListeners_(allocator_),
|
||||||
|
modifiers_(allocator_),
|
||||||
|
nextModifierId_(0),
|
||||||
|
deltaState_(allocator_.New<InputDeltaState>(allocator_)),
|
||||||
|
currentTime_(0),
|
||||||
|
GAINPUT_CONC_CONSTRUCT(concurrentInputs_),
|
||||||
|
displayWidth_(-1),
|
||||||
|
displayHeight_(-1),
|
||||||
|
useSystemTime_(useSystemTime),
|
||||||
|
debugRenderingEnabled_(false),
|
||||||
|
debugRenderer_(0)
|
||||||
|
{
|
||||||
|
GAINPUT_DEV_INIT(this);
|
||||||
|
#ifdef GAINPUT_PLATFORM_ANDROID
|
||||||
|
gGainputInputManager = this;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
InputManager::~InputManager()
|
||||||
|
{
|
||||||
|
allocator_.Delete(deltaState_);
|
||||||
|
|
||||||
|
for (DeviceMap::iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
allocator_.Delete(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
GAINPUT_DEV_SHUTDOWN(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::Update()
|
||||||
|
{
|
||||||
|
Change change;
|
||||||
|
while (GAINPUT_CONC_DEQUEUE(concurrentInputs_, change))
|
||||||
|
{
|
||||||
|
if (change.type == BT_BOOL)
|
||||||
|
{
|
||||||
|
HandleButton(*change.device, *change.state, change.delta, change.buttonId, change.b);
|
||||||
|
}
|
||||||
|
else if (change.type == BT_FLOAT)
|
||||||
|
{
|
||||||
|
HandleAxis(*change.device, *change.state, change.delta, change.buttonId, change.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDeltaState* ds = listeners_.empty() ? 0 : deltaState_;
|
||||||
|
|
||||||
|
for (DeviceMap::iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if (!it->second->IsLateUpdate())
|
||||||
|
{
|
||||||
|
it->second->Update(ds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GAINPUT_DEV_UPDATE(ds);
|
||||||
|
|
||||||
|
for (HashMap<ModifierId, DeviceStateModifier*>::iterator it = modifiers_.begin();
|
||||||
|
it != modifiers_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
it->second->Update(ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DeviceMap::iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if (it->second->IsLateUpdate())
|
||||||
|
{
|
||||||
|
it->second->Update(ds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds)
|
||||||
|
{
|
||||||
|
ds->NotifyListeners(sortedListeners_);
|
||||||
|
ds->Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::Update(uint64_t deltaTime)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(useSystemTime_ == false);
|
||||||
|
currentTime_ += deltaTime;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
InputManager::GetTime() const
|
||||||
|
{
|
||||||
|
if (useSystemTime_)
|
||||||
|
{
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
struct timespec ts;
|
||||||
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t t = ts.tv_sec*1000ul + ts.tv_nsec/1000000ul;
|
||||||
|
return t;
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
static LARGE_INTEGER perfFreq = { 0 };
|
||||||
|
if (perfFreq.QuadPart == 0)
|
||||||
|
{
|
||||||
|
QueryPerformanceFrequency(&perfFreq);
|
||||||
|
GAINPUT_ASSERT(perfFreq.QuadPart != 0);
|
||||||
|
}
|
||||||
|
LARGE_INTEGER count;
|
||||||
|
QueryPerformanceCounter(&count);
|
||||||
|
double t = 1000.0 * double(count.QuadPart) / double(perfFreq.QuadPart);
|
||||||
|
return static_cast<uint64_t>(t);
|
||||||
|
#elif defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
clock_serv_t cclock;
|
||||||
|
mach_timespec_t mts;
|
||||||
|
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||||
|
clock_get_time(cclock, &mts);
|
||||||
|
mach_port_deallocate(mach_task_self(), cclock);
|
||||||
|
uint64_t t = mts.tv_sec*1000ul + mts.tv_nsec/1000000ul;
|
||||||
|
return t;
|
||||||
|
#else
|
||||||
|
#error Gainput: No time support
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return currentTime_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceId
|
||||||
|
InputManager::FindDeviceId(const char* typeName, unsigned index) const
|
||||||
|
{
|
||||||
|
for (DeviceMap::const_iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if (strcmp(typeName, it->second->GetTypeName()) == 0
|
||||||
|
&& it->second->GetIndex() == index)
|
||||||
|
{
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InvalidDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceId
|
||||||
|
InputManager::FindDeviceId(InputDevice::DeviceType type, unsigned index) const
|
||||||
|
{
|
||||||
|
for (DeviceMap::const_iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if (it->second->GetType() == type
|
||||||
|
&& it->second->GetIndex() == index)
|
||||||
|
{
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InvalidDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListenerId
|
||||||
|
InputManager::AddListener(InputListener* listener)
|
||||||
|
{
|
||||||
|
listeners_[nextListenerId_] = listener;
|
||||||
|
ReorderListeners();
|
||||||
|
return nextListenerId_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::RemoveListener(ListenerId listenerId)
|
||||||
|
{
|
||||||
|
listeners_.erase(listenerId);
|
||||||
|
ReorderListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static int CompareListeners(const void* a, const void* b)
|
||||||
|
{
|
||||||
|
const InputListener* listener1 = *reinterpret_cast<const InputListener* const*>(a);
|
||||||
|
const InputListener* listener2 = *reinterpret_cast<const InputListener* const*>(b);
|
||||||
|
return listener2->GetPriority() - listener1->GetPriority();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::ReorderListeners()
|
||||||
|
{
|
||||||
|
sortedListeners_.clear();
|
||||||
|
for (HashMap<ListenerId, InputListener*>::iterator it = listeners_.begin();
|
||||||
|
it != listeners_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
sortedListeners_.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortedListeners_.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(&sortedListeners_[0],
|
||||||
|
sortedListeners_.size(),
|
||||||
|
sizeof(InputListener*),
|
||||||
|
&CompareListeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifierId
|
||||||
|
InputManager::AddDeviceStateModifier(DeviceStateModifier* modifier)
|
||||||
|
{
|
||||||
|
modifiers_[nextModifierId_] = modifier;
|
||||||
|
return nextModifierId_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::RemoveDeviceStateModifier(ModifierId modifierId)
|
||||||
|
{
|
||||||
|
modifiers_.erase(modifierId);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputManager::GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const
|
||||||
|
{
|
||||||
|
size_t buttonsFound = 0;
|
||||||
|
for (DeviceMap::const_iterator it = devices_.begin();
|
||||||
|
it != devices_.end() && maxButtonCount > buttonsFound;
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
buttonsFound += it->second->GetAnyButtonDown(outButtons+buttonsFound, maxButtonCount-buttonsFound);
|
||||||
|
}
|
||||||
|
return buttonsFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
InputManager::GetDeviceCountByType(InputDevice::DeviceType type) const
|
||||||
|
{
|
||||||
|
unsigned count = 0;
|
||||||
|
for (DeviceMap::const_iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if (it->second->GetType() == type)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::DeviceCreated(InputDevice* device)
|
||||||
|
{
|
||||||
|
GAINPUT_UNUSED(device);
|
||||||
|
GAINPUT_DEV_NEW_DEVICE(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||||
|
void
|
||||||
|
InputManager::HandleEvent(XEvent& event)
|
||||||
|
{
|
||||||
|
for (DeviceMap::const_iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
#if defined(GAINPUT_DEV)
|
||||||
|
if (it->second->IsSynced())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (it->second->GetType() == InputDevice::DT_KEYBOARD
|
||||||
|
&& it->second->GetVariant() == InputDevice::DV_STANDARD)
|
||||||
|
{
|
||||||
|
InputDeviceKeyboard* keyboard = static_cast<InputDeviceKeyboard*>(it->second);
|
||||||
|
InputDeviceKeyboardImplLinux* keyboardImpl = static_cast<InputDeviceKeyboardImplLinux*>(keyboard->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(keyboardImpl);
|
||||||
|
keyboardImpl->HandleEvent(event);
|
||||||
|
}
|
||||||
|
else if (it->second->GetType() == InputDevice::DT_MOUSE
|
||||||
|
&& it->second->GetVariant() == InputDevice::DV_STANDARD)
|
||||||
|
{
|
||||||
|
InputDeviceMouse* mouse = static_cast<InputDeviceMouse*>(it->second);
|
||||||
|
InputDeviceMouseImplLinux* mouseImpl = static_cast<InputDeviceMouseImplLinux*>(mouse->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(mouseImpl);
|
||||||
|
mouseImpl->HandleEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
void
|
||||||
|
InputManager::HandleMessage(const MSG& msg)
|
||||||
|
{
|
||||||
|
for (DeviceMap::const_iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
#if defined(GAINPUT_DEV)
|
||||||
|
if (it->second->IsSynced())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (it->second->GetType() == InputDevice::DT_KEYBOARD)
|
||||||
|
{
|
||||||
|
InputDeviceKeyboard* keyboard = static_cast<InputDeviceKeyboard*>(it->second);
|
||||||
|
if (it->second->GetVariant() == InputDevice::DV_STANDARD)
|
||||||
|
{
|
||||||
|
InputDeviceKeyboardImplWin* keyboardImpl = static_cast<InputDeviceKeyboardImplWin*>(keyboard->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(keyboardImpl);
|
||||||
|
keyboardImpl->HandleMessage(msg);
|
||||||
|
}
|
||||||
|
else if (it->second->GetVariant() == InputDevice::DV_RAW)
|
||||||
|
{
|
||||||
|
InputDeviceKeyboardImplWinRaw* keyboardImpl = static_cast<InputDeviceKeyboardImplWinRaw*>(keyboard->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(keyboardImpl);
|
||||||
|
keyboardImpl->HandleMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (it->second->GetType() == InputDevice::DT_MOUSE)
|
||||||
|
{
|
||||||
|
InputDeviceMouse* mouse = static_cast<InputDeviceMouse*>(it->second);
|
||||||
|
if (it->second->GetVariant() == InputDevice::DV_STANDARD)
|
||||||
|
{
|
||||||
|
InputDeviceMouseImplWin* mouseImpl = static_cast<InputDeviceMouseImplWin*>(mouse->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(mouseImpl);
|
||||||
|
mouseImpl->HandleMessage(msg);
|
||||||
|
}
|
||||||
|
else if (it->second->GetVariant() == InputDevice::DV_RAW)
|
||||||
|
{
|
||||||
|
InputDeviceMouseImplWinRaw* mouseImpl = static_cast<InputDeviceMouseImplWinRaw*>(mouse->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(mouseImpl);
|
||||||
|
mouseImpl->HandleMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
int32_t
|
||||||
|
InputManager::HandleInput(AInputEvent* event)
|
||||||
|
{
|
||||||
|
int handled = 0;
|
||||||
|
for (DeviceMap::const_iterator it = devices_.begin();
|
||||||
|
it != devices_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
#if defined(GAINPUT_DEV)
|
||||||
|
if (it->second->IsSynced())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (it->second->GetType() == InputDevice::DT_TOUCH)
|
||||||
|
{
|
||||||
|
InputDeviceTouch* touch = static_cast<InputDeviceTouch*>(it->second);
|
||||||
|
InputDeviceTouchImplAndroid* touchImpl = static_cast<InputDeviceTouchImplAndroid*>(touch->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(touchImpl);
|
||||||
|
handled |= touchImpl->HandleInput(event);
|
||||||
|
}
|
||||||
|
else if (it->second->GetType() == InputDevice::DT_KEYBOARD)
|
||||||
|
{
|
||||||
|
InputDeviceKeyboard* keyboard = static_cast<InputDeviceKeyboard*>(it->second);
|
||||||
|
InputDeviceKeyboardImplAndroid* keyboardImpl = static_cast<InputDeviceKeyboardImplAndroid*>(keyboard->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(keyboardImpl);
|
||||||
|
handled |= keyboardImpl->HandleInput(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::HandleDeviceInput(DeviceInput const& input)
|
||||||
|
{
|
||||||
|
DeviceId devId = FindDeviceId(input.deviceType, input.deviceIndex);
|
||||||
|
if (devId == InvalidDeviceId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice* device = GetDevice(devId);
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GAINPUT_DEV)
|
||||||
|
if (device->IsSynced())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InputState* state = device->GetNextInputState();
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
state = device->GetInputState();
|
||||||
|
}
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.buttonType == BT_BOOL)
|
||||||
|
{
|
||||||
|
EnqueueConcurrentChange(*device, *state, deltaState_, input.buttonId, input.value.b);
|
||||||
|
}
|
||||||
|
else if (input.buttonType == BT_FLOAT)
|
||||||
|
{
|
||||||
|
EnqueueConcurrentChange(*device, *state, deltaState_, input.buttonId, input.value.f);
|
||||||
|
}
|
||||||
|
else if (input.buttonType == BT_COUNT && input.deviceType == InputDevice::DT_PAD)
|
||||||
|
{
|
||||||
|
InputDevicePad* pad = static_cast<InputDevicePad*>(device);
|
||||||
|
InputDevicePadImplAndroid* impl = static_cast<InputDevicePadImplAndroid*>(pad->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(impl);
|
||||||
|
if (input.value.b)
|
||||||
|
{
|
||||||
|
impl->SetState(InputDevice::DeviceState::DS_OK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
impl->SetState(InputDevice::DeviceState::DS_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::ConnectForStateSync(const char* ip, unsigned port)
|
||||||
|
{
|
||||||
|
GAINPUT_UNUSED(ip); GAINPUT_UNUSED(port);
|
||||||
|
GAINPUT_DEV_CONNECT(this, ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::StartDeviceStateSync(DeviceId deviceId)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(GetDevice(deviceId));
|
||||||
|
GAINPUT_ASSERT(GetDevice(deviceId)->GetType() != InputDevice::DT_GESTURE);
|
||||||
|
GAINPUT_DEV_START_SYNC(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::SetDebugRenderingEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
debugRenderingEnabled_ = enabled;
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(debugRenderer_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::SetDebugRenderer(DebugRenderer* debugRenderer)
|
||||||
|
{
|
||||||
|
debugRenderer_ = debugRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::EnqueueConcurrentChange(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, bool value)
|
||||||
|
{
|
||||||
|
Change change;
|
||||||
|
change.device = &device;
|
||||||
|
change.state = &state;
|
||||||
|
change.delta = delta;
|
||||||
|
change.buttonId = buttonId;
|
||||||
|
change.type = BT_BOOL;
|
||||||
|
change.b = value;
|
||||||
|
GAINPUT_CONC_ENQUEUE(concurrentInputs_, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputManager::EnqueueConcurrentChange(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, float value)
|
||||||
|
{
|
||||||
|
Change change;
|
||||||
|
change.device = &device;
|
||||||
|
change.state = &state;
|
||||||
|
change.delta = delta;
|
||||||
|
change.buttonId = buttonId;
|
||||||
|
change.type = BT_FLOAT;
|
||||||
|
change.f = value;
|
||||||
|
GAINPUT_CONC_ENQUEUE(concurrentInputs_, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
extern "C" {
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_de_johanneskuhlmann_gainput_Gainput_nativeOnInputBool(JNIEnv * /*env*/, jobject /*thiz*/,
|
||||||
|
jint deviceType, jint deviceIndex,
|
||||||
|
jint buttonId, jboolean value)
|
||||||
|
{
|
||||||
|
if (!gGainputInputManager)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using namespace gainput;
|
||||||
|
InputManager::DeviceInput input;
|
||||||
|
input.deviceType = static_cast<InputDevice::DeviceType>(deviceType);
|
||||||
|
input.deviceIndex = deviceIndex;
|
||||||
|
input.buttonType = BT_BOOL;
|
||||||
|
if (input.deviceType == InputDevice::DT_KEYBOARD)
|
||||||
|
{
|
||||||
|
DeviceId deviceId = gGainputInputManager->FindDeviceId(input.deviceType, deviceIndex);
|
||||||
|
if (deviceId != InvalidDeviceId)
|
||||||
|
{
|
||||||
|
InputDevice* device = gGainputInputManager->GetDevice(deviceId);
|
||||||
|
if (device)
|
||||||
|
{
|
||||||
|
InputDeviceKeyboard* keyboard = static_cast<InputDeviceKeyboard*>(device);
|
||||||
|
InputDeviceKeyboardImplAndroid* keyboardImpl = static_cast<InputDeviceKeyboardImplAndroid*>(keyboard->GetPimpl());
|
||||||
|
GAINPUT_ASSERT(keyboardImpl);
|
||||||
|
DeviceButtonId newId = keyboardImpl->Translate(buttonId);
|
||||||
|
if (newId != InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
buttonId = newId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input.buttonId = buttonId;
|
||||||
|
input.value.b = value;
|
||||||
|
gGainputInputManager->HandleDeviceInput(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_de_johanneskuhlmann_gainput_Gainput_nativeOnInputFloat(JNIEnv * /*env*/, jobject /*thiz*/,
|
||||||
|
jint deviceType, jint deviceIndex,
|
||||||
|
jint buttonId, jfloat value)
|
||||||
|
{
|
||||||
|
if (!gGainputInputManager)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using namespace gainput;
|
||||||
|
InputManager::DeviceInput input;
|
||||||
|
input.deviceType = static_cast<InputDevice::DeviceType>(deviceType);
|
||||||
|
input.deviceIndex = deviceIndex;
|
||||||
|
input.buttonType = BT_FLOAT;
|
||||||
|
input.buttonId = buttonId;
|
||||||
|
input.value.f = value;
|
||||||
|
gGainputInputManager->HandleDeviceInput(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_de_johanneskuhlmann_gainput_Gainput_nativeOnDeviceChanged(JNIEnv * /*env*/, jobject /*thiz*/,
|
||||||
|
jint deviceId, jboolean value)
|
||||||
|
{
|
||||||
|
if (!gGainputInputManager)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using namespace gainput;
|
||||||
|
InputManager::DeviceInput input;
|
||||||
|
input.deviceType = InputDevice::DT_PAD;
|
||||||
|
input.deviceIndex = deviceId;
|
||||||
|
input.buttonType = BT_COUNT;
|
||||||
|
input.value.b = value;
|
||||||
|
gGainputInputManager->HandleDeviceInput(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
572
lib/source/gainput/GainputInputMap.cpp
Normal file
@@ -0,0 +1,572 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include "dev/GainputDev.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template<class T> T Min(const T&a, const T& b) { return a < b ? a : b; }
|
||||||
|
template<class T> T Max(const T&a, const T& b) { return a < b ? b : a; }
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
class MappedInput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeviceId device;
|
||||||
|
DeviceButtonId deviceButton;
|
||||||
|
|
||||||
|
float rangeMin;
|
||||||
|
float rangeMax;
|
||||||
|
|
||||||
|
FilterFunc_T filterFunc;
|
||||||
|
void* filterUserData;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Array<MappedInput> MappedInputList;
|
||||||
|
|
||||||
|
class UserButton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
UserButtonId userButton;
|
||||||
|
MappedInputList inputs;
|
||||||
|
InputMap::UserButtonPolicy policy;
|
||||||
|
float deadZone;
|
||||||
|
|
||||||
|
UserButton(Allocator& allocator) :
|
||||||
|
inputs(allocator),
|
||||||
|
deadZone(0.0f)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
InputMap::InputMap(InputManager& manager, const char* name, Allocator& allocator) :
|
||||||
|
manager_(manager),
|
||||||
|
name_(0),
|
||||||
|
allocator_(allocator),
|
||||||
|
userButtons_(allocator_),
|
||||||
|
nextUserButtonId_(0),
|
||||||
|
listeners_(allocator_),
|
||||||
|
sortedListeners_(allocator_),
|
||||||
|
nextListenerId_(0),
|
||||||
|
managerListener_(0)
|
||||||
|
{
|
||||||
|
static unsigned nextId = 0;
|
||||||
|
id_ = nextId++;
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
name_ = static_cast<char*>(allocator_.Allocate(strlen(name) + 1));
|
||||||
|
strcpy(name_, name);
|
||||||
|
}
|
||||||
|
GAINPUT_DEV_NEW_MAP(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputMap::~InputMap()
|
||||||
|
{
|
||||||
|
GAINPUT_DEV_REMOVE_MAP(this);
|
||||||
|
Clear();
|
||||||
|
allocator_.Deallocate(name_);
|
||||||
|
|
||||||
|
if (managerListener_)
|
||||||
|
{
|
||||||
|
manager_.RemoveListener(managerListenerId_);
|
||||||
|
allocator_.Delete(managerListener_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputMap::Clear()
|
||||||
|
{
|
||||||
|
for (UserButtonMap::iterator it = userButtons_.begin();
|
||||||
|
it != userButtons_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
allocator_.Delete(it->second);
|
||||||
|
GAINPUT_DEV_REMOVE_USER_BUTTON(this, it->first);
|
||||||
|
}
|
||||||
|
userButtons_.clear();
|
||||||
|
nextUserButtonId_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::MapBool(UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton)
|
||||||
|
{
|
||||||
|
UserButton* ub = GetUserButton(userButton);
|
||||||
|
|
||||||
|
if (!ub)
|
||||||
|
{
|
||||||
|
ub = allocator_.New<UserButton>(allocator_);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
ub->userButton = nextUserButtonId_++;
|
||||||
|
ub->policy = UBP_FIRST_DOWN;
|
||||||
|
userButtons_[userButton] = ub;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappedInput mi;
|
||||||
|
mi.device = device;
|
||||||
|
mi.deviceButton = deviceButton;
|
||||||
|
ub->inputs.push_back(mi);
|
||||||
|
|
||||||
|
GAINPUT_DEV_NEW_USER_BUTTON(this, userButton, device, deviceButton);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::MapFloat(UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton, float min, float max, FilterFunc_T filterFunc, void* filterUserData)
|
||||||
|
{
|
||||||
|
UserButton* ub = GetUserButton(userButton);
|
||||||
|
|
||||||
|
if (!ub)
|
||||||
|
{
|
||||||
|
ub = allocator_.New<UserButton>(allocator_);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
ub->userButton = nextUserButtonId_++;
|
||||||
|
ub->policy = UBP_FIRST_DOWN;
|
||||||
|
userButtons_[userButton] = ub;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappedInput mi;
|
||||||
|
mi.device = device;
|
||||||
|
mi.deviceButton = deviceButton;
|
||||||
|
mi.rangeMin = min;
|
||||||
|
mi.rangeMax = max;
|
||||||
|
mi.filterFunc = filterFunc;
|
||||||
|
mi.filterUserData = filterUserData;
|
||||||
|
ub->inputs.push_back(mi);
|
||||||
|
|
||||||
|
GAINPUT_DEV_NEW_USER_BUTTON(this, userButton, device, deviceButton);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputMap::Unmap(UserButtonId userButton)
|
||||||
|
{
|
||||||
|
UserButton* ub = GetUserButton(userButton);
|
||||||
|
if (ub)
|
||||||
|
{
|
||||||
|
allocator_.Delete(ub);
|
||||||
|
userButtons_.erase(userButton);
|
||||||
|
GAINPUT_DEV_REMOVE_USER_BUTTON(this, userButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::IsMapped(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
return GetUserButton(userButton) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputMap::GetMappings(UserButtonId userButton, DeviceButtonSpec* outButtons, size_t maxButtonCount) const
|
||||||
|
{
|
||||||
|
size_t buttonCount = 0;
|
||||||
|
const UserButton* ub = GetUserButton(userButton);
|
||||||
|
if (!ub)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (MappedInputList::const_iterator it = ub->inputs.begin();
|
||||||
|
it != ub->inputs.end() && buttonCount < maxButtonCount;
|
||||||
|
++it, ++buttonCount)
|
||||||
|
{
|
||||||
|
const MappedInput& mi = *it;
|
||||||
|
outButtons[buttonCount].deviceId = mi.device;
|
||||||
|
outButtons[buttonCount].buttonId = mi.deviceButton;
|
||||||
|
}
|
||||||
|
return buttonCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::SetUserButtonPolicy(UserButtonId userButton, UserButtonPolicy policy)
|
||||||
|
{
|
||||||
|
UserButton* ub = GetUserButton(userButton);
|
||||||
|
if (!ub)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ub->policy = policy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::SetDeadZone(UserButtonId userButton, float deadZone)
|
||||||
|
{
|
||||||
|
UserButton* ub = GetUserButton(userButton);
|
||||||
|
if (!ub)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ub->deadZone = deadZone;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::GetBool(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
const UserButton* ub = GetUserButton(userButton);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
for (MappedInputList::const_iterator it = ub->inputs.begin();
|
||||||
|
it != ub->inputs.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const MappedInput& mi = *it;
|
||||||
|
const InputDevice* device = manager_.GetDevice(mi.device);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
if (device->GetBool(mi.deviceButton))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::GetBoolIsNew(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
const UserButton* ub = GetUserButton(userButton);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
for (MappedInputList::const_iterator it = ub->inputs.begin();
|
||||||
|
it != ub->inputs.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const MappedInput& mi= *it;
|
||||||
|
const InputDevice* device = manager_.GetDevice(mi.device);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
if (device->GetBool(mi.deviceButton)
|
||||||
|
&& !device->GetBoolPrevious(mi.deviceButton))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::GetBoolPrevious(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
const UserButton* ub = GetUserButton(userButton);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
for (MappedInputList::const_iterator it = ub->inputs.begin();
|
||||||
|
it != ub->inputs.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const MappedInput& mi= *it;
|
||||||
|
const InputDevice* device = manager_.GetDevice(mi.device);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
if (device->GetBoolPrevious(mi.deviceButton))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputMap::GetBoolWasDown(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
const UserButton* ub = GetUserButton(userButton);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
for (MappedInputList::const_iterator it = ub->inputs.begin();
|
||||||
|
it != ub->inputs.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const MappedInput& mi= *it;
|
||||||
|
const InputDevice* device = manager_.GetDevice(mi.device);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
if (!device->GetBool(mi.deviceButton)
|
||||||
|
&& device->GetBoolPrevious(mi.deviceButton))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
InputMap::GetFloat(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
return GetFloatState(userButton, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
InputMap::GetFloatPrevious(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
return GetFloatState(userButton, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
InputMap::GetFloatDelta(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
return GetFloat(userButton) - GetFloatPrevious(userButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
InputMap::GetFloatState(UserButtonId userButton, bool previous) const
|
||||||
|
{
|
||||||
|
float value = 0.0f;
|
||||||
|
int downCount = 0;
|
||||||
|
const UserButton* ub = GetUserButton(userButton);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
for (MappedInputList::const_iterator it = ub->inputs.begin();
|
||||||
|
it != ub->inputs.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const MappedInput& mi= *it;
|
||||||
|
const InputDevice* device = manager_.GetDevice(mi.device);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
|
||||||
|
bool down = false;
|
||||||
|
float deviceValue = 0.0f;
|
||||||
|
if (device->GetButtonType(mi.deviceButton) == BT_BOOL)
|
||||||
|
{
|
||||||
|
down = previous ? device->GetBoolPrevious(mi.deviceButton) : device->GetBool(mi.deviceButton);
|
||||||
|
deviceValue = down ? mi.rangeMax : mi.rangeMin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const float tmpValue = previous ? device->GetFloatPrevious(mi.deviceButton) : device->GetFloat(mi.deviceButton);
|
||||||
|
if (tmpValue != 0.0f)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(device->GetButtonType(mi.deviceButton) == BT_FLOAT);
|
||||||
|
deviceValue = mi.rangeMin + tmpValue*mi.rangeMax;
|
||||||
|
down = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mi.filterFunc)
|
||||||
|
{
|
||||||
|
deviceValue = mi.filterFunc(deviceValue, mi.filterUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (down)
|
||||||
|
{
|
||||||
|
++downCount;
|
||||||
|
if (ub->policy == UBP_FIRST_DOWN)
|
||||||
|
{
|
||||||
|
value = deviceValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (ub->policy == UBP_MAX)
|
||||||
|
{
|
||||||
|
if (Abs(deviceValue) > Abs(value))
|
||||||
|
{
|
||||||
|
value = deviceValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ub->policy == UBP_MIN)
|
||||||
|
{
|
||||||
|
if (downCount == 1)
|
||||||
|
{
|
||||||
|
value = deviceValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Abs(deviceValue) < Abs(value))
|
||||||
|
{
|
||||||
|
value = deviceValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ub->policy == UBP_AVERAGE)
|
||||||
|
{
|
||||||
|
value += deviceValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ub->policy == UBP_AVERAGE && downCount)
|
||||||
|
{
|
||||||
|
value /= float(downCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Abs(value) <= ub->deadZone)
|
||||||
|
{
|
||||||
|
value = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputMap::GetUserButtonName(UserButtonId userButton, char* buffer, size_t bufferLength) const
|
||||||
|
{
|
||||||
|
const UserButton* ub = GetUserButton(userButton);
|
||||||
|
GAINPUT_ASSERT(ub);
|
||||||
|
for (MappedInputList::const_iterator it = ub->inputs.begin();
|
||||||
|
it != ub->inputs.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const MappedInput& mi = *it;
|
||||||
|
const InputDevice* device = manager_.GetDevice(mi.device);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
return device->GetButtonName(mi.deviceButton, buffer, bufferLength);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserButtonId
|
||||||
|
InputMap::GetUserButtonId(DeviceId device, DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
for (UserButtonMap::const_iterator it = userButtons_.begin();
|
||||||
|
it != userButtons_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const UserButton* ub = it->second;
|
||||||
|
for (MappedInputList::const_iterator it2 = ub->inputs.begin();
|
||||||
|
it2 != ub->inputs.end();
|
||||||
|
++it2)
|
||||||
|
{
|
||||||
|
const MappedInput& mi = *it2;
|
||||||
|
if (mi.device == device && mi.deviceButton == deviceButton)
|
||||||
|
{
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InvalidUserButtonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ManagerToMapListener : public InputListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ManagerToMapListener(InputMap& inputMap, Array<MappedInputListener*>& listeners) :
|
||||||
|
inputMap_(inputMap),
|
||||||
|
listeners_(listeners)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool OnDeviceButtonBool(DeviceId device, DeviceButtonId deviceButton, bool oldValue, bool newValue)
|
||||||
|
{
|
||||||
|
const UserButtonId userButton = inputMap_.GetUserButtonId(device, deviceButton);
|
||||||
|
if (userButton == InvalidUserButtonId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (Array<MappedInputListener*>::iterator it = listeners_.begin();
|
||||||
|
it != listeners_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if(!(*it)->OnUserButtonBool(userButton, oldValue, newValue))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnDeviceButtonFloat(DeviceId device, DeviceButtonId deviceButton, float oldValue, float newValue)
|
||||||
|
{
|
||||||
|
const UserButtonId userButton = inputMap_.GetUserButtonId(device, deviceButton);
|
||||||
|
if (userButton == InvalidUserButtonId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (Array<MappedInputListener*>::iterator it = listeners_.begin();
|
||||||
|
it != listeners_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if (!(*it)->OnUserButtonFloat(userButton, oldValue, newValue))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputMap& inputMap_;
|
||||||
|
Array<MappedInputListener*>& listeners_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
InputMap::AddListener(MappedInputListener* listener)
|
||||||
|
{
|
||||||
|
if (!managerListener_)
|
||||||
|
{
|
||||||
|
managerListener_ = allocator_.New<ManagerToMapListener>(*this, sortedListeners_);
|
||||||
|
managerListenerId_ = manager_.AddListener(managerListener_);
|
||||||
|
}
|
||||||
|
listeners_[nextListenerId_] = listener;
|
||||||
|
ReorderListeners();
|
||||||
|
return nextListenerId_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputMap::RemoveListener(unsigned listenerId)
|
||||||
|
{
|
||||||
|
listeners_.erase(listenerId);
|
||||||
|
ReorderListeners();
|
||||||
|
|
||||||
|
if (listeners_.empty())
|
||||||
|
{
|
||||||
|
manager_.RemoveListener(managerListenerId_);
|
||||||
|
allocator_.Delete(managerListener_);
|
||||||
|
managerListener_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static int CompareListeners(const void* a, const void* b)
|
||||||
|
{
|
||||||
|
const MappedInputListener* listener1 = *reinterpret_cast<const MappedInputListener* const*>(a);
|
||||||
|
const MappedInputListener* listener2 = *reinterpret_cast<const MappedInputListener* const*>(b);
|
||||||
|
return listener2->GetPriority() - listener1->GetPriority();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputMap::ReorderListeners()
|
||||||
|
{
|
||||||
|
sortedListeners_.clear();
|
||||||
|
for (HashMap<ListenerId, MappedInputListener*>::iterator it = listeners_.begin();
|
||||||
|
it != listeners_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
sortedListeners_.push_back(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortedListeners_.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(&sortedListeners_[0],
|
||||||
|
sortedListeners_.size(),
|
||||||
|
sizeof(MappedInputListener*),
|
||||||
|
&CompareListeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserButton*
|
||||||
|
InputMap::GetUserButton(UserButtonId userButton)
|
||||||
|
{
|
||||||
|
UserButtonMap::iterator it = userButtons_.find(userButton);
|
||||||
|
if (it == userButtons_.end())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserButton*
|
||||||
|
InputMap::GetUserButton(UserButtonId userButton) const
|
||||||
|
{
|
||||||
|
UserButtonMap::const_iterator it = userButtons_.find(userButton);
|
||||||
|
if (it == userButtons_.end())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
32
lib/source/gainput/GainputInputState.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
InputState::InputState(Allocator& allocator, unsigned int buttonCount) :
|
||||||
|
allocator_(allocator),
|
||||||
|
buttonCount_(buttonCount)
|
||||||
|
{
|
||||||
|
const size_t size = sizeof(Button) * buttonCount_;
|
||||||
|
buttons_ = static_cast<Button*>(allocator_.Allocate(size));
|
||||||
|
GAINPUT_ASSERT(buttons_);
|
||||||
|
memset(buttons_, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputState::~InputState()
|
||||||
|
{
|
||||||
|
allocator_.Deallocate(buttons_);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputState&
|
||||||
|
InputState::operator=(const InputState& other)
|
||||||
|
{
|
||||||
|
const size_t size = sizeof(Button) * buttonCount_;
|
||||||
|
memcpy(buttons_, other.buttons_, size);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
185
lib/source/gainput/GainputIos.mm
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
|
||||||
|
#include <gainput/GainputIos.h>
|
||||||
|
|
||||||
|
#include "touch/GainputInputDeviceTouchIos.h"
|
||||||
|
|
||||||
|
@implementation GainputView
|
||||||
|
{
|
||||||
|
gainput::InputManager* inputManager_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)frame inputManager:(gainput::InputManager&)inputManager
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:frame];
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
inputManager_ = &inputManager;
|
||||||
|
|
||||||
|
#if !defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
[self setMultipleTouchEnabled:YES];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
gainput::DeviceId deviceId = inputManager_->FindDeviceId(gainput::InputDevice::DT_TOUCH, 0);
|
||||||
|
if (deviceId != gainput::InvalidDeviceId)
|
||||||
|
{
|
||||||
|
gainput::InputDeviceTouch* device = static_cast<gainput::InputDeviceTouch*>(inputManager_->GetDevice(deviceId));
|
||||||
|
if (device)
|
||||||
|
{
|
||||||
|
gainput::InputDeviceTouchImplIos* deviceImpl = static_cast<gainput::InputDeviceTouchImplIos*>(device->GetPimpl());
|
||||||
|
if (deviceImpl)
|
||||||
|
{
|
||||||
|
bool supports = false;
|
||||||
|
UIWindow* window = [UIApplication sharedApplication].keyWindow;
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
UIViewController* rvc = [window rootViewController];
|
||||||
|
if (rvc)
|
||||||
|
{
|
||||||
|
UITraitCollection* tc = [rvc traitCollection];
|
||||||
|
if (tc && [tc respondsToSelector:@selector(forceTouchCapability)])
|
||||||
|
{
|
||||||
|
supports = [tc forceTouchCapability] == UIForceTouchCapabilityAvailable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deviceImpl->SetSupportsPressure(supports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||||
|
{
|
||||||
|
gainput::DeviceId deviceId = inputManager_->FindDeviceId(gainput::InputDevice::DT_TOUCH, 0);
|
||||||
|
if (deviceId == gainput::InvalidDeviceId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gainput::InputDeviceTouch* device = static_cast<gainput::InputDeviceTouch*>(inputManager_->GetDevice(deviceId));
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gainput::InputDeviceTouchImplIos* deviceImpl = static_cast<gainput::InputDeviceTouchImplIos*>(device->GetPimpl());
|
||||||
|
if (!deviceImpl)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UITouch *touch in touches)
|
||||||
|
{
|
||||||
|
CGPoint point = [touch locationInView:self];
|
||||||
|
|
||||||
|
CGFloat force = 0.f;
|
||||||
|
CGFloat maxForce = 1.f;
|
||||||
|
if ([touch respondsToSelector:@selector(force)])
|
||||||
|
{
|
||||||
|
maxForce = [touch maximumPossibleForce];
|
||||||
|
force = [touch force];
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = point.x / self.bounds.size.width;
|
||||||
|
float y = point.y / self.bounds.size.height;
|
||||||
|
float z = force / maxForce;
|
||||||
|
|
||||||
|
deviceImpl->HandleTouch(static_cast<void*>(touch), x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
|
||||||
|
{
|
||||||
|
gainput::DeviceId deviceId = inputManager_->FindDeviceId(gainput::InputDevice::DT_TOUCH, 0);
|
||||||
|
if (deviceId == gainput::InvalidDeviceId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gainput::InputDeviceTouch* device = static_cast<gainput::InputDeviceTouch*>(inputManager_->GetDevice(deviceId));
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gainput::InputDeviceTouchImplIos* deviceImpl = static_cast<gainput::InputDeviceTouchImplIos*>(device->GetPimpl());
|
||||||
|
if (!deviceImpl)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UITouch *touch in touches)
|
||||||
|
{
|
||||||
|
CGPoint point = [touch locationInView:self];
|
||||||
|
|
||||||
|
CGFloat force = 0.f;
|
||||||
|
CGFloat maxForce = 1.f;
|
||||||
|
if ([touch respondsToSelector:@selector(force)])
|
||||||
|
{
|
||||||
|
maxForce = [touch maximumPossibleForce];
|
||||||
|
force = [touch force];
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = point.x / self.bounds.size.width;
|
||||||
|
float y = point.y / self.bounds.size.height;
|
||||||
|
float z = force / maxForce;
|
||||||
|
|
||||||
|
deviceImpl->HandleTouch(static_cast<void*>(touch), x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
||||||
|
{
|
||||||
|
gainput::DeviceId deviceId = inputManager_->FindDeviceId(gainput::InputDevice::DT_TOUCH, 0);
|
||||||
|
if (deviceId == gainput::InvalidDeviceId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gainput::InputDeviceTouch* device = static_cast<gainput::InputDeviceTouch*>(inputManager_->GetDevice(deviceId));
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gainput::InputDeviceTouchImplIos* deviceImpl = static_cast<gainput::InputDeviceTouchImplIos*>(device->GetPimpl());
|
||||||
|
if (!deviceImpl)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UITouch *touch in touches)
|
||||||
|
{
|
||||||
|
CGPoint point = [touch locationInView:self];
|
||||||
|
|
||||||
|
CGFloat force = 0.f;
|
||||||
|
CGFloat maxForce = 1.f;
|
||||||
|
if ([touch respondsToSelector:@selector(force)])
|
||||||
|
{
|
||||||
|
maxForce = [touch maximumPossibleForce];
|
||||||
|
force = [touch force];
|
||||||
|
}
|
||||||
|
|
||||||
|
float x = point.x / self.bounds.size.width;
|
||||||
|
float y = point.y / self.bounds.size.height;
|
||||||
|
float z = force / maxForce;
|
||||||
|
|
||||||
|
deviceImpl->HandleTouchEnd(static_cast<void*>(touch), x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
|
||||||
|
{
|
||||||
|
[self touchesEnded:touches withEvent:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
||||||
18
lib/source/gainput/GainputMac.mm
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_PLATFORM_MAC
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
bool MacIsApplicationKey()
|
||||||
|
{
|
||||||
|
return [[NSApplication sharedApplication] keyWindow ] != nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
20
lib/source/gainput/GainputMapFilters.cpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/GainputMapFilters.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
float InvertSymmetricInput(float const value, void*)
|
||||||
|
{
|
||||||
|
return -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
float InvertInput(float const value, void*)
|
||||||
|
{
|
||||||
|
return 1.0f - value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
17
lib/source/gainput/GainputWindows.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTWINDOWS_H_
|
||||||
|
#define GAINPUTWINDOWS_H_
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Windowsx.h>
|
||||||
|
#ifdef DrawText
|
||||||
|
#undef DrawText
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
145
lib/source/gainput/builtin/GainputInputDeviceBuiltIn.cpp
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/GainputDebugRenderer.h>
|
||||||
|
|
||||||
|
#include "GainputInputDeviceBuiltInImpl.h"
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
#include <gainput/GainputLog.h>
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
#include "GainputInputDeviceBuiltInAndroid.h"
|
||||||
|
#elif defined(GAINPUT_PLATFORM_IOS)
|
||||||
|
#include "GainputInputDeviceBuiltInIos.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "GainputInputDeviceBuiltInNull.h"
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct DeviceButtonInfo
|
||||||
|
{
|
||||||
|
ButtonType type;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
DeviceButtonInfo deviceButtonInfos[] =
|
||||||
|
{
|
||||||
|
{ BT_FLOAT, "builtin_acceleration_x" },
|
||||||
|
{ BT_FLOAT, "builtin_acceleration_y" },
|
||||||
|
{ BT_FLOAT, "builtin_acceleration_z" },
|
||||||
|
{ BT_FLOAT, "builtin_gravity_x" },
|
||||||
|
{ BT_FLOAT, "builtin_gravity_y" },
|
||||||
|
{ BT_FLOAT, "builtin_gravity_z" },
|
||||||
|
{ BT_FLOAT, "builtin_gyroscope_x" },
|
||||||
|
{ BT_FLOAT, "builtin_gyroscope_y" },
|
||||||
|
{ BT_FLOAT, "builtin_gyroscope_z" },
|
||||||
|
{ BT_FLOAT, "builtin_magneticfield_x" },
|
||||||
|
{ BT_FLOAT, "builtin_magneticfield_y" },
|
||||||
|
{ BT_FLOAT, "builtin_magneticfield_z" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned BuiltInButtonCount = BuiltInButtonCount_;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
InputDeviceBuiltIn::InputDeviceBuiltIn(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputDevice(manager, device, index == InputDevice::AutoIndex ? manager.GetDeviceCountByType(DT_BUILTIN) : 0),
|
||||||
|
impl_(0)
|
||||||
|
{
|
||||||
|
state_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), BuiltInButtonCount);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), BuiltInButtonCount);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceBuiltInImplAndroid>(manager, *this, index_, *state_, *previousState_);
|
||||||
|
#elif defined(GAINPUT_PLATFORM_IOS)
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceBuiltInImplIos>(manager, *this, index_, *state_, *previousState_);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!impl_)
|
||||||
|
{
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceBuiltInImplNull>(manager, *this, index_, *state_, *previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
GAINPUT_ASSERT(impl_);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDeviceBuiltIn::~InputDeviceBuiltIn()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
manager_.GetAllocator().Delete(impl_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDeviceBuiltIn::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
impl_->Update(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceState
|
||||||
|
InputDeviceBuiltIn::InternalGetState() const
|
||||||
|
{
|
||||||
|
return impl_->GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceVariant
|
||||||
|
InputDeviceBuiltIn::GetVariant() const
|
||||||
|
{
|
||||||
|
return impl_->GetVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputDeviceBuiltIn::IsValidButtonId(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
return impl_->IsValidButton(deviceButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputDeviceBuiltIn::GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(outButtons);
|
||||||
|
GAINPUT_ASSERT(maxButtonCount > 0);
|
||||||
|
return CheckAllButtonsDown(outButtons, maxButtonCount, BuiltInButtonAccelerationX, BuiltInButtonCount_);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputDeviceBuiltIn::GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(IsValidButtonId(deviceButton));
|
||||||
|
GAINPUT_ASSERT(buffer);
|
||||||
|
GAINPUT_ASSERT(bufferLength > 0);
|
||||||
|
strncpy(buffer, deviceButtonInfos[deviceButton].name, bufferLength);
|
||||||
|
buffer[bufferLength-1] = 0;
|
||||||
|
const size_t nameLen = strlen(deviceButtonInfos[deviceButton].name);
|
||||||
|
return nameLen >= bufferLength ? bufferLength : nameLen+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonType
|
||||||
|
InputDeviceBuiltIn::GetButtonType(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
return deviceButtonInfos[deviceButton].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceButtonId
|
||||||
|
InputDeviceBuiltIn::GetButtonByName(const char* name) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(name);
|
||||||
|
for (unsigned i = 0; i < BuiltInButtonCount; ++i)
|
||||||
|
{
|
||||||
|
if (strcmp(name, deviceButtonInfos[i].name) == 0)
|
||||||
|
{
|
||||||
|
return DeviceButtonId(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InvalidDeviceButtonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
203
lib/source/gainput/builtin/GainputInputDeviceBuiltInAndroid.h
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEBUILTINANDROID_H_
|
||||||
|
#define GAINPUTINPUTDEVICEBUILTINANDROID_H_
|
||||||
|
|
||||||
|
#include <android/sensor.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
class InputDeviceBuiltInImplAndroid : public InputDeviceBuiltInImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputDeviceBuiltInImplAndroid(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState) :
|
||||||
|
manager_(manager),
|
||||||
|
device_(device),
|
||||||
|
state_(state),
|
||||||
|
previousState_(previousState),
|
||||||
|
deviceState_(InputDevice::DS_UNAVAILABLE),
|
||||||
|
buttonDialect_(manager_.GetAllocator()),
|
||||||
|
sensorManager_(0),
|
||||||
|
accelerometerSensor_(0),
|
||||||
|
gyroscopeSensor_(0),
|
||||||
|
sensorEventQueue_(0),
|
||||||
|
gravityInitialized_(false)
|
||||||
|
{
|
||||||
|
ALooper* looper = ALooper_forThread();
|
||||||
|
if (!looper)
|
||||||
|
{
|
||||||
|
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!looper)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sensorManager_ = ASensorManager_getInstance();
|
||||||
|
if (!sensorManager_)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sensorEventQueue_ = ASensorManager_createEventQueue(sensorManager_, looper, ALOOPER_POLL_CALLBACK, NULL, NULL);
|
||||||
|
if (!sensorEventQueue_)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
accelerometerSensor_ = ASensorManager_getDefaultSensor(sensorManager_, ASENSOR_TYPE_ACCELEROMETER);
|
||||||
|
if (accelerometerSensor_)
|
||||||
|
{
|
||||||
|
ASensorEventQueue_setEventRate(sensorEventQueue_, accelerometerSensor_, ASensor_getMinDelay(accelerometerSensor_));
|
||||||
|
ASensorEventQueue_enableSensor(sensorEventQueue_, accelerometerSensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
gyroscopeSensor_ = ASensorManager_getDefaultSensor(sensorManager_, ASENSOR_TYPE_GYROSCOPE);
|
||||||
|
if (gyroscopeSensor_)
|
||||||
|
{
|
||||||
|
ASensorEventQueue_setEventRate(sensorEventQueue_, gyroscopeSensor_, ASensor_getMinDelay(gyroscopeSensor_));
|
||||||
|
ASensorEventQueue_enableSensor(sensorEventQueue_, gyroscopeSensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
magneticFieldSensor_ = ASensorManager_getDefaultSensor(sensorManager_, ASENSOR_TYPE_MAGNETIC_FIELD);
|
||||||
|
if (magneticFieldSensor_)
|
||||||
|
{
|
||||||
|
ASensorEventQueue_setEventRate(sensorEventQueue_, magneticFieldSensor_, ASensor_getMinDelay(magneticFieldSensor_));
|
||||||
|
ASensorEventQueue_enableSensor(sensorEventQueue_, magneticFieldSensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceState_ = InputDevice::DS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
~InputDeviceBuiltInImplAndroid()
|
||||||
|
{
|
||||||
|
if (!sensorManager_)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sensorEventQueue_)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (accelerometerSensor_)
|
||||||
|
{
|
||||||
|
ASensorEventQueue_disableSensor(sensorEventQueue_, accelerometerSensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gyroscopeSensor_)
|
||||||
|
{
|
||||||
|
ASensorEventQueue_disableSensor(sensorEventQueue_, gyroscopeSensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (magneticFieldSensor_)
|
||||||
|
{
|
||||||
|
ASensorEventQueue_disableSensor(sensorEventQueue_, magneticFieldSensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASensorManager_destroyEventQueue(sensorManager_, sensorEventQueue_);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceVariant GetVariant() const
|
||||||
|
{
|
||||||
|
return InputDevice::DV_STANDARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
ASensorEvent event;
|
||||||
|
|
||||||
|
while (ASensorEventQueue_getEvents(sensorEventQueue_, &event, 1) > 0)
|
||||||
|
{
|
||||||
|
if (event.type == ASENSOR_TYPE_ACCELEROMETER)
|
||||||
|
{
|
||||||
|
// https://developer.android.com/reference/android/hardware/SensorEvent.html#values
|
||||||
|
static const float kAlpha = 0.8f;
|
||||||
|
|
||||||
|
if (!gravityInitialized_)
|
||||||
|
{
|
||||||
|
gravity_[0] = event.acceleration.x / ASENSOR_STANDARD_GRAVITY;
|
||||||
|
gravity_[1] = event.acceleration.y / ASENSOR_STANDARD_GRAVITY;
|
||||||
|
gravity_[2] = event.acceleration.z / ASENSOR_STANDARD_GRAVITY;
|
||||||
|
gravityInitialized_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gravity_[0] = kAlpha * gravity_[0] + (1.0f - kAlpha) * (event.acceleration.x / ASENSOR_STANDARD_GRAVITY);
|
||||||
|
gravity_[1] = kAlpha * gravity_[1] + (1.0f - kAlpha) * (event.acceleration.y / ASENSOR_STANDARD_GRAVITY);
|
||||||
|
gravity_[2] = kAlpha * gravity_[2] + (1.0f - kAlpha) * (event.acceleration.z / ASENSOR_STANDARD_GRAVITY);
|
||||||
|
|
||||||
|
float accel[3];
|
||||||
|
accel[0] = (event.acceleration.x / ASENSOR_STANDARD_GRAVITY) - gravity_[0];
|
||||||
|
accel[1] = (event.acceleration.y / ASENSOR_STANDARD_GRAVITY) - gravity_[1];
|
||||||
|
accel[2] = (event.acceleration.z / ASENSOR_STANDARD_GRAVITY) - gravity_[2];
|
||||||
|
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGravityX, gravity_[0]);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGravityY, gravity_[1]);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGravityZ, gravity_[2]);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonAccelerationX, accel[0]);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonAccelerationY, accel[1]);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonAccelerationZ, accel[2]);
|
||||||
|
}
|
||||||
|
else if (event.type == ASENSOR_TYPE_GYROSCOPE)
|
||||||
|
{
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGyroscopeX, event.vector.x / ASENSOR_STANDARD_GRAVITY);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGyroscopeY, event.vector.y / ASENSOR_STANDARD_GRAVITY);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGyroscopeZ, event.vector.z / ASENSOR_STANDARD_GRAVITY);
|
||||||
|
}
|
||||||
|
else if (event.type == ASENSOR_TYPE_MAGNETIC_FIELD)
|
||||||
|
{
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonMagneticFieldX, event.magnetic.x / ASENSOR_MAGNETIC_FIELD_EARTH_MAX);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonMagneticFieldY, event.magnetic.y / ASENSOR_MAGNETIC_FIELD_EARTH_MAX);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonMagneticFieldZ, event.magnetic.z / ASENSOR_MAGNETIC_FIELD_EARTH_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceState GetState() const
|
||||||
|
{
|
||||||
|
return deviceState_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidButton(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
if (deviceButton <= BuiltInButtonAccelerationZ && accelerometerSensor_)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceButton >= BuiltInButtonGyroscopeX && deviceButton <= BuiltInButtonGyroscopeZ && gyroscopeSensor_)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceButton >= BuiltInButtonMagneticFieldX && deviceButton <= BuiltInButtonMagneticFieldZ && magneticFieldSensor_)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputManager& manager_;
|
||||||
|
InputDevice& device_;
|
||||||
|
InputState& state_;
|
||||||
|
InputState& previousState_;
|
||||||
|
InputDevice::DeviceState deviceState_;
|
||||||
|
HashMap<unsigned, DeviceButtonId> buttonDialect_;
|
||||||
|
ASensorManager* sensorManager_;
|
||||||
|
const ASensor* accelerometerSensor_;
|
||||||
|
const ASensor* gyroscopeSensor_;
|
||||||
|
const ASensor* magneticFieldSensor_;
|
||||||
|
ASensorEventQueue* sensorEventQueue_;
|
||||||
|
float gravity_[3];
|
||||||
|
bool gravityInitialized_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
21
lib/source/gainput/builtin/GainputInputDeviceBuiltInImpl.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEBUILTINIMPL_H_
|
||||||
|
#define GAINPUTINPUTDEVICEBUILTINIMPL_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
class InputDeviceBuiltInImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~InputDeviceBuiltInImpl() { }
|
||||||
|
virtual InputDevice::DeviceVariant GetVariant() const = 0;
|
||||||
|
virtual InputDevice::DeviceState GetState() const { return InputDevice::DS_OK; }
|
||||||
|
virtual void Update(InputDeltaState* delta) = 0;
|
||||||
|
virtual bool IsValidButton(DeviceButtonId deviceButton) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
52
lib/source/gainput/builtin/GainputInputDeviceBuiltInIos.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEBUILTINIOS_H_
|
||||||
|
#define GAINPUTINPUTDEVICEBUILTINIOS_H_
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
class InputDeviceBuiltInImplIos : public InputDeviceBuiltInImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputDeviceBuiltInImplIos(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState);
|
||||||
|
~InputDeviceBuiltInImplIos();
|
||||||
|
|
||||||
|
InputDevice::DeviceVariant GetVariant() const
|
||||||
|
{
|
||||||
|
return InputDevice::DV_STANDARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(InputDeltaState* delta);
|
||||||
|
|
||||||
|
InputDevice::DeviceState GetState() const
|
||||||
|
{
|
||||||
|
return deviceState_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidButton(DeviceButtonId deviceButton) const;
|
||||||
|
|
||||||
|
bool Vibrate(float leftMotor, float rightMotor)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pausePressed_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputManager& manager_;
|
||||||
|
InputDevice& device_;
|
||||||
|
unsigned index_;
|
||||||
|
bool padFound_;
|
||||||
|
InputState& state_;
|
||||||
|
InputState& previousState_;
|
||||||
|
InputDevice::DeviceState deviceState_;
|
||||||
|
|
||||||
|
void* motionManager_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
82
lib/source/gainput/builtin/GainputInputDeviceBuiltInIos.mm
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_PLATFORM_IOS
|
||||||
|
|
||||||
|
#include "GainputInputDeviceBuiltInImpl.h"
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
#include <gainput/GainputLog.h>
|
||||||
|
|
||||||
|
#include "GainputInputDeviceBuiltInIos.h"
|
||||||
|
|
||||||
|
#import <CoreMotion/CoreMotion.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
InputDeviceBuiltInImplIos::InputDeviceBuiltInImplIos(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState)
|
||||||
|
: pausePressed_(false),
|
||||||
|
manager_(manager),
|
||||||
|
device_(device),
|
||||||
|
index_(index),
|
||||||
|
padFound_(false),
|
||||||
|
state_(state),
|
||||||
|
previousState_(previousState),
|
||||||
|
deviceState_(InputDevice::DS_UNAVAILABLE),
|
||||||
|
motionManager_(0)
|
||||||
|
{
|
||||||
|
CMMotionManager* motionManager = [[CMMotionManager alloc] init];
|
||||||
|
[motionManager startDeviceMotionUpdates];
|
||||||
|
motionManager_ = motionManager;
|
||||||
|
deviceState_ = InputDevice::DS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDeviceBuiltInImplIos::~InputDeviceBuiltInImplIos()
|
||||||
|
{
|
||||||
|
CMMotionManager* motionManager = reinterpret_cast<CMMotionManager*>(motionManager_);
|
||||||
|
[motionManager stopDeviceMotionUpdates];
|
||||||
|
[motionManager release];
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputDeviceBuiltInImplIos::Update(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(motionManager_);
|
||||||
|
@autoreleasepool {
|
||||||
|
CMMotionManager* motionManager = reinterpret_cast<CMMotionManager*>(motionManager_);
|
||||||
|
CMDeviceMotion* motion = motionManager.deviceMotion;
|
||||||
|
if (!motion)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonAccelerationX, motion.userAcceleration.x);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonAccelerationY, motion.userAcceleration.y);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonAccelerationZ, motion.userAcceleration.z);
|
||||||
|
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGravityX, motion.gravity.x);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGravityY, motion.gravity.y);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGravityZ, motion.gravity.z);
|
||||||
|
|
||||||
|
const float gyroX = 2.0f * (motion.attitude.quaternion.x * motion.attitude.quaternion.z + motion.attitude.quaternion.w * motion.attitude.quaternion.y);
|
||||||
|
const float gyroY = 2.0f * (motion.attitude.quaternion.y * motion.attitude.quaternion.z - motion.attitude.quaternion.w * motion.attitude.quaternion.x);
|
||||||
|
const float gyroZ = 1.0f - 2.0f * (motion.attitude.quaternion.x * motion.attitude.quaternion.x + motion.attitude.quaternion.y * motion.attitude.quaternion.y);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGyroscopeX, gyroX);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGyroscopeY, gyroY);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonGyroscopeZ, gyroZ);
|
||||||
|
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonMagneticFieldX, motion.magneticField.field.x);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonMagneticFieldY, motion.magneticField.field.y);
|
||||||
|
HandleAxis(device_, state_, delta, BuiltInButtonMagneticFieldZ, motion.magneticField.field.z);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputDeviceBuiltInImplIos::IsValidButton(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
return deviceButton >= BuiltInButtonAccelerationX && deviceButton <= BuiltInButtonMagneticFieldZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
38
lib/source/gainput/builtin/GainputInputDeviceBuiltInNull.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEBUILTINNULL_H_
|
||||||
|
#define GAINPUTINPUTDEVICEBUILTINNULL_H_
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
class InputDeviceBuiltInImplNull : public InputDeviceBuiltInImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputDeviceBuiltInImplNull(InputManager& /*manager*/, InputDevice& /*device*/, unsigned /*index*/, InputState& /*state*/, InputState& /*previousState*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceVariant GetVariant() const
|
||||||
|
{
|
||||||
|
return InputDevice::DV_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(InputDeltaState* /*delta*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceState GetState() const
|
||||||
|
{
|
||||||
|
return InputDevice::DS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidButton(DeviceButtonId /*deviceButton*/) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
717
lib/source/gainput/dev/GainputDev.cpp
Normal file
@@ -0,0 +1,717 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_DEV
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
#include <android/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "GainputDev.h"
|
||||||
|
#include "GainputNetAddress.h"
|
||||||
|
#include "GainputNetListener.h"
|
||||||
|
#include "GainputNetConnection.h"
|
||||||
|
#include "GainputMemoryStream.h"
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
#include <gainput/GainputLog.h>
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
static NetListener* devListener = 0;
|
||||||
|
static NetConnection* devConnection = 0;
|
||||||
|
static InputManager* inputManager = 0;
|
||||||
|
static Allocator* allocator = 0;
|
||||||
|
static Array<const InputMap*> devMaps(GetDefaultAllocator());
|
||||||
|
static Array<const InputDevice*> devDevices(GetDefaultAllocator());
|
||||||
|
static bool devSendInfos = false;
|
||||||
|
static Array<DeviceId> devSyncedDevices(GetDefaultAllocator());
|
||||||
|
static size_t devFrame = 0;
|
||||||
|
static bool useHttp = false;
|
||||||
|
|
||||||
|
static const unsigned kMaxReadTries = 1000000;
|
||||||
|
|
||||||
|
static size_t SendMessage(Stream& stream)
|
||||||
|
{
|
||||||
|
const uint8_t length = stream.GetSize();
|
||||||
|
GAINPUT_ASSERT(length > 0);
|
||||||
|
size_t sent = devConnection->Send(&length, sizeof(length));
|
||||||
|
sent += devConnection->Send(stream);
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReadMessage(Stream& stream, bool& outFailed)
|
||||||
|
{
|
||||||
|
stream.Reset();
|
||||||
|
size_t received = devConnection->Receive(stream, 1);
|
||||||
|
if (!received)
|
||||||
|
return false;
|
||||||
|
uint8_t length;
|
||||||
|
stream.Read(length);
|
||||||
|
stream.Reset();
|
||||||
|
received = 0;
|
||||||
|
unsigned tries = 0;
|
||||||
|
bool failed = false;
|
||||||
|
while (received < length)
|
||||||
|
{
|
||||||
|
stream.SeekEnd(0);
|
||||||
|
received += devConnection->Receive(stream, length - received);
|
||||||
|
++tries;
|
||||||
|
if (tries >= kMaxReadTries)
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outFailed = failed;
|
||||||
|
if (failed)
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("GAINPUT: ReadMessage failed.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stream.SeekBegin(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DevUserButtonListener : public MappedInputListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DevUserButtonListener(const InputMap* map) : map_(map) { }
|
||||||
|
|
||||||
|
bool OnUserButtonBool(UserButtonId userButton, bool, bool newValue)
|
||||||
|
{
|
||||||
|
if (!devConnection || !devSendInfos)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(32, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdUserButtonChanged));
|
||||||
|
stream->Write(uint32_t(map_->GetId()));
|
||||||
|
stream->Write(uint32_t(userButton));
|
||||||
|
stream->Write(uint8_t(0));
|
||||||
|
stream->Write(uint8_t(newValue));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnUserButtonFloat(UserButtonId userButton, float, float newValue)
|
||||||
|
{
|
||||||
|
if (!devConnection || !devSendInfos)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(32, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdUserButtonChanged));
|
||||||
|
stream->Write(uint32_t(map_->GetId()));
|
||||||
|
stream->Write(uint32_t(userButton));
|
||||||
|
stream->Write(uint8_t(1));
|
||||||
|
stream->Write(newValue);
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const InputMap* map_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DevDeviceButtonListener : public InputListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DevDeviceButtonListener(const InputManager* inputManager) : inputManager_(inputManager) { }
|
||||||
|
|
||||||
|
bool OnDeviceButtonBool(DeviceId deviceId, DeviceButtonId deviceButton, bool, bool newValue)
|
||||||
|
{
|
||||||
|
if (!devConnection || devSyncedDevices.find(deviceId) == devSyncedDevices.end())
|
||||||
|
return true;
|
||||||
|
const InputDevice* device = inputManager_->GetDevice(deviceId);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(32, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdSetDeviceButton));
|
||||||
|
stream->Write(uint8_t(device->GetType()));
|
||||||
|
stream->Write(uint8_t(device->GetIndex()));
|
||||||
|
stream->Write(uint32_t(deviceButton));
|
||||||
|
stream->Write(uint8_t(newValue));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnDeviceButtonFloat(DeviceId deviceId, DeviceButtonId deviceButton, float, float newValue)
|
||||||
|
{
|
||||||
|
if (!devConnection || devSyncedDevices.find(deviceId) == devSyncedDevices.end())
|
||||||
|
return true;
|
||||||
|
const InputDevice* device = inputManager_->GetDevice(deviceId);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(32, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdSetDeviceButton));
|
||||||
|
stream->Write(uint8_t(device->GetType()));
|
||||||
|
stream->Write(uint8_t(device->GetIndex()));
|
||||||
|
stream->Write(uint32_t(deviceButton));
|
||||||
|
stream->Write(newValue);
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const InputManager* inputManager_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static HashMap<const InputMap*, DevUserButtonListener*> devUserButtonListeners(GetDefaultAllocator());
|
||||||
|
DevDeviceButtonListener* devDeviceButtonListener = 0;
|
||||||
|
ListenerId devDeviceButtonListenerId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SendDevice(const InputDevice* device, Stream* stream, NetConnection*)
|
||||||
|
{
|
||||||
|
const DeviceId deviceId = device->GetDeviceId();
|
||||||
|
stream->Reset();
|
||||||
|
stream->Write(uint8_t(DevCmdDevice));
|
||||||
|
stream->Write(uint32_t(device->GetDeviceId()));
|
||||||
|
char deviceName[64];
|
||||||
|
snprintf(deviceName, 64, "%s%d", device->GetTypeName(), device->GetIndex());
|
||||||
|
stream->Write(uint8_t(strlen(deviceName)));
|
||||||
|
stream->Write(deviceName, strlen(deviceName));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
|
||||||
|
for (DeviceButtonId buttonId = 0; buttonId < device->GetInputState()->GetButtonCount(); ++buttonId)
|
||||||
|
{
|
||||||
|
if (device->IsValidButtonId(buttonId))
|
||||||
|
{
|
||||||
|
stream->Reset();
|
||||||
|
stream->Write(uint8_t(DevCmdDeviceButton));
|
||||||
|
stream->Write(uint32_t(deviceId));
|
||||||
|
stream->Write(uint32_t(buttonId));
|
||||||
|
char buttonName[128];
|
||||||
|
const size_t len= device->GetButtonName(buttonId, buttonName, 128);
|
||||||
|
stream->Write(uint8_t(len));
|
||||||
|
if (len)
|
||||||
|
stream->Write(buttonName, len);
|
||||||
|
stream->Write(uint8_t(device->GetButtonType(buttonId)));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SendMap(const InputMap* map, Stream* stream, NetConnection*)
|
||||||
|
{
|
||||||
|
stream->Reset();
|
||||||
|
stream->Write(uint8_t(DevCmdMap));
|
||||||
|
stream->Write(uint32_t(map->GetId()));
|
||||||
|
stream->Write(uint8_t(strlen(map->GetName())));
|
||||||
|
stream->Write(map->GetName(), strlen(map->GetName()));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
|
||||||
|
DeviceButtonSpec mappings[32];
|
||||||
|
for (UserButtonId buttonId = 0; buttonId < 1000; ++buttonId)
|
||||||
|
{
|
||||||
|
if (map->IsMapped(buttonId))
|
||||||
|
{
|
||||||
|
const size_t n = map->GetMappings(buttonId, mappings, 32);
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
stream->Reset();
|
||||||
|
stream->Write(uint8_t(DevCmdUserButton));
|
||||||
|
stream->Write(uint32_t(map->GetId()));
|
||||||
|
stream->Write(uint32_t(buttonId));
|
||||||
|
stream->Write(uint32_t(mappings[i].deviceId));
|
||||||
|
stream->Write(uint32_t(mappings[i].buttonId));
|
||||||
|
stream->Write(map->GetFloat(buttonId));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevSetHttp(bool enable)
|
||||||
|
{
|
||||||
|
useHttp = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevInit(InputManager* manager)
|
||||||
|
{
|
||||||
|
if (devListener)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
WSADATA wsaData;
|
||||||
|
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inputManager = manager;
|
||||||
|
allocator = &manager->GetAllocator();
|
||||||
|
|
||||||
|
NetAddress address("0.0.0.0", 1211);
|
||||||
|
devListener = allocator->New<NetListener>(address, *allocator);
|
||||||
|
|
||||||
|
if (devListener->Start(false))
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("TOOL: Listening...\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("TOOL: Unable to listen\n");
|
||||||
|
allocator->Delete(devListener);
|
||||||
|
devListener = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevShutdown(const InputManager* manager)
|
||||||
|
{
|
||||||
|
if (inputManager != manager)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devConnection)
|
||||||
|
{
|
||||||
|
devConnection->Close();
|
||||||
|
allocator->Delete(devConnection);
|
||||||
|
devConnection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devListener)
|
||||||
|
{
|
||||||
|
devListener->Stop();
|
||||||
|
allocator->Delete(devListener);
|
||||||
|
devListener = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (HashMap<const InputMap*, DevUserButtonListener*>::iterator it = devUserButtonListeners.begin();
|
||||||
|
it != devUserButtonListeners.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
allocator->Delete(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devDeviceButtonListener)
|
||||||
|
{
|
||||||
|
inputManager->RemoveListener(devDeviceButtonListenerId);
|
||||||
|
allocator->Delete(devDeviceButtonListener);
|
||||||
|
devDeviceButtonListener = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DevUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
if (!devConnection && devListener)
|
||||||
|
{
|
||||||
|
devConnection = devListener->Accept();
|
||||||
|
if (!useHttp && devConnection)
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("GAINPUT: New connection\n");
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(1024, *allocator);
|
||||||
|
|
||||||
|
stream->Write(uint8_t(DevCmdHello));
|
||||||
|
stream->Write(uint32_t(DevProtocolVersion));
|
||||||
|
stream->Write(uint32_t(GetLibVersion()));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
|
||||||
|
allocator->Delete(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!devConnection)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useHttp)
|
||||||
|
{
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(128, *allocator);
|
||||||
|
stream->Reset();
|
||||||
|
size_t received = devConnection->Receive(*stream, 128);
|
||||||
|
if (received > 0)
|
||||||
|
{
|
||||||
|
char* buf = (char*)allocator->Allocate(received+1);
|
||||||
|
stream->Read(buf, received);
|
||||||
|
buf[received] = 0;
|
||||||
|
int touchDevice;
|
||||||
|
int id;
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
int down;
|
||||||
|
sscanf(buf, "GET /%i/%i/%f/%f/%i HTTP", &touchDevice, &id, &x, &y, &down);
|
||||||
|
//GAINPUT_LOG("Touch device #%d state #%d: %f/%f - %d\n", touchDevice, id, x, y, down);
|
||||||
|
allocator->Deallocate(buf);
|
||||||
|
|
||||||
|
allocator->Delete(stream);
|
||||||
|
devConnection->Close();
|
||||||
|
allocator->Delete(devConnection);
|
||||||
|
devConnection = 0;
|
||||||
|
|
||||||
|
const DeviceId deviceId = inputManager->FindDeviceId(InputDevice::DT_TOUCH, touchDevice);
|
||||||
|
InputDevice* device = inputManager->GetDevice(deviceId);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
GAINPUT_ASSERT(device->GetInputState());
|
||||||
|
GAINPUT_ASSERT(device->GetPreviousInputState());
|
||||||
|
HandleButton(*device, *device->GetInputState(), delta, Touch0Down + id*4, down != 0);
|
||||||
|
HandleAxis(*device, *device->GetInputState(), delta, Touch0X + id*4, x);
|
||||||
|
HandleAxis(*device, *device->GetInputState(), delta, Touch0Pressure + id*4, float(down)*1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(1024, *allocator);
|
||||||
|
bool readFailed = false;
|
||||||
|
while (ReadMessage(*stream, readFailed))
|
||||||
|
{
|
||||||
|
uint8_t cmd;
|
||||||
|
stream->Read(cmd);
|
||||||
|
|
||||||
|
if (cmd == DevCmdGetAllInfos)
|
||||||
|
{
|
||||||
|
devSendInfos = true;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
// Send existing devices
|
||||||
|
for (InputManager::const_iterator it = inputManager->begin();
|
||||||
|
it != inputManager->end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const InputDevice* device = it->second;
|
||||||
|
SendDevice(device, stream, devConnection);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
GAINPUT_LOG("GAINPUT: Sent %d devices.\n", count);
|
||||||
|
|
||||||
|
// Send existing maps
|
||||||
|
count = 0;
|
||||||
|
for (Array<const InputMap*>::const_iterator it = devMaps.begin();
|
||||||
|
it != devMaps.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const InputMap* map = *it;
|
||||||
|
SendMap(map, stream, devConnection);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
GAINPUT_LOG("GAINPUT: Sent %d maps.\n", count);
|
||||||
|
}
|
||||||
|
else if (cmd == DevCmdStartDeviceSync)
|
||||||
|
{
|
||||||
|
uint8_t deviceType;
|
||||||
|
uint8_t deviceIndex;
|
||||||
|
stream->Read(deviceType);
|
||||||
|
stream->Read(deviceIndex);
|
||||||
|
const DeviceId deviceId = inputManager->FindDeviceId(InputDevice::DeviceType(deviceType), deviceIndex);
|
||||||
|
InputDevice* device = inputManager->GetDevice(deviceId);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
device->SetSynced(true);
|
||||||
|
devSyncedDevices.push_back(deviceId);
|
||||||
|
GAINPUT_LOG("GAINPUT: Starting to sync device #%d.\n", deviceId);
|
||||||
|
}
|
||||||
|
else if (cmd == DevCmdSetDeviceButton)
|
||||||
|
{
|
||||||
|
uint8_t deviceType;
|
||||||
|
uint8_t deviceIndex;
|
||||||
|
uint32_t deviceButtonId;
|
||||||
|
stream->Read(deviceType);
|
||||||
|
stream->Read(deviceIndex);
|
||||||
|
stream->Read(deviceButtonId);
|
||||||
|
const DeviceId deviceId = inputManager->FindDeviceId(InputDevice::DeviceType(deviceType), deviceIndex);
|
||||||
|
InputDevice* device = inputManager->GetDevice(deviceId);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
GAINPUT_ASSERT(device->GetInputState());
|
||||||
|
GAINPUT_ASSERT(device->GetPreviousInputState());
|
||||||
|
if (device->GetButtonType(deviceButtonId) == BT_BOOL)
|
||||||
|
{
|
||||||
|
uint8_t value;
|
||||||
|
stream->Read(value);
|
||||||
|
bool boolValue = (0 != value);
|
||||||
|
HandleButton(*device, *device->GetInputState(), delta, deviceButtonId, boolValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float value;
|
||||||
|
stream->Read(value);
|
||||||
|
HandleAxis(*device, *device->GetInputState(), delta, deviceButtonId, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pingFailed = false;
|
||||||
|
if (devFrame % 100 == 0 && devConnection->IsConnected())
|
||||||
|
{
|
||||||
|
stream->Reset();
|
||||||
|
stream->Write(uint8_t(DevCmdPing));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
if (SendMessage(*stream) == 0)
|
||||||
|
{
|
||||||
|
pingFailed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allocator->Delete(stream);
|
||||||
|
|
||||||
|
if (readFailed || !devConnection->IsConnected() || pingFailed)
|
||||||
|
{
|
||||||
|
GAINPUT_LOG("GAINPUT: Disconnected\n");
|
||||||
|
devConnection->Close();
|
||||||
|
allocator->Delete(devConnection);
|
||||||
|
devConnection = 0;
|
||||||
|
|
||||||
|
for (Array<DeviceId>::iterator it = devSyncedDevices.begin();
|
||||||
|
it != devSyncedDevices.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
InputDevice* device = inputManager->GetDevice(*it);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
device->SetSynced(false);
|
||||||
|
GAINPUT_LOG("GAINPUT: Stopped syncing device #%d.\n", *it);
|
||||||
|
}
|
||||||
|
devSyncedDevices.clear();
|
||||||
|
|
||||||
|
if (devDeviceButtonListener)
|
||||||
|
{
|
||||||
|
inputManager->RemoveListener(devDeviceButtonListenerId);
|
||||||
|
allocator->Delete(devDeviceButtonListener);
|
||||||
|
devDeviceButtonListener = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++devFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevNewMap(InputMap* inputMap)
|
||||||
|
{
|
||||||
|
if (devMaps.find(inputMap) != devMaps.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
devMaps.push_back(inputMap);
|
||||||
|
|
||||||
|
DevUserButtonListener* listener = allocator->New<DevUserButtonListener>(inputMap);
|
||||||
|
devUserButtonListeners[inputMap] = listener;
|
||||||
|
inputMap->AddListener(listener);
|
||||||
|
|
||||||
|
if (devConnection && devSendInfos)
|
||||||
|
{
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(1024, *allocator);
|
||||||
|
SendMap(inputMap, stream, devConnection);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevNewUserButton(InputMap* inputMap, UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton)
|
||||||
|
{
|
||||||
|
if (!devConnection || devMaps.find(inputMap) == devMaps.end() || !devSendInfos)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(1024, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdUserButton));
|
||||||
|
stream->Write(uint32_t(inputMap->GetId()));
|
||||||
|
stream->Write(uint32_t(userButton));
|
||||||
|
stream->Write(uint32_t(device));
|
||||||
|
stream->Write(uint32_t(deviceButton));
|
||||||
|
stream->Write(inputMap->GetFloat(userButton));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevRemoveUserButton(InputMap* inputMap, UserButtonId userButton)
|
||||||
|
{
|
||||||
|
if (!devConnection || !devSendInfos)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(1024, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdRemoveUserButton));
|
||||||
|
stream->Write(uint32_t(inputMap->GetId()));
|
||||||
|
stream->Write(uint32_t(userButton));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevRemoveMap(InputMap* inputMap)
|
||||||
|
{
|
||||||
|
if (!devConnection || devMaps.find(inputMap) == devMaps.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devSendInfos)
|
||||||
|
{
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(1024, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdRemoveMap));
|
||||||
|
stream->Write(uint32_t(inputMap->GetId()));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
devMaps.erase(devMaps.find(inputMap));
|
||||||
|
|
||||||
|
HashMap<const InputMap*, DevUserButtonListener*>::iterator it = devUserButtonListeners.find(inputMap);
|
||||||
|
if (it != devUserButtonListeners.end())
|
||||||
|
{
|
||||||
|
allocator->Delete(it->second);
|
||||||
|
devUserButtonListeners.erase(it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevNewDevice(InputDevice* device)
|
||||||
|
{
|
||||||
|
if (devDevices.find(device) != devDevices.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
devDevices.push_back(device);
|
||||||
|
|
||||||
|
if (devConnection && devSendInfos)
|
||||||
|
{
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(1024, *allocator);
|
||||||
|
SendDevice(device, stream, devConnection);
|
||||||
|
allocator->Delete(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevConnect(InputManager* manager, const char* ip, unsigned port)
|
||||||
|
{
|
||||||
|
if (devConnection)
|
||||||
|
{
|
||||||
|
devConnection->Close();
|
||||||
|
allocator->Delete(devConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devListener)
|
||||||
|
{
|
||||||
|
devListener->Stop();
|
||||||
|
allocator->Delete(devListener);
|
||||||
|
devListener = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputManager = manager;
|
||||||
|
allocator = &manager->GetAllocator();
|
||||||
|
|
||||||
|
devConnection = allocator->New<NetConnection>(NetAddress(ip, port));
|
||||||
|
|
||||||
|
if (!devConnection->Connect(false) || !devConnection->IsConnected())
|
||||||
|
{
|
||||||
|
devConnection->Close();
|
||||||
|
allocator->Delete(devConnection);
|
||||||
|
devConnection = 0;
|
||||||
|
GAINPUT_LOG("GAINPUT: Unable to connect to %s:%d.\n", ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
GAINPUT_LOG("GAINPUT: Connected to %s:%d.\n", ip, port);
|
||||||
|
|
||||||
|
if (!devDeviceButtonListener)
|
||||||
|
{
|
||||||
|
devDeviceButtonListener = allocator->New<DevDeviceButtonListener>(manager);
|
||||||
|
devDeviceButtonListenerId = inputManager->AddListener(devDeviceButtonListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DevStartDeviceSync(DeviceId deviceId)
|
||||||
|
{
|
||||||
|
if (devSyncedDevices.find(deviceId) != devSyncedDevices.end()
|
||||||
|
|| !devConnection)
|
||||||
|
return;
|
||||||
|
devSyncedDevices.push_back(deviceId);
|
||||||
|
|
||||||
|
const InputDevice* device = inputManager->GetDevice(deviceId);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
|
||||||
|
Stream* stream = allocator->New<MemoryStream>(32, *allocator);
|
||||||
|
stream->Write(uint8_t(DevCmdStartDeviceSync));
|
||||||
|
stream->Write(uint8_t(device->GetType()));
|
||||||
|
stream->Write(uint8_t(device->GetIndex()));
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
|
||||||
|
// Send device state
|
||||||
|
for (DeviceButtonId buttonId = 0; buttonId < device->GetInputState()->GetButtonCount(); ++buttonId)
|
||||||
|
{
|
||||||
|
if (device->IsValidButtonId(buttonId))
|
||||||
|
{
|
||||||
|
stream->Reset();
|
||||||
|
stream->Write(uint8_t(DevCmdSetDeviceButton));
|
||||||
|
stream->Write(uint8_t(device->GetType()));
|
||||||
|
stream->Write(uint8_t(device->GetIndex()));
|
||||||
|
stream->Write(uint32_t(buttonId));
|
||||||
|
if (device->GetButtonType(buttonId) == BT_BOOL)
|
||||||
|
{
|
||||||
|
stream->Write(uint8_t(device->GetBool(buttonId)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream->Write(device->GetFloat(buttonId));
|
||||||
|
}
|
||||||
|
stream->SeekBegin(0);
|
||||||
|
SendMessage(*stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allocator->Delete(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
void
|
||||||
|
DevSetHttp(bool /*enable*/)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
52
lib/source/gainput/dev/GainputDev.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTDEV_H_
|
||||||
|
#define GAINPUTDEV_H_
|
||||||
|
|
||||||
|
#ifdef GAINPUT_DEV
|
||||||
|
|
||||||
|
#include "GainputDevProtocol.h"
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
void DevInit(InputManager* inputManager);
|
||||||
|
void DevShutdown(const InputManager* inputManager);
|
||||||
|
void DevUpdate(InputDeltaState* delta);
|
||||||
|
void DevNewMap(InputMap* inputMap);
|
||||||
|
void DevNewUserButton(InputMap* inputMap, UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton);
|
||||||
|
void DevRemoveUserButton(InputMap* inputMap, UserButtonId userButton);
|
||||||
|
void DevRemoveMap(InputMap* inputMap);
|
||||||
|
void DevNewDevice(InputDevice* device);
|
||||||
|
void DevConnect(InputManager* inputManager, const char* ip, unsigned port);
|
||||||
|
void DevStartDeviceSync(DeviceId deviceId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GAINPUT_DEV_INIT(inputManager) DevInit(inputManager)
|
||||||
|
#define GAINPUT_DEV_SHUTDOWN(inputManager) DevShutdown(inputManager)
|
||||||
|
#define GAINPUT_DEV_UPDATE(delta) DevUpdate(delta)
|
||||||
|
#define GAINPUT_DEV_NEW_MAP(inputMap) DevNewMap(inputMap)
|
||||||
|
#define GAINPUT_DEV_NEW_USER_BUTTON(inputMap, userButton, device, deviceButton) DevNewUserButton(inputMap, userButton, device, deviceButton)
|
||||||
|
#define GAINPUT_DEV_REMOVE_USER_BUTTON(inputMap, userButton) DevRemoveUserButton(inputMap, userButton)
|
||||||
|
#define GAINPUT_DEV_REMOVE_MAP(inputMap) DevRemoveMap(inputMap)
|
||||||
|
#define GAINPUT_DEV_NEW_DEVICE(device) DevNewDevice(device)
|
||||||
|
#define GAINPUT_DEV_CONNECT(inputManager, ip, port) DevConnect(inputManager, ip, port)
|
||||||
|
#define GAINPUT_DEV_START_SYNC(deviceId) DevStartDeviceSync(deviceId)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define GAINPUT_DEV_INIT(inputManager)
|
||||||
|
#define GAINPUT_DEV_SHUTDOWN(inputManager)
|
||||||
|
#define GAINPUT_DEV_UPDATE(delta)
|
||||||
|
#define GAINPUT_DEV_NEW_MAP(inputMap)
|
||||||
|
#define GAINPUT_DEV_NEW_USER_BUTTON(inputMap, userButton, device, deviceButton)
|
||||||
|
#define GAINPUT_DEV_REMOVE_USER_BUTTON(inputMap, userButton)
|
||||||
|
#define GAINPUT_DEV_REMOVE_MAP(inputMap)
|
||||||
|
#define GAINPUT_DEV_NEW_DEVICE(device)
|
||||||
|
#define GAINPUT_DEV_CONNECT(inputManager, ip, port)
|
||||||
|
#define GAINPUT_DEV_START_SYNC(device)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
28
lib/source/gainput/dev/GainputDevProtocol.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef GAINPUTDEVPROTOCOL_H_
|
||||||
|
#define GAINPUTDEVPROTOCOL_H_
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
enum DevCmd
|
||||||
|
{
|
||||||
|
DevCmdHello,
|
||||||
|
DevCmdDevice,
|
||||||
|
DevCmdDeviceButton,
|
||||||
|
DevCmdMap,
|
||||||
|
DevCmdRemoveMap,
|
||||||
|
DevCmdUserButton,
|
||||||
|
DevCmdRemoveUserButton,
|
||||||
|
DevCmdPing,
|
||||||
|
DevCmdUserButtonChanged,
|
||||||
|
DevCmdGetAllInfos,
|
||||||
|
DevCmdStartDeviceSync,
|
||||||
|
DevCmdSetDeviceButton,
|
||||||
|
};
|
||||||
|
|
||||||
|
const static unsigned DevProtocolVersion = 0x3;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
91
lib/source/gainput/dev/GainputMemoryStream.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#if defined(GAINPUT_DEV) || defined(GAINPUT_ENABLE_RECORDER)
|
||||||
|
#include "GainputMemoryStream.h"
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
MemoryStream::MemoryStream(void* data, size_t length, size_t capacity, bool ownership) :
|
||||||
|
data_(data),
|
||||||
|
length_(length),
|
||||||
|
capacity_(capacity),
|
||||||
|
ownership_(ownership),
|
||||||
|
position_(0)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryStream::MemoryStream(size_t capacity, Allocator& allocator) :
|
||||||
|
allocator_(&allocator),
|
||||||
|
length_(0),
|
||||||
|
capacity_(capacity),
|
||||||
|
ownership_(true),
|
||||||
|
position_(0)
|
||||||
|
{
|
||||||
|
data_ = this->allocator_->Allocate(capacity_);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryStream::~MemoryStream()
|
||||||
|
{
|
||||||
|
if (ownership_)
|
||||||
|
{
|
||||||
|
assert(allocator_);
|
||||||
|
allocator_->Deallocate(data_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
MemoryStream::Read(void* dest, size_t readLength)
|
||||||
|
{
|
||||||
|
assert(position_ + readLength <= length_);
|
||||||
|
memcpy(dest, (void*)( (uint8_t*)data_ + position_), readLength);
|
||||||
|
position_ += readLength;
|
||||||
|
return readLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
MemoryStream::Write(const void* src, size_t writeLength)
|
||||||
|
{
|
||||||
|
assert(position_ + writeLength <= capacity_);
|
||||||
|
memcpy((void*)( (uint8_t*)data_ + position_), src, writeLength);
|
||||||
|
position_ += writeLength;
|
||||||
|
length_ += writeLength;
|
||||||
|
return writeLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MemoryStream::SeekBegin(int offset)
|
||||||
|
{
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
position_ = offset;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MemoryStream::SeekCurrent(int offset)
|
||||||
|
{
|
||||||
|
if (offset + position_ > length_)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
position_ += offset;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MemoryStream::SeekEnd(int offset)
|
||||||
|
{
|
||||||
|
if (offset > 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
position_ = length_ + offset;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
49
lib/source/gainput/dev/GainputMemoryStream.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#ifndef GAINPUTMEMORYSTREAM_H_
|
||||||
|
#define GAINPUTMEMORYSTREAM_H_
|
||||||
|
|
||||||
|
#include "GainputStream.h"
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
class MemoryStream : public Stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemoryStream(void* data, size_t length, size_t capacity, bool ownership = false);
|
||||||
|
MemoryStream(size_t capacity, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
~MemoryStream();
|
||||||
|
|
||||||
|
size_t Read(void* dest, size_t readLength);
|
||||||
|
size_t Write(const void* src, size_t writeLength);
|
||||||
|
|
||||||
|
size_t GetSize() const { return length_; }
|
||||||
|
size_t GetLeft() const { return length_ - position_; }
|
||||||
|
|
||||||
|
bool SeekBegin(int offset);
|
||||||
|
bool SeekCurrent(int offset);
|
||||||
|
bool SeekEnd(int offset);
|
||||||
|
|
||||||
|
virtual void Reset() { length_ = 0; position_ = 0; }
|
||||||
|
|
||||||
|
bool IsEof() const
|
||||||
|
{
|
||||||
|
return position_ >= length_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GetData() { return data_; }
|
||||||
|
size_t GetPosition() const { return position_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator* allocator_;
|
||||||
|
void* data_;
|
||||||
|
size_t length_;
|
||||||
|
size_t capacity_;
|
||||||
|
bool ownership_;
|
||||||
|
|
||||||
|
size_t position_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
44
lib/source/gainput/dev/GainputNetAddress.cpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_DEV
|
||||||
|
#include "GainputNetAddress.h"
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_WIN) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
NetAddress::NetAddress(const char* ip, unsigned port)
|
||||||
|
{
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
struct in_addr inp;
|
||||||
|
if (!inet_aton(ip, &inp))
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr.sin_addr.s_addr = inp.s_addr;
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
addr.sin_addr.s_addr = inet_addr(ip);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetAddress::NetAddress(const struct sockaddr_in& rhs)
|
||||||
|
{
|
||||||
|
addr.sin_family = rhs.sin_family;
|
||||||
|
addr.sin_addr.s_addr = rhs.sin_addr.s_addr;
|
||||||
|
addr.sin_port = rhs.sin_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
53
lib/source/gainput/dev/GainputNetAddress.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef GAINPUTADDRESS_H_
|
||||||
|
#define GAINPUTADDRESS_H_
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
class NetAddress
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NetAddress(const char* ip, unsigned port);
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_WIN) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
NetAddress(const struct sockaddr_in& rhs);
|
||||||
|
|
||||||
|
const struct sockaddr_in& GetAddr() const { return addr; }
|
||||||
|
struct sockaddr_in& GetAddr() { return addr; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NetAddress& operator = (const NetAddress& rhs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_WIN) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline
|
||||||
|
NetAddress&
|
||||||
|
NetAddress::operator = (const NetAddress& rhs)
|
||||||
|
{
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_WIN) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
addr.sin_family = rhs.addr.sin_family;
|
||||||
|
addr.sin_addr.s_addr = rhs.addr.sin_addr.s_addr;
|
||||||
|
addr.sin_port = rhs.addr.sin_port;
|
||||||
|
#endif
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
261
lib/source/gainput/dev/GainputNetConnection.cpp
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_DEV
|
||||||
|
#include "GainputNetAddress.h"
|
||||||
|
#include "GainputNetConnection.h"
|
||||||
|
|
||||||
|
#include "GainputStream.h"
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_WIN) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
#include <cassert>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
NetConnection::NetConnection(const NetAddress& address, Allocator& allocator) :
|
||||||
|
allocator(allocator),
|
||||||
|
address(address),
|
||||||
|
fd(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetConnection::NetConnection(const NetAddress& remoteAddress, int fd, Allocator& allocator) :
|
||||||
|
allocator(allocator),
|
||||||
|
address(remoteAddress),
|
||||||
|
fd(fd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetConnection::~NetConnection()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetConnection::Connect(bool shouldBlock)
|
||||||
|
{
|
||||||
|
assert(fd == -1);
|
||||||
|
|
||||||
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(fd, (struct sockaddr*)&address.GetAddr(), sizeof(struct sockaddr_in)) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldBlock && fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetConnection::IsConnected() const
|
||||||
|
{
|
||||||
|
return fd != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetConnection::Close()
|
||||||
|
{
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
NetConnection::NetConnection(const NetAddress& address, Allocator& allocator) :
|
||||||
|
allocator(allocator),
|
||||||
|
address(address),
|
||||||
|
fd(INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetConnection::NetConnection(const NetAddress& remoteAddress, SOCKET fd, Allocator& allocator) :
|
||||||
|
allocator(allocator),
|
||||||
|
address(remoteAddress),
|
||||||
|
fd(fd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetConnection::~NetConnection()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetConnection::Connect(bool shouldBlock)
|
||||||
|
{
|
||||||
|
assert(fd == INVALID_SOCKET);
|
||||||
|
|
||||||
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(fd, (struct sockaddr*)&address.GetAddr(), sizeof(struct sockaddr_in)) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldBlock)
|
||||||
|
{
|
||||||
|
u_long NonBlock = 1;
|
||||||
|
if (ioctlsocket(fd, FIONBIO, &NonBlock) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetConnection::IsConnected() const
|
||||||
|
{
|
||||||
|
return fd != INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetConnection::Close()
|
||||||
|
{
|
||||||
|
if (fd == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(fd);
|
||||||
|
fd = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetConnection::IsReady(bool read, bool write)
|
||||||
|
{
|
||||||
|
fd_set read_fds;
|
||||||
|
fd_set write_fds;
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
FD_ZERO(&write_fds);
|
||||||
|
|
||||||
|
if (read)
|
||||||
|
{
|
||||||
|
FD_SET(fd, &read_fds);
|
||||||
|
}
|
||||||
|
if (write)
|
||||||
|
{
|
||||||
|
FD_SET(fd, &write_fds);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
int rc = select(sizeof(read_fds)*8, &read_fds, &write_fds, 0, &timeout);
|
||||||
|
if (rc == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
if (rc > 0)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
if (read && !FD_ISSET(fd, &read_fds))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
if (write && !FD_ISSET(fd, &write_fds))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
NetConnection::Send(const void* buf, size_t length)
|
||||||
|
{
|
||||||
|
if (!IsConnected())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert(IsConnected());
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
std::ptrdiff_t const result = send(fd, buf, length, MSG_NOSIGNAL);
|
||||||
|
if (result == -1 && errno == EPIPE)
|
||||||
|
#elif defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC)|| defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
std::ptrdiff_t const result = send(fd, buf, length, 0);
|
||||||
|
if (result == -1 && errno == EPIPE)
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
std::ptrdiff_t const result = send(fd, (const char*)buf, length, 0);
|
||||||
|
if (result == -1)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
return result >= 0 ? static_cast<std::size_t>(result) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
NetConnection::Send(Stream& stream)
|
||||||
|
{
|
||||||
|
const size_t length = stream.GetLeft();
|
||||||
|
char* buf = (char*)allocator.Allocate(length);
|
||||||
|
stream.Read(buf, length);
|
||||||
|
size_t sentLength = Send(buf, length);
|
||||||
|
allocator.Deallocate(buf);
|
||||||
|
return sentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
NetConnection::Receive(void* buffer, size_t length)
|
||||||
|
{
|
||||||
|
assert(IsConnected());
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
ssize_t receivedLength = recv(fd, (char*)buffer, length, 0);
|
||||||
|
if (receivedLength == -1)
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
int receivedLength = recv(fd, (char*)buffer, length, 0);
|
||||||
|
if (receivedLength == SOCKET_ERROR)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return receivedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
NetConnection::Receive(Stream& stream, size_t maxLength)
|
||||||
|
{
|
||||||
|
char* buf = (char*)allocator.Allocate(maxLength);
|
||||||
|
size_t receivedLength = Receive(buf, maxLength);
|
||||||
|
stream.Write(buf, receivedLength);
|
||||||
|
stream.SeekBegin(0);
|
||||||
|
allocator.Deallocate(buf);
|
||||||
|
return receivedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
47
lib/source/gainput/dev/GainputNetConnection.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef GAINPUTCONNECTION_H_
|
||||||
|
#define GAINPUTCONNECTION_H_
|
||||||
|
|
||||||
|
#include "GainputNetAddress.h"
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
class Stream;
|
||||||
|
|
||||||
|
class NetConnection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NetConnection(const NetAddress& address, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
NetConnection(const NetAddress& remoteAddress, int fd, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
NetConnection(const NetAddress& remoteAddress, SOCKET fd, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
#endif
|
||||||
|
~NetConnection();
|
||||||
|
|
||||||
|
bool Connect(bool shouldBlock);
|
||||||
|
void Close();
|
||||||
|
bool IsConnected() const;
|
||||||
|
bool IsReady(bool read, bool write);
|
||||||
|
|
||||||
|
size_t Send(const void* buffer, size_t length);
|
||||||
|
size_t Send(Stream& stream);
|
||||||
|
|
||||||
|
size_t Receive(void* buffer, size_t length);
|
||||||
|
size_t Receive(Stream& stream, size_t maxLength);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Allocator& allocator;
|
||||||
|
NetAddress address;
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
int fd;
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
SOCKET fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
185
lib/source/gainput/dev/GainputNetListener.cpp
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_DEV
|
||||||
|
#include "GainputNetAddress.h"
|
||||||
|
#include "GainputNetConnection.h"
|
||||||
|
#include "GainputNetListener.h"
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
NetListener::NetListener(const NetAddress& address, Allocator& allocator) :
|
||||||
|
address(address),
|
||||||
|
allocator(allocator),
|
||||||
|
blocking(true),
|
||||||
|
fd(-1)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NetListener::~NetListener()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetListener::Start(bool shouldBlock)
|
||||||
|
{
|
||||||
|
assert(fd == -1);
|
||||||
|
|
||||||
|
blocking = shouldBlock;
|
||||||
|
|
||||||
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldBlock && fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int sock_reuse_optval = 1;
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sock_reuse_optval, sizeof(sock_reuse_optval));
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr*)&address.GetAddr(), sizeof(struct sockaddr_in)) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(fd, 50) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetListener::Stop()
|
||||||
|
{
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetConnection*
|
||||||
|
NetListener::Accept()
|
||||||
|
{
|
||||||
|
assert(fd != -1);
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
|
int remoteFd = accept(fd, (struct sockaddr*)&addr, &addr_len);
|
||||||
|
if (remoteFd == -1)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blocking)
|
||||||
|
{
|
||||||
|
fcntl(remoteFd, F_SETFL, O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetAddress remoteAddress(addr);
|
||||||
|
NetConnection* connection = allocator.New<NetConnection>(remoteAddress, remoteFd, allocator);
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
NetListener::NetListener(const NetAddress& address, Allocator& allocator) :
|
||||||
|
address(address),
|
||||||
|
allocator(allocator),
|
||||||
|
blocking(true),
|
||||||
|
listenSocket(INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NetListener::~NetListener()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetListener::Start(bool shouldBlock)
|
||||||
|
{
|
||||||
|
assert(listenSocket == INVALID_SOCKET);
|
||||||
|
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (listenSocket == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldBlock)
|
||||||
|
{
|
||||||
|
u_long NonBlock = 1;
|
||||||
|
if (ioctlsocket(listenSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(listenSocket, (struct sockaddr*)&address.GetAddr(), sizeof(struct sockaddr_in)) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
closesocket(listenSocket);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(listenSocket, SOMAXCONN ) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
closesocket(listenSocket);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetListener::Stop()
|
||||||
|
{
|
||||||
|
if (listenSocket == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(listenSocket);
|
||||||
|
listenSocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetConnection*
|
||||||
|
NetListener::Accept()
|
||||||
|
{
|
||||||
|
assert(listenSocket != INVALID_SOCKET);
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int addr_len = sizeof(struct sockaddr_in);
|
||||||
|
SOCKET remoteSocket = accept(listenSocket, (struct sockaddr*)&addr, &addr_len);
|
||||||
|
if (remoteSocket == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
NetAddress remoteAddress(addr);
|
||||||
|
NetConnection* connection = allocator.New<NetConnection>(remoteAddress, remoteSocket, allocator);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
38
lib/source/gainput/dev/GainputNetListener.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef GAINPUTLISTENER_H_
|
||||||
|
#define GAINPUTLISTENER_H_
|
||||||
|
|
||||||
|
#include <gainput/GainputAllocator.h>
|
||||||
|
#include "GainputNetAddress.h"
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
class NetConnection;
|
||||||
|
|
||||||
|
class NetListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NetListener(const NetAddress& address, Allocator& allocator = GetDefaultAllocator());
|
||||||
|
~NetListener();
|
||||||
|
|
||||||
|
bool Start(bool shouldBlock);
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
NetConnection* Accept();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NetAddress address;
|
||||||
|
Allocator& allocator;
|
||||||
|
bool blocking;
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID) || defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
|
||||||
|
int fd;
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
SOCKET listenSocket;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
145
lib/source/gainput/dev/GainputStream.h
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#ifndef GAINPUTSTREAM_H_
|
||||||
|
#define GAINPUTSTREAM_H_
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX) || defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
#include <Winsock2.h>
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef __int16 int16_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef __int32 int32_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace gainput {
|
||||||
|
|
||||||
|
class Stream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Stream() { }
|
||||||
|
|
||||||
|
virtual size_t Read(void* dest, size_t length) = 0;
|
||||||
|
virtual size_t Write(const void* src, size_t length) = 0;
|
||||||
|
|
||||||
|
virtual size_t GetSize() const = 0;
|
||||||
|
virtual size_t GetLeft() const = 0;
|
||||||
|
|
||||||
|
virtual bool SeekBegin(int offset) = 0;
|
||||||
|
virtual bool SeekCurrent(int offset) = 0;
|
||||||
|
virtual bool SeekEnd(int offset) = 0;
|
||||||
|
|
||||||
|
virtual void Reset() = 0;
|
||||||
|
|
||||||
|
virtual bool IsEof() const = 0;
|
||||||
|
|
||||||
|
template<class T> size_t Read(T& dest) { return Read(&dest, sizeof(T)); }
|
||||||
|
template<class T> size_t Write(const T& src) { return Write(&src, sizeof(T)); }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Read(uint16_t& dest)
|
||||||
|
{
|
||||||
|
const size_t result = Read(&dest, sizeof(dest));
|
||||||
|
dest = ntohs(dest);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Read(int16_t& dest)
|
||||||
|
{
|
||||||
|
const size_t result = Read(&dest, sizeof(dest));
|
||||||
|
dest = ntohs((uint16_t)dest);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Read(uint32_t& dest)
|
||||||
|
{
|
||||||
|
const size_t result = Read(&dest, sizeof(dest));
|
||||||
|
dest = ntohl(dest);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Read(int32_t& dest)
|
||||||
|
{
|
||||||
|
const size_t result = Read(&dest, sizeof(dest));
|
||||||
|
dest = ntohl((uint32_t)dest);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Read(float& dest)
|
||||||
|
{
|
||||||
|
const size_t result = Read(&dest, sizeof(dest));
|
||||||
|
const uint32_t tmpInt = ntohl(*(uint32_t*)&dest);
|
||||||
|
const float* tmpFloatP = (float*)&tmpInt;
|
||||||
|
dest = *tmpFloatP;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Write(const uint16_t& src)
|
||||||
|
{
|
||||||
|
const uint16_t tmp = htons(src);
|
||||||
|
return Write(&tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Write(const int16_t& src)
|
||||||
|
{
|
||||||
|
const int16_t tmp = htons((uint16_t)src);
|
||||||
|
return Write(&tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Write(const uint32_t& src)
|
||||||
|
{
|
||||||
|
const uint32_t tmp = htonl(src);
|
||||||
|
return Write(&tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Write(const int32_t& src)
|
||||||
|
{
|
||||||
|
const int32_t tmp = htonl((uint32_t)src);
|
||||||
|
return Write(&tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline
|
||||||
|
size_t
|
||||||
|
Stream::Write(const float& src)
|
||||||
|
{
|
||||||
|
const uint32_t tmpInt = htonl(*(uint32_t*)&src);
|
||||||
|
const float* tmpFloatP = (float*)&tmpInt;
|
||||||
|
const float tmp = *tmpFloatP;
|
||||||
|
return Write(&tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
383
lib/source/gainput/gainput.cpp
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
\mainpage Gainput Documentation
|
||||||
|
|
||||||
|
Gainput is a C++ Open Source input library for games. It collects input data from different devices (like keyboards, mice or gamepads) and makes the inputs accessible through a unified interface. On top of that, inputs can be mapped to user-defined buttons and other advanced features are offered. Gainput aims to be a one-stop solution to acquire input from players for your game.
|
||||||
|
|
||||||
|
If there are any problems, please report them on <a href="https://github.com/jkuhlmann/gainput/issues" target="_blank">GitHub</a> or contact: <tt>gainput -a-t- johanneskuhlmann.de</tt>.
|
||||||
|
|
||||||
|
These pages are Gainput's API documentation. In order to download Gainput go to the <a href="http://gainput.johanneskuhlmann.de/" target="_blank">Gainput website</a>.
|
||||||
|
|
||||||
|
\section contents Contents
|
||||||
|
- \ref page_start
|
||||||
|
- \ref page_building
|
||||||
|
- \ref page_platforms
|
||||||
|
- \ref page_dependencies
|
||||||
|
- \ref page_faq
|
||||||
|
|
||||||
|
\section using Using Gainput
|
||||||
|
A minimal usage sample:
|
||||||
|
|
||||||
|
\code
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
|
||||||
|
// Define your user buttons somewhere global
|
||||||
|
enum Button
|
||||||
|
{
|
||||||
|
ButtonConfirm
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting up Gainput
|
||||||
|
gainput::InputManager manager;
|
||||||
|
const gainput::DeviceId mouseId = manager.CreateDevice<gainput::InputDeviceMouse>();
|
||||||
|
|
||||||
|
manager.SetDisplaySize(width, height);
|
||||||
|
|
||||||
|
gainput::InputMap map(manager);
|
||||||
|
map.MapBool(ButtonConfirm, mouseId, gainput::MouseButtonLeft);
|
||||||
|
|
||||||
|
while (game_running)
|
||||||
|
{
|
||||||
|
// Call every frame
|
||||||
|
manager.Update();
|
||||||
|
|
||||||
|
// May have to call platform-specific event-handling functions here.
|
||||||
|
|
||||||
|
// Check button state
|
||||||
|
if (map.GetBoolWasDown(ButtonConfirm))
|
||||||
|
{
|
||||||
|
// Confirmed!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
|
||||||
|
\section license License
|
||||||
|
|
||||||
|
Gainput is licensed under the MIT license:
|
||||||
|
|
||||||
|
\include "LICENSE"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\page page_start Getting Started
|
||||||
|
\tableofcontents
|
||||||
|
This page gives an overview on how to get Gainput into your game and use it for getting your players' input.
|
||||||
|
|
||||||
|
|
||||||
|
\section sect_obtaining Obtaining Gainput
|
||||||
|
Gainput can be obtained in source from <a href="https://github.com/jkuhlmann/gainput">GitHub</a>.
|
||||||
|
|
||||||
|
\section sect_building Building
|
||||||
|
Build Gainput as described on the \ref page_building page.
|
||||||
|
|
||||||
|
|
||||||
|
\section sect_integrating Integration Into Your Project
|
||||||
|
To begin with, your project should link to the dynamic or static version of the Gainput library. On Linux, the files are \c libgainput.so (dynamic library) and \c libgainputstatic.a (static library). On Windows, the filenames are \c gainput.lib (used with \c gainput.dll) and \c gainputstatic.lib. In case you decide to use the dynamic library, make sure to distribute the dynamic library together with your executable.
|
||||||
|
|
||||||
|
To have the API available, you have to include Gainput's main header file:
|
||||||
|
|
||||||
|
\code
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
You should have the \c lib/include/ folder as an include folder in your project settings for this to work. The file includes most of Gainput's other header files so that you shouldn't need to include anything else.
|
||||||
|
|
||||||
|
|
||||||
|
\section sect_setup Setting up Gainput
|
||||||
|
Gainput's most important class is gainput::InputManager. You should create one that you use throughout your game. Create some input devices using gainput::InputManager::CreateDevice(). And then, during your game loop, call gainput::InputManager::Update() every frame.
|
||||||
|
|
||||||
|
Some platform-specific function calls may be necessary, like gainput::InputManager::HandleMessage().
|
||||||
|
|
||||||
|
On top of your gainput::InputManager, you should create at least one gainput::InputMap and map some device-specific buttons to your custom user buttons using gainput::InputMap::MapBool() or gainput::InputMap::MapFloat(). This will allow you to more conventienly provide alternative input methods or enable the player to change button mappings.
|
||||||
|
|
||||||
|
|
||||||
|
\section sect_using Using Gainput
|
||||||
|
After everything has been set up, use gainput::InputMap::GetBool() or gainput::InputMap::GetFloat() (and related functions) anywhere in your game to get player input.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\page page_building Building
|
||||||
|
Gainput is built using CMake which makes it easy to build the library.
|
||||||
|
|
||||||
|
Simply run these commands:
|
||||||
|
-# `mkdir build`
|
||||||
|
-# `cd build`
|
||||||
|
-# `cmake ..`
|
||||||
|
-# `make`
|
||||||
|
|
||||||
|
There are the regular CMake build configurations from which you choose by adding one these to the `cmake` call, for example:
|
||||||
|
- `-DCMAKE_BUILD_TYPE=Debug`
|
||||||
|
- `-DCMAKE_BUILD_TYPE=Release`
|
||||||
|
|
||||||
|
Building Gainput as shown above, will build a dynamic-link library, a static-link library, and all samples. The executables can be found in the \c build/ folder.
|
||||||
|
|
||||||
|
|
||||||
|
\section sect_defines Build Configuration Defines
|
||||||
|
There is a number of defines that determine what is included in the library and how it behaves. Normally, most of these are set by the build scripts or in gainput.h, but it may be necessary to set these when doing custom builds or modifying the build process. All defines must be set during compilation of the library itself.
|
||||||
|
|
||||||
|
Name | Description
|
||||||
|
-----|------------
|
||||||
|
\c GAINPUT_DEBUG | Enables debugging of the library itself, i.e. enables a lot of internal logs and checks.
|
||||||
|
\c GAINPUT_DEV | Enables the built-in development tool server that external tools or other Gainput instances can connect to.
|
||||||
|
\c GAINPUT_ENABLE_ALL_GESTURES | Enables all gestures. Note that there is also an individual define for each gesture (see gainput::InputGesture).
|
||||||
|
\c GAINPUT_ENABLE_RECORDER | Enables recording of inputs.
|
||||||
|
\c GAINPUT_LIB_BUILD | Should be set if Gainput is being built as a library.
|
||||||
|
|
||||||
|
|
||||||
|
\section sect_android_build Android NDK
|
||||||
|
In order to cross-compile for Android, the build has to be configured differently.
|
||||||
|
|
||||||
|
Naturally, the Android NDK must be installed. Make sure that \c ANDROID_NDK_PATH is set to the absolute path to your installation. And then follow these steps:
|
||||||
|
|
||||||
|
- Run `cmake -DCMAKE_TOOLCHAIN_FILE=../extern/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DANDROID_ABI="armeabi-v7a" -DANDROID_NATIVE_API_LEVEL=android-19 -DANDROID_STL="gnustl_static"`
|
||||||
|
- Build as above.
|
||||||
|
|
||||||
|
Executing these commands will also yield both a dynamic and static library in the \c build/ folder.
|
||||||
|
|
||||||
|
|
||||||
|
\page sample_fw Sample Framework
|
||||||
|
This framework makes it easier to provide succinct samples by taking care of the platform-dependent window creation/destruction.
|
||||||
|
|
||||||
|
In a proper project, everything that is handled by the sample framework should be handled for you by some other library or engine. The sample framework is not meant for production use.
|
||||||
|
|
||||||
|
\example ../../../samples/basic/basicsample_win.cpp
|
||||||
|
Shows the most basic initialization and usage of Gainput. It has separate implementations for all supported platforms.
|
||||||
|
|
||||||
|
\example ../../../samples/basic/basicsample_linux.cpp
|
||||||
|
Shows the most basic initialization and usage of Gainput. It has separate implementations for all supported platforms.
|
||||||
|
|
||||||
|
\example ../../../samples/basic/basicsample_android.cpp
|
||||||
|
Shows the most basic initialization and usage of Gainput. It has separate implementations for all supported platforms.
|
||||||
|
|
||||||
|
\example ../../../samples/dynamic/dynamicsample.cpp
|
||||||
|
Shows how to let the user dynamically change button mappings as well as how to load and save mappings. Uses the \ref sample_fw.
|
||||||
|
|
||||||
|
\example ../../../samples/gesture/gesturesample.cpp
|
||||||
|
Shows how to use input gestures. Also shows how to implement your own custom input device. Uses the \ref sample_fw.
|
||||||
|
|
||||||
|
\example ../../../samples/listener/listenersample.cpp
|
||||||
|
Shows how to use device button listeners as well as user button listeners. Uses the \ref sample_fw.
|
||||||
|
|
||||||
|
\example ../../../samples/recording/recordingsample.cpp
|
||||||
|
Shows how to record, play and serialize/deserialize input sequences. Uses the \ref sample_fw.
|
||||||
|
|
||||||
|
\example ../../../samples/sync/syncsample.cpp
|
||||||
|
Shows how to connect two Gainput instances to each other and send the device state over the network. Uses the \ref sample_fw. Works only in the \c dev build configuration.
|
||||||
|
|
||||||
|
|
||||||
|
\page page_platforms Platform Notes
|
||||||
|
\tableofcontents
|
||||||
|
|
||||||
|
\section platform_matrix Device Support Matrix
|
||||||
|
|
||||||
|
Platform \\ Device | Built-In | Keyboard | Mouse | Pad | Touch
|
||||||
|
-------------------|----------|----------|-------|-----|------
|
||||||
|
Android NDK | YES | YES | | | YES
|
||||||
|
iOS | YES | | | YES | YES
|
||||||
|
Linux | | STD RAW | STD RAW | YES | |
|
||||||
|
Mac OS X | | YES | YES | YES | |
|
||||||
|
Windows | | STD RAW | STD RAW | YES | |
|
||||||
|
|
||||||
|
What the entries mean:
|
||||||
|
- YES: This device is supported on this platform (basically, the same as STD).
|
||||||
|
- STD: This device is supported in standard variant on this platform (gainput::InputDevice::DV_STANDARD).
|
||||||
|
- RAW: This device is supported in raw variant on this platform (gainput::InputDevice::DV_RAW).
|
||||||
|
|
||||||
|
|
||||||
|
\section platform_android Android NDK
|
||||||
|
The keyboard support is limited to hardware keyboards, including, for example, hardware home buttons.
|
||||||
|
|
||||||
|
\section platform_linux Linux
|
||||||
|
Evdev is used for the raw input variants. Evdev has permission issues on some Linux distributions where the devices (\c /dev/input/event*) are only readable by root or a specific group. If a raw device's state is gainput::InputDevice::DS_UNAVAILABLE this may very well be the cause.
|
||||||
|
|
||||||
|
These gamepads have been tested and are explicitly supported:
|
||||||
|
- Microsoft X-Box 360 pad
|
||||||
|
- Sony PLAYSTATION(R)3 Controller
|
||||||
|
|
||||||
|
\section platform_osx Mac OS X
|
||||||
|
These gamepads have been tested and are explicitly supported:
|
||||||
|
- Microsoft X-Box 360 pad
|
||||||
|
- Sony PLAYSTATION(R)3 Controller
|
||||||
|
|
||||||
|
\section platform_windows Windows
|
||||||
|
The gamepad support is implemented using XINPUT which is Microsoft's most current API for such devices. However, that means that only Xbox 360 pads and compatible devices are supported.
|
||||||
|
|
||||||
|
|
||||||
|
\page page_dependencies Dependencies
|
||||||
|
Gainput has very few external dependencies in order to make it as self-contained as possible. Normally, the only extra piece of software you might have to install is CMake. Anything else should come with your IDE (or regular platform SDK).
|
||||||
|
|
||||||
|
\section sect_libs Libraries
|
||||||
|
Most importantly, Gainput does not depend on the STL or any other unnecessary helper libraries. Input is acquired using the following methods:
|
||||||
|
|
||||||
|
Android NDK: All input is acquired through the NDK. Native App Glue is used for most inputs.
|
||||||
|
|
||||||
|
iOS:
|
||||||
|
- CoreMotion framework for built-in device sensors
|
||||||
|
- GameController framework for gamepad inputs
|
||||||
|
- UIKit for touch inputs
|
||||||
|
|
||||||
|
Linux:
|
||||||
|
- the X11 message loop is used for keyboard and mouse
|
||||||
|
- the kernel's joystick API is used for pads
|
||||||
|
|
||||||
|
Mac OS X:
|
||||||
|
- AppKit for mouse
|
||||||
|
- IOKit's IOHIDManager for keyboard and gamepads
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
- the Win32 message loop is used for keyboard and mouse
|
||||||
|
- XINPUT is used for gamepads
|
||||||
|
|
||||||
|
\section sect_building Building
|
||||||
|
Gainput is built using <a href="http://www.cmake.org/" target="_blank">CMake</a>
|
||||||
|
|
||||||
|
|
||||||
|
\page page_faq FAQ
|
||||||
|
|
||||||
|
\tableofcontents
|
||||||
|
|
||||||
|
\section faq0 Why another library when input is included in most engines/libraries?
|
||||||
|
There are lots of other ways to acquire input, most are part of more complete engines or more comprehensive libraries. For one, Gainput is meant for those who are using something without input capabilities (for example, pure rendering engines) or those who are developing something themselves and want to skip input handling.
|
||||||
|
|
||||||
|
In the long run, Gainput aims to be better and offer more advanced features than built-in input solutions. That's the reason why more advanced features, like input recording/playback, remote syncing, gestures and external tool support, are already part of the library.
|
||||||
|
|
||||||
|
|
||||||
|
\page page_devprotocol Development Tool Protocol
|
||||||
|
If Gainput is built with \c GAINPUT_DEV defined, it features a server that external tools can connect to obtain information on devices, mappings and button states. The underlying protocol is TCP/IP and the default port 1211.
|
||||||
|
|
||||||
|
The following messages are defined:
|
||||||
|
|
||||||
|
\code
|
||||||
|
hello
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t protocolVersion
|
||||||
|
uint32_t libVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
device
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t deviceId
|
||||||
|
string name
|
||||||
|
}
|
||||||
|
|
||||||
|
device button
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t deviceId
|
||||||
|
uint32_t buttonId
|
||||||
|
string name
|
||||||
|
uint8_t type
|
||||||
|
}
|
||||||
|
|
||||||
|
map
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t mapId
|
||||||
|
string name
|
||||||
|
}
|
||||||
|
|
||||||
|
remove map
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t mapId
|
||||||
|
}
|
||||||
|
|
||||||
|
user button
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t mapId
|
||||||
|
uint32_t buttonId
|
||||||
|
uint32_t deviceId
|
||||||
|
uint32_t deviceButtonId
|
||||||
|
float value
|
||||||
|
}
|
||||||
|
|
||||||
|
remove user button
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t mapId
|
||||||
|
uint32_t buttonId
|
||||||
|
}
|
||||||
|
|
||||||
|
user button changed
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint32_t mapId
|
||||||
|
uint32_t buttonId
|
||||||
|
uint8_t type
|
||||||
|
uint8_t/float value
|
||||||
|
}
|
||||||
|
|
||||||
|
ping
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
get all infos
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
start device sync
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint8_t deviceType
|
||||||
|
uint8_t deviceIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
set device button
|
||||||
|
{
|
||||||
|
uint8_t cmd
|
||||||
|
uint8_t deviceType
|
||||||
|
uint8_t deviceIndex
|
||||||
|
uint32_t deviceButtonId
|
||||||
|
uint8_t/float value
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
The message IDs (\c cmd) are defined in GainputDevProtocol.h.
|
||||||
|
|
||||||
|
Each message is prefaced with a \c uint8_t that specifies the message's length.
|
||||||
|
|
||||||
|
All integers are in network byte order.
|
||||||
|
|
||||||
|
Strings are represented like this:
|
||||||
|
|
||||||
|
\code
|
||||||
|
{
|
||||||
|
uint8_t length
|
||||||
|
char text[length] // without the trailing \0
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
const char*
|
||||||
|
GetLibName()
|
||||||
|
{
|
||||||
|
return "Gainput";
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
GetLibVersion()
|
||||||
|
{
|
||||||
|
return ((1 << GAINPUT_VER_MAJOR_SHIFT) | (0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
GetLibVersionString()
|
||||||
|
{
|
||||||
|
return "1.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
74
lib/source/gainput/gestures/GainputButtonStickGesture.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/gestures/GainputButtonStickGesture.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_BUTTON_STICK_GESTURE
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
ButtonStickGesture::ButtonStickGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputGesture(manager, device, index)
|
||||||
|
{
|
||||||
|
negativeAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
positiveAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
|
||||||
|
state_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonStickGesture::~ButtonStickGesture()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ButtonStickGesture::Initialize(DeviceId negativeAxisDevice, DeviceButtonId negativeAxis,
|
||||||
|
DeviceId positiveAxisDevice, DeviceButtonId positiveAxis)
|
||||||
|
{
|
||||||
|
negativeAxis_.deviceId = negativeAxisDevice;
|
||||||
|
negativeAxis_.buttonId = negativeAxis;
|
||||||
|
positiveAxis_.deviceId = positiveAxisDevice;
|
||||||
|
positiveAxis_.buttonId = positiveAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ButtonStickGesture::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
if (negativeAxis_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| positiveAxis_.buttonId == InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputDevice* negativeDevice = manager_.GetDevice(negativeAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(negativeDevice);
|
||||||
|
const bool isDown = negativeDevice->GetBool(negativeAxis_.buttonId);
|
||||||
|
|
||||||
|
const InputDevice* positiveDevice = manager_.GetDevice(positiveAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(positiveDevice);
|
||||||
|
const bool isDown2 = positiveDevice->GetBool(positiveAxis_.buttonId);
|
||||||
|
|
||||||
|
if (isDown && !isDown2)
|
||||||
|
{
|
||||||
|
HandleAxis(*this, *state_, delta, ButtonStickAxis, -1.0f);
|
||||||
|
}
|
||||||
|
else if (!isDown && isDown2)
|
||||||
|
{
|
||||||
|
HandleAxis(*this, *state_, delta, ButtonStickAxis, 1.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleAxis(*this, *state_, delta, ButtonStickAxis, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
124
lib/source/gainput/gestures/GainputDoubleClickGesture.cpp
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/gestures/GainputDoubleClickGesture.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_DOUBLE_CLICK_GESTURE
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
DoubleClickGesture::DoubleClickGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputGesture(manager, device, index),
|
||||||
|
timeSpan_(1000),
|
||||||
|
firstClickTime_(0),
|
||||||
|
clicksRegistered_(0),
|
||||||
|
clicksTargetCount_(2)
|
||||||
|
{
|
||||||
|
actionButton_.buttonId = InvalidDeviceButtonId;
|
||||||
|
xAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
|
||||||
|
state_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleClickGesture::~DoubleClickGesture()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DoubleClickGesture::Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, uint64_t timeSpan)
|
||||||
|
{
|
||||||
|
actionButton_.deviceId = actionButtonDevice;
|
||||||
|
actionButton_.buttonId = actionButton;
|
||||||
|
xAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
timeSpan_ = timeSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DoubleClickGesture::Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis, float xTolerance,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis, float yTolerance,
|
||||||
|
uint64_t timeSpan)
|
||||||
|
{
|
||||||
|
actionButton_.deviceId = actionButtonDevice;
|
||||||
|
actionButton_.buttonId = actionButton;
|
||||||
|
xAxis_.deviceId = xAxisDevice;
|
||||||
|
xAxis_.buttonId = xAxis;
|
||||||
|
xTolerance_ = xTolerance;
|
||||||
|
yAxis_.deviceId = yAxisDevice;
|
||||||
|
yAxis_.buttonId = yAxis;
|
||||||
|
yTolerance_ = yTolerance;
|
||||||
|
timeSpan_ = timeSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DoubleClickGesture::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
if (actionButton_.buttonId == InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputDevice* actionDevice = manager_.GetDevice(actionButton_.deviceId);
|
||||||
|
GAINPUT_ASSERT(actionDevice);
|
||||||
|
|
||||||
|
bool positionValid = false;
|
||||||
|
float clickX = 0.0f;
|
||||||
|
float clickY = 0.0f;
|
||||||
|
if (xAxis_.buttonId != InvalidDeviceButtonId && yAxis_.buttonId != InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
const InputDevice* xAxisDevice = manager_.GetDevice(xAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(xAxisDevice);
|
||||||
|
clickX = xAxisDevice->GetFloat(xAxis_.buttonId);
|
||||||
|
const InputDevice* yAxisDevice = manager_.GetDevice(yAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(yAxisDevice);
|
||||||
|
clickY = yAxisDevice->GetFloat(yAxis_.buttonId);
|
||||||
|
positionValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionDevice->GetBoolPrevious(actionButton_.buttonId)
|
||||||
|
&& !actionDevice->GetBool(actionButton_.buttonId))
|
||||||
|
{
|
||||||
|
if (clicksRegistered_ == 0)
|
||||||
|
{
|
||||||
|
firstClickTime_ = manager_.GetTime();
|
||||||
|
firstClickX_ = clickX;
|
||||||
|
firstClickY_ = clickY;
|
||||||
|
}
|
||||||
|
++clicksRegistered_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstClickTime_ + timeSpan_ < manager_.GetTime())
|
||||||
|
{
|
||||||
|
clicksRegistered_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (positionValid && clicksRegistered_ > 1
|
||||||
|
&& (Abs(clickX - firstClickX_) > xTolerance_ || Abs(clickY - firstClickY_) > yTolerance_))
|
||||||
|
{
|
||||||
|
clicksRegistered_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clicksRegistered_ >= clicksTargetCount_)
|
||||||
|
{
|
||||||
|
clicksRegistered_ = 0;
|
||||||
|
HandleButton(*this, *state_, delta, DoubleClickTriggered, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleButton(*this, *state_, delta, DoubleClickTriggered, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
134
lib/source/gainput/gestures/GainputHoldGesture.cpp
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/gestures/GainputHoldGesture.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_HOLD_GESTURE
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
HoldGesture::HoldGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputGesture(manager, device, index),
|
||||||
|
oneShotReset_(true),
|
||||||
|
firstDownTime_(0)
|
||||||
|
{
|
||||||
|
actionButton_.buttonId = InvalidDeviceButtonId;
|
||||||
|
xAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
|
||||||
|
state_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
HoldGesture::~HoldGesture()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HoldGesture::Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, bool oneShot, uint64_t timeSpan)
|
||||||
|
{
|
||||||
|
actionButton_.deviceId = actionButtonDevice;
|
||||||
|
actionButton_.buttonId = actionButton;
|
||||||
|
xAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
oneShot_ = oneShot;
|
||||||
|
timeSpan_ = timeSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HoldGesture::Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis, float xTolerance,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis, float yTolerance,
|
||||||
|
bool oneShot,
|
||||||
|
uint64_t timeSpan)
|
||||||
|
{
|
||||||
|
actionButton_.deviceId = actionButtonDevice;
|
||||||
|
actionButton_.buttonId = actionButton;
|
||||||
|
xAxis_.deviceId = xAxisDevice;
|
||||||
|
xAxis_.buttonId = xAxis;
|
||||||
|
xTolerance_ = xTolerance;
|
||||||
|
yAxis_.deviceId = yAxisDevice;
|
||||||
|
yAxis_.buttonId = yAxis;
|
||||||
|
yTolerance_ = yTolerance;
|
||||||
|
oneShot_ = oneShot;
|
||||||
|
timeSpan_ = timeSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HoldGesture::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
if (actionButton_.buttonId == InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputDevice* actionDevice = manager_.GetDevice(actionButton_.deviceId);
|
||||||
|
GAINPUT_ASSERT(actionDevice);
|
||||||
|
|
||||||
|
bool positionValid = false;
|
||||||
|
float posX = 0.0f;
|
||||||
|
float posY = 0.0f;
|
||||||
|
if (xAxis_.buttonId != InvalidDeviceButtonId && yAxis_.buttonId != InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
const InputDevice* xAxisDevice = manager_.GetDevice(xAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(xAxisDevice);
|
||||||
|
posX = xAxisDevice->GetFloat(xAxis_.buttonId);
|
||||||
|
const InputDevice* yAxisDevice = manager_.GetDevice(yAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(yAxisDevice);
|
||||||
|
posY = yAxisDevice->GetFloat(yAxis_.buttonId);
|
||||||
|
positionValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionDevice->GetBool(actionButton_.buttonId))
|
||||||
|
{
|
||||||
|
if (firstDownTime_ == 0)
|
||||||
|
{
|
||||||
|
firstDownTime_ = manager_.GetTime();
|
||||||
|
firstDownX_ = posX;
|
||||||
|
firstDownY_ = posY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oneShotReset_ = true;
|
||||||
|
firstDownTime_ = 0;
|
||||||
|
HandleButton(*this, *state_, delta, HoldTriggered, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (positionValid
|
||||||
|
&& (Abs(posX - firstDownX_) > xTolerance_ || Abs(posY - firstDownY_) > yTolerance_))
|
||||||
|
{
|
||||||
|
firstDownTime_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool downLongEnough = firstDownTime_ + timeSpan_ <= manager_.GetTime();
|
||||||
|
|
||||||
|
if (oneShot_)
|
||||||
|
{
|
||||||
|
if (downLongEnough && oneShotReset_)
|
||||||
|
{
|
||||||
|
HandleButton(*this, *state_, delta, HoldTriggered, true);
|
||||||
|
oneShotReset_ = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleButton(*this, *state_, delta, HoldTriggered, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleButton(*this, *state_, delta, HoldTriggered, downLongEnough);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
120
lib/source/gainput/gestures/GainputPinchGesture.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/gestures/GainputPinchGesture.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_PINCH_GESTURE
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
PinchGesture::PinchGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputGesture(manager, device, index),
|
||||||
|
pinching_(false)
|
||||||
|
{
|
||||||
|
downButton_.buttonId = InvalidDeviceButtonId;
|
||||||
|
xAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
downButton2_.buttonId = InvalidDeviceButtonId;
|
||||||
|
xAxis2_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis2_.buttonId = InvalidDeviceButtonId;
|
||||||
|
|
||||||
|
state_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 2);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 2);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
PinchGesture::~PinchGesture()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PinchGesture::Initialize(DeviceId downDevice, DeviceButtonId downButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis,
|
||||||
|
DeviceId down2Device, DeviceButtonId downButton2,
|
||||||
|
DeviceId xAxis2Device, DeviceButtonId xAxis2,
|
||||||
|
DeviceId yAxis2Device, DeviceButtonId yAxis2)
|
||||||
|
{
|
||||||
|
downButton_.deviceId = downDevice;
|
||||||
|
downButton_.buttonId = downButton;
|
||||||
|
xAxis_.deviceId = xAxisDevice;
|
||||||
|
xAxis_.buttonId = xAxis;
|
||||||
|
yAxis_.deviceId = yAxisDevice;
|
||||||
|
yAxis_.buttonId = yAxis;
|
||||||
|
downButton2_.deviceId = down2Device;
|
||||||
|
downButton2_.buttonId = downButton2;
|
||||||
|
xAxis2_.deviceId = xAxis2Device;
|
||||||
|
xAxis2_.buttonId = xAxis2;
|
||||||
|
yAxis2_.deviceId = yAxis2Device;
|
||||||
|
yAxis2_.buttonId = yAxis2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PinchGesture::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
if (downButton_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| xAxis_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| yAxis_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| downButton2_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| xAxis2_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| yAxis2_.buttonId == InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputDevice* downDevice = manager_.GetDevice(downButton_.deviceId);
|
||||||
|
GAINPUT_ASSERT(downDevice);
|
||||||
|
const bool isDown = downDevice->GetBool(downButton_.buttonId);
|
||||||
|
|
||||||
|
const InputDevice* downDevice2 = manager_.GetDevice(downButton2_.deviceId);
|
||||||
|
GAINPUT_ASSERT(downDevice2);
|
||||||
|
const bool isDown2 = downDevice2->GetBool(downButton2_.buttonId);
|
||||||
|
|
||||||
|
if (!isDown || !isDown2)
|
||||||
|
{
|
||||||
|
HandleButton(*this, *state_, delta, PinchTriggered, false);
|
||||||
|
pinching_ = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleButton(*this, *state_, delta, PinchTriggered, true);
|
||||||
|
|
||||||
|
const InputDevice* xAxisDevice = manager_.GetDevice(xAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(xAxisDevice);
|
||||||
|
const float posX = xAxisDevice->GetFloat(xAxis_.buttonId);
|
||||||
|
const InputDevice* yAxisDevice = manager_.GetDevice(yAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(yAxisDevice);
|
||||||
|
const float posY = yAxisDevice->GetFloat(yAxis_.buttonId);
|
||||||
|
|
||||||
|
const InputDevice* xAxis2Device = manager_.GetDevice(xAxis2_.deviceId);
|
||||||
|
GAINPUT_ASSERT(xAxis2Device);
|
||||||
|
const float posX2 = xAxis2Device->GetFloat(xAxis2_.buttonId);
|
||||||
|
const InputDevice* yAxis2Device = manager_.GetDevice(yAxis2_.deviceId);
|
||||||
|
GAINPUT_ASSERT(yAxis2Device);
|
||||||
|
const float posY2 = yAxis2Device->GetFloat(yAxis2_.buttonId);
|
||||||
|
|
||||||
|
const float xd = posX - posX2;
|
||||||
|
const float yd = posY - posY2;
|
||||||
|
const float dist = sqrtf(xd*xd + yd*yd);
|
||||||
|
|
||||||
|
if (!pinching_ && dist > 0.0f)
|
||||||
|
{
|
||||||
|
pinching_ = true;
|
||||||
|
initialDistance_ = dist;
|
||||||
|
HandleAxis(*this, *state_, delta, PinchScale, 1.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleAxis(*this, *state_, delta, PinchScale, dist / initialDistance_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
126
lib/source/gainput/gestures/GainputRotateGesture.cpp
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/gestures/GainputRotateGesture.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_ROTATE_GESTURE
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
RotateGesture::RotateGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputGesture(manager, device, index),
|
||||||
|
rotating_(false)
|
||||||
|
{
|
||||||
|
downButton_.buttonId = InvalidDeviceButtonId;
|
||||||
|
xAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis_.buttonId = InvalidDeviceButtonId;
|
||||||
|
downButton2_.buttonId = InvalidDeviceButtonId;
|
||||||
|
xAxis2_.buttonId = InvalidDeviceButtonId;
|
||||||
|
yAxis2_.buttonId = InvalidDeviceButtonId;
|
||||||
|
|
||||||
|
state_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 2);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 2);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
RotateGesture::~RotateGesture()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RotateGesture::Initialize(DeviceId downDevice, DeviceButtonId downButton,
|
||||||
|
DeviceId xAxisDevice, DeviceButtonId xAxis,
|
||||||
|
DeviceId yAxisDevice, DeviceButtonId yAxis,
|
||||||
|
DeviceId down2Device, DeviceButtonId downButton2,
|
||||||
|
DeviceId xAxis2Device, DeviceButtonId xAxis2,
|
||||||
|
DeviceId yAxis2Device, DeviceButtonId yAxis2)
|
||||||
|
{
|
||||||
|
downButton_.deviceId = downDevice;
|
||||||
|
downButton_.buttonId = downButton;
|
||||||
|
xAxis_.deviceId = xAxisDevice;
|
||||||
|
xAxis_.buttonId = xAxis;
|
||||||
|
yAxis_.deviceId = yAxisDevice;
|
||||||
|
yAxis_.buttonId = yAxis;
|
||||||
|
downButton2_.deviceId = down2Device;
|
||||||
|
downButton2_.buttonId = downButton2;
|
||||||
|
xAxis2_.deviceId = xAxis2Device;
|
||||||
|
xAxis2_.buttonId = xAxis2;
|
||||||
|
yAxis2_.deviceId = yAxis2Device;
|
||||||
|
yAxis2_.buttonId = yAxis2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RotateGesture::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
if (downButton_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| xAxis_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| yAxis_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| downButton2_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| xAxis2_.buttonId == InvalidDeviceButtonId
|
||||||
|
|| yAxis2_.buttonId == InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputDevice* downDevice = manager_.GetDevice(downButton_.deviceId);
|
||||||
|
GAINPUT_ASSERT(downDevice);
|
||||||
|
const bool isDown = downDevice->GetBool(downButton_.buttonId);
|
||||||
|
|
||||||
|
const InputDevice* downDevice2 = manager_.GetDevice(downButton2_.deviceId);
|
||||||
|
GAINPUT_ASSERT(downDevice2);
|
||||||
|
const bool isDown2 = downDevice2->GetBool(downButton2_.buttonId);
|
||||||
|
|
||||||
|
if (!isDown || !isDown2)
|
||||||
|
{
|
||||||
|
HandleButton(*this, *state_, delta, RotateTriggered, false);
|
||||||
|
rotating_ = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleButton(*this, *state_, delta, RotateTriggered, true);
|
||||||
|
|
||||||
|
const InputDevice* xAxisDevice = manager_.GetDevice(xAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(xAxisDevice);
|
||||||
|
const float posX = xAxisDevice->GetFloat(xAxis_.buttonId);
|
||||||
|
const InputDevice* yAxisDevice = manager_.GetDevice(yAxis_.deviceId);
|
||||||
|
GAINPUT_ASSERT(yAxisDevice);
|
||||||
|
const float posY = yAxisDevice->GetFloat(yAxis_.buttonId);
|
||||||
|
|
||||||
|
const InputDevice* xAxis2Device = manager_.GetDevice(xAxis2_.deviceId);
|
||||||
|
GAINPUT_ASSERT(xAxis2Device);
|
||||||
|
const float posX2 = xAxis2Device->GetFloat(xAxis2_.buttonId);
|
||||||
|
const InputDevice* yAxis2Device = manager_.GetDevice(yAxis2_.deviceId);
|
||||||
|
GAINPUT_ASSERT(yAxis2Device);
|
||||||
|
const float posY2 = yAxis2Device->GetFloat(yAxis2_.buttonId);
|
||||||
|
|
||||||
|
const float angle = atan2f(posY2 - posY, posX2 - posX);
|
||||||
|
|
||||||
|
if (!rotating_)
|
||||||
|
{
|
||||||
|
rotating_ = true;
|
||||||
|
initialAngle_ = angle;
|
||||||
|
HandleAxis(*this, *state_, delta, RotateAngle, 0.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float currentAngle = angle - initialAngle_;
|
||||||
|
if (currentAngle < 0.0f)
|
||||||
|
{
|
||||||
|
currentAngle += static_cast<float>(M_PI)*2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleAxis(*this, *state_, delta, RotateAngle, currentAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/gestures/GainputSimultaneouslyDownGesture.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_SIMULTANEOUSLY_DOWN_GESTURE
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
SimultaneouslyDownGesture::SimultaneouslyDownGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputGesture(manager, device, index),
|
||||||
|
buttons_(manager.GetAllocator())
|
||||||
|
{
|
||||||
|
state_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimultaneouslyDownGesture::~SimultaneouslyDownGesture()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SimultaneouslyDownGesture::AddButton(DeviceId device, DeviceButtonId button)
|
||||||
|
{
|
||||||
|
DeviceButtonSpec spec;
|
||||||
|
spec.deviceId = device;
|
||||||
|
spec.buttonId = button;
|
||||||
|
buttons_.push_back(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SimultaneouslyDownGesture::ClearButtons()
|
||||||
|
{
|
||||||
|
buttons_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SimultaneouslyDownGesture::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
bool allDown = !buttons_.empty();
|
||||||
|
|
||||||
|
for (Array<DeviceButtonSpec>::const_iterator it = buttons_.begin();
|
||||||
|
it != buttons_.end() && allDown;
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
const InputDevice* device = manager_.GetDevice(it->deviceId);
|
||||||
|
GAINPUT_ASSERT(device);
|
||||||
|
allDown = allDown && device->GetBool(it->buttonId);
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleButton(*this, *state_, delta, SimultaneouslyDownTriggered, allDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
71
lib/source/gainput/gestures/GainputTapGesture.cpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/gestures/GainputTapGesture.h>
|
||||||
|
|
||||||
|
#ifdef GAINPUT_ENABLE_TAP_GESTURE
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
TapGesture::TapGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||||
|
InputGesture(manager, device, index),
|
||||||
|
firstDownTime_(0)
|
||||||
|
{
|
||||||
|
actionButton_.buttonId = InvalidDeviceButtonId;
|
||||||
|
|
||||||
|
state_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager_.GetAllocator().New<InputState>(manager.GetAllocator(), 1);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TapGesture::~TapGesture()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TapGesture::Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, uint64_t timeSpan)
|
||||||
|
{
|
||||||
|
actionButton_.deviceId = actionButtonDevice;
|
||||||
|
actionButton_.buttonId = actionButton;
|
||||||
|
timeSpan_ = timeSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TapGesture::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
if (actionButton_.buttonId == InvalidDeviceButtonId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputDevice* actionDevice = manager_.GetDevice(actionButton_.deviceId);
|
||||||
|
GAINPUT_ASSERT(actionDevice);
|
||||||
|
|
||||||
|
HandleButton(*this, *state_, delta, TapTriggered, false);
|
||||||
|
|
||||||
|
if (actionDevice->GetBool(actionButton_.buttonId))
|
||||||
|
{
|
||||||
|
if (firstDownTime_ == 0)
|
||||||
|
{
|
||||||
|
firstDownTime_ = manager_.GetTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (firstDownTime_ > 0 && firstDownTime_ + timeSpan_ >= manager_.GetTime())
|
||||||
|
{
|
||||||
|
HandleButton(*this, *state_, delta, TapTriggered, true);
|
||||||
|
}
|
||||||
|
firstDownTime_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
191
lib/source/gainput/keyboard/GainputInputDeviceKeyboard.cpp
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
#include <gainput/gainput.h>
|
||||||
|
#include <gainput/GainputDebugRenderer.h>
|
||||||
|
|
||||||
|
#include "GainputInputDeviceKeyboardImpl.h"
|
||||||
|
#include "GainputKeyboardKeyNames.h"
|
||||||
|
#include <gainput/GainputInputDeltaState.h>
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
#include <gainput/GainputLog.h>
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||||
|
#include "GainputInputDeviceKeyboardLinux.h"
|
||||||
|
#include "GainputInputDeviceKeyboardEvdev.h"
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
#include "GainputInputDeviceKeyboardWin.h"
|
||||||
|
#include "GainputInputDeviceKeyboardWinRaw.h"
|
||||||
|
#elif defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
#include "GainputInputDeviceKeyboardAndroid.h"
|
||||||
|
#elif defined(GAINPUT_PLATFORM_MAC)
|
||||||
|
#include "GainputInputDeviceKeyboardMac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "GainputInputDeviceKeyboardNull.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
InputDeviceKeyboard::InputDeviceKeyboard(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant) :
|
||||||
|
InputDevice(manager, device, index == InputDevice::AutoIndex ? manager.GetDeviceCountByType(DT_KEYBOARD): index),
|
||||||
|
impl_(0),
|
||||||
|
keyNames_(manager_.GetAllocator())
|
||||||
|
{
|
||||||
|
state_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), KeyCount_);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
previousState_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), KeyCount_);
|
||||||
|
GAINPUT_ASSERT(previousState_);
|
||||||
|
|
||||||
|
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||||
|
if (variant == DV_STANDARD)
|
||||||
|
{
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceKeyboardImplLinux>(manager, *this, *state_, *previousState_);
|
||||||
|
}
|
||||||
|
else if (variant == DV_RAW)
|
||||||
|
{
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceKeyboardImplEvdev>(manager, *this, *state_, *previousState_);
|
||||||
|
}
|
||||||
|
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||||
|
if (variant == DV_STANDARD)
|
||||||
|
{
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceKeyboardImplWin>(manager, *this, *state_, *previousState_);
|
||||||
|
}
|
||||||
|
else if (variant == DV_RAW)
|
||||||
|
{
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceKeyboardImplWinRaw>(manager, *this, *state_, *previousState_);
|
||||||
|
}
|
||||||
|
#elif defined(GAINPUT_PLATFORM_ANDROID)
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceKeyboardImplAndroid>(manager, *this, *state_, *previousState_);
|
||||||
|
#elif defined(GAINPUT_PLATFORM_MAC)
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceKeyboardImplMac>(manager, *this, *state_, *previousState_);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!impl_)
|
||||||
|
{
|
||||||
|
impl_ = manager.GetAllocator().New<InputDeviceKeyboardImplNull>(manager, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
GAINPUT_ASSERT(impl_);
|
||||||
|
|
||||||
|
GetKeyboardKeyNames(keyNames_);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDeviceKeyboard::~InputDeviceKeyboard()
|
||||||
|
{
|
||||||
|
manager_.GetAllocator().Delete(state_);
|
||||||
|
manager_.GetAllocator().Delete(previousState_);
|
||||||
|
manager_.GetAllocator().Delete(impl_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDeviceKeyboard::InternalUpdate(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
impl_->Update(delta);
|
||||||
|
|
||||||
|
if ((manager_.IsDebugRenderingEnabled() || IsDebugRenderingEnabled())
|
||||||
|
&& manager_.GetDebugRenderer())
|
||||||
|
{
|
||||||
|
DebugRenderer* debugRenderer = manager_.GetDebugRenderer();
|
||||||
|
InputState* state = GetInputState();
|
||||||
|
char buf[64];
|
||||||
|
const float x = 0.2f;
|
||||||
|
float y = 0.2f;
|
||||||
|
for (int i = 0; i < KeyCount_; ++i)
|
||||||
|
{
|
||||||
|
if (state->GetBool(i))
|
||||||
|
{
|
||||||
|
GetButtonName(i, buf, 64);
|
||||||
|
debugRenderer->DrawText(x, y, buf);
|
||||||
|
y += 0.025f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceState
|
||||||
|
InputDeviceKeyboard::InternalGetState() const
|
||||||
|
{
|
||||||
|
return impl_->GetState();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceVariant
|
||||||
|
InputDeviceKeyboard::GetVariant() const
|
||||||
|
{
|
||||||
|
return impl_->GetVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputDeviceKeyboard::GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(outButtons);
|
||||||
|
GAINPUT_ASSERT(maxButtonCount > 0);
|
||||||
|
return CheckAllButtonsDown(outButtons, maxButtonCount, 0, KeyCount_);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
InputDeviceKeyboard::GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(IsValidButtonId(deviceButton));
|
||||||
|
GAINPUT_ASSERT(buffer);
|
||||||
|
GAINPUT_ASSERT(bufferLength > 0);
|
||||||
|
HashMap<Key, const char*>::const_iterator it = keyNames_.find(Key(deviceButton));
|
||||||
|
if (it == keyNames_.end())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strncpy(buffer, it->second, bufferLength);
|
||||||
|
buffer[bufferLength-1] = 0;
|
||||||
|
const size_t nameLen = strlen(it->second);
|
||||||
|
return nameLen >= bufferLength ? bufferLength : nameLen+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonType
|
||||||
|
InputDeviceKeyboard::GetButtonType(DeviceButtonId deviceButton) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(IsValidButtonId(deviceButton));
|
||||||
|
return BT_BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceButtonId
|
||||||
|
InputDeviceKeyboard::GetButtonByName(const char* name) const
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(name);
|
||||||
|
for (HashMap<Key, const char*>::const_iterator it = keyNames_.begin();
|
||||||
|
it != keyNames_.end();
|
||||||
|
++it)
|
||||||
|
{
|
||||||
|
if (strcmp(name, it->second) == 0)
|
||||||
|
{
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return InvalidDeviceButtonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputState*
|
||||||
|
InputDeviceKeyboard::GetNextInputState()
|
||||||
|
{
|
||||||
|
return impl_->GetNextInputState();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InputDeviceKeyboard::IsTextInputEnabled() const
|
||||||
|
{
|
||||||
|
return impl_->IsTextInputEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputDeviceKeyboard::SetTextInputEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
impl_->SetTextInputEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
char
|
||||||
|
InputDeviceKeyboard::GetNextCharacter()
|
||||||
|
{
|
||||||
|
return impl_->GetNextCharacter();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
206
lib/source/gainput/keyboard/GainputInputDeviceKeyboardAndroid.h
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
|
||||||
|
#ifndef GAINPUTINPUTDEVICEKEYBOARDANDROID_H_
|
||||||
|
#define GAINPUTINPUTDEVICEKEYBOARDANDROID_H_
|
||||||
|
|
||||||
|
#include <android/native_activity.h>
|
||||||
|
|
||||||
|
#include "GainputInputDeviceKeyboardImpl.h"
|
||||||
|
#include <gainput/GainputHelpers.h>
|
||||||
|
|
||||||
|
namespace gainput
|
||||||
|
{
|
||||||
|
|
||||||
|
class InputDeviceKeyboardImplAndroid : public InputDeviceKeyboardImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputDeviceKeyboardImplAndroid(InputManager& manager, InputDevice& device, InputState& state, InputState& previousState) :
|
||||||
|
manager_(manager),
|
||||||
|
device_(device),
|
||||||
|
textInputEnabled_(true),
|
||||||
|
dialect_(manager_.GetAllocator()),
|
||||||
|
state_(&state),
|
||||||
|
previousState_(&previousState),
|
||||||
|
nextState_(manager.GetAllocator(), KeyCount_),
|
||||||
|
delta_(0)
|
||||||
|
{
|
||||||
|
dialect_[AKEYCODE_SPACE] = KeySpace;
|
||||||
|
|
||||||
|
dialect_[AKEYCODE_APOSTROPHE] = KeyApostrophe;
|
||||||
|
dialect_[AKEYCODE_COMMA] = KeyComma;
|
||||||
|
|
||||||
|
dialect_[AKEYCODE_0] = Key0;
|
||||||
|
dialect_[AKEYCODE_1] = Key1;
|
||||||
|
dialect_[AKEYCODE_2] = Key2;
|
||||||
|
dialect_[AKEYCODE_3] = Key3;
|
||||||
|
dialect_[AKEYCODE_4] = Key4;
|
||||||
|
dialect_[AKEYCODE_5] = Key5;
|
||||||
|
dialect_[AKEYCODE_6] = Key6;
|
||||||
|
dialect_[AKEYCODE_7] = Key7;
|
||||||
|
dialect_[AKEYCODE_8] = Key8;
|
||||||
|
dialect_[AKEYCODE_9] = Key9;
|
||||||
|
|
||||||
|
dialect_[AKEYCODE_A] = KeyA;
|
||||||
|
dialect_[AKEYCODE_B] = KeyB;
|
||||||
|
dialect_[AKEYCODE_C] = KeyC;
|
||||||
|
dialect_[AKEYCODE_D] = KeyD;
|
||||||
|
dialect_[AKEYCODE_E] = KeyE;
|
||||||
|
dialect_[AKEYCODE_F] = KeyF;
|
||||||
|
dialect_[AKEYCODE_G] = KeyG;
|
||||||
|
dialect_[AKEYCODE_H] = KeyH;
|
||||||
|
dialect_[AKEYCODE_I] = KeyI;
|
||||||
|
dialect_[AKEYCODE_J] = KeyJ;
|
||||||
|
dialect_[AKEYCODE_K] = KeyK;
|
||||||
|
dialect_[AKEYCODE_L] = KeyL;
|
||||||
|
dialect_[AKEYCODE_M] = KeyM;
|
||||||
|
dialect_[AKEYCODE_N] = KeyN;
|
||||||
|
dialect_[AKEYCODE_O] = KeyO;
|
||||||
|
dialect_[AKEYCODE_P] = KeyP;
|
||||||
|
dialect_[AKEYCODE_Q] = KeyQ;
|
||||||
|
dialect_[AKEYCODE_R] = KeyR;
|
||||||
|
dialect_[AKEYCODE_S] = KeyS;
|
||||||
|
dialect_[AKEYCODE_T] = KeyT;
|
||||||
|
dialect_[AKEYCODE_U] = KeyU;
|
||||||
|
dialect_[AKEYCODE_V] = KeyV;
|
||||||
|
dialect_[AKEYCODE_W] = KeyW;
|
||||||
|
dialect_[AKEYCODE_X] = KeyX;
|
||||||
|
dialect_[AKEYCODE_Y] = KeyY;
|
||||||
|
dialect_[AKEYCODE_Z] = KeyZ;
|
||||||
|
|
||||||
|
dialect_[AKEYCODE_DPAD_LEFT] = KeyLeft;
|
||||||
|
dialect_[AKEYCODE_DPAD_RIGHT] = KeyRight;
|
||||||
|
dialect_[AKEYCODE_DPAD_UP] = KeyUp;
|
||||||
|
dialect_[AKEYCODE_DPAD_DOWN] = KeyDown;
|
||||||
|
dialect_[AKEYCODE_HOME] = KeyHome;
|
||||||
|
dialect_[AKEYCODE_DEL] = KeyDelete;
|
||||||
|
dialect_[AKEYCODE_PAGE_UP] = KeyPageUp;
|
||||||
|
dialect_[AKEYCODE_PAGE_DOWN] = KeyPageDown;
|
||||||
|
|
||||||
|
dialect_[AKEYCODE_TAB] = KeyTab;
|
||||||
|
dialect_[AKEYCODE_ENTER] = KeyReturn;
|
||||||
|
dialect_[AKEYCODE_SHIFT_LEFT] = KeyShiftL;
|
||||||
|
dialect_[AKEYCODE_ALT_LEFT] = KeyAltL;
|
||||||
|
dialect_[AKEYCODE_ALT_RIGHT] = KeyAltR;
|
||||||
|
dialect_[AKEYCODE_MENU] = KeyMenu;
|
||||||
|
dialect_[AKEYCODE_SHIFT_RIGHT] = KeyShiftR;
|
||||||
|
|
||||||
|
dialect_[AKEYCODE_BACKSLASH] = KeyBackslash;
|
||||||
|
dialect_[AKEYCODE_LEFT_BRACKET] = KeyBracketLeft;
|
||||||
|
dialect_[AKEYCODE_RIGHT_BRACKET] = KeyBracketRight;
|
||||||
|
dialect_[AKEYCODE_NUM] = KeyNumLock;
|
||||||
|
dialect_[AKEYCODE_GRAVE] = KeyGrave;
|
||||||
|
|
||||||
|
dialect_[AKEYCODE_BACK] = KeyBack;
|
||||||
|
dialect_[AKEYCODE_SOFT_LEFT] = KeySoftLeft;
|
||||||
|
dialect_[AKEYCODE_SOFT_RIGHT] = KeySoftRight;
|
||||||
|
dialect_[AKEYCODE_CALL] = KeyCall;
|
||||||
|
dialect_[AKEYCODE_ENDCALL] = KeyEndcall;
|
||||||
|
dialect_[AKEYCODE_STAR] = KeyStar;
|
||||||
|
dialect_[AKEYCODE_POUND] = KeyPound;
|
||||||
|
dialect_[AKEYCODE_DPAD_CENTER] = KeyDpadCenter;
|
||||||
|
dialect_[AKEYCODE_VOLUME_UP] = KeyVolumeUp;
|
||||||
|
dialect_[AKEYCODE_VOLUME_DOWN] = KeyVolumeDown;
|
||||||
|
dialect_[AKEYCODE_POWER] = KeyPower;
|
||||||
|
dialect_[AKEYCODE_CAMERA] = KeyCamera;
|
||||||
|
dialect_[AKEYCODE_CLEAR] = KeyClear;
|
||||||
|
dialect_[AKEYCODE_PERIOD] = KeyPeriod;
|
||||||
|
dialect_[AKEYCODE_SYM] = KeySymbol;
|
||||||
|
dialect_[AKEYCODE_EXPLORER] = KeyExplorer;
|
||||||
|
dialect_[AKEYCODE_ENVELOPE] = KeyEnvelope;
|
||||||
|
dialect_[AKEYCODE_MINUS] = KeyMinus;
|
||||||
|
dialect_[AKEYCODE_EQUALS] = KeyEquals;
|
||||||
|
dialect_[AKEYCODE_SEMICOLON] = KeySemicolon;
|
||||||
|
dialect_[AKEYCODE_SLASH] = KeySlash;
|
||||||
|
dialect_[AKEYCODE_AT] = KeyAt;
|
||||||
|
dialect_[AKEYCODE_HEADSETHOOK] = KeyHeadsethook;
|
||||||
|
dialect_[AKEYCODE_FOCUS] = KeyFocus;
|
||||||
|
dialect_[AKEYCODE_PLUS] = KeyPlus;
|
||||||
|
dialect_[AKEYCODE_NOTIFICATION] = KeyNotification;
|
||||||
|
dialect_[AKEYCODE_SEARCH] = KeySearch;
|
||||||
|
dialect_[AKEYCODE_MEDIA_PLAY_PAUSE] = KeyMediaPlayPause;
|
||||||
|
dialect_[AKEYCODE_MEDIA_STOP] = KeyMediaStop;
|
||||||
|
dialect_[AKEYCODE_MEDIA_NEXT] = KeyMediaNext;
|
||||||
|
dialect_[AKEYCODE_MEDIA_PREVIOUS] = KeyMediaPrevious;
|
||||||
|
dialect_[AKEYCODE_MEDIA_REWIND] = KeyMediaRewind;
|
||||||
|
dialect_[AKEYCODE_MEDIA_FAST_FORWARD] = KeyMediaFastForward;
|
||||||
|
dialect_[AKEYCODE_MUTE] = KeyMute;
|
||||||
|
dialect_[AKEYCODE_PICTSYMBOLS] = KeyPictsymbols;
|
||||||
|
dialect_[AKEYCODE_SWITCH_CHARSET] = KeySwitchCharset;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputDevice::DeviceVariant GetVariant() const
|
||||||
|
{
|
||||||
|
return InputDevice::DV_STANDARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(InputDeltaState* delta)
|
||||||
|
{
|
||||||
|
delta_ = delta;
|
||||||
|
*state_ = nextState_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTextInputEnabled() const { return textInputEnabled_; }
|
||||||
|
void SetTextInputEnabled(bool enabled) { textInputEnabled_ = enabled; }
|
||||||
|
|
||||||
|
char GetNextCharacter()
|
||||||
|
{
|
||||||
|
if (!textBuffer_.CanGet())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return textBuffer_.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
InputState* GetNextInputState()
|
||||||
|
{
|
||||||
|
return &nextState_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t HandleInput(AInputEvent* event)
|
||||||
|
{
|
||||||
|
GAINPUT_ASSERT(event);
|
||||||
|
GAINPUT_ASSERT(state_);
|
||||||
|
|
||||||
|
if (AInputEvent_getType(event) != AINPUT_EVENT_TYPE_KEY)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool pressed = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN;
|
||||||
|
const int32_t keyCode = AKeyEvent_getKeyCode(event);
|
||||||
|
if (dialect_.count(keyCode))
|
||||||
|
{
|
||||||
|
const DeviceButtonId buttonId = dialect_[keyCode];
|
||||||
|
HandleButton(device_, nextState_, delta_, buttonId, pressed);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceButtonId Translate(int keyCode) const
|
||||||
|
{
|
||||||
|
HashMap<unsigned, DeviceButtonId>::const_iterator it = dialect_.find(keyCode);
|
||||||
|
if (it != dialect_.end())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return InvalidDeviceButtonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputManager& manager_;
|
||||||
|
InputDevice& device_;
|
||||||
|
bool textInputEnabled_;
|
||||||
|
RingBuffer<GAINPUT_TEXT_INPUT_QUEUE_LENGTH, char> textBuffer_;
|
||||||
|
HashMap<unsigned, DeviceButtonId> dialect_;
|
||||||
|
InputState* state_;
|
||||||
|
InputState* previousState_;
|
||||||
|
InputState nextState_;
|
||||||
|
InputDeltaState* delta_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||