Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import org.fossify.keyboard.extensions.getKeyboardLanguageText
import org.fossify.keyboard.extensions.getKeyboardLanguagesRadioItems
import org.fossify.keyboard.extensions.getVoiceInputMethods
import org.fossify.keyboard.extensions.getVoiceInputRadioItems
import org.fossify.keyboard.helpers.CURSOR_SPEED_FAST
import org.fossify.keyboard.helpers.CURSOR_SPEED_NORMAL
import org.fossify.keyboard.helpers.CURSOR_SPEED_SLOW
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_100_PERCENT
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_120_PERCENT
import org.fossify.keyboard.helpers.KEYBOARD_HEIGHT_140_PERCENT
Expand Down Expand Up @@ -65,6 +68,7 @@ class SettingsActivity : SimpleActivity() {
setupShowLanguageSwitchKey()
setupShowClipboardContent()
setupSentencesCapitalization()
setupSpaceBarCursorSpeed()
setupShowNumbersRow()
setupVoiceInputMethod()

Expand Down Expand Up @@ -272,6 +276,31 @@ class SettingsActivity : SimpleActivity() {
}
}

private fun setupSpaceBarCursorSpeed() {
binding.apply {
settingsSpaceBarCursorSpeed.text = getCursorSpeedText(config.spaceBarCursorSpeed)
settingsSpaceBarCursorSpeedHolder.setOnClickListener {
val items = arrayListOf(
RadioItem(CURSOR_SPEED_SLOW, getString(R.string.cursor_speed_slow)),
RadioItem(CURSOR_SPEED_NORMAL, getString(R.string.cursor_speed_normal)),
RadioItem(CURSOR_SPEED_FAST, getString(R.string.cursor_speed_fast))
)
RadioGroupDialog(this@SettingsActivity, items, config.spaceBarCursorSpeed) {
config.spaceBarCursorSpeed = it as Int
settingsSpaceBarCursorSpeed.text = getCursorSpeedText(config.spaceBarCursorSpeed)
}
}
}
}

private fun getCursorSpeedText(speed: Int): String = getString(
when (speed) {
CURSOR_SPEED_SLOW -> R.string.cursor_speed_slow
CURSOR_SPEED_NORMAL -> R.string.cursor_speed_normal
else -> R.string.cursor_speed_fast
}
)

private fun setupShowEmojiKey() {
binding.apply {
settingsShowEmojiKeyHolder.setOnClickListener {
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/kotlin/org/fossify/keyboard/helpers/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getString(VOICE_INPUT_METHOD, "")!!
set(voiceInputMethod) = prefs.edit().putString(VOICE_INPUT_METHOD, voiceInputMethod).apply()

var spaceBarCursorSpeed: Int
get() = prefs.getInt(SPACE_BAR_CURSOR_SPEED, CURSOR_SPEED_NORMAL)
set(spaceBarCursorSpeed) = prefs.edit().putInt(SPACE_BAR_CURSOR_SPEED, spaceBarCursorSpeed).apply()

var selectedLanguages: MutableSet<Int>
get() {
val defaultLanguage = getDefaultLanguage().toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ const val SHOW_NUMBERS_ROW = "show_numbers_row"
const val SELECTED_LANGUAGES = "selected_languages"
const val VOICE_INPUT_METHOD = "voice_input_method"
const val RECENTLY_USED_EMOJIS = "recently_used_emojis"
const val SPACE_BAR_CURSOR_SPEED = "space_bar_cursor_speed"

// cursor movement speed, higher = cursor moves with less finger travel
const val CURSOR_SPEED_SLOW = 0
const val CURSOR_SPEED_NORMAL = 1
const val CURSOR_SPEED_FAST = 2

// differentiate current and pinned clips at the keyboards' Clipboard section
const val ITEM_SECTION_LABEL = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class KeyboardFeedbackManager(private val context: Context) {
if (isOreoMr1Plus()) {
@Suppress("DEPRECATION")
view.performHapticFeedback(
HapticFeedbackConstants.TEXT_HANDLE_MOVE,
HapticFeedbackConstants.KEYBOARD_TAP,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
)
}
Expand Down
131 changes: 86 additions & 45 deletions app/src/main/kotlin/org/fossify/keyboard/views/MyKeyboardView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ import org.fossify.keyboard.extensions.isDeviceLocked
import org.fossify.keyboard.extensions.onScroll
import org.fossify.keyboard.extensions.safeStorageContext
import org.fossify.keyboard.helpers.AccessHelper
import org.fossify.keyboard.helpers.CURSOR_SPEED_NORMAL
import org.fossify.keyboard.helpers.CURSOR_SPEED_SLOW
import org.fossify.keyboard.helpers.EMOJI_SPEC_FILE_PATH
import org.fossify.keyboard.helpers.EmojiData
import org.fossify.keyboard.helpers.KeyboardFeedbackManager
Expand Down Expand Up @@ -116,6 +118,7 @@ import org.fossify.keyboard.models.ClipsSectionLabel
import org.fossify.keyboard.models.ListItem
import java.util.Arrays
import java.util.Locale
import kotlin.math.abs

@SuppressLint("UseCompatLoadingForDrawables", "ClickableViewAccessibility")
class MyKeyboardView @JvmOverloads constructor(
Expand Down Expand Up @@ -194,13 +197,16 @@ class MyKeyboardView @JvmOverloads constructor(
private var mRepeatKeyIndex = NOT_A_KEY
private var mPopupLayout = 0
private var mAbortKey = false
private var mCursorControlActive = false
private var mLastSpaceMoveX = 0
private var mSpaceCursorArmed = false
private var mSpaceCursorActive = false
private var mSpaceCursorDownX = 0
private var mSpaceCursorAnchorX = 0
private var mSpaceCursorStepPx = 0
private val mSpaceCursorSlopPx = ViewConfiguration.get(context).scaledTouchSlop
private var mPopupMaxMoveDistance = 0f
private var mTopSmallNumberSize = 0f
private var mTopSmallNumberMarginWidth = 0f
private var mTopSmallNumberMarginHeight = 0f
private val mSpaceMoveThreshold: Int
private var ignoreTouches = false

private var mKeyBackground: Drawable? = null
Expand Down Expand Up @@ -270,7 +276,6 @@ class MyKeyboardView @JvmOverloads constructor(
mLabelTextSize = resources.getDimension(R.dimen.label_text_size).toInt()
mSpaceBarTextSize = resources.getDimension(R.dimen.space_bar_text_size).toInt()
mPreviewHeight = resources.getDimension(R.dimen.key_height).toInt()
mSpaceMoveThreshold = resources.getDimension(R.dimen.medium_margin).toInt()

with(safeStorageContext) {
mTextColor = getProperTextColor()
Expand Down Expand Up @@ -1439,11 +1444,11 @@ class MyKeyboardView @JvmOverloads constructor(

val msg = mHandler!!.obtainMessage(MSG_REPEAT)
mHandler!!.sendMessageDelayed(msg, REPEAT_START_DELAY.toLong())
// if the user long presses space bar, move the cursor after swiping left/right
// holding the space bar and swiping left/right moves the cursor instead of repeating the key
if (mKeys[mCurrentKey].code == KEYCODE_SPACE) {
mLastSpaceMoveX = -1
mCursorControlActive = false
armSpaceCursor(touchX)
} else {
mSpaceCursorArmed = false
repeatKey()
}

Expand Down Expand Up @@ -1488,29 +1493,10 @@ class MyKeyboardView @JvmOverloads constructor(
}
}

// activate cursor control immediately on sufficient movement
val currentKey = mKeys.getOrNull(mCurrentKey)
if (currentKey?.code == KEYCODE_SPACE && mLastSpaceMoveX != 0) {
if (mLastSpaceMoveX == -1) {
mLastSpaceMoveX = mLastX
}

val diff = mLastX - mLastSpaceMoveX
if (diff < -mSpaceMoveThreshold) {
for (i in diff / mSpaceMoveThreshold until 0) {
mOnKeyboardActionListener?.moveCursorLeft()
}
mLastSpaceMoveX = mLastX
if (!mCursorControlActive) mHandler?.removeMessages(MSG_LONGPRESS)
mCursorControlActive = true
} else if (diff > mSpaceMoveThreshold) {
for (i in 0 until diff / mSpaceMoveThreshold) {
mOnKeyboardActionListener?.moveCursorRight()
}
mLastSpaceMoveX = mLastX
if (!mCursorControlActive) mHandler?.removeMessages(MSG_LONGPRESS)
mCursorControlActive = true
}
// move the cursor when the space bar is held and swiped, without waiting for a long press
val isSpaceCursorSwipe = mSpaceCursorArmed && mKeys.getOrNull(mCurrentKey)?.code == KEYCODE_SPACE
if (isSpaceCursorSwipe) {
moveCursorBySpaceSwipe(touchX)
} else if (!continueLongPress) {
// Cancel old long-press
mHandler!!.removeMessages(MSG_LONGPRESS)
Expand All @@ -1530,7 +1516,7 @@ class MyKeyboardView @JvmOverloads constructor(
MotionEvent.ACTION_UP -> {
setCurrentKeyPressed(false)

mLastSpaceMoveX = 0
mSpaceCursorArmed = false
removeMessages()
if (keyIndex == mCurrentKey) {
mCurrentKeyTime += eventTime - mLastMoveTime
Expand All @@ -1554,18 +1540,18 @@ class MyKeyboardView @JvmOverloads constructor(
// If we're not on a repeating key (which sends on a DOWN event)
if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) {
detectAndSendKey(mCurrentKey, touchX, touchY, eventTime)
} else if (currentKeyCode == KEYCODE_SPACE && !mCursorControlActive) {
} else if (currentKeyCode == KEYCODE_SPACE && !mSpaceCursorActive) {
detectAndSendKey(mCurrentKey, touchX, touchY, eventTime)
}

mRepeatKeyIndex = NOT_A_KEY
mOnKeyboardActionListener!!.onActionUp()
mCursorControlActive = false
mSpaceCursorActive = false
}

MotionEvent.ACTION_CANCEL -> {
mCursorControlActive = false
mLastSpaceMoveX = 0
mSpaceCursorActive = false
mSpaceCursorArmed = false
removeMessages()
dismissPopupKeyboard()
mAbortKey = true
Expand Down Expand Up @@ -1607,17 +1593,72 @@ class MyKeyboardView @JvmOverloads constructor(
setupStoredClips()
}

private fun onSpaceBarLongPressed(): Boolean {
return if (!mCursorControlActive) {
setCurrentKeyPressed(false)
mRepeatKeyIndex = NOT_A_KEY
mHandler?.removeMessages(MSG_REPEAT)
vibrateIfNeeded()
SwitchLanguageDialog(this) {
mOnKeyboardActionListener?.reloadKeyboard()
/**
* Arms cursor control for a space bar press. Nothing moves yet: the finger must first travel past the touch
* slop for the press to count as a swipe (which cancels the pending long press), and the cursor then moves one
* character per [mSpaceCursorStepPx] of further travel.
*/
private fun armSpaceCursor(downX: Int) {
mSpaceCursorArmed = true
mSpaceCursorActive = false
mSpaceCursorDownX = downX
mSpaceCursorAnchorX = downX
mSpaceCursorStepPx = getSpaceCursorStepPx()
}

/**
* Moves the cursor left/right by one character for each [mSpaceCursorStepPx] the finger travelled along the
* space bar. The long press is cancelled as soon as the finger moves, so the language dialog never opens
* mid-swipe.
*/
private fun moveCursorBySpaceSwipe(x: Int) {
if (!mSpaceCursorActive) {
if (abs(x - mSpaceCursorDownX) <= mSpaceCursorSlopPx) return
mSpaceCursorActive = true
mHandler?.removeMessages(MSG_LONGPRESS)
}

val diff = x - mSpaceCursorAnchorX
when {
diff <= -mSpaceCursorStepPx -> repeat(-diff / mSpaceCursorStepPx) {
mOnKeyboardActionListener?.moveCursorLeft()
}
true
} else false
diff >= mSpaceCursorStepPx -> repeat(diff / mSpaceCursorStepPx) {
mOnKeyboardActionListener?.moveCursorRight()
}
else -> return
}
mSpaceCursorAnchorX = x
}

/**
* Distance the finger must travel along the space bar to move the cursor by one character, based on the speed
* setting.
*/
private fun getSpaceCursorStepPx(): Int {
val step = when (context.config.spaceBarCursorSpeed) {
CURSOR_SPEED_SLOW -> R.dimen.space_cursor_step_slow
CURSOR_SPEED_NORMAL -> R.dimen.space_cursor_step_normal
else -> R.dimen.space_cursor_step_fast // CURSOR_SPEED_FAST, the original Fossify speed
}
return resources.getDimension(step).toInt()
}

private fun onSpaceBarLongPressed(): Boolean {
if (mSpaceCursorActive) {
return false
}

// the language dialog takes over, so stop tracking the space bar for cursor control
mSpaceCursorArmed = false
setCurrentKeyPressed(false)
mRepeatKeyIndex = NOT_A_KEY
mHandler?.removeMessages(MSG_REPEAT)
vibrateIfNeeded()
SwitchLanguageDialog(this) {
mOnKeyboardActionListener?.reloadKeyboard()
}
return true
}

private fun onEmojiOrLanguageLongPressed(): Boolean {
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/res/layout/activity_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,28 @@

</RelativeLayout>

<RelativeLayout
android:id="@+id/settings_space_bar_cursor_speed_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<org.fossify.commons.views.MyTextView
android:id="@+id/settings_space_bar_cursor_speed_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/space_bar_cursor_speed" />

<org.fossify.commons.views.MyTextView
android:id="@+id/settings_space_bar_cursor_speed"
style="@style/SettingsTextValueStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_space_bar_cursor_speed_label" />

</RelativeLayout>

<RelativeLayout
android:id="@+id/settings_voice_input_method_holder"
style="@style/SettingsHolderTextViewStyle"
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
<dimen name="emoji_palette_btn_size">42dp</dimen>
<dimen name="suggestion_max_width">200dp</dimen>

<dimen name="space_cursor_step_slow">24dp</dimen>
<dimen name="space_cursor_step_normal">16dp</dimen>
<dimen name="space_cursor_step_fast">8dp</dimen>

<dimen name="keyboard_text_size">22sp</dimen>
<dimen name="preview_text_size">26sp</dimen>
<dimen name="label_text_size">16sp</dimen> <!-- text size used at keys with longer labels, like "123" -->
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
<string name="show_key_borders">Show key borders</string>
<string name="show_numbers_row">Show numbers on a separate row</string>
<string name="start_sentences_capitalized">Start sentences with a capital letter</string>
<string name="space_bar_cursor_speed">Cursor movement speed</string>
<string name="cursor_speed_slow">Slow</string>
<string name="cursor_speed_normal">Normal</string>
<string name="cursor_speed_fast">Fast</string>
<string name="show_emoji_key">Show emoji key</string>
<string name="show_language_switch_key">Show language switch key</string>
<!-- Emojis -->
Expand Down
Loading