1
0
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:
Ivan Savenko
2023-07-13 12:56:54 +03:00
committed by GitHub
11 changed files with 77 additions and 3 deletions

View File

@@ -74,6 +74,8 @@
"vcmi.systemOptions.longTouchMenu.entry" : "%d milliseconds",
"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.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.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.",

View File

@@ -74,6 +74,8 @@
"vcmi.systemOptions.longTouchMenu.entry" : "%d Millisekunden",
"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.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.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",

View File

@@ -3,6 +3,7 @@
package="eu.vcmi.vcmi">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:extractNativeLibs="true"

View File

@@ -3,11 +3,14 @@ package eu.vcmi.vcmi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.VibrationEffect;
import android.os.Vibrator;
import org.libsdl.app.SDL;
import org.libsdl.app.SDLActivity;
@@ -139,6 +142,17 @@ public class NativeMethods
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)
{
final Context ctx = SDL.getContext();

View File

@@ -22,6 +22,12 @@
#include "../gui/MouseButton.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_hints.h>
#include <SDL_timer.h>
@@ -32,6 +38,7 @@ InputSourceTouch::InputSourceTouch()
params.useRelativeMode = settings["general"]["userRelativePointer"].Bool();
params.relativeModeSpeedFactor = settings["general"]["relativePointerSpeedMultiplier"].Float();
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
params.hapticFeedbackEnabled = settings["general"]["hapticFeedback"].Bool();
if (params.useRelativeMode)
state = TouchState::RELATIVE_MODE;
@@ -100,6 +107,7 @@ void InputSourceTouch::handleEventFingerDown(const SDL_TouchFingerEvent & tfinge
{
// FIXME: better place to update potentially changed settings?
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
params.hapticFeedbackEnabled = settings["general"]["hapticFeedback"].Bool();
lastTapTimeTicks = tfinger.timestamp;
@@ -215,6 +223,7 @@ void InputSourceTouch::handleUpdate()
if (currentTime > lastTapTimeTicks + params.longTouchTimeMilliseconds)
{
GH.events().dispatchShowPopup(GH.getCursorPosition());
hapticFeedback();
if (GH.windows().isTopWindowPopup())
state = TouchState::TAP_DOWN_LONG;
@@ -287,3 +296,14 @@ void InputSourceTouch::emitPinchEvent(const SDL_TouchFingerEvent & tfinger)
if (distanceOld > params.pinchSensitivityThreshold)
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
}
}

View File

@@ -79,6 +79,8 @@ struct TouchInputParameters
uint32_t pinchSensitivityThreshold = 10;
bool useRelativeMode = false;
bool hapticFeedbackEnabled = false;
};
/// Class that handles touchscreen input from SDL events
@@ -95,6 +97,8 @@ class InputSourceTouch
void emitPanningEvent(const SDL_TouchFingerEvent & tfinger);
void emitPinchEvent(const SDL_TouchFingerEvent & tfinger);
void hapticFeedback();
public:
InputSourceTouch();

View File

@@ -15,4 +15,6 @@ double screenScale();
void showLoadingIndicator();
void hideLoadingIndicator();
void hapticFeedback();
}

View File

@@ -43,4 +43,10 @@ void hideLoadingIndicator()
[indicator removeFromSuperview];
indicator = nil;
}
void hapticFeedback()
{
auto hapticGen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
[hapticGen impactOccurred];
}
}

View File

@@ -153,6 +153,10 @@ GeneralOptionsTab::GeneralOptionsTab()
{
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
addCallback("availableCreaturesAsDwellingChanged", [=](int value)
@@ -190,6 +194,10 @@ GeneralOptionsTab::GeneralOptionsTab()
std::shared_ptr<CToggleButton> framerateCheckbox = widget<CToggleButton>("framerateCheckbox");
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");
musicSlider->scrollTo(CCS->musich->getVolume());

View File

@@ -33,7 +33,8 @@
"extraDump",
"userRelativePointer",
"relativePointerSpeedMultiplier",
"longTouchTimeMilliseconds"
"longTouchTimeMilliseconds",
"hapticFeedback"
],
"properties" : {
"playerName" : {
@@ -101,6 +102,10 @@
"longTouchTimeMilliseconds" : {
"type" : "number",
"default" : 1000
},
"hapticFeedback" : {
"type" : "boolean",
"default" : false
}
}
},

View File

@@ -57,6 +57,10 @@
"name": "longTouchLabel",
"text": "vcmi.systemOptions.longTouchButton.hover",
"created" : "touchscreen"
},
{
"text": "vcmi.systemOptions.hapticFeedbackButton.hover",
"created" : "mobile"
}
]
},
@@ -76,7 +80,7 @@
"name": "scalingButton",
"type": "buttonGear",
"help": "vcmi.systemOptions.scalingButton",
"callback": "setGameScaling",
"callback": "setGameScaling"
},
{
"name": "fullscreenBorderlessCheckbox",
@@ -106,6 +110,12 @@
"help": "vcmi.systemOptions.longTouchButton",
"callback": "setLongTouchDuration",
"created" : "touchscreen"
},
{
"name": "hapticFeedbackCheckbox",
"help": "vcmi.systemOptions.hapticFeedbackButton",
"callback": "hapticFeedbackChanged",
"created" : "mobile"
}
]
},