mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Merge pull request #2301 from Laserlicht/haptic_feedback
Haptic feedback
This commit is contained in:
@@ -74,6 +74,8 @@
|
|||||||
"vcmi.systemOptions.longTouchMenu.entry" : "%d milliseconds",
|
"vcmi.systemOptions.longTouchMenu.entry" : "%d milliseconds",
|
||||||
"vcmi.systemOptions.framerateButton.hover" : "Show FPS",
|
"vcmi.systemOptions.framerateButton.hover" : "Show FPS",
|
||||||
"vcmi.systemOptions.framerateButton.help" : "{Show FPS}\n\nToggle the visibility of the Frames Per Second counter in the corner of the game window",
|
"vcmi.systemOptions.framerateButton.help" : "{Show FPS}\n\nToggle the visibility of the Frames Per Second counter in the corner of the game window",
|
||||||
|
"vcmi.systemOptions.hapticFeedbackButton.hover" : "Haptic feedback",
|
||||||
|
"vcmi.systemOptions.hapticFeedbackButton.help" : "{Haptic feedback}\n\nToggle the haptic feedback on touch inputs",
|
||||||
|
|
||||||
"vcmi.adventureOptions.infoBarPick.hover" : "Show Messages in Info Panel",
|
"vcmi.adventureOptions.infoBarPick.hover" : "Show Messages in Info Panel",
|
||||||
"vcmi.adventureOptions.infoBarPick.help" : "{Show Messages in Info Panel}\n\nWhenever possible, game messages from visiting map objects will be shown in the info panel, instead of popping up in a separate window.",
|
"vcmi.adventureOptions.infoBarPick.help" : "{Show Messages in Info Panel}\n\nWhenever possible, game messages from visiting map objects will be shown in the info panel, instead of popping up in a separate window.",
|
||||||
|
@@ -74,6 +74,8 @@
|
|||||||
"vcmi.systemOptions.longTouchMenu.entry" : "%d Millisekunden",
|
"vcmi.systemOptions.longTouchMenu.entry" : "%d Millisekunden",
|
||||||
"vcmi.systemOptions.framerateButton.hover" : "FPS anzeigen",
|
"vcmi.systemOptions.framerateButton.hover" : "FPS anzeigen",
|
||||||
"vcmi.systemOptions.framerateButton.help" : "{FPS anzeigen}\n\n Schaltet die Sichtbarkeit des Zählers für die Bilder pro Sekunde in der Ecke des Spielfensters um.",
|
"vcmi.systemOptions.framerateButton.help" : "{FPS anzeigen}\n\n Schaltet die Sichtbarkeit des Zählers für die Bilder pro Sekunde in der Ecke des Spielfensters um.",
|
||||||
|
"vcmi.systemOptions.hapticFeedbackButton.hover" : "Haptisches Feedback",
|
||||||
|
"vcmi.systemOptions.hapticFeedbackButton.help" : "{Haptisches Feedback}\n\nHaptisches Feedback bei Touch-Eingaben.",
|
||||||
|
|
||||||
"vcmi.adventureOptions.infoBarPick.hover" : "Meldungen im Infobereich anzeigen",
|
"vcmi.adventureOptions.infoBarPick.hover" : "Meldungen im Infobereich anzeigen",
|
||||||
"vcmi.adventureOptions.infoBarPick.help" : "{Meldungen im Infobereich anzeigen}\n\nWann immer möglich, werden Spielnachrichten von besuchten Kartenobjekten in der Infoleiste angezeigt, anstatt als Popup-Fenster zu erscheinen",
|
"vcmi.adventureOptions.infoBarPick.help" : "{Meldungen im Infobereich anzeigen}\n\nWann immer möglich, werden Spielnachrichten von besuchten Kartenobjekten in der Infoleiste angezeigt, anstatt als Popup-Fenster zu erscheinen",
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
package="eu.vcmi.vcmi">
|
package="eu.vcmi.vcmi">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:extractNativeLibs="true"
|
android:extractNativeLibs="true"
|
||||||
@@ -50,4 +51,4 @@
|
|||||||
android:exported="false"/>
|
android:exported="false"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@@ -3,11 +3,14 @@ package eu.vcmi.vcmi;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.os.VibrationEffect;
|
||||||
|
import android.os.Vibrator;
|
||||||
|
|
||||||
import org.libsdl.app.SDL;
|
import org.libsdl.app.SDL;
|
||||||
import org.libsdl.app.SDLActivity;
|
import org.libsdl.app.SDLActivity;
|
||||||
@@ -138,6 +141,17 @@ public class NativeMethods
|
|||||||
{
|
{
|
||||||
internalProgressDisplay(false);
|
internalProgressDisplay(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings(Const.JNI_METHOD_SUPPRESS)
|
||||||
|
public static void hapticFeedback()
|
||||||
|
{
|
||||||
|
final Context ctx = SDL.getContext();
|
||||||
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
((Vibrator) ctx.getSystemService(ctx.VIBRATOR_SERVICE)).vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK));
|
||||||
|
} else {
|
||||||
|
((Vibrator) ctx.getSystemService(ctx.VIBRATOR_SERVICE)).vibrate(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void internalProgressDisplay(final boolean show)
|
private static void internalProgressDisplay(final boolean show)
|
||||||
{
|
{
|
||||||
|
@@ -22,6 +22,12 @@
|
|||||||
#include "../gui/MouseButton.h"
|
#include "../gui/MouseButton.h"
|
||||||
#include "../gui/WindowHandler.h"
|
#include "../gui/WindowHandler.h"
|
||||||
|
|
||||||
|
#if defined(VCMI_ANDROID)
|
||||||
|
#include "../../lib/CAndroidVMHelper.h"
|
||||||
|
#elif defined(VCMI_IOS)
|
||||||
|
#include "../ios/utils.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <SDL_events.h>
|
#include <SDL_events.h>
|
||||||
#include <SDL_hints.h>
|
#include <SDL_hints.h>
|
||||||
#include <SDL_timer.h>
|
#include <SDL_timer.h>
|
||||||
@@ -32,6 +38,7 @@ InputSourceTouch::InputSourceTouch()
|
|||||||
params.useRelativeMode = settings["general"]["userRelativePointer"].Bool();
|
params.useRelativeMode = settings["general"]["userRelativePointer"].Bool();
|
||||||
params.relativeModeSpeedFactor = settings["general"]["relativePointerSpeedMultiplier"].Float();
|
params.relativeModeSpeedFactor = settings["general"]["relativePointerSpeedMultiplier"].Float();
|
||||||
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
|
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
|
||||||
|
params.hapticFeedbackEnabled = settings["general"]["hapticFeedback"].Bool();
|
||||||
|
|
||||||
if (params.useRelativeMode)
|
if (params.useRelativeMode)
|
||||||
state = TouchState::RELATIVE_MODE;
|
state = TouchState::RELATIVE_MODE;
|
||||||
@@ -100,6 +107,7 @@ void InputSourceTouch::handleEventFingerDown(const SDL_TouchFingerEvent & tfinge
|
|||||||
{
|
{
|
||||||
// FIXME: better place to update potentially changed settings?
|
// FIXME: better place to update potentially changed settings?
|
||||||
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
|
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
|
||||||
|
params.hapticFeedbackEnabled = settings["general"]["hapticFeedback"].Bool();
|
||||||
|
|
||||||
lastTapTimeTicks = tfinger.timestamp;
|
lastTapTimeTicks = tfinger.timestamp;
|
||||||
|
|
||||||
@@ -215,6 +223,7 @@ void InputSourceTouch::handleUpdate()
|
|||||||
if (currentTime > lastTapTimeTicks + params.longTouchTimeMilliseconds)
|
if (currentTime > lastTapTimeTicks + params.longTouchTimeMilliseconds)
|
||||||
{
|
{
|
||||||
GH.events().dispatchShowPopup(GH.getCursorPosition());
|
GH.events().dispatchShowPopup(GH.getCursorPosition());
|
||||||
|
hapticFeedback();
|
||||||
|
|
||||||
if (GH.windows().isTopWindowPopup())
|
if (GH.windows().isTopWindowPopup())
|
||||||
state = TouchState::TAP_DOWN_LONG;
|
state = TouchState::TAP_DOWN_LONG;
|
||||||
@@ -287,3 +296,14 @@ void InputSourceTouch::emitPinchEvent(const SDL_TouchFingerEvent & tfinger)
|
|||||||
if (distanceOld > params.pinchSensitivityThreshold)
|
if (distanceOld > params.pinchSensitivityThreshold)
|
||||||
GH.events().dispatchGesturePinch(lastTapPosition, distanceNew / distanceOld);
|
GH.events().dispatchGesturePinch(lastTapPosition, distanceNew / distanceOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputSourceTouch::hapticFeedback() {
|
||||||
|
if(params.hapticFeedbackEnabled) {
|
||||||
|
#if defined(VCMI_ANDROID)
|
||||||
|
CAndroidVMHelper vmHelper;
|
||||||
|
vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "hapticFeedback");
|
||||||
|
#elif defined(VCMI_IOS)
|
||||||
|
iOS_utils::hapticFeedback();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -79,6 +79,8 @@ struct TouchInputParameters
|
|||||||
uint32_t pinchSensitivityThreshold = 10;
|
uint32_t pinchSensitivityThreshold = 10;
|
||||||
|
|
||||||
bool useRelativeMode = false;
|
bool useRelativeMode = false;
|
||||||
|
|
||||||
|
bool hapticFeedbackEnabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Class that handles touchscreen input from SDL events
|
/// Class that handles touchscreen input from SDL events
|
||||||
@@ -94,6 +96,8 @@ class InputSourceTouch
|
|||||||
|
|
||||||
void emitPanningEvent(const SDL_TouchFingerEvent & tfinger);
|
void emitPanningEvent(const SDL_TouchFingerEvent & tfinger);
|
||||||
void emitPinchEvent(const SDL_TouchFingerEvent & tfinger);
|
void emitPinchEvent(const SDL_TouchFingerEvent & tfinger);
|
||||||
|
|
||||||
|
void hapticFeedback();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InputSourceTouch();
|
InputSourceTouch();
|
||||||
|
@@ -15,4 +15,6 @@ double screenScale();
|
|||||||
|
|
||||||
void showLoadingIndicator();
|
void showLoadingIndicator();
|
||||||
void hideLoadingIndicator();
|
void hideLoadingIndicator();
|
||||||
|
|
||||||
|
void hapticFeedback();
|
||||||
}
|
}
|
||||||
|
@@ -43,4 +43,10 @@ void hideLoadingIndicator()
|
|||||||
[indicator removeFromSuperview];
|
[indicator removeFromSuperview];
|
||||||
indicator = nil;
|
indicator = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hapticFeedback()
|
||||||
|
{
|
||||||
|
auto hapticGen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
|
||||||
|
[hapticGen impactOccurred];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -153,6 +153,10 @@ GeneralOptionsTab::GeneralOptionsTab()
|
|||||||
{
|
{
|
||||||
setBoolSetting("video", "showfps", value);
|
setBoolSetting("video", "showfps", value);
|
||||||
});
|
});
|
||||||
|
addCallback("hapticFeedbackChanged", [](bool value)
|
||||||
|
{
|
||||||
|
setBoolSetting("general", "hapticFeedback", value);
|
||||||
|
});
|
||||||
|
|
||||||
//moved from "other" tab that is disabled for now to avoid excessible tabs with barely any content
|
//moved from "other" tab that is disabled for now to avoid excessible tabs with barely any content
|
||||||
addCallback("availableCreaturesAsDwellingChanged", [=](int value)
|
addCallback("availableCreaturesAsDwellingChanged", [=](int value)
|
||||||
@@ -190,6 +194,10 @@ GeneralOptionsTab::GeneralOptionsTab()
|
|||||||
std::shared_ptr<CToggleButton> framerateCheckbox = widget<CToggleButton>("framerateCheckbox");
|
std::shared_ptr<CToggleButton> framerateCheckbox = widget<CToggleButton>("framerateCheckbox");
|
||||||
framerateCheckbox->setSelected(settings["video"]["showfps"].Bool());
|
framerateCheckbox->setSelected(settings["video"]["showfps"].Bool());
|
||||||
|
|
||||||
|
std::shared_ptr<CToggleButton> hapticFeedbackCheckbox = widget<CToggleButton>("hapticFeedbackCheckbox");
|
||||||
|
if (hapticFeedbackCheckbox)
|
||||||
|
hapticFeedbackCheckbox->setSelected(settings["general"]["hapticFeedback"].Bool());
|
||||||
|
|
||||||
std::shared_ptr<CSlider> musicSlider = widget<CSlider>("musicSlider");
|
std::shared_ptr<CSlider> musicSlider = widget<CSlider>("musicSlider");
|
||||||
musicSlider->scrollTo(CCS->musich->getVolume());
|
musicSlider->scrollTo(CCS->musich->getVolume());
|
||||||
|
|
||||||
|
@@ -33,7 +33,8 @@
|
|||||||
"extraDump",
|
"extraDump",
|
||||||
"userRelativePointer",
|
"userRelativePointer",
|
||||||
"relativePointerSpeedMultiplier",
|
"relativePointerSpeedMultiplier",
|
||||||
"longTouchTimeMilliseconds"
|
"longTouchTimeMilliseconds",
|
||||||
|
"hapticFeedback"
|
||||||
],
|
],
|
||||||
"properties" : {
|
"properties" : {
|
||||||
"playerName" : {
|
"playerName" : {
|
||||||
@@ -101,6 +102,10 @@
|
|||||||
"longTouchTimeMilliseconds" : {
|
"longTouchTimeMilliseconds" : {
|
||||||
"type" : "number",
|
"type" : "number",
|
||||||
"default" : 1000
|
"default" : 1000
|
||||||
|
},
|
||||||
|
"hapticFeedback" : {
|
||||||
|
"type" : "boolean",
|
||||||
|
"default" : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -57,6 +57,10 @@
|
|||||||
"name": "longTouchLabel",
|
"name": "longTouchLabel",
|
||||||
"text": "vcmi.systemOptions.longTouchButton.hover",
|
"text": "vcmi.systemOptions.longTouchButton.hover",
|
||||||
"created" : "touchscreen"
|
"created" : "touchscreen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "vcmi.systemOptions.hapticFeedbackButton.hover",
|
||||||
|
"created" : "mobile"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -76,7 +80,7 @@
|
|||||||
"name": "scalingButton",
|
"name": "scalingButton",
|
||||||
"type": "buttonGear",
|
"type": "buttonGear",
|
||||||
"help": "vcmi.systemOptions.scalingButton",
|
"help": "vcmi.systemOptions.scalingButton",
|
||||||
"callback": "setGameScaling",
|
"callback": "setGameScaling"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fullscreenBorderlessCheckbox",
|
"name": "fullscreenBorderlessCheckbox",
|
||||||
@@ -106,6 +110,12 @@
|
|||||||
"help": "vcmi.systemOptions.longTouchButton",
|
"help": "vcmi.systemOptions.longTouchButton",
|
||||||
"callback": "setLongTouchDuration",
|
"callback": "setLongTouchDuration",
|
||||||
"created" : "touchscreen"
|
"created" : "touchscreen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hapticFeedbackCheckbox",
|
||||||
|
"help": "vcmi.systemOptions.hapticFeedbackButton",
|
||||||
|
"callback": "hapticFeedbackChanged",
|
||||||
|
"created" : "mobile"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user