diff --git a/.gitignore b/.gitignore
index 0be35df..ab69f14 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,5 @@ local.properties
.settings/
/svg
+
+/release
diff --git a/app/build.gradle b/app/build.gradle
index 2c9ee75..c255b96 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "io.github.deton.androidtutcode"
minSdkVersion 21
targetSdk 34
- versionCode 7
- versionName "1.4.0"
+ versionCode 8
+ versionName "1.5.0"
}
buildTypes {
@@ -32,15 +32,16 @@ android {
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = "17"
+ jvmTarget = '17'
}
}
dependencies {
implementation files('libs/jdbm-1.0.jar')
/* implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01' */
- implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.preference:preference-ktx:1.2.1'
+ implementation 'androidx.core:core-ktx:1.13.1'
}
repositories {
mavenCentral()
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2a8d312..50acfa2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -25,7 +25,12 @@
+ android:label="@string/label_pref_activity"
+ android:exported="true">
+
+
+
+
{
when (flick) {
- FLICK_STATE_NONE -> mService.commitTextSKK(",", 0)
- FLICK_STATE_LEFT -> mService.commitTextSKK(".", 0)
- FLICK_STATE_UP -> mService.commitTextSKK("-", 0)
- FLICK_STATE_RIGHT -> mService.commitTextSKK(":", 0)
+ FLICK_STATE_NONE -> mService.commitTextSKK(",")
+ FLICK_STATE_LEFT -> mService.commitTextSKK(".")
+ FLICK_STATE_UP -> mService.commitTextSKK("-")
+ FLICK_STATE_RIGHT -> mService.commitTextSKK(":")
}
return
}
@@ -721,7 +721,7 @@ class FlickJPKeyboardView : KeyboardView, KeyboardView.OnKeyboardActionListener
val cm = mService.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val cs = cm.text
val clip = cs?.toString() ?: ""
- mService.commitTextSKK(clip, 1)
+ mService.commitTextSKK(clip)
}
}
}
diff --git a/app/src/main/java/jp/deadend/noname/skk/Keyboard.kt b/app/src/main/java/jp/deadend/noname/skk/Keyboard.kt
index df8f0c4..82f22a3 100644
--- a/app/src/main/java/jp/deadend/noname/skk/Keyboard.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/Keyboard.kt
@@ -157,11 +157,10 @@ open class Keyboard {
a.recycle()
}
- fun onPressed() { pressed = !pressed }
-
- fun onReleased(inside: Boolean) {
- pressed = !pressed
- if (sticky && inside) { on = !on }
+ fun press() { pressed = true }
+ fun release() {
+ pressed = false
+ if (sticky) { on != on }
}
fun isInside(x: Int, y: Int): Boolean {
@@ -497,6 +496,13 @@ open class Keyboard {
a.recycle()
}
+ fun resetKeys() {
+ for (key in keys) {
+ key.on = false
+ key.pressed = false
+ }
+ }
+
companion object {
const val TAG = "Keyboard"
diff --git a/app/src/main/java/jp/deadend/noname/skk/KeyboardView.kt b/app/src/main/java/jp/deadend/noname/skk/KeyboardView.kt
index 9fb9eff..a8f2747 100644
--- a/app/src/main/java/jp/deadend/noname/skk/KeyboardView.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/KeyboardView.kt
@@ -4,11 +4,11 @@ import android.content.Context
import android.graphics.*
import android.graphics.Paint.Align
import android.graphics.drawable.Drawable
+import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.AttributeSet
-import android.util.TypedValue
import android.view.*
import android.view.GestureDetector.SimpleOnGestureListener
import android.widget.PopupWindow
@@ -35,15 +35,12 @@ open class KeyboardView @JvmOverloads constructor(
}
private var mKeyboard = Keyboard(context, R.xml.keys_null)
- private var mCurrentKeyIndex = NOT_A_KEY
+ private var mCurrentPreviewKeyIndex = NOT_A_KEY
private var mLabelTextSize = 0
private var mKeyTextSize = 0
private var mKeyTextColor = 0
- private var mShadowRadius = 0f
- private var mShadowColor = 0
private var mPreviewText: TextView? = null
private val mPreviewPopup = PopupWindow(context)
- private var mPreviewTextSizeLarge = 0
private var mPreviewOffset = 0
private var mPreviewHeight = 0
private val mCoordinates = IntArray(2) // working variable
@@ -76,7 +73,6 @@ open class KeyboardView @JvmOverloads constructor(
private var mDownKey = NOT_A_KEY
private var mLastKeyTime: Long = 0
private var mCurrentKeyTime: Long = 0
- private var mGestureDetector: GestureDetector? = null
private var mRepeatKeyIndex = NOT_A_KEY
private var mPopupLayout = 0
private var mAbortKey = false
@@ -84,8 +80,8 @@ open class KeyboardView @JvmOverloads constructor(
private val mClipRegion = Rect(0, 0, 0, 0)
private var mPossiblePoly = false
private val mSwipeTracker = SwipeTracker()
- private val mSwipeThreshold: Int
- private val mDisambiguateSwipe: Boolean
+ private val mSwipeThreshold = (500 * resources.displayMetrics.density).toInt()
+ private val mDisambiguateSwipe = resources.getBoolean(R.bool.config_swipeDisambiguation)
// Variables for dealing with multiple pointers
private var mOldPointerCount = 1
@@ -109,17 +105,69 @@ open class KeyboardView @JvmOverloads constructor(
private val mHandler: Handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
- MSG_SHOW_PREVIEW -> showKey(msg.arg1)
- MSG_REMOVE_PREVIEW -> mPreviewText?.visibility = INVISIBLE
- MSG_REPEAT -> if (repeatKey()) {
- val repeat = Message.obtain(this, MSG_REPEAT)
- sendMessageDelayed(repeat, REPEAT_INTERVAL.toLong())
+ MSG_SHOW_PREVIEW -> showKeyInPreview(msg.arg1)
+ MSG_REMOVE_PREVIEW -> {
+ mPreviewText?.visibility = INVISIBLE
+ mPreviewPopup.dismiss()
+ }
+ MSG_REPEAT -> {
+ detectAndSendKey(mCurrentKey, mLastTapTime)
+ sendMessageDelayed(Message.obtain(this, MSG_REPEAT), REPEAT_INTERVAL.toLong())
}
MSG_LONGPRESS -> openPopupIfRequired()
}
}
}
+ private val mGestureDetector = GestureDetector(context, object : SimpleOnGestureListener() {
+ override fun onFling(
+ me1: MotionEvent?, me2: MotionEvent, velocityX: Float, velocityY: Float
+ ): Boolean {
+ if (mPossiblePoly || me1 == null) return false
+ val absX = abs(velocityX)
+ val absY = abs(velocityY)
+ val deltaX = me2.x - me1.x
+ val deltaY = me2.y - me1.y
+ val travelX = width / 2 // Half the keyboard width
+ val travelY = height / 2 // Half the keyboard height
+ mSwipeTracker.computeCurrentVelocity(1000)
+ val endingVelocityX = mSwipeTracker.xVelocity
+ val endingVelocityY = mSwipeTracker.yVelocity
+ var sendDownKey = false
+ if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) {
+ if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) {
+ sendDownKey = true
+ } else {
+ swipeRight()
+ return true
+ }
+ } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) {
+ if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) {
+ sendDownKey = true
+ } else {
+ swipeLeft()
+ return true
+ }
+ } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) {
+ if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) {
+ sendDownKey = true
+ } else {
+ swipeUp()
+ return true
+ }
+ } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) {
+ if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) {
+ sendDownKey = true
+ } else {
+ swipeDown()
+ return true
+ }
+ }
+ if (sendDownKey) { detectAndSendKey(mDownKey, me1.eventTime) }
+ return false
+ }
+ })
+
init {
// val a = context.obtainStyledAttributes(
// attrs, R.styleable.KeyboardView, defStyleAttr, defStyleRes
@@ -148,10 +196,6 @@ open class KeyboardView @JvmOverloads constructor(
mLabelTextSize = a.getDimensionPixelSize(attr, 14)
R.styleable.KeyboardView_popupLayout ->
mPopupLayout = a.getResourceId(attr, 0)
- R.styleable.KeyboardView_shadowColor ->
- mShadowColor = a.getColor(attr, 0)
- R.styleable.KeyboardView_shadowRadius ->
- mShadowRadius = a.getFloat(attr, 0f)
}
}
a.recycle()
@@ -160,15 +204,21 @@ open class KeyboardView @JvmOverloads constructor(
mPreviewText =
(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
.inflate(previewLayout, null) as TextView
- mPreviewTextSizeLarge = mPreviewText?.textSize?.toInt() ?: 0
mPreviewPopup.contentView = mPreviewText
mPreviewPopup.setBackgroundDrawable(null)
+ mPreviewPopup.isClippingEnabled = false
+ mPreviewPopup.animationStyle = 0
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mPreviewPopup.enterTransition = null
+ mPreviewPopup.exitTransition = null
+ }
} else {
isPreviewEnabled = false
}
mPreviewPopup.isTouchable = false
mPopupKeyboard.setBackgroundDrawable(null)
+ mPopupKeyboard.isClippingEnabled = false
mPopupParent = this
mPaint.isAntiAlias = true
@@ -178,76 +228,17 @@ open class KeyboardView @JvmOverloads constructor(
mKeyBackground?.getPadding(mPadding)
- mSwipeThreshold = (500 * resources.displayMetrics.density).toInt()
- mDisambiguateSwipe = resources.getBoolean(R.bool.config_swipeDisambiguation)
+ mGestureDetector.setIsLongpressEnabled(false)
resetMultiTap()
}
- override fun onAttachedToWindow() {
- super.onAttachedToWindow()
- initGestureDetector()
- }
-
- private fun initGestureDetector() {
- if (mGestureDetector == null) {
- mGestureDetector = GestureDetector(context, object : SimpleOnGestureListener() {
- override fun onFling(
- me1: MotionEvent?, me2: MotionEvent, velocityX: Float, velocityY: Float
- ): Boolean {
- if (mPossiblePoly || me1 == null) return false
- val absX = abs(velocityX)
- val absY = abs(velocityY)
- val deltaX = me2.x - me1.x
- val deltaY = me2.y - me1.y
- val travelX = width / 2 // Half the keyboard width
- val travelY = height / 2 // Half the keyboard height
- mSwipeTracker.computeCurrentVelocity(1000)
- val endingVelocityX = mSwipeTracker.xVelocity
- val endingVelocityY = mSwipeTracker.yVelocity
- var sendDownKey = false
- if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) {
- sendDownKey = if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) {
- true
- } else {
- swipeRight()
- return true
- }
- } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) {
- sendDownKey = if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) {
- true
- } else {
- swipeLeft()
- return true
- }
- } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) {
- sendDownKey = if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) {
- true
- } else {
- swipeUp()
- return true
- }
- } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) {
- sendDownKey = if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) {
- true
- } else {
- swipeDown()
- return true
- }
- }
- if (sendDownKey) { detectAndSendKey(mDownKey, mStartX, mStartY, me1.eventTime) }
- return false
- }
- })
- mGestureDetector?.setIsLongpressEnabled(false)
- }
- }
-
var keyboard: Keyboard
get() = mKeyboard
set(keyboard) {
removeMessages()
mKeyboard = keyboard
+ mKeyboard.resetKeys()
requestLayout()
// Hint to reallocate the buffer if the size changed
mKeyboardChanged = true
@@ -264,11 +255,11 @@ open class KeyboardView @JvmOverloads constructor(
if (mKeyboard.setShifted(value)) { invalidateAllKeys() }
}
- fun setPopupParent(v: View) {
+ private fun setPopupParent(v: View) {
mPopupParent = v
}
- fun setPopupOffset(x: Int, y: Int) {
+ private fun setPopupOffset(x: Int, y: Int) {
mMiniKeyboardOffsetX = x
mMiniKeyboardOffsetY = y
if (mPreviewPopup.isShowing) { mPreviewPopup.dismiss() }
@@ -289,10 +280,9 @@ open class KeyboardView @JvmOverloads constructor(
}
public override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- var width = mKeyboard.width + paddingLeft + paddingRight
- if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) {
- width = MeasureSpec.getSize(widthMeasureSpec)
- }
+ val size = MeasureSpec.getSize(widthMeasureSpec)
+ val width = if (size < width + 10) size else mKeyboard.width + paddingLeft + paddingRight
+
setMeasuredDimension(width, mKeyboard.height + paddingTop + paddingBottom)
}
@@ -329,21 +319,19 @@ open class KeyboardView @JvmOverloads constructor(
val kbdPaddingTop = paddingTop
val invalidKey = mInvalidatedKey
mPaint.color = mKeyTextColor
- var drawSingleKey = false
- if (invalidKey != null && canvas.getClipBounds(mClipRegion)) {
- // Is clipRegion completely contained within the invalidated key?
- if (invalidKey.x + kbdPaddingLeft - 1 <= mClipRegion.left
+ val drawSingleKey = (
+ invalidKey != null
+ && canvas.getClipBounds(mClipRegion)
+ // Is clipRegion completely contained within the invalidated key?
+ && invalidKey.x + kbdPaddingLeft - 1 <= mClipRegion.left
&& invalidKey.y + kbdPaddingTop - 1 <= mClipRegion.top
&& invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= mClipRegion.right
&& invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= mClipRegion.bottom
- ) {
- drawSingleKey = true
- }
- }
+ )
keyBackground?.alpha = backgroundAlpha
canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR)
- for (i in 0 until mKeyboard.keys.size) {
- val key = mKeyboard.keys[i]
+
+ for (key in mKeyboard.keys) {
if (drawSingleKey && invalidKey !== key) { continue }
keyBackground?.state = key.currentDrawableState
@@ -366,8 +354,6 @@ open class KeyboardView @JvmOverloads constructor(
mPaint.textSize = mKeyTextSize.toFloat()
mPaint.typeface = Typeface.DEFAULT
}
- // Draw a drop shadow for the text
- mPaint.setShadowLayer(mShadowRadius, 0f, 0f, mShadowColor)
// Draw the text
canvas.drawText(
label,
@@ -375,8 +361,6 @@ open class KeyboardView @JvmOverloads constructor(
(key.height - mPadding.top - mPadding.bottom) / 2f + (mPaint.textSize - mPaint.descent()) / 2 + mPadding.top,
mPaint
)
- // Turn off drop shadow
- mPaint.setShadowLayer(0f, 0f, 0f, 0)
} else if (icon != null) {
val drawableX =
(key.width - mPadding.left - mPadding.right - icon.intrinsicWidth) / 2 + mPadding.left
@@ -402,19 +386,13 @@ open class KeyboardView @JvmOverloads constructor(
}
}
- private fun getKeyIndices(x: Int, y: Int): Int {
- var primaryIndex = NOT_A_KEY
- val nearestKeyIndices = mKeyboard.getNearestKeys(x, y)
- for (i in nearestKeyIndices.indices) {
- if (mKeyboard.keys[nearestKeyIndices[i]].isInside(x, y)) {
- primaryIndex = nearestKeyIndices[i]
- }
- }
-
- return primaryIndex
+ private fun getKeyIndex(x: Int, y: Int): Int {
+ return mKeyboard.getNearestKeys(x, y).findLast {
+ mKeyboard.keys[it].isInside(x, y)
+ } ?: NOT_A_KEY
}
- private fun detectAndSendKey(index: Int, x: Int, y: Int, eventTime: Long) {
+ private fun detectAndSendKey(index: Int, eventTime: Long) {
if (index != NOT_A_KEY && index < mKeyboard.keys.size) {
val key = mKeyboard.keys[index]
val text = key.text
@@ -423,8 +401,6 @@ open class KeyboardView @JvmOverloads constructor(
onKeyboardActionListener?.onRelease(NOT_A_KEY)
} else {
var code = key.codes[0]
- //TextEntryState.keyPressedAt(key, x, y);
- getKeyIndices(x, y)
// Multi-tap
if (mInMultiTap) {
if (mTapCount != -1) {
@@ -452,35 +428,31 @@ open class KeyboardView @JvmOverloads constructor(
}
}
+ private fun pressKey(keyIndex: Int) {
+ if (keyIndex < 0 || keyIndex >= mKeyboard.keys.size) { return }
+ mKeyboard.keys[keyIndex].press()
+ invalidateKey(keyIndex)
+ showPreview(keyIndex)
+ }
+
+ private fun releaseKey(keyIndex: Int) {
+ if (keyIndex < 0 || keyIndex >= mKeyboard.keys.size) { return }
+ mKeyboard.keys[keyIndex].release()
+ invalidateKey(keyIndex)
+ hidePreview()
+ }
+
+
private fun showPreview(keyIndex: Int) {
- val oldKeyIndex = mCurrentKeyIndex
- mCurrentKeyIndex = keyIndex
- // Release the old key and press the new key
- val keys = mKeyboard.keys
- if (oldKeyIndex != mCurrentKeyIndex) {
- if (oldKeyIndex != NOT_A_KEY && keys.size > oldKeyIndex) {
- keys[oldKeyIndex].onReleased(mCurrentKeyIndex == NOT_A_KEY)
- invalidateKey(oldKeyIndex)
- }
- if (mCurrentKeyIndex != NOT_A_KEY && keys.size > mCurrentKeyIndex) {
- keys[mCurrentKeyIndex].onPressed()
- invalidateKey(mCurrentKeyIndex)
- }
- }
- if (oldKeyIndex != mCurrentKeyIndex && isPreviewEnabled) {
+ val oldKeyIndex = mCurrentPreviewKeyIndex
+ mCurrentPreviewKeyIndex = keyIndex
+
+ if (isPreviewEnabled && oldKeyIndex != mCurrentPreviewKeyIndex) {
mHandler.removeMessages(MSG_SHOW_PREVIEW)
- if (mPreviewPopup.isShowing) {
- if (keyIndex == NOT_A_KEY) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_REMOVE_PREVIEW),
- DELAY_AFTER_PREVIEW.toLong()
- )
- }
- }
if (keyIndex != NOT_A_KEY) {
if (mPreviewPopup.isShowing && mPreviewText?.visibility == VISIBLE) {
// Show right away, if it's already visible and finger is moving around
- showKey(keyIndex)
+ showKeyInPreview(keyIndex)
} else {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0),
@@ -491,27 +463,26 @@ open class KeyboardView @JvmOverloads constructor(
}
}
- private fun showKey(keyIndex: Int) {
+ private fun hidePreview() {
+ mCurrentPreviewKeyIndex = NOT_A_KEY
+ mHandler.removeMessages(MSG_SHOW_PREVIEW)
+ if (isPreviewEnabled && mPreviewPopup.isShowing) {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_REMOVE_PREVIEW),
+ DELAY_AFTER_PREVIEW.toLong()
+ )
+ }
+ }
+
+ private fun showKeyInPreview(keyIndex: Int) {
mPreviewText?.let { previewText ->
if (keyIndex < 0 || keyIndex >= mKeyboard.keys.size) { return }
val key = mKeyboard.keys[keyIndex]
- if (key.icon != null) {
- previewText.setCompoundDrawables(
- null, null, null,
- if (key.iconPreview != null) key.iconPreview else key.icon
- )
- previewText.text = null
- } else {
- previewText.setCompoundDrawables(null, null, null, null)
- previewText.text = getPreviewText(key)
- if (key.label.length > 1 && key.codes.size < 2) {
- previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize.toFloat())
- previewText.typeface = Typeface.DEFAULT_BOLD
- } else {
- previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge.toFloat())
- previewText.typeface = Typeface.DEFAULT
- }
- }
+ if (key.icon != null || (key.label.length > 1 && key.codes.size < 2)) { return }
+ // show only single character keys
+
+ previewText.text = getPreviewText(key)
+ previewText.typeface = Typeface.DEFAULT
previewText.measure(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
@@ -564,6 +535,19 @@ open class KeyboardView @JvmOverloads constructor(
}
}
+ protected fun switchCaseInPreview() {
+ mPreviewText?.let {
+ val previewText = it.text
+ if (previewText.isNotEmpty()) {
+ it.text = if (Character.isLowerCase(previewText[0])) {
+ previewText.toString().uppercase(Locale.getDefault())
+ } else {
+ previewText.toString().lowercase(Locale.getDefault())
+ }
+ }
+ }
+ }
+
fun invalidateAllKeys() {
mDirtyRect.union(0, 0, width, height)
mDrawPending = true
@@ -590,7 +574,7 @@ open class KeyboardView @JvmOverloads constructor(
val result = onLongPress(mKeyboard.keys[mCurrentKey])
if (result) {
mAbortKey = true
- showPreview(NOT_A_KEY)
+ releaseKey(mCurrentKey)
}
return result
}
@@ -598,15 +582,16 @@ open class KeyboardView @JvmOverloads constructor(
protected open fun onLongPress(key: Keyboard.Key): Boolean {
val popupKeyboardId = key.popupResId
if (popupKeyboardId != 0) {
- var miniKeyboardContainer = mMiniKeyboardCache[key]
- val mMiniKeyboard: KeyboardView
- if (miniKeyboardContainer == null) {
- miniKeyboardContainer =
- (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
- .inflate(mPopupLayout, null)
- mMiniKeyboard = miniKeyboardContainer.findViewById(R.id.keyboardView)
+ val cached = mMiniKeyboardCache[key]
+ val miniKeyboardContainer: View
+ val miniKeyboardView: KeyboardView
+
+ if (cached == null) {
+ miniKeyboardContainer = (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
+ .inflate(mPopupLayout, null)
miniKeyboardContainer.findViewById(R.id.closeButton)?.setOnClickListener(this)
- mMiniKeyboard.onKeyboardActionListener = object : OnKeyboardActionListener {
+ miniKeyboardView = miniKeyboardContainer.findViewById(R.id.keyboardView)
+ miniKeyboardView.onKeyboardActionListener = object : OnKeyboardActionListener {
override fun onKey(primaryCode: Int) {
onKeyboardActionListener?.onKey(primaryCode)
dismissPopupKeyboard()
@@ -631,7 +616,7 @@ open class KeyboardView @JvmOverloads constructor(
}
}
val popupChars = key.popupCharacters
- val kb: Keyboard = if (popupChars != null) {
+ miniKeyboardView.keyboard = if (popupChars != null) {
Keyboard(
context, popupKeyboardId,
popupChars, -1, paddingLeft + paddingRight
@@ -639,39 +624,41 @@ open class KeyboardView @JvmOverloads constructor(
} else {
Keyboard(context, popupKeyboardId)
}
- mMiniKeyboard.keyboard = kb
- mMiniKeyboard.setPopupParent(this)
+ miniKeyboardView.setPopupParent(this)
+ mKeyBackground?.let { miniKeyboardView.setKeyBackground(it) } // for inset
miniKeyboardContainer.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)
)
mMiniKeyboardCache[key] = miniKeyboardContainer
} else {
- mMiniKeyboard = miniKeyboardContainer.findViewById(R.id.keyboardView)
+ miniKeyboardContainer = cached
+ miniKeyboardView = miniKeyboardContainer.findViewById(R.id.keyboardView)
}
+
getLocationInWindow(mCoordinates)
- var mPopupX = key.x + paddingLeft
- var mPopupY = key.y + paddingTop
- mPopupX += key.width - miniKeyboardContainer!!.measuredWidth
- mPopupY -= miniKeyboardContainer.measuredHeight
- val x = mPopupX + miniKeyboardContainer.paddingRight + mCoordinates[0]
+ val mPopupX = key.x + paddingLeft + key.width - miniKeyboardContainer.measuredWidth
+ val mPopupY = key.y + paddingTop - miniKeyboardContainer.measuredHeight
+ val x = (mPopupX + miniKeyboardContainer.paddingRight + mCoordinates[0]).coerceAtLeast(0)
val y = mPopupY + miniKeyboardContainer.paddingBottom + mCoordinates[1]
- mMiniKeyboard.setPopupOffset(x.coerceAtLeast(0), y)
- mMiniKeyboard.isShifted = isShifted
+ miniKeyboardView.setPopupOffset(x.coerceAtLeast(0), y)
+ miniKeyboardView.isShifted = isShifted
+
mPopupKeyboard.contentView = miniKeyboardContainer
mPopupKeyboard.width = miniKeyboardContainer.measuredWidth
mPopupKeyboard.height = miniKeyboardContainer.measuredHeight
mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y)
mMiniKeyboardOnScreen = true
- //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me));
+ //miniKeyboardView.onTouchEvent(getTranslatedEvent(me));
invalidateAllKeys()
+
return true
}
return false
}
override fun onTouchEvent(event: MotionEvent): Boolean {
- if (!isEnabled) { return true }
+ if (!isEnabled) { return false }
// Convert multi-pointer up/down events to single up/down events to
// deal with the typical multi-pointer behavior of two-thumb typing
val pointerCount = event.pointerCount
@@ -719,7 +706,7 @@ open class KeyboardView @JvmOverloads constructor(
if (touchY >= -mVerticalCorrection) { touchY += mVerticalCorrection }
val action = me.action
val eventTime = me.eventTime
- val keyIndex = getKeyIndices(touchX, touchY)
+ val keyIndex = getKeyIndex(touchX, touchY)
mPossiblePoly = possiblePoly
// Track the last few movements to look for spurious swipes.
@@ -731,8 +718,8 @@ open class KeyboardView @JvmOverloads constructor(
return true
}
- if (mGestureDetector?.onTouchEvent(me) == true) {
- showPreview(NOT_A_KEY)
+ if (mGestureDetector.onTouchEvent(me)) {
+ releaseKey(mCurrentKey)
mHandler.removeMessages(MSG_REPEAT)
mHandler.removeMessages(MSG_LONGPRESS)
return true
@@ -765,17 +752,18 @@ open class KeyboardView @JvmOverloads constructor(
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MSG_REPEAT), REPEAT_START_DELAY.toLong()
)
- repeatKey()
+ detectAndSendKey(mCurrentKey, mLastTapTime)
+ if (mAbortKey) { // Delivering the key could have caused an abort
+ mRepeatKeyIndex = NOT_A_KEY
+ }
}
- if (mAbortKey) { // Delivering the key could have caused an abort
- mRepeatKeyIndex = NOT_A_KEY
- } else {
+ if (!mAbortKey) {
if (mCurrentKey != NOT_A_KEY) {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MSG_LONGPRESS, me), LONGPRESS_TIMEOUT.toLong()
)
}
- showPreview(keyIndex)
+ pressKey(keyIndex)
}
}
MotionEvent.ACTION_MOVE -> {
@@ -784,11 +772,14 @@ open class KeyboardView @JvmOverloads constructor(
if (mCurrentKey == NOT_A_KEY) {
mCurrentKey = keyIndex
mCurrentKeyTime = eventTime - mDownTime
+ pressKey(keyIndex)
} else {
if (keyIndex == mCurrentKey) {
mCurrentKeyTime += eventTime - mLastMoveTime
continueLongPress = true
} else if (mRepeatKeyIndex == NOT_A_KEY) {
+ releaseKey(mCurrentKey)
+ pressKey(keyIndex)
resetMultiTap()
mLastKey = mCurrentKey
mLastCodeX = mLastX
@@ -809,7 +800,6 @@ open class KeyboardView @JvmOverloads constructor(
)
}
}
- showPreview(mCurrentKey)
mLastMoveTime = eventTime
}
MotionEvent.ACTION_UP -> {
@@ -828,20 +818,20 @@ open class KeyboardView @JvmOverloads constructor(
touchX = mLastCodeX
touchY = mLastCodeY
}
- showPreview(NOT_A_KEY)
+ releaseKey(mCurrentKey)
+ releaseKey(keyIndex)
// 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)
+ detectAndSendKey(mCurrentKey, eventTime)
}
- invalidateKey(keyIndex)
mRepeatKeyIndex = NOT_A_KEY
}
MotionEvent.ACTION_CANCEL -> {
removeMessages()
dismissPopupKeyboard()
mAbortKey = true
- showPreview(NOT_A_KEY)
- invalidateKey(mCurrentKey)
+ releaseKey(mCurrentKey)
+ releaseKey(keyIndex)
}
}
mLastX = touchX
@@ -849,12 +839,6 @@ open class KeyboardView @JvmOverloads constructor(
return true
}
- private fun repeatKey(): Boolean {
- val key = mKeyboard.keys[mRepeatKeyIndex]
- detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime)
- return true
- }
-
protected open fun swipeRight() = onKeyboardActionListener?.swipeRight()
protected open fun swipeLeft() = onKeyboardActionListener?.swipeLeft()
protected open fun swipeUp() = onKeyboardActionListener?.swipeUp()
@@ -888,7 +872,7 @@ open class KeyboardView @JvmOverloads constructor(
}
}
- fun handleBack(): Boolean {
+ open fun handleBack(): Boolean {
if (mPopupKeyboard.isShowing) {
dismissPopupKeyboard()
return true
diff --git a/app/src/main/java/jp/deadend/noname/skk/QwertyKeyboardView.kt b/app/src/main/java/jp/deadend/noname/skk/QwertyKeyboardView.kt
index 4149b11..43084bc 100644
--- a/app/src/main/java/jp/deadend/noname/skk/QwertyKeyboardView.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/QwertyKeyboardView.kt
@@ -4,9 +4,15 @@ import android.content.Context
import android.view.KeyEvent
import android.view.MotionEvent
import android.util.AttributeSet
+import java.io.BufferedReader
+import java.io.IOException
+import java.io.InputStream
+import java.io.InputStreamReader
class QwertyKeyboardView : KeyboardView, KeyboardView.OnKeyboardActionListener {
private lateinit var mService: SKKService
+ private val mInputHistory = StringBuilder() // suggestion用に入力の履歴を覚えておく
+ private val mList = mutableListOf() // suggestion用の単語リスト(頻度順)
private val mLatinKeyboard = Keyboard(context, R.xml.qwerty)
private val mSymbolsKeyboard = Keyboard(context, R.xml.symbols)
@@ -30,6 +36,23 @@ class QwertyKeyboardView : KeyboardView, KeyboardView.OnKeyboardActionListener {
isShifted = false
}
+ override fun handleBack(): Boolean {
+ clearSuggestions()
+ return super.handleBack()
+ }
+
+ @Throws(IOException::class)
+ internal fun loadFrequencyList(inputStream: InputStream) {
+ mList.clear()
+ BufferedReader(InputStreamReader(inputStream)).use { bufferedReader ->
+ bufferedReader.forEachLine { line ->
+ if (line.length > 3) { mList.add(line) }
+ // 短い単語はsuggestionに入れない
+ // 読んだ順に入れるだけなので、ファイルの内容自体が頻度順に並んでいることが前提
+ }
+ }
+ }
+
fun setService(listener: SKKService) {
mService = listener
}
@@ -61,7 +84,9 @@ class QwertyKeyboardView : KeyboardView, KeyboardView.OnKeyboardActionListener {
val dy2 = dy * dy
if (dx2 + dy2 > mFlickSensitivitySquared) {
if (dy < 0 && dx2 < dy2) {
+ val oldMFlicked = mFlicked
mFlicked = true
+ if (!oldMFlicked) { switchCaseInPreview() }
return true
}
}
@@ -75,6 +100,13 @@ class QwertyKeyboardView : KeyboardView, KeyboardView.OnKeyboardActionListener {
when (primaryCode) {
Keyboard.KEYCODE_DELETE -> {
if (!mService.handleBackspace()) mService.keyDownUp(KeyEvent.KEYCODE_DEL)
+ if (mInputHistory.length > 1) {
+ mInputHistory.deleteCharAt(mInputHistory.length - 1)
+ updateAsciiSuggestions(mInputHistory.toString())
+ } else if (mInputHistory.length == 1) {
+ clearSuggestions()
+ }
+ return
}
Keyboard.KEYCODE_SHIFT -> {
isShifted = !isShifted
@@ -98,9 +130,39 @@ class QwertyKeyboardView : KeyboardView, KeyboardView.OnKeyboardActionListener {
} else {
primaryCode
}
- mService.commitTextSKK(code.toChar().toString(), 1)
+ if (keyboard == mLatinKeyboard && isShifted) { isShifted = false }
+
+ mService.commitTextSKK(code.toChar().toString())
+ if (code.toChar().isLetter()) {
+ mInputHistory.append(code.toChar())
+ mService.getTextBeforeCursor(mInputHistory.length)?.let {
+ if (!mInputHistory.contentEquals(it)) {
+ mInputHistory.clear()
+ mInputHistory.append(code.toChar())
+ }
+ updateAsciiSuggestions(mInputHistory.toString())
+ return
+ }
+ }
}
}
+
+ clearSuggestions()
+ }
+
+ private fun updateAsciiSuggestions(str: String) {
+ mService.setCandidates(
+ mList.filter { it.startsWith(str) }.take(20)
+ )
+ }
+
+ fun getHistoryLength() = mInputHistory.length
+
+ fun clearSuggestions() {
+ if (mInputHistory.isNotEmpty()) {
+ mInputHistory.clear()
+ mService.clearCandidatesView()
+ }
}
override fun onPress(primaryCode: Int) {}
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKDicManager.kt b/app/src/main/java/jp/deadend/noname/skk/SKKDicManager.kt
index 48344a3..06ff4f0 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKDicManager.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKDicManager.kt
@@ -90,6 +90,7 @@ class SKKDicManager : AppCompatActivity() {
val intent = Intent(SKKService.ACTION_COMMAND)
+ intent.setPackage(packageName)
intent.putExtra(SKKService.KEY_COMMAND, SKKService.COMMAND_RELOAD_DICS)
sendBroadcast(intent)
}
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKMushroom.kt b/app/src/main/java/jp/deadend/noname/skk/SKKMushroom.kt
index da5ccf8..f520406 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKMushroom.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKMushroom.kt
@@ -31,6 +31,7 @@ class SKKMushroom : AppCompatActivity() {
val s = if (extras == null) "" else extras.getString(REPLACE_KEY)
val retIntent = Intent(ACTION_BROADCAST)
+ retIntent.setPackage(packageName)
retIntent.addCategory(CATEGORY_BROADCAST)
retIntent.putExtra(REPLACE_KEY, s)
sendBroadcast(retIntent)
@@ -38,8 +39,8 @@ class SKKMushroom : AppCompatActivity() {
finish()
}
- override fun onCreate(icicle: Bundle?) {
- super.onCreate(icicle)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
binding = ActivityListBinding.inflate(layoutInflater)
setContentView(binding.root)
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKPrefs.kt b/app/src/main/java/jp/deadend/noname/skk/SKKPrefs.kt
index 8048dbc..02c458c 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKPrefs.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKPrefs.kt
@@ -86,11 +86,11 @@ class SKKPrefs(context: Context) {
var keyWidthPort: Int
get() = prefs.getInt(res.getString(R.string.prefkey_key_width_port), 100)
- set(value) = prefs.edit().putInt(res.getString(R.string.prefkey_key_height_port), value).apply()
+ set(value) = prefs.edit().putInt(res.getString(R.string.prefkey_key_width_port), value).apply()
var keyWidthLand: Int
get() = prefs.getInt(res.getString(R.string.prefkey_key_width_land), 100)
- set(value) = prefs.edit().putInt(res.getString(R.string.prefkey_key_height_land), value).apply()
+ set(value) = prefs.edit().putInt(res.getString(R.string.prefkey_key_width_land), value).apply()
var keyPosition: String
get() = prefs.getString(res.getString(R.string.prefkey_key_position), null) ?: "center"
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKService.kt b/app/src/main/java/jp/deadend/noname/skk/SKKService.kt
index 29892f6..a4251f2 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKService.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKService.kt
@@ -1,5 +1,6 @@
package jp.deadend.noname.skk
+import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.BroadcastReceiver
@@ -17,7 +18,10 @@ import android.speech.RecognitionListener
import android.speech.RecognizerIntent
import android.speech.SpeechRecognizer
import android.content.ClipboardManager
+import android.content.pm.PackageManager
+import android.net.Uri
import android.os.Build
+import android.provider.Settings
import android.text.InputType
import android.util.Log
import android.util.TypedValue
@@ -49,8 +53,6 @@ class SKKService : InputMethodService() {
// onKeyDown()でEnterキーのイベントを消費したかどうかのフラグ.onKeyUp()で判定するのに使う
private var isEnterUsed = false
- private var isCandidatesViewShownFlag = false
-
private val mShiftKey = SKKStickyShift(this)
private var mStickyShift = false
private var mSandS = false
@@ -266,7 +268,7 @@ class SKKService : InputMethodService() {
results?.let {
it.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)?.let { matches ->
if (matches.size == 1) {
- commitTextSKK(matches[0], 0)
+ commitTextSKK(matches[0])
} else {
val intent = Intent(this@SKKService, SKKSpeechRecognitionResultsList::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@@ -309,7 +311,11 @@ class SKKService : InputMethodService() {
val abbrev = mAbbrevKeyboardView
if (flick == null || qwerty == null || abbrev == null) return
- val context = applicationContext
+ val context = when (skkPrefs.theme) {
+ "light" -> createNightModeContext(applicationContext, false)
+ "dark" -> createNightModeContext(applicationContext, true)
+ else -> applicationContext
+ }
val config = resources.configuration
val keyHeight: Int
val keyWidth: Int
@@ -340,6 +346,8 @@ class SKKService : InputMethodService() {
qwerty.setFlickSensitivity(sensitivity)
qwerty.backgroundAlpha = 255 * alpha / 100
abbrev.backgroundAlpha = 255 * alpha / 100
+
+ qwerty.loadFrequencyList(resources.assets.open(FREQUENCY_LIST_FILE))
}
private fun checkUseSoftKeyboard(): Boolean {
@@ -458,6 +466,16 @@ class SKKService : InputMethodService() {
}
mEngine.resetOnStartInput()
+
+ if (mUseSoftKeyboard || skkPrefs.useCandidatesView) {
+ if (attribute.inputType != InputType.TYPE_NULL) {
+ setCandidatesViewShown(true)
+ mCandidateViewContainer?.setAlpha(96)
+ } else {
+ requestHideSelf(0)
+ }
+ }
+
when (attribute.inputType and InputType.TYPE_MASK_CLASS) {
InputType.TYPE_CLASS_NUMBER,
InputType.TYPE_CLASS_DATETIME,
@@ -477,11 +495,6 @@ class SKKService : InputMethodService() {
}
}
}
-
- if (mUseSoftKeyboard || skkPrefs.useCandidatesView) {
- setCandidatesViewShown(true)
- mCandidateViewContainer?.setAlpha(96)
- }
}
/**
@@ -489,37 +502,38 @@ class SKKService : InputMethodService() {
* needs to be generated, like [.onCreateInputView].
*/
override fun onCreateCandidatesView(): View {
- val context = when (skkPrefs.theme) {
- "light" -> createNightModeContext(applicationContext, false)
- "dark" -> createNightModeContext(applicationContext, true)
- else -> applicationContext
- }
+ if (mCandidateViewContainer == null) {
+ val context = when (skkPrefs.theme) {
+ "light" -> createNightModeContext(applicationContext, false)
+ "dark" -> createNightModeContext(applicationContext, true)
+ else -> applicationContext
+ }
- val container = LayoutInflater.from(context).inflate(R.layout.view_candidates, null) as CandidateViewContainer
- container.initViews()
- val view = container.findViewById(R.id.candidates) as CandidateView
- view.setService(this)
- view.setContainer(container)
- mCandidateView = view
+ val container = LayoutInflater.from(context)
+ .inflate(R.layout.view_candidates, null) as CandidateViewContainer
+ container.initViews()
- val sp = skkPrefs.candidatesSize
- val px = TypedValue.applyDimension(
+ val sp = skkPrefs.candidatesSize
+ val px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, sp.toFloat(), context.resources.displayMetrics
- ).toInt()
- container.setSize(px)
+ ).toInt()
+ container.setSize(px)
+ setCandidatesView(container)
- mCandidateViewContainer = container
+ val view: CandidateView = container.findViewById(R.id.candidates)
+ view.setService(this)
+ view.setContainer(container)
+ mCandidateView = view
- return container
- }
+ mCandidateViewContainer = container
+ }
- override fun onStartCandidatesView(info: EditorInfo, restarting: Boolean) {
- isCandidatesViewShownFlag = true
- }
+ if (mUseSoftKeyboard || skkPrefs.useCandidatesView) {
+ setCandidatesViewShown(true)
+ mCandidateViewContainer?.setAlpha(96)
+ }
- override fun onFinishCandidatesView(finishingInput: Boolean) {
- isCandidatesViewShownFlag = false
- super.onFinishCandidatesView(finishingInput)
+ return mCandidateViewContainer!!
}
/**
@@ -531,7 +545,6 @@ class SKKService : InputMethodService() {
mQwertyInputView?.handleBack()
mAbbrevKeyboardView?.handleBack()
- setCandidatesViewShown(false)
}
override fun onDestroy() {
@@ -714,11 +727,30 @@ class SKKService : InputMethodService() {
fun changeLastChar(type: String) {
mEngine.changeLastChar(type)
}
- fun commitTextSKK(text: CharSequence, newCursorPosition: Int) {
- mEngine.commitTextSKK(text, newCursorPosition)
+ fun commitTextSKK(text: CharSequence) {
+ mEngine.commitTextSKK(text)
}
fun pickCandidateViewManually(index: Int) {
- mEngine.pickCandidateViewManually(index)
+ if (mEngine.state === SKKASCIIState) {
+ mQwertyInputView?.let { qwerty ->
+ mCandidateView?.let { cand ->
+ val ic = currentInputConnection ?: return
+ ic.deleteSurroundingText(qwerty.getHistoryLength(), 0)
+ ic.commitText(cand.getContent(index), 1)
+ }
+ qwerty.clearSuggestions()
+ }
+ } else {
+ mEngine.pickCandidateViewManually(index)
+ }
+ }
+
+ fun getTextBeforeCursor(length: Int): CharSequence? {
+ currentInputConnection?.let {
+ return it.getTextBeforeCursor(length, 0)
+ }
+
+ return null
}
fun handleBackspace(): Boolean {
@@ -804,6 +836,24 @@ class SKKService : InputMethodService() {
// mSpeechRecognizer.stopListening()
return
}
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // checkSelfPermission は api 23 必要
+ if (listOf(Manifest.permission.RECORD_AUDIO).any { // 将来複数必要になったときのため List.any
+ checkSelfPermission(it) == PackageManager.PERMISSION_DENIED
+ }) {
+ mHandler.post {
+ Toast.makeText(
+ applicationContext, getText(R.string.error_permission_record_audio), Toast.LENGTH_LONG
+ ).show()
+ }
+ // requestPermissions は activity が必要なので雑に設定画面を出すだけにする
+ startActivity(
+ Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ .setData(Uri.fromParts("package", packageName, null))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+ return
+ }
+ }
mStreamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0)
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
@@ -882,6 +932,7 @@ class SKKService : InputMethodService() {
internal const val COMMAND_SPEECH_RECOGNITION = "io.github.deton.androidtutcode.COMMAND_SPEECH_RECOGNITION"
internal const val COMMAND_RELOAD_ROMAJIMAP = "io.github.deton.androidtutcode.COMMAND_RELOAD_ROMAJIMAP"
internal const val DICT_ZIP_FILE = "skk_dict_btree_db.zip"
+ internal const val FREQUENCY_LIST_FILE = "en_US_wordlist.txt"
internal const val FILENAME_ROMAJIMAP = "romajimap.txt"
private const val CHANNEL_ID = "tutcode_notification"
private const val CHANNEL_NAME = "TUTCode"
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKSettingsActivity.kt b/app/src/main/java/jp/deadend/noname/skk/SKKSettingsActivity.kt
index 5ac120d..9fbc109 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKSettingsActivity.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKSettingsActivity.kt
@@ -122,6 +122,7 @@ class SKKSettingsActivity : AppCompatActivity(),
super.onPause()
val intent = Intent(SKKService.ACTION_COMMAND)
+ intent.setPackage(packageName)
intent.putExtra(SKKService.KEY_COMMAND, SKKService.COMMAND_READ_PREFS)
sendBroadcast(intent)
}
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKSpeechRecognitionResultsList.kt b/app/src/main/java/jp/deadend/noname/skk/SKKSpeechRecognitionResultsList.kt
index 5bba463..b8d2793 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKSpeechRecognitionResultsList.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKSpeechRecognitionResultsList.kt
@@ -22,6 +22,7 @@ class SKKSpeechRecognitionResultsList : AppCompatActivity() {
binding.listView.adapter = ArrayAdapter(this, R.layout.listitem_text_row, mResults)
binding.listView.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
val retIntent = Intent(SKKService.ACTION_COMMAND)
+ retIntent.setPackage(packageName)
retIntent.putExtra(SKKService.KEY_COMMAND, SKKService.COMMAND_SPEECH_RECOGNITION)
retIntent.putExtra(RESULTS_KEY, mResults[position])
sendBroadcast(retIntent)
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKUserDicTool.kt b/app/src/main/java/jp/deadend/noname/skk/SKKUserDicTool.kt
index 22b8270..fbaee70 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKUserDicTool.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKUserDicTool.kt
@@ -110,6 +110,7 @@ class SKKUserDicTool : AppCompatActivity() {
}
val intent = Intent(SKKService.ACTION_COMMAND)
+ intent.setPackage(packageName)
intent.putExtra(SKKService.KEY_COMMAND, SKKService.COMMAND_COMMIT_USERDIC)
sendBroadcast(intent)
diff --git a/app/src/main/java/jp/deadend/noname/skk/SKKUserDictionary.kt b/app/src/main/java/jp/deadend/noname/skk/SKKUserDictionary.kt
index 7332316..aa0f48c 100644
--- a/app/src/main/java/jp/deadend/noname/skk/SKKUserDictionary.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/SKKUserDictionary.kt
@@ -39,12 +39,12 @@ class SKKUserDictionary private constructor (
// 送りがなブロック以外の部分を追加
valList.takeWhile { !it.startsWith("[") }.forEach { cd.add(it) }
- if (value.contains("[") && value.contains("]")) {
+ if (value.contains("/[") && value.contains("/]")) {
// 送りがなブロック
- val regex = """\[.*?\]""".toRegex()
+ val regex = """/\[.*?/\]""".toRegex()
regex.findAll(value).forEach { result: MatchResult ->
okr.add(
- result.value.substring(1, result.value.length - 2) // "[" と "/]" をとる
+ result.value.substring(2, result.value.length - 2) // "/[" と "/]" をとる
.split('/')
.let { Pair(it[0], it[1]) }
)
diff --git a/app/src/main/java/jp/deadend/noname/skk/engine/SKKASCIIState.kt b/app/src/main/java/jp/deadend/noname/skk/engine/SKKASCIIState.kt
index 7c6d5a7..6e384b1 100644
--- a/app/src/main/java/jp/deadend/noname/skk/engine/SKKASCIIState.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/engine/SKKASCIIState.kt
@@ -9,7 +9,7 @@ object SKKASCIIState : SKKState {
override fun handleEisuKey(context: SKKEngine) {}
override fun processKey(context: SKKEngine, pcode: Int) {
- context.commitTextSKK(pcode.toChar().toString(), 1)
+ context.commitTextSKK(pcode.toChar().toString())
}
override fun afterBackspace(context: SKKEngine) {}
diff --git a/app/src/main/java/jp/deadend/noname/skk/engine/SKKAbbrevState.kt b/app/src/main/java/jp/deadend/noname/skk/engine/SKKAbbrevState.kt
index 1108b93..0d7d03b 100644
--- a/app/src/main/java/jp/deadend/noname/skk/engine/SKKAbbrevState.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/engine/SKKAbbrevState.kt
@@ -30,7 +30,7 @@ object SKKAbbrevState : SKKState {
-1010 -> {
// 全角変換
val buf = kanjiKey.map { hankaku2zenkaku(it.code).toChar() }.joinToString("")
- context.commitTextSKK(buf, 1)
+ context.commitTextSKK(buf)
context.changeState(SKKHiraganaState)
}
else -> {
diff --git a/app/src/main/java/jp/deadend/noname/skk/engine/SKKEngine.kt b/app/src/main/java/jp/deadend/noname/skk/engine/SKKEngine.kt
index c3c0292..0eee77b 100644
--- a/app/src/main/java/jp/deadend/noname/skk/engine/SKKEngine.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/engine/SKKEngine.kt
@@ -119,7 +119,7 @@ class SKKEngine(
when (state) {
SKKChooseState, SKKNarrowingState -> pickCandidate(mCurrentCandidateIndex)
SKKKanjiState, SKKAbbrevState -> {
- commitTextSKK(mKanjiKey, 1)
+ commitTextSKK(mKanjiKey)
changeState(SKKHiraganaState)
}
else -> {
@@ -130,7 +130,7 @@ class SKKEngine(
return false
}
} else {
- commitTextSKK(mComposing, 1)
+ commitTextSKK(mComposing)
mComposing.setLength(0)
}
}
@@ -182,17 +182,16 @@ class SKKEngine(
/**
* commitTextのラッパー 登録作業中なら登録内容に追加し,表示を更新
* @param text
- * @param newCursorPosition
*/
- fun commitTextSKK(text: CharSequence, newCursorPosition: Int) {
+ fun commitTextSKK(text: CharSequence) {
val ic = mService.currentInputConnection ?: return
val firstEntry = mRegistrationStack.peekFirst()?.entry
if (firstEntry != null) {
firstEntry.append(text)
- setComposingTextSKK("", newCursorPosition)
+ setComposingTextSKK("", 1)
} else {
- ic.commitText(text, newCursorPosition)
+ ic.commitText(text, 1)
}
}
@@ -464,7 +463,7 @@ class SKKEngine(
// 小文字大文字変換,濁音,半濁音に使う
fun changeLastChar(type: String) {
when {
- state === SKKKanjiState && mComposing.isEmpty() -> {
+ state === SKKKanjiState && mComposing.isEmpty() && mKanjiKey.isNotEmpty() -> {
val s = mKanjiKey.toString()
val idx = s.length - 1
val newLastChar = RomajiConverter.convertLastChar(s.substring(idx), type) ?: return
@@ -474,7 +473,7 @@ class SKKEngine(
setComposingTextSKK(mKanjiKey, 1)
updateSuggestions(mKanjiKey.toString())
}
- state === SKKNarrowingState && mComposing.isEmpty() -> {
+ state === SKKNarrowingState && mComposing.isEmpty() && SKKNarrowingState.mHint.isNotEmpty() -> {
val hint = SKKNarrowingState.mHint
val idx = hint.length - 1
val newLastChar = RomajiConverter.convertLastChar(hint.substring(idx), type) ?: return
@@ -670,9 +669,9 @@ class SKKEngine(
mUserDict.addEntry(regInfo.key, regEntryStr, regInfo.okurigana)
mUserDict.commitChanges()
if (regInfo.okurigana.isNullOrEmpty()) {
- commitTextSKK(regInfo.entry, 1)
+ commitTextSKK(regInfo.entry)
} else {
- commitTextSKK(regInfo.entry.append(regInfo.okurigana), 1)
+ commitTextSKK(regInfo.entry.append(regInfo.okurigana))
}
}
reset()
@@ -746,10 +745,10 @@ class SKKEngine(
mUserDict.addEntry(mKanjiKey.toString(), candList[index], mOkurigana)
// ユーザー辞書登録時はエスケープや注釈を消さない
- commitTextSKK(candidate, 1)
+ commitTextSKK(candidate)
val okuri = mOkurigana
if (okuri != null) {
- commitTextSKK(okuri, 1)
+ commitTextSKK(okuri)
if (mRegistrationStack.isEmpty()) {
mLastConversion = ConversionInfo(
candidate + okuri, candList, index, mKanjiKey.toString(), okuri
diff --git a/app/src/main/java/jp/deadend/noname/skk/engine/SKKHiraganaState.kt b/app/src/main/java/jp/deadend/noname/skk/engine/SKKHiraganaState.kt
index 7c5aa62..2644cb2 100644
--- a/app/src/main/java/jp/deadend/noname/skk/engine/SKKHiraganaState.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/engine/SKKHiraganaState.kt
@@ -28,7 +28,7 @@ object SKKHiraganaState : SKKState {
val hchr = context.romaji2kana(composing.toString())
when (hchr) {
null -> { // ローマ字シーケンス外の文字が来た場合はそのまま確定
- context.commitTextSKK(composing, 1)
+ context.commitTextSKK(composing)
composing.setLength(0)
}
"@cont" -> { // ローマ字内の文字ならComposingに積む
@@ -176,7 +176,7 @@ object SKKHiraganaState : SKKState {
override fun processKey(context: SKKEngine, pcode: Int) {
if (context.changeInputMode(pcode, true)) return
processKana(context, pcode) { engine, hchr ->
- engine.commitTextSKK(hchr, 1)
+ engine.commitTextSKK(hchr)
engine.mComposing.setLength(0)
}
}
diff --git a/app/src/main/java/jp/deadend/noname/skk/engine/SKKKatakanaState.kt b/app/src/main/java/jp/deadend/noname/skk/engine/SKKKatakanaState.kt
index 40ebfed..1ed7139 100644
--- a/app/src/main/java/jp/deadend/noname/skk/engine/SKKKatakanaState.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/engine/SKKKatakanaState.kt
@@ -25,7 +25,7 @@ object SKKKatakanaState : SKKState {
if (context.changeInputMode(pcode, false)) return
SKKHiraganaState.processKana(context, pcode) { engine, hchr ->
val str = hirakana2katakana(hchr)
- if (str != null) engine.commitTextSKK(str, 1)
+ if (str != null) engine.commitTextSKK(str)
engine.mComposing.setLength(0)
}
}
diff --git a/app/src/main/java/jp/deadend/noname/skk/engine/SKKZenkakuState.kt b/app/src/main/java/jp/deadend/noname/skk/engine/SKKZenkakuState.kt
index 2b701a5..2d93cfd 100644
--- a/app/src/main/java/jp/deadend/noname/skk/engine/SKKZenkakuState.kt
+++ b/app/src/main/java/jp/deadend/noname/skk/engine/SKKZenkakuState.kt
@@ -22,7 +22,7 @@ object SKKZenkakuState : SKKState {
}
override fun processKey(context: SKKEngine, pcode: Int) {
- context.commitTextSKK(hankaku2zenkaku(pcode).toChar().toString(), 1)
+ context.commitTextSKK(hankaku2zenkaku(pcode).toChar().toString())
}
override fun afterBackspace(context: SKKEngine) {}
diff --git a/app/src/main/res/drawable/key_bg.xml b/app/src/main/res/drawable/key_bg.xml
index b319564..d8b0259 100644
--- a/app/src/main/res/drawable/key_bg.xml
+++ b/app/src/main/res/drawable/key_bg.xml
@@ -7,6 +7,13 @@
+ -
+
+
+
+
+
+
-
diff --git a/app/src/main/res/drawable/popup_bg.xml b/app/src/main/res/drawable/popup_bg.xml
new file mode 100644
index 0000000..40fb12a
--- /dev/null
+++ b/app/src/main/res/drawable/popup_bg.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/popup_frame.xml b/app/src/main/res/drawable/popup_frame.xml
index da08b22..309b997 100644
--- a/app/src/main/res/drawable/popup_frame.xml
+++ b/app/src/main/res/drawable/popup_frame.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/app/src/main/res/drawable/popup_label.xml b/app/src/main/res/drawable/popup_label.xml
index 3f80745..f4bcd9e 100644
--- a/app/src/main/res/drawable/popup_label.xml
+++ b/app/src/main/res/drawable/popup_label.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/app/src/main/res/layout/keyboard_key_preview.xml b/app/src/main/res/layout/keyboard_key_preview.xml
index 6a09772..709a1bd 100644
--- a/app/src/main/res/layout/keyboard_key_preview.xml
+++ b/app/src/main/res/layout/keyboard_key_preview.xml
@@ -3,8 +3,8 @@
android:layout_width="wrap_content"
android:layout_height="80sp"
android:textSize="40sp"
- android:textColor="?android:attr/textColorPrimaryInverse"
+ android:textColor="@color/key_char_color"
android:minWidth="32dip"
android:gravity="center"
- android:background="@drawable/key_bg"
+ android:background="@drawable/popup_bg"
/>
\ No newline at end of file
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index fb06f59..9de425a 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -5,7 +5,9 @@
#BBEEEEEE
#FF6E6E6E
#FF555555
+ #FFAFB42B
#FF222222
#FF283593
#FFFFFFFF
+ #787878
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 9a25ced..377cdcd 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -23,7 +23,9 @@
#ff808080
#FFE6E6E6
#FFEBEBEB
+ #FFFFFF00
#FFC8C8C8
#FF00E2FF
#FF000000
+ #DCDCDC
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1231541..fcf6e24 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -38,6 +38,7 @@
UTF-8のファイルではないようです
この辞書はすでに存在します: %1$s
変換辞書の解凍に失敗しました。一旦アンインストールしてみてください
+ 「マイク」の使用を許可してください
漢字表ファイル読みこみ失敗。タブ区切りになっていない行があります
PrefKeyImportRomajiMap
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 378b8bb..35d30b4 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -11,10 +11,9 @@
- @drawable/key_bg
- -12dp
- 80dp
+ - @layout/keyboard_key_preview
- 14sp
- @layout/keyboard_popup_keyboard
- -10dp
- - @android:color/transparent
- - 2.75
\ No newline at end of file
diff --git a/app/src/main/res/xml/abbrev.xml b/app/src/main/res/xml/abbrev.xml
index 250be33..20a1fc0 100644
--- a/app/src/main/res/xml/abbrev.xml
+++ b/app/src/main/res/xml/abbrev.xml
@@ -1,11 +1,9 @@
-
+ app:keyHeight="8%p">
diff --git a/app/src/main/res/xml/keys_flick_jp.xml b/app/src/main/res/xml/keys_flick_jp.xml
index e974dd3..172b514 100644
--- a/app/src/main/res/xml/keys_flick_jp.xml
+++ b/app/src/main/res/xml/keys_flick_jp.xml
@@ -1,11 +1,9 @@
-
+ app:keyHeight="8%p">
diff --git a/app/src/main/res/xml/keys_flick_number.xml b/app/src/main/res/xml/keys_flick_number.xml
index 1205a01..c1cf603 100644
--- a/app/src/main/res/xml/keys_flick_number.xml
+++ b/app/src/main/res/xml/keys_flick_number.xml
@@ -1,11 +1,9 @@
-
+ app:keyHeight="8%p">
diff --git a/app/src/main/res/xml/keys_flick_voice.xml b/app/src/main/res/xml/keys_flick_voice.xml
index 9772b41..1f6d21f 100644
--- a/app/src/main/res/xml/keys_flick_voice.xml
+++ b/app/src/main/res/xml/keys_flick_voice.xml
@@ -1,11 +1,9 @@
-
+ app:keyHeight="8%p">
diff --git a/app/src/main/res/xml/keys_null.xml b/app/src/main/res/xml/keys_null.xml
index 9610c00..2ecc167 100644
--- a/app/src/main/res/xml/keys_null.xml
+++ b/app/src/main/res/xml/keys_null.xml
@@ -1,5 +1,3 @@
-
+
diff --git a/app/src/main/res/xml/keys_popup.xml b/app/src/main/res/xml/keys_popup.xml
index 6221b4f..0dfa2aa 100644
--- a/app/src/main/res/xml/keys_popup.xml
+++ b/app/src/main/res/xml/keys_popup.xml
@@ -1,7 +1,5 @@
-
+ app:keyHeight="10%p">
\ No newline at end of file
diff --git a/app/src/main/res/xml/prefs_softkey.xml b/app/src/main/res/xml/prefs_softkey.xml
index f0c3f6e..6feed8a 100644
--- a/app/src/main/res/xml/prefs_softkey.xml
+++ b/app/src/main/res/xml/prefs_softkey.xml
@@ -111,7 +111,7 @@
-
+ app:keyHeight="8%p">
diff --git a/app/src/main/res/xml/symbols.xml b/app/src/main/res/xml/symbols.xml
index 718b543..a700fe7 100644
--- a/app/src/main/res/xml/symbols.xml
+++ b/app/src/main/res/xml/symbols.xml
@@ -1,11 +1,9 @@
-
+ app:keyHeight="8%p">
diff --git a/app/src/main/res/xml/symbols_shift.xml b/app/src/main/res/xml/symbols_shift.xml
index bf6cb05..59d275e 100644
--- a/app/src/main/res/xml/symbols_shift.xml
+++ b/app/src/main/res/xml/symbols_shift.xml
@@ -1,11 +1,9 @@
-
+ app:keyHeight="8%p">
diff --git a/build.gradle b/build.gradle
index 800fa0e..f66e089 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,12 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.9.0'
+ ext.kotlin_version = '2.0.0'
repositories {
google()
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.2.0'
+ classpath 'com.android.tools.build:gradle:8.5.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0001fdd..7e4c624 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Sat Jan 29 13:15:47 JST 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME