Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,16 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
return
}
KeyCode.TOGGLE_AUTOCORRECT -> return settings.toggleAutoCorrect()
KeyCode.TOGGLE_AUTO_CAP, KeyCode.TOGGLE_FORCE_AUTO_CAPS -> {
if (primaryCode == KeyCode.TOGGLE_AUTO_CAP) settings.toggleAutoCapitalization()
else settings.toggleForceAutoCapitalization()
// An automatic shift refresh must not consume an explicit one-shot Shift.
if (keyboardSwitcher.keyboard?.mId?.isAlphabetShiftedManually != true) {
keyboardSwitcher.requestUpdatingShiftState(latinIME.currentAutoCapsState, latinIME.currentRecapitalizeState)
}
keyboardSwitcher.suggestionStripView?.updateToolbarButtonsActivatedState()
return
}
KeyCode.TOGGLE_INCOGNITO_MODE -> {
settings.toggleAlwaysIncognitoMode()
// Invalidate keyboard to update spacebar incognito icon immediately
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ class KeyboardIconsSet private constructor() {
ToolbarKey.TOUCHPAD -> R.drawable.ic_touchpad
ToolbarKey.TEXT_EDIT -> R.drawable.ic_text_edit
ToolbarKey.AUTOCORRECT -> R.drawable.ic_autocorrect
ToolbarKey.AUTO_CAP -> R.drawable.ic_auto_cap
ToolbarKey.FORCE_AUTO_CAPS -> R.drawable.ic_force_auto_caps
ToolbarKey.CLEAR_CLIPBOARD -> R.drawable.ic_bin
ToolbarKey.CLOSE_HISTORY -> R.drawable.ic_close
ToolbarKey.HANDWRITING -> R.drawable.ic_edit
Expand Down Expand Up @@ -245,6 +247,8 @@ class KeyboardIconsSet private constructor() {
ToolbarKey.TOUCHPAD -> R.drawable.ic_touchpad
ToolbarKey.TEXT_EDIT -> R.drawable.ic_text_edit
ToolbarKey.AUTOCORRECT -> R.drawable.ic_autocorrect
ToolbarKey.AUTO_CAP -> R.drawable.ic_auto_cap
ToolbarKey.FORCE_AUTO_CAPS -> R.drawable.ic_force_auto_caps
ToolbarKey.CLEAR_CLIPBOARD -> R.drawable.ic_bin
ToolbarKey.CLOSE_HISTORY -> R.drawable.ic_close
ToolbarKey.HANDWRITING -> R.drawable.ic_edit
Expand Down Expand Up @@ -325,6 +329,8 @@ class KeyboardIconsSet private constructor() {
ToolbarKey.TOUCHPAD -> R.drawable.ic_touchpad_rounded
ToolbarKey.TEXT_EDIT -> R.drawable.ic_text_edit
ToolbarKey.AUTOCORRECT -> R.drawable.ic_autocorrect_rounded
ToolbarKey.AUTO_CAP -> R.drawable.ic_auto_cap
ToolbarKey.FORCE_AUTO_CAPS -> R.drawable.ic_force_auto_caps
ToolbarKey.CLEAR_CLIPBOARD -> R.drawable.ic_bin
ToolbarKey.CLOSE_HISTORY -> R.drawable.ic_close_rounded
ToolbarKey.HANDWRITING -> R.drawable.ic_edit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ object KeyCode {
const val CLEAR_HANDWRITING = -10075
const val SWITCH_TO_USER_IME = -10076
const val OCR = -10077
const val TOGGLE_AUTO_CAP = -10079
const val TOGGLE_FORCE_AUTO_CAPS = -10080


// Intents
Expand All @@ -231,7 +233,7 @@ object KeyCode {
SEND_INTENT_THREE, INLINE_EMOJI_SEARCH_DONE, META_LOCK, PROOFREAD, TRANSLATE, SHOW_TRANSLATE_LANGUAGES,
CUSTOM_AI_1, CUSTOM_AI_2, CUSTOM_AI_3, CUSTOM_AI_4, CUSTOM_AI_5,
CUSTOM_AI_6, CUSTOM_AI_7, CUSTOM_AI_8, CUSTOM_AI_9, CUSTOM_AI_10, CLIPBOARD_SEARCH, TOGGLE_FLOATING_KEYBOARD, TOGGLE_TOUCHPAD_MODE, TOGGLE_TEXT_EDIT_MODE, TOGGLE_SELECTION_MODE, HANDWRITING, CLEAR_HANDWRITING, OCR,
CUSTOM1, CUSTOM2, CUSTOM3, CUSTOM4, CUSTOM5, SWITCH_TO_USER_IME
CUSTOM1, CUSTOM2, CUSTOM3, CUSTOM4, CUSTOM5, SWITCH_TO_USER_IME, TOGGLE_AUTO_CAP, TOGGLE_FORCE_AUTO_CAPS
-> this

// conversion
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/helium314/keyboard/latin/settings/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ class Settings private constructor() : SharedPreferences.OnSharedPreferenceChang
prefs.edit().putBoolean(PREF_AUTO_CORRECTION, !oldValue).apply()
}

fun toggleAutoCapitalization() {
val prefs = mPrefs ?: return
val oldValue = prefs.getBoolean(PREF_AUTO_CAP, Defaults.PREF_AUTO_CAP)
prefs.edit().putBoolean(PREF_AUTO_CAP, !oldValue).apply()
}

fun toggleForceAutoCapitalization() {
val prefs = mPrefs ?: return
val oldValue = prefs.getBoolean(PREF_FORCE_AUTO_CAPS, Defaults.PREF_FORCE_AUTO_CAPS)
prefs.edit().putBoolean(PREF_FORCE_AUTO_CAPS, !oldValue).apply()
}

fun toggleAlwaysIncognitoMode() {
val prefs = mPrefs ?: return
val oldValue = prefs.getBoolean(PREF_ALWAYS_INCOGNITO_MODE, Defaults.PREF_ALWAYS_INCOGNITO_MODE)
Expand Down
23 changes: 21 additions & 2 deletions app/src/main/java/helium314/keyboard/latin/utils/ToolbarUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import android.os.Handler
import android.os.Looper
import android.annotation.SuppressLint
import androidx.core.view.forEach
import androidx.core.view.ViewCompat
import helium314.keyboard.keyboard.internal.KeyboardIconsSet
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import helium314.keyboard.latin.BuildConfig
Expand Down Expand Up @@ -179,6 +180,8 @@ class TagDrawable(private val text: String) : Drawable() {
fun setToolbarButtonsActivatedStateOnPrefChange(buttonsGroup: ViewGroup, key: String?) {
// settings need to be updated when buttons change
if (key != Settings.PREF_AUTO_CORRECTION
&& key != Settings.PREF_AUTO_CAP
&& key != Settings.PREF_FORCE_AUTO_CAPS
&& key != Settings.PREF_ALWAYS_INCOGNITO_MODE
&& key?.startsWith(Settings.PREF_ONE_HANDED_MODE_PREFIX) == false)
return
Expand All @@ -202,12 +205,26 @@ fun setToolbarButtonActivatedState(button: ImageButton) {
ONE_HANDED -> Settings.getValues().mOneHandedModeEnabled
SPLIT -> Settings.getValues().mIsSplitKeyboardEnabled
AUTOCORRECT -> Settings.getValues().mAutoCorrectionEnabledPerUserSettings
AUTO_CAP -> Settings.getValues().mAutoCap
FORCE_AUTO_CAPS -> Settings.getValues().mAutoCap && Settings.getValues().mForceAutoCaps
SELECT_MODE -> helium314.keyboard.keyboard.KeyboardActionListenerImpl.sPersistentSelectionModeActive
else -> true
}
button.isActivated = activated
if (button.tag == AUTO_CAP || button.tag == FORCE_AUTO_CAPS) {
val prefs = button.context.prefs()
val saved = if (button.tag == AUTO_CAP) prefs.getBoolean(Settings.PREF_AUTO_CAP, Defaults.PREF_AUTO_CAP)
else prefs.getBoolean(Settings.PREF_FORCE_AUTO_CAPS, Defaults.PREF_FORCE_AUTO_CAPS)
val state = when {
!saved -> R.string.caps_control_off
activated -> R.string.caps_control_on
!prefs.getBoolean(Settings.PREF_AUTO_CAP, Defaults.PREF_AUTO_CAP) -> R.string.caps_control_paused_auto_cap
else -> R.string.caps_control_no_uppercase
}
ViewCompat.setStateDescription(button, button.context.getString(state))
}
val colors = Settings.getValues().mColors
if (activated && button.tag in listOf(INCOGNITO, ONE_HANDED, SPLIT, AUTOCORRECT, SELECT_MODE)) {
if (activated && button.tag in listOf(INCOGNITO, ONE_HANDED, SPLIT, AUTOCORRECT, AUTO_CAP, FORCE_AUTO_CAPS, SELECT_MODE)) {
colors.setColor(button.background, ColorType.TOOL_BAR_KEY_ENABLED_BACKGROUND)
if (button.drawable != null) {
button.clearColorFilter()
Expand Down Expand Up @@ -243,6 +260,8 @@ fun getCodeForToolbarKey(key: ToolbarKey) = Settings.getInstance().getCustomTool
TOUCHPAD -> KeyCode.TOGGLE_TOUCHPAD_MODE
TEXT_EDIT -> KeyCode.TOGGLE_TEXT_EDIT_MODE
AUTOCORRECT -> KeyCode.TOGGLE_AUTOCORRECT
AUTO_CAP -> KeyCode.TOGGLE_AUTO_CAP
FORCE_AUTO_CAPS -> KeyCode.TOGGLE_FORCE_AUTO_CAPS
CLEAR_CLIPBOARD -> KeyCode.CLIPBOARD_CLEAR_HISTORY
CLOSE_HISTORY -> KeyCode.ALPHA
EMOJI -> KeyCode.EMOJI
Expand Down Expand Up @@ -299,7 +318,7 @@ fun getCodeForToolbarKeyLongClick(key: ToolbarKey) = Settings.getInstance().getC
// names need to be aligned with resources strings (using lowercase of key.name)
enum class ToolbarKey {
VOICE, CLIPBOARD, CLIPBOARD_SEARCH, NUMPAD, HANDWRITING, UNDO, REDO, SETTINGS, SELECT_ALL, SELECT_WORD, COPY, CUT, PASTE, ONE_HANDED, SPLIT, FLOATING,
INCOGNITO, TOUCHPAD, TEXT_EDIT, AUTOCORRECT, CLEAR_CLIPBOARD, CLOSE_HISTORY, EMOJI, LEFT, RIGHT, UP, DOWN, WORD_LEFT, WORD_RIGHT,
INCOGNITO, TOUCHPAD, TEXT_EDIT, AUTOCORRECT, AUTO_CAP, FORCE_AUTO_CAPS, CLEAR_CLIPBOARD, CLOSE_HISTORY, EMOJI, LEFT, RIGHT, UP, DOWN, WORD_LEFT, WORD_RIGHT,
PAGE_UP, PAGE_DOWN, FULL_LEFT, FULL_RIGHT, PAGE_START, PAGE_END, PROOFREAD, TRANSLATE, OCR, SELECT_MODE,
CUSTOM_AI_1, CUSTOM_AI_2, CUSTOM_AI_3, CUSTOM_AI_4, CUSTOM_AI_5,
CUSTOM_AI_6, CUSTOM_AI_7, CUSTOM_AI_8, CUSTOM_AI_9, CUSTOM_AI_10
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_auto_cap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:fillType="evenOdd"
android:pathData="M2,20L7,6h2l5,14h-2.3l-1.1,-3.5H5.4L4.3,20zM6.1,14.5h3.8L8,9zM16,3a5,5 0,0 1,5 5v1h2l-3,3 -3,-3h2V8a3,3 0,0 0,-3 -3z" />
</vector>
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_force_auto_caps.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:fillType="evenOdd"
android:pathData="M2,20L7,6h2l5,14h-2.3l-1.1,-3.5H5.4L4.3,20zM6.1,14.5h3.8L8,9zM18,3h4l-3,6h4l-7,10 1,-8h-3z" />
</vector>
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,11 @@ New dictionary:
<string name="space_swipe_touchpad_mode_entry">Touchpad mode</string>
<string name="touchpad_sensitivity">Touchpad sensitivity</string>
<string name="force_auto_caps_title">Force auto-capitalization</string>
<string name="force_auto_caps">@string/force_auto_caps_title</string>
<string name="caps_control_on">On</string>
<string name="caps_control_off">Off</string>
<string name="caps_control_paused_auto_cap">Saved on; requires Auto-capitalization</string>
<string name="caps_control_no_uppercase">Saved on; this language has no uppercase letters</string>
<string name="force_auto_caps_summary">Force sentence capitalization on all text fields except passwords</string>
<!-- Title of the setting for variable toolbar direction -->
<string name="var_toolbar_direction">Variable toolbar direction</string>
Expand Down
54 changes: 54 additions & 0 deletions app/src/test/java/helium314/keyboard/KeyboardParserTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package helium314.keyboard

import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodSubtype
import androidx.core.content.edit
import com.android.inputmethod.keyboard.ProximityInfo
import helium314.keyboard.keyboard.Key
import helium314.keyboard.keyboard.Key.KeyParams
Expand All @@ -19,16 +20,22 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.POPUP_KEYS_NORMAL
import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToParams
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import helium314.keyboard.latin.LatinIME
import helium314.keyboard.latin.BuildConfig
import helium314.keyboard.latin.RichInputMethodSubtype
import helium314.keyboard.latin.common.Constants
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.LayoutType
import helium314.keyboard.latin.utils.LayoutType.Companion.toExtraValue
import helium314.keyboard.latin.utils.LayoutUtilsCustom
import helium314.keyboard.latin.utils.POPUP_KEYS_LAYOUT
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
import helium314.keyboard.latin.utils.clearCustomToolbarKeyCodes
import helium314.keyboard.latin.utils.prefs
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config
import org.robolectric.annotation.Implementation
import org.robolectric.annotation.Implements
Expand All @@ -51,6 +58,9 @@ class ParserTest {
private lateinit var params: KeyboardParams

@BeforeTest fun setUp() {
shadowOf(RuntimeEnvironment.getApplication()).grantPermissions(
"${BuildConfig.APPLICATION_ID}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
)
latinIME = Robolectric.setupService(LatinIME::class.java)
ShadowLog.setupLogging()
ShadowLog.stream = System.out
Expand Down Expand Up @@ -154,6 +164,50 @@ f""", // no newline at the end
assertIsExpected("""[[{ "label": "a" }]]""", Expected('a'.code, "a"))
}

@Test @Config(sdk = [32, 35])
fun capsControlsHaveKeywordNumericAndPopupActions() {
for ((label, code) in listOf("auto_cap" to -10079, "force_auto_caps" to -10080)) {
assertEquals(1, KeyCode::class.java.fields.count {
it.type == Int::class.javaPrimitiveType && it.getInt(null) == code
}, "$label must have a unique keycode")
assertIsExpected("""[[{"label":"$label"}]]""", Expected(code, icon = label))
assertIsExpected("""[[{"label":"caps","code":$code}]]""", Expected(code, "caps"))
assertIsExpected("""[[{"label":"x","popup":{"main":{"label":"$label"}}}]]""",
Expected('x'.code, "x", popups = listOf(null to code)))
val keyword = LayoutParser.parseJsonString("""[[{"label":"$label"}]]""")
.single().single().compute(params)!!.toKeyParams(params)
assertEquals(null, keyword.outputText)
val popup = LayoutParser.parseJsonString("""[[{"label":"x","popup":{"main":{"label":"$label"}}}]]""")
.single().single().compute(params)!!.toKeyParams(params).mPopupKeys!!.single()
assertEquals(label, popup.mIconName)
assertEquals(null, popup.mOutputText)
}
assertIsExpected("""[[{"label":"force_auto_cap"}]]""",
Expected(KeyCode.MULTIPLE_CODE_POINTS, "force_auto_cap", text = "force_auto_cap"))
}

@Test @Config(sdk = [32, 35])
fun capsControlKeywordsRespectToolbarRemapsButNumericCodesStayFixed() {
val prefs = latinIME.prefs()
val original = prefs.getString(Settings.PREF_TOOLBAR_CUSTOM_KEY_CODES, null)
try {
prefs.edit { putString(Settings.PREF_TOOLBAR_CUSTOM_KEY_CODES, "AUTO_CAP,-7,null;FORCE_AUTO_CAPS,-8,null") }
clearCustomToolbarKeyCodes()
for ((label, code, remapped) in listOf(
Triple("auto_cap", -10079, KeyCode.DELETE),
Triple("force_auto_caps", -10080, KeyCode.DELETE_WORD)
)) {
assertIsExpected("""[[{"label":"$label"}]]""", Expected(remapped, icon = label))
assertIsExpected("""[[{"label":"caps","code":$code}]]""", Expected(code, "caps"))
assertIsExpected("""[[{"label":"x","popup":{"main":{"label":"$label"}}}]]""",
Expected('x'.code, "x", popups = listOf(null to remapped)))
}
} finally {
prefs.edit { putString(Settings.PREF_TOOLBAR_CUSTOM_KEY_CODES, original) }
clearCustomToolbarKeyCodes()
}
}

@Test fun labelAndExplicitCode() {
assertIsExpected("""[[{ "$": "text_key" "label": "a", "code": 98 }]]""", Expected('b'.code, "a"))
}
Expand Down
Loading
Loading