feat: add option to play sound on keypress (#361)

* feat: add option to play sound on keypress

* fix: use consistent naming

* fix: respect system preference by default

Refs: https://github.com/FossifyOrg/Keyboard/issues/79
This commit is contained in:
Naveen Singh
2025-12-27 19:43:59 +05:30
committed by GitHub
parent 5dce3dabf0
commit 6bfa38d7f6
9 changed files with 231 additions and 22 deletions

View File

@@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Option to play sound on keypress ([#79])
- Optional key to quickly switch keyboard language ([#62])
- Added apostrophe as a pop-up character on the dot key ([#356])
@@ -123,6 +124,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#47]: https://github.com/FossifyOrg/Keyboard/issues/47
[#62]: https://github.com/FossifyOrg/Keyboard/issues/62
[#78]: https://github.com/FossifyOrg/Keyboard/issues/78
[#79]: https://github.com/FossifyOrg/Keyboard/issues/79
[#100]: https://github.com/FossifyOrg/Keyboard/issues/100
[#117]: https://github.com/FossifyOrg/Keyboard/issues/117
[#129]: https://github.com/FossifyOrg/Keyboard/issues/129

View File

@@ -3,10 +3,8 @@ package org.fossify.keyboard.activities
import android.content.Intent
import android.os.Bundle
import org.fossify.commons.dialogs.RadioGroupDialog
import org.fossify.commons.extensions.beGoneIf
import org.fossify.commons.extensions.beVisibleIf
import org.fossify.commons.extensions.getProperPrimaryColor
import org.fossify.commons.extensions.isOrWasThankYouInstalled
import org.fossify.commons.extensions.toast
import org.fossify.commons.extensions.updateTextColors
import org.fossify.commons.extensions.viewBinding
@@ -29,6 +27,9 @@ import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_160_PERCENT
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_70_PERCENT
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_80_PERCENT
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_90_PERCENT
import org.fossify.keyboard.helpers.SOUND_ALWAYS
import org.fossify.keyboard.helpers.SOUND_NONE
import org.fossify.keyboard.helpers.SOUND_SYSTEM
import java.util.Locale
import kotlin.system.exitProcess
@@ -54,6 +55,7 @@ class SettingsActivity : SimpleActivity() {
setupLanguage()
setupManageClipboardItems()
setupVibrateOnKeypress()
setupSoundOnKeypress()
setupShowPopupOnKeypress()
setupShowKeyBorders()
setupManageKeyboardLanguages()
@@ -128,6 +130,35 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupSoundOnKeypress() {
binding.apply {
settingsSoundOnKeypress.text = getSoundOnKeypressText(config.soundOnKeypress)
settingsSoundOnKeypressHolder.setOnClickListener {
val items = arrayListOf(
RadioItem(SOUND_NONE, getString(R.string.sound_none)),
RadioItem(SOUND_SYSTEM, getString(R.string.sound_system)),
RadioItem(SOUND_ALWAYS, getString(R.string.sound_always))
)
RadioGroupDialog(
activity = this@SettingsActivity,
items = items,
checkedItemId = config.soundOnKeypress
) {
config.soundOnKeypress = it as Int
settingsSoundOnKeypress.text = getSoundOnKeypressText(config.soundOnKeypress)
}
}
}
}
private fun getSoundOnKeypressText(mode: Int): String = getString(
when (mode) {
SOUND_SYSTEM -> R.string.sound_system
SOUND_ALWAYS -> R.string.sound_always
else -> R.string.sound_none
}
)
private fun setupShowPopupOnKeypress() {
binding.apply {
settingsShowPopupOnKeypress.isChecked = config.showPopupOnKeypress

View File

@@ -15,6 +15,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getBoolean(VIBRATE_ON_KEYPRESS, true)
set(vibrateOnKeypress) = prefs.edit().putBoolean(VIBRATE_ON_KEYPRESS, vibrateOnKeypress).apply()
var soundOnKeypress: Int
get() = prefs.getInt(SOUND_ON_KEYPRESS, SOUND_SYSTEM)
set(soundOnKeypress) = prefs.edit().putInt(SOUND_ON_KEYPRESS, soundOnKeypress).apply()
var showPopupOnKeypress: Boolean
get() = prefs.getBoolean(SHOW_POPUP_ON_KEYPRESS, true)
set(showPopupOnKeypress) = prefs.edit().putBoolean(SHOW_POPUP_ON_KEYPRESS, showPopupOnKeypress).apply()

View File

@@ -12,6 +12,12 @@ const val MAX_KEYS_PER_MINI_ROW = 9
// shared prefs
const val VIBRATE_ON_KEYPRESS = "vibrate_on_keypress"
const val SOUND_ON_KEYPRESS = "sound_on_keypress"
const val SOUND_NONE = 0
const val SOUND_SYSTEM = 1
const val SOUND_ALWAYS = 2
const val SHOW_POPUP_ON_KEYPRESS = "show_popup_on_keypress"
const val SHOW_KEY_BORDERS = "show_key_borders"
const val SENTENCES_CAPITALIZATION = "sentences_capitalization"

View File

@@ -0,0 +1,70 @@
package org.fossify.keyboard.helpers
import android.content.Context
import android.media.AudioManager
import android.view.HapticFeedbackConstants
import android.view.View
import org.fossify.commons.extensions.performHapticFeedback
import org.fossify.commons.helpers.isOreoMr1Plus
import org.fossify.keyboard.extensions.config
import org.fossify.keyboard.extensions.safeStorageContext
/**
* Helper for keypress haptics and audio.
*/
class KeyboardFeedbackManager(private val context: Context) {
private val config = context.safeStorageContext.config
private val audioManager by lazy {
context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
}
/**
* Perform haptic feedback for standard keypress.
*/
fun vibrateIfNeeded(view: View) {
if (config.vibrateOnKeypress) view.performHapticFeedback()
}
/**
* Perform haptic feedback for cursor handle movement.
*/
fun performHapticHandleMove(view: View) {
if (!config.vibrateOnKeypress) return
if (isOreoMr1Plus()) {
@Suppress("DEPRECATION")
view.performHapticFeedback(
HapticFeedbackConstants.TEXT_HANDLE_MOVE,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
)
}
}
/**
* Play keypress sound if enabled.
*/
fun playKeypressSoundIfNeeded(code: Int) {
val soundMode = config.soundOnKeypress
if (soundMode == SOUND_NONE) return
val effect = when (code) {
MyKeyboard.KEYCODE_DELETE -> AudioManager.FX_KEYPRESS_DELETE
MyKeyboard.KEYCODE_ENTER -> AudioManager.FX_KEYPRESS_RETURN
MyKeyboard.KEYCODE_SPACE -> AudioManager.FX_KEYPRESS_SPACEBAR
else -> AudioManager.FX_KEYPRESS_STANDARD
}
when (soundMode) {
SOUND_SYSTEM -> audioManager.playSoundEffect(effect)
SOUND_ALWAYS -> audioManager.playSoundEffect(effect, 1.0f)
}
}
/**
* Perform both haptic and audio feedback for a keypress.
*/
fun performKeypressFeedback(view: View, keyCode: Int) {
vibrateIfNeeded(view)
playKeypressSoundIfNeeded(keyCode)
}
}

View File

@@ -12,16 +12,28 @@ import android.icu.util.ULocale
import android.inputmethodservice.InputMethodService
import android.os.Build
import android.os.Bundle
import android.text.InputType.*
import android.text.InputType.TYPE_CLASS_DATETIME
import android.text.InputType.TYPE_CLASS_NUMBER
import android.text.InputType.TYPE_CLASS_PHONE
import android.text.InputType.TYPE_CLASS_TEXT
import android.text.InputType.TYPE_MASK_CLASS
import android.text.InputType.TYPE_MASK_VARIATION
import android.text.InputType.TYPE_NULL
import android.text.TextUtils
import android.util.Size
import android.view.KeyEvent
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.*
import android.view.inputmethod.CursorAnchorInfo
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.EditorInfo.IME_ACTION_NONE
import android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION
import android.view.inputmethod.EditorInfo.IME_MASK_ACTION
import android.view.inputmethod.ExtractedTextRequest
import android.view.inputmethod.InlineSuggestionsRequest
import android.view.inputmethod.InlineSuggestionsResponse
import android.view.inputmethod.InputConnection
import android.view.inputmethod.InputMethodSubtype
import android.widget.inline.InlinePresentationSpec
import androidx.annotation.RequiresApi
import androidx.autofill.inline.UiVersions
@@ -35,8 +47,23 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat.Type
import androidx.core.view.updatePadding
import org.fossify.commons.extensions.*
import org.fossify.commons.helpers.*
import org.fossify.commons.extensions.applyColorFilter
import org.fossify.commons.extensions.getProperBackgroundColor
import org.fossify.commons.extensions.getProperTextColor
import org.fossify.commons.extensions.getSharedPrefs
import org.fossify.commons.extensions.setSystemBarsAppearance
import org.fossify.commons.helpers.ACCENT_COLOR
import org.fossify.commons.helpers.BACKGROUND_COLOR
import org.fossify.commons.helpers.CUSTOM_ACCENT_COLOR
import org.fossify.commons.helpers.CUSTOM_BACKGROUND_COLOR
import org.fossify.commons.helpers.CUSTOM_PRIMARY_COLOR
import org.fossify.commons.helpers.CUSTOM_TEXT_COLOR
import org.fossify.commons.helpers.IS_GLOBAL_THEME_ENABLED
import org.fossify.commons.helpers.IS_SYSTEM_THEME_ENABLED
import org.fossify.commons.helpers.PRIMARY_COLOR
import org.fossify.commons.helpers.TEXT_COLOR
import org.fossify.commons.helpers.isNougatPlus
import org.fossify.commons.helpers.isPiePlus
import org.fossify.keyboard.R
import org.fossify.keyboard.activities.SettingsActivity
import org.fossify.keyboard.databinding.KeyboardViewKeyboardBinding
@@ -46,7 +73,56 @@ import org.fossify.keyboard.extensions.getKeyboardLanguageText
import org.fossify.keyboard.extensions.getSelectedLanguagesSorted
import org.fossify.keyboard.extensions.getStrokeColor
import org.fossify.keyboard.extensions.safeStorageContext
import org.fossify.keyboard.helpers.*
import org.fossify.keyboard.helpers.HEIGHT_PERCENTAGE
import org.fossify.keyboard.helpers.KEYBOARD_LANGUAGE
import org.fossify.keyboard.helpers.LANGUAGE_ARABIC
import org.fossify.keyboard.helpers.LANGUAGE_BELARUSIAN_CYRL
import org.fossify.keyboard.helpers.LANGUAGE_BELARUSIAN_LATN
import org.fossify.keyboard.helpers.LANGUAGE_BENGALI
import org.fossify.keyboard.helpers.LANGUAGE_BULGARIAN
import org.fossify.keyboard.helpers.LANGUAGE_CENTRAL_KURDISH
import org.fossify.keyboard.helpers.LANGUAGE_CHUVASH
import org.fossify.keyboard.helpers.LANGUAGE_CZECH_QWERTY
import org.fossify.keyboard.helpers.LANGUAGE_CZECH_QWERTZ
import org.fossify.keyboard.helpers.LANGUAGE_DANISH
import org.fossify.keyboard.helpers.LANGUAGE_DUTCH
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_ASSET
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_COLEMAK
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_COLEMAKDH
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_DVORAK
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_NIRO
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_QWERTZ
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_SOUL
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_WORKMAN
import org.fossify.keyboard.helpers.LANGUAGE_ESPERANTO
import org.fossify.keyboard.helpers.LANGUAGE_FRENCH_AZERTY
import org.fossify.keyboard.helpers.LANGUAGE_FRENCH_BEPO
import org.fossify.keyboard.helpers.LANGUAGE_GERMAN
import org.fossify.keyboard.helpers.LANGUAGE_GERMAN_QWERTZ
import org.fossify.keyboard.helpers.LANGUAGE_GREEK
import org.fossify.keyboard.helpers.LANGUAGE_HEBREW
import org.fossify.keyboard.helpers.LANGUAGE_ITALIAN
import org.fossify.keyboard.helpers.LANGUAGE_KABYLE_AZERTY
import org.fossify.keyboard.helpers.LANGUAGE_LATVIAN
import org.fossify.keyboard.helpers.LANGUAGE_LITHUANIAN
import org.fossify.keyboard.helpers.LANGUAGE_NORWEGIAN
import org.fossify.keyboard.helpers.LANGUAGE_POLISH
import org.fossify.keyboard.helpers.LANGUAGE_PORTUGUESE
import org.fossify.keyboard.helpers.LANGUAGE_PORTUGUESE_HCESAR
import org.fossify.keyboard.helpers.LANGUAGE_ROMANIAN
import org.fossify.keyboard.helpers.LANGUAGE_RUSSIAN
import org.fossify.keyboard.helpers.LANGUAGE_SLOVENIAN
import org.fossify.keyboard.helpers.LANGUAGE_SPANISH
import org.fossify.keyboard.helpers.LANGUAGE_SWEDISH
import org.fossify.keyboard.helpers.LANGUAGE_TURKISH
import org.fossify.keyboard.helpers.LANGUAGE_TURKISH_Q
import org.fossify.keyboard.helpers.LANGUAGE_UKRAINIAN
import org.fossify.keyboard.helpers.MyKeyboard
import org.fossify.keyboard.helpers.SHOW_KEY_BORDERS
import org.fossify.keyboard.helpers.SHOW_NUMBERS_ROW
import org.fossify.keyboard.helpers.ShiftState
import org.fossify.keyboard.helpers.VOICE_INPUT_METHOD
import org.fossify.keyboard.helpers.cachedVNTelexData
import org.fossify.keyboard.interfaces.OnKeyboardActionListener
import org.fossify.keyboard.views.MyKeyboardView
import java.io.ByteArrayOutputStream
@@ -108,7 +184,7 @@ class SimpleKeyboardIME : InputMethodService(), OnKeyboardActionListener, Shared
override fun onPress(primaryCode: Int) {
if (primaryCode != 0) {
keyboardView?.vibrateIfNeeded()
keyboardView?.performKeypressFeedback(primaryCode)
}
}

View File

@@ -26,7 +26,6 @@ import android.os.Message
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.HapticFeedbackConstants
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -61,12 +60,10 @@ import org.fossify.commons.extensions.getProperPrimaryColor
import org.fossify.commons.extensions.getProperTextColor
import org.fossify.commons.extensions.isDynamicTheme
import org.fossify.commons.extensions.lightenColor
import org.fossify.commons.extensions.performHapticFeedback
import org.fossify.commons.extensions.removeUnderlines
import org.fossify.commons.extensions.toast
import org.fossify.commons.helpers.HIGHER_ALPHA
import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.commons.helpers.isOreoMr1Plus
import org.fossify.commons.helpers.isPiePlus
import org.fossify.keyboard.R
import org.fossify.keyboard.activities.ManageClipboardItemsActivity
@@ -90,6 +87,7 @@ import org.fossify.keyboard.extensions.safeStorageContext
import org.fossify.keyboard.helpers.AccessHelper
import org.fossify.keyboard.helpers.EMOJI_SPEC_FILE_PATH
import org.fossify.keyboard.helpers.EmojiData
import org.fossify.keyboard.helpers.KeyboardFeedbackManager
import org.fossify.keyboard.helpers.LANGUAGE_TURKISH_Q
import org.fossify.keyboard.helpers.LANGUAGE_VIETNAMESE_TELEX
import org.fossify.keyboard.helpers.LANGUAGE_VN_TELEX
@@ -137,6 +135,7 @@ class MyKeyboardView @JvmOverloads constructor(
private var keyboardViewBinding: KeyboardViewKeyboardBinding? = null
private var accessHelper: AccessHelper? = null
private val feedbackManager by lazy { KeyboardFeedbackManager(context) }
private var mKeyboard: MyKeyboard? = null
private var mCurrentKeyIndex: Int = NOT_A_KEY
@@ -546,20 +545,15 @@ class MyKeyboardView @JvmOverloads constructor(
}
fun vibrateIfNeeded() {
if (context.config.vibrateOnKeypress) {
performHapticFeedback()
}
feedbackManager.vibrateIfNeeded(this)
}
fun performKeypressFeedback(keyCode: Int) {
feedbackManager.performKeypressFeedback(this, keyCode)
}
fun performHapticHandleMove() {
if (!context.config.vibrateOnKeypress) return
if (isOreoMr1Plus()) {
@Suppress("DEPRECATION")
performHapticFeedback(
HapticFeedbackConstants.TEXT_HANDLE_MOVE,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
)
}
feedbackManager.performHapticHandleMove(this)
}
/**

View File

@@ -177,6 +177,28 @@
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_sound_on_keypress_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<org.fossify.commons.views.MyTextView
android:id="@+id/settings_sound_on_keypress_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sound_on_keypress" />
<org.fossify.commons.views.MyTextView
android:id="@+id/settings_sound_on_keypress"
style="@style/SettingsTextValueStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_sound_on_keypress_label" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_show_popup_on_keypress_holder"
style="@style/SettingsHolderSwitchStyle"

View File

@@ -31,6 +31,10 @@
<string name="show_clipboard_content">Show clipboard content if available</string>
<string name="show_popup">Show a popup on keypress</string>
<string name="vibrate_on_keypress">Vibrate on keypress</string>
<string name="sound_on_keypress">Sound on keypress</string>
<string name="sound_none">Off</string>
<string name="sound_system">Follow system</string>
<string name="sound_always">Always on</string>
<string name="keyboard_language">Keyboard language</string>
<string name="keyboard_height">Keyboard height</string>
<string name="show_key_borders">Show key borders</string>