diff --git a/CHANGELOG.md b/CHANGELOG.md
index c98f44ed..8fd8308f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/app/src/main/kotlin/org/fossify/keyboard/activities/SettingsActivity.kt b/app/src/main/kotlin/org/fossify/keyboard/activities/SettingsActivity.kt
index 5133024c..ead937ca 100644
--- a/app/src/main/kotlin/org/fossify/keyboard/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/org/fossify/keyboard/activities/SettingsActivity.kt
@@ -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
diff --git a/app/src/main/kotlin/org/fossify/keyboard/helpers/Config.kt b/app/src/main/kotlin/org/fossify/keyboard/helpers/Config.kt
index 58b8f510..46003b5c 100644
--- a/app/src/main/kotlin/org/fossify/keyboard/helpers/Config.kt
+++ b/app/src/main/kotlin/org/fossify/keyboard/helpers/Config.kt
@@ -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()
diff --git a/app/src/main/kotlin/org/fossify/keyboard/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/keyboard/helpers/Constants.kt
index b60629ec..c31276db 100644
--- a/app/src/main/kotlin/org/fossify/keyboard/helpers/Constants.kt
+++ b/app/src/main/kotlin/org/fossify/keyboard/helpers/Constants.kt
@@ -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"
diff --git a/app/src/main/kotlin/org/fossify/keyboard/helpers/KeyboardFeedbackManager.kt b/app/src/main/kotlin/org/fossify/keyboard/helpers/KeyboardFeedbackManager.kt
new file mode 100644
index 00000000..5655a1ff
--- /dev/null
+++ b/app/src/main/kotlin/org/fossify/keyboard/helpers/KeyboardFeedbackManager.kt
@@ -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)
+ }
+}
diff --git a/app/src/main/kotlin/org/fossify/keyboard/services/SimpleKeyboardIME.kt b/app/src/main/kotlin/org/fossify/keyboard/services/SimpleKeyboardIME.kt
index 02784ac6..45b1cbdb 100644
--- a/app/src/main/kotlin/org/fossify/keyboard/services/SimpleKeyboardIME.kt
+++ b/app/src/main/kotlin/org/fossify/keyboard/services/SimpleKeyboardIME.kt
@@ -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)
}
}
diff --git a/app/src/main/kotlin/org/fossify/keyboard/views/MyKeyboardView.kt b/app/src/main/kotlin/org/fossify/keyboard/views/MyKeyboardView.kt
index 01ac4a48..cf79d6f6 100644
--- a/app/src/main/kotlin/org/fossify/keyboard/views/MyKeyboardView.kt
+++ b/app/src/main/kotlin/org/fossify/keyboard/views/MyKeyboardView.kt
@@ -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)
}
/**
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index 80e300b1..490c7c92 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -177,6 +177,28 @@
+
+
+
+
+
+
+
+
Show clipboard content if available
Show a popup on keypress
Vibrate on keypress
+ Sound on keypress
+ Off
+ Follow system
+ Always on
Keyboard language
Keyboard height
Show key borders