Skip to content

Commit 6bfa38d

Browse files
authored
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: #79
1 parent 5dce3da commit 6bfa38d

File tree

9 files changed

+231
-22
lines changed

9 files changed

+231
-22
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88
### Added
9+
- Option to play sound on keypress ([#79])
910
- Optional key to quickly switch keyboard language ([#62])
1011
- Added apostrophe as a pop-up character on the dot key ([#356])
1112

@@ -123,6 +124,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
123124
[#47]: https://github.com/FossifyOrg/Keyboard/issues/47
124125
[#62]: https://github.com/FossifyOrg/Keyboard/issues/62
125126
[#78]: https://github.com/FossifyOrg/Keyboard/issues/78
127+
[#79]: https://github.com/FossifyOrg/Keyboard/issues/79
126128
[#100]: https://github.com/FossifyOrg/Keyboard/issues/100
127129
[#117]: https://github.com/FossifyOrg/Keyboard/issues/117
128130
[#129]: https://github.com/FossifyOrg/Keyboard/issues/129

app/src/main/kotlin/org/fossify/keyboard/activities/SettingsActivity.kt

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ package org.fossify.keyboard.activities
33
import android.content.Intent
44
import android.os.Bundle
55
import org.fossify.commons.dialogs.RadioGroupDialog
6-
import org.fossify.commons.extensions.beGoneIf
76
import org.fossify.commons.extensions.beVisibleIf
87
import org.fossify.commons.extensions.getProperPrimaryColor
9-
import org.fossify.commons.extensions.isOrWasThankYouInstalled
108
import org.fossify.commons.extensions.toast
119
import org.fossify.commons.extensions.updateTextColors
1210
import org.fossify.commons.extensions.viewBinding
@@ -29,6 +27,9 @@ import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_160_PERCENT
2927
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_70_PERCENT
3028
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_80_PERCENT
3129
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_90_PERCENT
30+
import org.fossify.keyboard.helpers.SOUND_ALWAYS
31+
import org.fossify.keyboard.helpers.SOUND_NONE
32+
import org.fossify.keyboard.helpers.SOUND_SYSTEM
3233
import java.util.Locale
3334
import kotlin.system.exitProcess
3435

@@ -54,6 +55,7 @@ class SettingsActivity : SimpleActivity() {
5455
setupLanguage()
5556
setupManageClipboardItems()
5657
setupVibrateOnKeypress()
58+
setupSoundOnKeypress()
5759
setupShowPopupOnKeypress()
5860
setupShowKeyBorders()
5961
setupManageKeyboardLanguages()
@@ -128,6 +130,35 @@ class SettingsActivity : SimpleActivity() {
128130
}
129131
}
130132

133+
private fun setupSoundOnKeypress() {
134+
binding.apply {
135+
settingsSoundOnKeypress.text = getSoundOnKeypressText(config.soundOnKeypress)
136+
settingsSoundOnKeypressHolder.setOnClickListener {
137+
val items = arrayListOf(
138+
RadioItem(SOUND_NONE, getString(R.string.sound_none)),
139+
RadioItem(SOUND_SYSTEM, getString(R.string.sound_system)),
140+
RadioItem(SOUND_ALWAYS, getString(R.string.sound_always))
141+
)
142+
RadioGroupDialog(
143+
activity = this@SettingsActivity,
144+
items = items,
145+
checkedItemId = config.soundOnKeypress
146+
) {
147+
config.soundOnKeypress = it as Int
148+
settingsSoundOnKeypress.text = getSoundOnKeypressText(config.soundOnKeypress)
149+
}
150+
}
151+
}
152+
}
153+
154+
private fun getSoundOnKeypressText(mode: Int): String = getString(
155+
when (mode) {
156+
SOUND_SYSTEM -> R.string.sound_system
157+
SOUND_ALWAYS -> R.string.sound_always
158+
else -> R.string.sound_none
159+
}
160+
)
161+
131162
private fun setupShowPopupOnKeypress() {
132163
binding.apply {
133164
settingsShowPopupOnKeypress.isChecked = config.showPopupOnKeypress

app/src/main/kotlin/org/fossify/keyboard/helpers/Config.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class Config(context: Context) : BaseConfig(context) {
1515
get() = prefs.getBoolean(VIBRATE_ON_KEYPRESS, true)
1616
set(vibrateOnKeypress) = prefs.edit().putBoolean(VIBRATE_ON_KEYPRESS, vibrateOnKeypress).apply()
1717

18+
var soundOnKeypress: Int
19+
get() = prefs.getInt(SOUND_ON_KEYPRESS, SOUND_SYSTEM)
20+
set(soundOnKeypress) = prefs.edit().putInt(SOUND_ON_KEYPRESS, soundOnKeypress).apply()
21+
1822
var showPopupOnKeypress: Boolean
1923
get() = prefs.getBoolean(SHOW_POPUP_ON_KEYPRESS, true)
2024
set(showPopupOnKeypress) = prefs.edit().putBoolean(SHOW_POPUP_ON_KEYPRESS, showPopupOnKeypress).apply()

app/src/main/kotlin/org/fossify/keyboard/helpers/Constants.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ const val MAX_KEYS_PER_MINI_ROW = 9
1212

1313
// shared prefs
1414
const val VIBRATE_ON_KEYPRESS = "vibrate_on_keypress"
15+
16+
const val SOUND_ON_KEYPRESS = "sound_on_keypress"
17+
const val SOUND_NONE = 0
18+
const val SOUND_SYSTEM = 1
19+
const val SOUND_ALWAYS = 2
20+
1521
const val SHOW_POPUP_ON_KEYPRESS = "show_popup_on_keypress"
1622
const val SHOW_KEY_BORDERS = "show_key_borders"
1723
const val SENTENCES_CAPITALIZATION = "sentences_capitalization"
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package org.fossify.keyboard.helpers
2+
3+
import android.content.Context
4+
import android.media.AudioManager
5+
import android.view.HapticFeedbackConstants
6+
import android.view.View
7+
import org.fossify.commons.extensions.performHapticFeedback
8+
import org.fossify.commons.helpers.isOreoMr1Plus
9+
import org.fossify.keyboard.extensions.config
10+
import org.fossify.keyboard.extensions.safeStorageContext
11+
12+
/**
13+
* Helper for keypress haptics and audio.
14+
*/
15+
class KeyboardFeedbackManager(private val context: Context) {
16+
17+
private val config = context.safeStorageContext.config
18+
private val audioManager by lazy {
19+
context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
20+
}
21+
22+
/**
23+
* Perform haptic feedback for standard keypress.
24+
*/
25+
fun vibrateIfNeeded(view: View) {
26+
if (config.vibrateOnKeypress) view.performHapticFeedback()
27+
}
28+
29+
/**
30+
* Perform haptic feedback for cursor handle movement.
31+
*/
32+
fun performHapticHandleMove(view: View) {
33+
if (!config.vibrateOnKeypress) return
34+
if (isOreoMr1Plus()) {
35+
@Suppress("DEPRECATION")
36+
view.performHapticFeedback(
37+
HapticFeedbackConstants.TEXT_HANDLE_MOVE,
38+
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
39+
)
40+
}
41+
}
42+
43+
/**
44+
* Play keypress sound if enabled.
45+
*/
46+
fun playKeypressSoundIfNeeded(code: Int) {
47+
val soundMode = config.soundOnKeypress
48+
if (soundMode == SOUND_NONE) return
49+
50+
val effect = when (code) {
51+
MyKeyboard.KEYCODE_DELETE -> AudioManager.FX_KEYPRESS_DELETE
52+
MyKeyboard.KEYCODE_ENTER -> AudioManager.FX_KEYPRESS_RETURN
53+
MyKeyboard.KEYCODE_SPACE -> AudioManager.FX_KEYPRESS_SPACEBAR
54+
else -> AudioManager.FX_KEYPRESS_STANDARD
55+
}
56+
57+
when (soundMode) {
58+
SOUND_SYSTEM -> audioManager.playSoundEffect(effect)
59+
SOUND_ALWAYS -> audioManager.playSoundEffect(effect, 1.0f)
60+
}
61+
}
62+
63+
/**
64+
* Perform both haptic and audio feedback for a keypress.
65+
*/
66+
fun performKeypressFeedback(view: View, keyCode: Int) {
67+
vibrateIfNeeded(view)
68+
playKeypressSoundIfNeeded(keyCode)
69+
}
70+
}

app/src/main/kotlin/org/fossify/keyboard/services/SimpleKeyboardIME.kt

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,28 @@ import android.icu.util.ULocale
1212
import android.inputmethodservice.InputMethodService
1313
import android.os.Build
1414
import android.os.Bundle
15-
import android.text.InputType.*
15+
import android.text.InputType.TYPE_CLASS_DATETIME
16+
import android.text.InputType.TYPE_CLASS_NUMBER
17+
import android.text.InputType.TYPE_CLASS_PHONE
18+
import android.text.InputType.TYPE_CLASS_TEXT
19+
import android.text.InputType.TYPE_MASK_CLASS
20+
import android.text.InputType.TYPE_MASK_VARIATION
21+
import android.text.InputType.TYPE_NULL
1622
import android.text.TextUtils
1723
import android.util.Size
1824
import android.view.KeyEvent
1925
import android.view.View
2026
import android.view.ViewGroup
21-
import android.view.inputmethod.*
27+
import android.view.inputmethod.CursorAnchorInfo
28+
import android.view.inputmethod.EditorInfo
2229
import android.view.inputmethod.EditorInfo.IME_ACTION_NONE
2330
import android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION
2431
import android.view.inputmethod.EditorInfo.IME_MASK_ACTION
32+
import android.view.inputmethod.ExtractedTextRequest
33+
import android.view.inputmethod.InlineSuggestionsRequest
34+
import android.view.inputmethod.InlineSuggestionsResponse
35+
import android.view.inputmethod.InputConnection
36+
import android.view.inputmethod.InputMethodSubtype
2537
import android.widget.inline.InlinePresentationSpec
2638
import androidx.annotation.RequiresApi
2739
import androidx.autofill.inline.UiVersions
@@ -35,8 +47,23 @@ import androidx.core.view.ViewCompat
3547
import androidx.core.view.WindowCompat
3648
import androidx.core.view.WindowInsetsCompat.Type
3749
import androidx.core.view.updatePadding
38-
import org.fossify.commons.extensions.*
39-
import org.fossify.commons.helpers.*
50+
import org.fossify.commons.extensions.applyColorFilter
51+
import org.fossify.commons.extensions.getProperBackgroundColor
52+
import org.fossify.commons.extensions.getProperTextColor
53+
import org.fossify.commons.extensions.getSharedPrefs
54+
import org.fossify.commons.extensions.setSystemBarsAppearance
55+
import org.fossify.commons.helpers.ACCENT_COLOR
56+
import org.fossify.commons.helpers.BACKGROUND_COLOR
57+
import org.fossify.commons.helpers.CUSTOM_ACCENT_COLOR
58+
import org.fossify.commons.helpers.CUSTOM_BACKGROUND_COLOR
59+
import org.fossify.commons.helpers.CUSTOM_PRIMARY_COLOR
60+
import org.fossify.commons.helpers.CUSTOM_TEXT_COLOR
61+
import org.fossify.commons.helpers.IS_GLOBAL_THEME_ENABLED
62+
import org.fossify.commons.helpers.IS_SYSTEM_THEME_ENABLED
63+
import org.fossify.commons.helpers.PRIMARY_COLOR
64+
import org.fossify.commons.helpers.TEXT_COLOR
65+
import org.fossify.commons.helpers.isNougatPlus
66+
import org.fossify.commons.helpers.isPiePlus
4067
import org.fossify.keyboard.R
4168
import org.fossify.keyboard.activities.SettingsActivity
4269
import org.fossify.keyboard.databinding.KeyboardViewKeyboardBinding
@@ -46,7 +73,56 @@ import org.fossify.keyboard.extensions.getKeyboardLanguageText
4673
import org.fossify.keyboard.extensions.getSelectedLanguagesSorted
4774
import org.fossify.keyboard.extensions.getStrokeColor
4875
import org.fossify.keyboard.extensions.safeStorageContext
49-
import org.fossify.keyboard.helpers.*
76+
import org.fossify.keyboard.helpers.HEIGHT_PERCENTAGE
77+
import org.fossify.keyboard.helpers.KEYBOARD_LANGUAGE
78+
import org.fossify.keyboard.helpers.LANGUAGE_ARABIC
79+
import org.fossify.keyboard.helpers.LANGUAGE_BELARUSIAN_CYRL
80+
import org.fossify.keyboard.helpers.LANGUAGE_BELARUSIAN_LATN
81+
import org.fossify.keyboard.helpers.LANGUAGE_BENGALI
82+
import org.fossify.keyboard.helpers.LANGUAGE_BULGARIAN
83+
import org.fossify.keyboard.helpers.LANGUAGE_CENTRAL_KURDISH
84+
import org.fossify.keyboard.helpers.LANGUAGE_CHUVASH
85+
import org.fossify.keyboard.helpers.LANGUAGE_CZECH_QWERTY
86+
import org.fossify.keyboard.helpers.LANGUAGE_CZECH_QWERTZ
87+
import org.fossify.keyboard.helpers.LANGUAGE_DANISH
88+
import org.fossify.keyboard.helpers.LANGUAGE_DUTCH
89+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_ASSET
90+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_COLEMAK
91+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_COLEMAKDH
92+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_DVORAK
93+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_NIRO
94+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_QWERTZ
95+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_SOUL
96+
import org.fossify.keyboard.helpers.LANGUAGE_ENGLISH_WORKMAN
97+
import org.fossify.keyboard.helpers.LANGUAGE_ESPERANTO
98+
import org.fossify.keyboard.helpers.LANGUAGE_FRENCH_AZERTY
99+
import org.fossify.keyboard.helpers.LANGUAGE_FRENCH_BEPO
100+
import org.fossify.keyboard.helpers.LANGUAGE_GERMAN
101+
import org.fossify.keyboard.helpers.LANGUAGE_GERMAN_QWERTZ
102+
import org.fossify.keyboard.helpers.LANGUAGE_GREEK
103+
import org.fossify.keyboard.helpers.LANGUAGE_HEBREW
104+
import org.fossify.keyboard.helpers.LANGUAGE_ITALIAN
105+
import org.fossify.keyboard.helpers.LANGUAGE_KABYLE_AZERTY
106+
import org.fossify.keyboard.helpers.LANGUAGE_LATVIAN
107+
import org.fossify.keyboard.helpers.LANGUAGE_LITHUANIAN
108+
import org.fossify.keyboard.helpers.LANGUAGE_NORWEGIAN
109+
import org.fossify.keyboard.helpers.LANGUAGE_POLISH
110+
import org.fossify.keyboard.helpers.LANGUAGE_PORTUGUESE
111+
import org.fossify.keyboard.helpers.LANGUAGE_PORTUGUESE_HCESAR
112+
import org.fossify.keyboard.helpers.LANGUAGE_ROMANIAN
113+
import org.fossify.keyboard.helpers.LANGUAGE_RUSSIAN
114+
import org.fossify.keyboard.helpers.LANGUAGE_SLOVENIAN
115+
import org.fossify.keyboard.helpers.LANGUAGE_SPANISH
116+
import org.fossify.keyboard.helpers.LANGUAGE_SWEDISH
117+
import org.fossify.keyboard.helpers.LANGUAGE_TURKISH
118+
import org.fossify.keyboard.helpers.LANGUAGE_TURKISH_Q
119+
import org.fossify.keyboard.helpers.LANGUAGE_UKRAINIAN
120+
import org.fossify.keyboard.helpers.MyKeyboard
121+
import org.fossify.keyboard.helpers.SHOW_KEY_BORDERS
122+
import org.fossify.keyboard.helpers.SHOW_NUMBERS_ROW
123+
import org.fossify.keyboard.helpers.ShiftState
124+
import org.fossify.keyboard.helpers.VOICE_INPUT_METHOD
125+
import org.fossify.keyboard.helpers.cachedVNTelexData
50126
import org.fossify.keyboard.interfaces.OnKeyboardActionListener
51127
import org.fossify.keyboard.views.MyKeyboardView
52128
import java.io.ByteArrayOutputStream
@@ -108,7 +184,7 @@ class SimpleKeyboardIME : InputMethodService(), OnKeyboardActionListener, Shared
108184

109185
override fun onPress(primaryCode: Int) {
110186
if (primaryCode != 0) {
111-
keyboardView?.vibrateIfNeeded()
187+
keyboardView?.performKeypressFeedback(primaryCode)
112188
}
113189
}
114190

app/src/main/kotlin/org/fossify/keyboard/views/MyKeyboardView.kt

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import android.os.Message
2626
import android.util.AttributeSet
2727
import android.util.TypedValue
2828
import android.view.Gravity
29-
import android.view.HapticFeedbackConstants
3029
import android.view.LayoutInflater
3130
import android.view.MotionEvent
3231
import android.view.View
@@ -61,12 +60,10 @@ import org.fossify.commons.extensions.getProperPrimaryColor
6160
import org.fossify.commons.extensions.getProperTextColor
6261
import org.fossify.commons.extensions.isDynamicTheme
6362
import org.fossify.commons.extensions.lightenColor
64-
import org.fossify.commons.extensions.performHapticFeedback
6563
import org.fossify.commons.extensions.removeUnderlines
6664
import org.fossify.commons.extensions.toast
6765
import org.fossify.commons.helpers.HIGHER_ALPHA
6866
import org.fossify.commons.helpers.ensureBackgroundThread
69-
import org.fossify.commons.helpers.isOreoMr1Plus
7067
import org.fossify.commons.helpers.isPiePlus
7168
import org.fossify.keyboard.R
7269
import org.fossify.keyboard.activities.ManageClipboardItemsActivity
@@ -90,6 +87,7 @@ import org.fossify.keyboard.extensions.safeStorageContext
9087
import org.fossify.keyboard.helpers.AccessHelper
9188
import org.fossify.keyboard.helpers.EMOJI_SPEC_FILE_PATH
9289
import org.fossify.keyboard.helpers.EmojiData
90+
import org.fossify.keyboard.helpers.KeyboardFeedbackManager
9391
import org.fossify.keyboard.helpers.LANGUAGE_TURKISH_Q
9492
import org.fossify.keyboard.helpers.LANGUAGE_VIETNAMESE_TELEX
9593
import org.fossify.keyboard.helpers.LANGUAGE_VN_TELEX
@@ -137,6 +135,7 @@ class MyKeyboardView @JvmOverloads constructor(
137135
private var keyboardViewBinding: KeyboardViewKeyboardBinding? = null
138136

139137
private var accessHelper: AccessHelper? = null
138+
private val feedbackManager by lazy { KeyboardFeedbackManager(context) }
140139

141140
private var mKeyboard: MyKeyboard? = null
142141
private var mCurrentKeyIndex: Int = NOT_A_KEY
@@ -546,20 +545,15 @@ class MyKeyboardView @JvmOverloads constructor(
546545
}
547546

548547
fun vibrateIfNeeded() {
549-
if (context.config.vibrateOnKeypress) {
550-
performHapticFeedback()
551-
}
548+
feedbackManager.vibrateIfNeeded(this)
549+
}
550+
551+
fun performKeypressFeedback(keyCode: Int) {
552+
feedbackManager.performKeypressFeedback(this, keyCode)
552553
}
553554

554555
fun performHapticHandleMove() {
555-
if (!context.config.vibrateOnKeypress) return
556-
if (isOreoMr1Plus()) {
557-
@Suppress("DEPRECATION")
558-
performHapticFeedback(
559-
HapticFeedbackConstants.TEXT_HANDLE_MOVE,
560-
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
561-
)
562-
}
556+
feedbackManager.performHapticHandleMove(this)
563557
}
564558

565559
/**

app/src/main/res/layout/activity_settings.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,28 @@
177177

178178
</RelativeLayout>
179179

180+
<RelativeLayout
181+
android:id="@+id/settings_sound_on_keypress_holder"
182+
style="@style/SettingsHolderTextViewStyle"
183+
android:layout_width="match_parent"
184+
android:layout_height="wrap_content">
185+
186+
<org.fossify.commons.views.MyTextView
187+
android:id="@+id/settings_sound_on_keypress_label"
188+
style="@style/SettingsTextLabelStyle"
189+
android:layout_width="wrap_content"
190+
android:layout_height="wrap_content"
191+
android:text="@string/sound_on_keypress" />
192+
193+
<org.fossify.commons.views.MyTextView
194+
android:id="@+id/settings_sound_on_keypress"
195+
style="@style/SettingsTextValueStyle"
196+
android:layout_width="wrap_content"
197+
android:layout_height="wrap_content"
198+
android:layout_below="@+id/settings_sound_on_keypress_label" />
199+
200+
</RelativeLayout>
201+
180202
<RelativeLayout
181203
android:id="@+id/settings_show_popup_on_keypress_holder"
182204
style="@style/SettingsHolderSwitchStyle"

0 commit comments

Comments
 (0)