Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add amplitude argument to Input.vibrate_handheld #91143

Merged
merged 1 commit into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions core/input/input.compat.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**************************************************************************/
/* input.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/

#ifndef DISABLE_DEPRECATED

void Input::_vibrate_handheld_bind_compat_91143(int p_duration_ms) {
vibrate_handheld(p_duration_ms, -1.0);
}

void Input::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::_vibrate_handheld_bind_compat_91143, DEFVAL(500));
}

#endif // DISABLE_DEPRECATED
7 changes: 4 additions & 3 deletions core/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
/**************************************************************************/

#include "input.h"
#include "input.compat.inc"

#include "core/config/project_settings.h"
#include "core/input/default_controller_mappings.h"
Expand Down Expand Up @@ -120,7 +121,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500));
ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms", "amplitude"), &Input::vibrate_handheld, DEFVAL(500), DEFVAL(-1.0));
ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);
Expand Down Expand Up @@ -803,8 +804,8 @@ void Input::stop_joy_vibration(int p_device) {
joy_vibration[p_device] = vibration;
}

void Input::vibrate_handheld(int p_duration_ms) {
OS::get_singleton()->vibrate_handheld(p_duration_ms);
void Input::vibrate_handheld(int p_duration_ms, float p_amplitude) {
OS::get_singleton()->vibrate_handheld(p_duration_ms, p_amplitude);
}

void Input::set_gravity(const Vector3 &p_gravity) {
Expand Down
7 changes: 6 additions & 1 deletion core/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ class Input : public Object {

EventDispatchFunc event_dispatch_function = nullptr;

#ifndef DISABLE_DEPRECATED
void _vibrate_handheld_bind_compat_91143(int p_duration_ms = 500);
static void _bind_compatibility_methods();
#endif // DISABLE_DEPRECATED

protected:
static void _bind_methods();

Expand Down Expand Up @@ -323,7 +328,7 @@ class Input : public Object {

void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
void stop_joy_vibration(int p_device);
void vibrate_handheld(int p_duration_ms = 500);
void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0);

void set_mouse_position(const Point2 &p_posf);

Expand Down
2 changes: 1 addition & 1 deletion core/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class OS {
virtual int get_process_id() const;
virtual bool is_process_running(const ProcessID &p_pid) const = 0;
virtual int get_process_exit_code(const ProcessID &p_pid) const = 0;
virtual void vibrate_handheld(int p_duration_ms = 500) {}
virtual void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0) {}

virtual Error shell_open(const String &p_uri);
virtual Error shell_show_in_file_manager(String p_path, bool p_open_folder = true);
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/Input.xml
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,14 @@
<method name="vibrate_handheld">
<return type="void" />
<param index="0" name="duration_ms" type="int" default="500" />
<param index="1" name="amplitude" type="float" default="-1.0" />
<description>
[b]Note:[/b] While [code skip-lint]amplitude[/code] expects a value between 0 and 1, -1 does the default amplitude for the device.
Vibrate the handheld device for the specified duration in milliseconds.
[b]Note:[/b] This method is implemented on Android, iOS, and Web. It has no effect on other platforms.
[b]Note:[/b] For Android, [method vibrate_handheld] requires enabling the [code]VIBRATE[/code] permission in the export preset. Otherwise, [method vibrate_handheld] will have no effect.
[b]Note:[/b] For iOS, specifying the duration is only supported in iOS 13 and later.
[b]Note:[/b] For Web, the amplitude cannot be changed.
[b]Note:[/b] Some web browsers such as Safari and Firefox for Android do not support [method vibrate_handheld].
</description>
</method>
Expand Down
7 changes: 7 additions & 0 deletions misc/extension_api_validation/4.2-stable.expected
Original file line number Diff line number Diff line change
Expand Up @@ -337,3 +337,10 @@ GH-91098
Validate extension JSON: Error: Field 'classes/RichTextLabel/methods/remove_paragraph/arguments': size changed value in new API, from 1 to 2.

Added optional argument. Compatibility method registered.

RadiantUwU marked this conversation as resolved.
Show resolved Hide resolved

GH-91143
--------
Validate extension JSON: Error: Field 'classes/Input/methods/vibrate_handheld/arguments': size changed value in new API, from 1 to 2.

Added optional argument. Compatibility method registered.
RadiantUwU marked this conversation as resolved.
Show resolved Hide resolved
21 changes: 15 additions & 6 deletions platform/android/java/lib/src/org/godotengine/godot/Godot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -894,16 +894,25 @@ class Godot(private val context: Context) : SensorEventListener {
*/
@SuppressLint("MissingPermission")
@Keep
private fun vibrate(durationMs: Int) {
private fun vibrate(durationMs: Int, amplitude: Int) {
if (durationMs > 0 && requestPermission("VIBRATE")) {
val vibratorService = getActivity()?.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator? ?: return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibratorService.vibrate(
VibrationEffect.createOneShot(
durationMs.toLong(),
VibrationEffect.DEFAULT_AMPLITUDE
if (amplitude <= -1) {
vibratorService.vibrate(
VibrationEffect.createOneShot(
durationMs.toLong(),
VibrationEffect.DEFAULT_AMPLITUDE
)
)
)
} else {
vibratorService.vibrate(
VibrationEffect.createOneShot(
durationMs.toLong(),
amplitude
)
)
}
} else {
// deprecated in API 26
vibratorService.vibrate(durationMs.toLong())
Expand Down
13 changes: 10 additions & 3 deletions platform/android/java_godot_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
_get_granted_permissions = p_env->GetMethodID(godot_class, "getGrantedPermissions", "()[Ljava/lang/String;");
_get_ca_certificates = p_env->GetMethodID(godot_class, "getCACertificates", "()Ljava/lang/String;");
_init_input_devices = p_env->GetMethodID(godot_class, "initInputDevices", "()V");
_vibrate = p_env->GetMethodID(godot_class, "vibrate", "(I)V");
_vibrate = p_env->GetMethodID(godot_class, "vibrate", "(II)V");
_get_input_fallback_mapping = p_env->GetMethodID(godot_class, "getInputFallbackMapping", "()Ljava/lang/String;");
_on_godot_setup_completed = p_env->GetMethodID(godot_class, "onGodotSetupCompleted", "()V");
_on_godot_main_loop_started = p_env->GetMethodID(godot_class, "onGodotMainLoopStarted", "()V");
Expand Down Expand Up @@ -331,11 +331,18 @@ void GodotJavaWrapper::init_input_devices() {
}
}

void GodotJavaWrapper::vibrate(int p_duration_ms) {
void GodotJavaWrapper::vibrate(int p_duration_ms, float p_amplitude) {
if (_vibrate) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL(env);
env->CallVoidMethod(godot_instance, _vibrate, p_duration_ms);

int j_amplitude = -1.0;

if (p_amplitude != -1.0) {
j_amplitude = CLAMP(int(p_amplitude * 255), 1, 255);
}

env->CallVoidMethod(godot_instance, _vibrate, p_duration_ms, j_amplitude);
}
}

Expand Down
2 changes: 1 addition & 1 deletion platform/android/java_godot_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class GodotJavaWrapper {
Vector<String> get_granted_permissions() const;
String get_ca_certificates() const;
void init_input_devices();
void vibrate(int p_duration_ms);
void vibrate(int p_duration_ms, float p_amplitude = -1.0);
String get_input_fallback_mapping();
int create_new_godot_instance(const List<String> &args);
void begin_benchmark_measure(const String &p_context, const String &p_label);
Expand Down
4 changes: 2 additions & 2 deletions platform/android/os_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,8 +746,8 @@ ANativeWindow *OS_Android::get_native_window() const {
#endif
}

void OS_Android::vibrate_handheld(int p_duration_ms) {
godot_java->vibrate(p_duration_ms);
void OS_Android::vibrate_handheld(int p_duration_ms, float p_amplitude) {
godot_java->vibrate(p_duration_ms, p_amplitude);
}

String OS_Android::get_config_path() const {
Expand Down
2 changes: 1 addition & 1 deletion platform/android/os_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class OS_Android : public OS_Unix {

virtual Error move_to_trash(const String &p_path) override;

void vibrate_handheld(int p_duration_ms) override;
void vibrate_handheld(int p_duration_ms, float p_amplitude = -1.0) override;

virtual String get_config_path() const override;

Expand Down
2 changes: 1 addition & 1 deletion platform/ios/ios.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class iOS : public Object {
static void alert(const char *p_alert, const char *p_title);

bool supports_haptic_engine();
void vibrate_haptic_engine(float p_duration_seconds);
void vibrate_haptic_engine(float p_duration_seconds, float p_amplitude);

String get_model() const;
String get_rate_url(int p_app_id) const;
Expand Down
42 changes: 31 additions & 11 deletions platform/ios/ios.mm
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,41 @@
return haptic_engine;
}

void iOS::vibrate_haptic_engine(float p_duration_seconds) API_AVAILABLE(ios(13)) {
void iOS::vibrate_haptic_engine(float p_duration_seconds, float p_amplitude) API_AVAILABLE(ios(13)) {
if (@available(iOS 13, *)) { // We need the @available check every time to make the compiler happy...
if (supports_haptic_engine()) {
CHHapticEngine *cur_haptic_engine = get_haptic_engine_instance();
if (cur_haptic_engine) {
NSDictionary *hapticDict = @{
CHHapticPatternKeyPattern : @[
@{CHHapticPatternKeyEvent : @{
CHHapticPatternKeyEventType : CHHapticEventTypeHapticContinuous,
CHHapticPatternKeyTime : @(CHHapticTimeImmediate),
CHHapticPatternKeyEventDuration : @(p_duration_seconds)
},
},
],
};
NSDictionary *hapticDict;
if (p_amplitude < 0) {
hapticDict = @{
CHHapticPatternKeyPattern : @[
@{CHHapticPatternKeyEvent : @{
CHHapticPatternKeyEventType : CHHapticEventTypeHapticContinuous,
CHHapticPatternKeyTime : @(CHHapticTimeImmediate),
CHHapticPatternKeyEventDuration : @(p_duration_seconds),
},
},
],
};
} else {
hapticDict = @{
CHHapticPatternKeyPattern : @[
@{CHHapticPatternKeyEvent : @{
CHHapticPatternKeyEventType : CHHapticEventTypeHapticContinuous,
CHHapticPatternKeyTime : @(CHHapticTimeImmediate),
CHHapticPatternKeyEventDuration : @(p_duration_seconds),
CHHapticPatternKeyEventParameters : @[
@{
CHHapticPatternKeyParameterID : @("HapticIntensity"),
CHHapticPatternKeyParameterValue : @(p_amplitude)
},
],
},
},
],
};
}

NSError *error;
CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithDictionary:hapticDict error:&error];
Expand Down
2 changes: 1 addition & 1 deletion platform/ios/os_ios.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class OS_IOS : public OS_Unix {
virtual String get_unique_id() const override;
virtual String get_processor_name() const override;

virtual void vibrate_handheld(int p_duration_ms = 500) override;
virtual void vibrate_handheld(int p_duration_ms = 500, float p_amplitude = -1.0) override;

virtual bool _check_internal_feature_support(const String &p_feature) override;

Expand Down
8 changes: 6 additions & 2 deletions platform/ios/os_ios.mm
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,13 @@ void register_dynamic_symbol(char *name, void *address) {
return ret;
}

void OS_IOS::vibrate_handheld(int p_duration_ms) {
void OS_IOS::vibrate_handheld(int p_duration_ms, float p_amplitude) {
if (ios->supports_haptic_engine()) {
ios->vibrate_haptic_engine((float)p_duration_ms / 1000.f);
if (p_amplitude > 0.0) {
p_amplitude = CLAMP(p_amplitude, 0.0, 1.0);
}

ios->vibrate_haptic_engine((float)p_duration_ms / 1000.f, p_amplitude);
} else {
// iOS <13 does not support duration for vibration
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Expand Down
2 changes: 1 addition & 1 deletion platform/web/os_web.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ void OS_Web::add_frame_delay(bool p_can_draw) {
#endif
}

void OS_Web::vibrate_handheld(int p_duration_ms) {
void OS_Web::vibrate_handheld(int p_duration_ms, float p_amplitude) {
godot_js_input_vibrate_handheld(p_duration_ms);
}

Expand Down
2 changes: 1 addition & 1 deletion platform/web/os_web.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class OS_Web : public OS_Unix {
// Implemented in web_main.cpp loop callback instead.
void add_frame_delay(bool p_can_draw) override;

void vibrate_handheld(int p_duration_ms) override;
void vibrate_handheld(int p_duration_ms, float p_amplitude) override;

String get_cache_path() const override;
String get_config_path() const override;
Expand Down
Loading