Support long-click for morekeys with Talkback

This commit is contained in:
Aleksandras Kostarevas 2024-09-23 20:11:15 +03:00
parent db758a975d
commit 2c632bd4bd
6 changed files with 71 additions and 65 deletions

View File

@ -29,10 +29,8 @@ import android.view.inputmethod.EditorInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
import androidx.customview.widget.ExploreByTouchHelper;
import org.futo.inputmethod.keyboard.Key;
@ -121,7 +119,7 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
*/
protected void sendWindowStateChanged(final String text) {
final AccessibilityEvent stateChange = AccessibilityEvent.obtain(
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
AccessibilityEvent.TYPE_ANNOUNCEMENT);
mKeyboardView.onInitializeAccessibilityEvent(stateChange);
stateChange.getText().add(text);
stateChange.setContentDescription(null);
@ -183,10 +181,14 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
node.setFocusable(true);
node.setScreenReaderFocusable(true);
if(k.isActionKey() || k.getCode() == Constants.CODE_SWITCH_ALPHA_SYMBOL || k.getCode() == Constants.CODE_EMOJI || k.getCode() == Constants.CODE_SYMBOL_SHIFT) {
if(k.isActionKey() || k.getCode() == Constants.CODE_SWITCH_ALPHA_SYMBOL || k.getCode() == Constants.CODE_EMOJI || k.getCode() == Constants.CODE_SYMBOL_SHIFT || (k.getCode() >= Constants.CODE_ACTION_0 && k.getCode() <= Constants.CODE_ACTION_MAX)) {
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
node.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK);
node.setClickable(true);
} else {
if(k.isLongPressEnabled()) {
node.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK);
}
node.setTextEntryKey(true);
}
}
@ -200,6 +202,10 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
// Handle the click action for the virtual button
performClickOn(k);
return true;
} else if(action == AccessibilityNodeInfoCompat.ACTION_LONG_CLICK) {
// Show morekeys
performLongClickOn(k);
return true;
}
return false;
}

View File

@ -227,38 +227,6 @@ public final class MainKeyboardAccessibilityDelegate
Log.d(TAG, "performLongClickOn: key=" + key);
}
final PointerTracker tracker = PointerTracker.getPointerTracker(HOVER_EVENT_POINTER_ID);
final long eventTime = SystemClock.uptimeMillis();
final int x = key.getHitBox().centerX();
final int y = key.getHitBox().centerY();
final MotionEvent downEvent = MotionEvent.obtain(
eventTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0 /* metaState */);
// Inject a fake down event to {@link PointerTracker} to handle a long press correctly.
tracker.processMotionEvent(downEvent, mKeyDetector);
downEvent.recycle();
// Invoke {@link PointerTracker#onLongPressed()} as if a long press timeout has passed.
tracker.onLongPressed();
// If {@link Key#hasNoPanelAutoMoreKeys()} is true (such as "0 +" key on the phone layout)
// or a key invokes IME switcher dialog, we should just ignore the next
// {@link #onRegisterHoverKey(Key,MotionEvent)}. It can be determined by whether
// {@link PointerTracker} is in operation or not.
if (tracker.isInOperation()) {
// This long press shows a more keys keyboard and further hover events should be
// handled.
mBoundsToIgnoreHoverEvent.setEmpty();
return;
}
// This long press has handled at {@link MainKeyboardView#onLongPress(PointerTracker)}.
// We should ignore further hover events on this key.
mBoundsToIgnoreHoverEvent.set(key.getHitBox());
if (key.getHasNoPanelAutoMoreKey()) {
// This long press has registered a code point without showing a more keys keyboard.
// We should talk back the code point if possible.
final int codePointOfNoPanelAutoMoreKey = key.getMoreKeys().get(0).mCode;
final String text = KeyCodeDescriptionMapper.getInstance().getDescriptionForCodePoint(
mKeyboardView.getContext(), codePointOfNoPanelAutoMoreKey);
if (text != null) {
sendWindowStateChanged(text);
}
}
mKeyboardView.showMoreKeysKeyboard(key, tracker);
}
}

View File

@ -17,8 +17,8 @@
package org.futo.inputmethod.accessibility;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.HapticFeedbackConstants;
import android.view.SoundEffectConstants;
import android.view.accessibility.AccessibilityEvent;
import androidx.core.view.accessibility.AccessibilityEventCompat;
@ -27,7 +27,6 @@ import androidx.core.view.accessibility.AccessibilityRecordCompat;
import org.futo.inputmethod.keyboard.Key;
import org.futo.inputmethod.keyboard.KeyDetector;
import org.futo.inputmethod.keyboard.MoreKeysKeyboardView;
import org.futo.inputmethod.keyboard.PointerTracker;
/**
* This class represents a delegate that can be registered in {@link MoreKeysKeyboardView} to
@ -57,6 +56,9 @@ public class MoreKeysKeyboardAccessibilityDelegate
public void onShowMoreKeysKeyboard() {
sendWindowStateChanged(mOpenAnnounceResId);
mKeyboardView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
mKeyboardView.playSoundEffect(SoundEffectConstants.CLICK);
}
public void onDismissMoreKeysKeyboard() {

View File

@ -300,22 +300,6 @@ data class Key(
((actionFlags and KeyConsts.ACTION_FLAGS_ENABLE_LONG_PRESS) != 0
&& (labelFlags and KeyConsts.LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) == 0)
fun markAsLeftEdge(params: KeyboardParams) {
hitBox.left = params.mLeftPadding
}
fun markAsRightEdge(params: KeyboardParams) {
hitBox.right = params.mOccupiedWidth - params.mRightPadding
}
fun markAsTopEdge(params: KeyboardParams) {
hitBox.top = params.mTopPadding
}
fun markAsBottomEdge(params: KeyboardParams) {
hitBox.bottom = params.mOccupiedHeight + params.mBottomPadding
}
fun selectTypeface(params: KeyDrawParams): Typeface {
return when (labelFlags and KeyConsts.LABEL_FLAGS_FONT_MASK) {
KeyConsts.LABEL_FLAGS_FONT_NORMAL -> Typeface.DEFAULT

View File

@ -248,10 +248,10 @@ public final class MoreKeysKeyboard extends Keyboard {
}
public void markAsEdgeKey(final Key key, final int row) {
if (row == 0)
key.markAsTopEdge(this);
if (isTopRow(row))
key.markAsBottomEdge(this);
//if (row == 0)
// key.markAsTopEdge(this);
//if (isTopRow(row))
// key.markAsBottomEdge(this);
}
private boolean isTopRow(final int rowCount) {

View File

@ -25,9 +25,12 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import org.futo.inputmethod.accessibility.AccessibilityUtils;
import org.futo.inputmethod.accessibility.MoreKeysKeyboardAccessibilityDelegate;
import org.futo.inputmethod.keyboard.internal.KeyDrawParams;
@ -43,7 +46,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
private final int[] mCoordinates = CoordinateUtils.newInstance();
private final Drawable mDivider;
protected final KeyDetector mKeyDetector;
protected final MoreKeysDetector mKeyDetector;
private Controller mController = EMPTY_CONTROLLER;
protected KeyboardActionListener mListener;
private int mOriginX;
@ -104,8 +107,6 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
@Override
public void setKeyboard(final Keyboard keyboard) {
super.setKeyboard(keyboard);
mKeyDetector.setKeyboard(
keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
if (mAccessibilityDelegate == null) {
mAccessibilityDelegate = new MoreKeysKeyboardAccessibilityDelegate(
@ -114,8 +115,15 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_keys_keyboard);
}
mAccessibilityDelegate.setKeyboard(keyboard);
// No vertical correction
mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop());
} else {
mAccessibilityDelegate = null;
// With vertical correction
mKeyDetector.setKeyboard(
keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
}
}
@ -139,8 +147,13 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
container.setX(panelX);
container.setY(panelY);
if(AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
mOriginX = (int)container.getX() - CoordinateUtils.x(mCoordinates);
mOriginY = (int)container.getY() - CoordinateUtils.y(mCoordinates);
} else {
mOriginX = CoordinateUtils.x(touchOrigin) - getDefaultCoordX();
mOriginY = CoordinateUtils.y(touchOrigin) - container.getMeasuredHeight();
}
controller.onShowMoreKeysPanel(this);
final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
if (accessibilityDelegate != null
@ -194,6 +207,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
* Performs the specific action for this panel when the user presses a key on the panel.
*/
protected void onKeyInput(final Key key, final int x, final int y) {
dismissMoreKeysPanel();
final int code = key.getCode();
if (code == Constants.CODE_OUTPUT_TEXT) {
mListener.onTextInput(mCurrentKey.getOutputText());
@ -315,6 +330,36 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
public void showInParent(final ViewGroup parentView) {
removeFromParent();
parentView.addView(getContainerView());
if(mAccessibilityDelegate != null && AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
parentView.setTouchDelegate(new MyTouchDelegate(parentView, getContainerView()));
}
}
class MyTouchDelegate extends TouchDelegate {
public MyTouchDelegate(View parentView, View delegateView) {
super(new Rect(Integer.MIN_VALUE / 2, Integer.MIN_VALUE / 2, Integer.MAX_VALUE / 2 - 1, Integer.MAX_VALUE / 2 - 1), delegateView);
}
@Override
public boolean onTouchExplorationHoverEvent(@NonNull MotionEvent event) {
MotionEvent copy = MotionEvent.obtain(event);
copy.offsetLocation(-getContainerView().getX(), -getContainerView().getY());
// Dismiss the panel if we exit outside of the range
if(copy.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
if (mKeyDetector.detectHitKey(
(int)copy.getX(),
(int)copy.getY()
) == null) {
dismissMoreKeysPanel();
}
return true;
} else {
return MoreKeysKeyboardView.this.dispatchHoverEvent(copy);
}
}
}
@Override
@ -323,6 +368,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
final ViewGroup currentParent = (ViewGroup)containerView.getParent();
if (currentParent != null) {
currentParent.removeView(containerView);
currentParent.setTouchDelegate(null);
}
}