react-native-external-keyboard 0.5.6 → 0.6.1-rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +277 -14
- package/android/src/main/java/com/externalkeyboard/delegates/FocusOrderDelegate.java +213 -0
- package/android/src/main/java/com/externalkeyboard/helper/FocusHelper.java +44 -0
- package/android/src/main/java/com/externalkeyboard/helper/Linking/A11yOrderLinking.java +81 -0
- package/android/src/main/java/com/externalkeyboard/helper/Linking/LinkingQueue.java +94 -0
- package/android/src/main/java/com/externalkeyboard/helper/ReactNativeVersionChecker.java +24 -0
- package/android/src/main/java/com/externalkeyboard/services/FocusLinkObserver/FocusLinkObserver.java +131 -0
- package/android/src/main/java/com/externalkeyboard/services/FocusLinkObserver/FocusLinkObserverSingleton.java +20 -0
- package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardView/ExternalKeyboardView.java +144 -0
- package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardView/ExternalKeyboardViewManager.java +128 -8
- package/android/src/main/java/com/externalkeyboard/views/KeyboardFocusGroup/KeyboardFocusGroupManager.java +7 -3
- package/android/src/main/java/com/externalkeyboard/views/TextInputFocusWrapper/TextInputFocusWrapper.java +2 -13
- package/android/src/oldarch/ExternalKeyboardViewManagerSpec.java +25 -0
- package/android/src/oldarch/KeyboardFocusGroupManagerSpec.java +8 -1
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.h +33 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.mm +577 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderProtocol.h +34 -0
- package/ios/Delegates/RNCEKVGroupIdentifierDelegate/RNCEKVGroupIdentifierDelegate.h +1 -0
- package/ios/Delegates/RNCEKVGroupIdentifierDelegate/RNCEKVGroupIdentifierDelegate.mm +9 -0
- package/ios/Helpers/RNCEKVPropHelper/RNCEKVPropHelper.h +22 -0
- package/ios/Helpers/RNCEKVPropHelper/RNCEKVPropHelper.mm +48 -0
- package/ios/Services/RNCEKVFocusLinkObserver.h +27 -0
- package/ios/Services/RNCEKVFocusLinkObserver.mm +101 -0
- package/ios/Services/RNCEKVFocusLinkObserverManager.h +23 -0
- package/ios/Services/RNCEKVFocusLinkObserverManager.mm +30 -0
- package/ios/Services/RNCEKVOrderLinking.h +33 -0
- package/ios/Services/RNCEKVOrderLinking.mm +143 -0
- package/ios/Services/RNCEKVOrderSubscriber.h +24 -0
- package/ios/Services/RNCEKVOrderSubscriber.mm +23 -0
- package/ios/Services/RNCEKVRelashioship.h +28 -0
- package/ios/Services/RNCEKVRelashioship.mm +61 -0
- package/ios/Services/RNCEKVSortedMap.h +22 -0
- package/ios/Services/RNCEKVSortedMap.mm +112 -0
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardView.h +34 -3
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardView.mm +214 -54
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardViewManager.h +9 -0
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardViewManager.mm +80 -55
- package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroup.h +2 -0
- package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroup.mm +161 -3
- package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroupManager.mm +6 -0
- package/lib/commonjs/components/BaseKeyboardView/BaseKeyboardView.js +56 -3
- package/lib/commonjs/components/BaseKeyboardView/BaseKeyboardView.js.map +1 -1
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js +30 -0
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.js.map +1 -1
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.js.map +1 -1
- package/lib/commonjs/context/OrderFocusContext.js +23 -0
- package/lib/commonjs/context/OrderFocusContext.js.map +1 -0
- package/lib/commonjs/index.js +19 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/nativeSpec/ExternalKeyboardViewNativeComponent.js.map +1 -1
- package/lib/commonjs/nativeSpec/KeyboardFocusGroupNativeComponent.js.map +1 -1
- package/lib/commonjs/types/BaseKeyboardView.js +12 -0
- package/lib/commonjs/types/BaseKeyboardView.js.map +1 -1
- package/lib/commonjs/utils/withKeyboardFocus.js +25 -1
- package/lib/commonjs/utils/withKeyboardFocus.js.map +1 -1
- package/lib/module/components/BaseKeyboardView/BaseKeyboardView.js +55 -2
- package/lib/module/components/BaseKeyboardView/BaseKeyboardView.js.map +1 -1
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js +23 -0
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js.map +1 -0
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.js.map +1 -1
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.js.map +1 -1
- package/lib/module/context/OrderFocusContext.js +14 -0
- package/lib/module/context/OrderFocusContext.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeSpec/ExternalKeyboardViewNativeComponent.js.map +1 -1
- package/lib/module/nativeSpec/KeyboardFocusGroupNativeComponent.js.map +1 -1
- package/lib/module/types/BaseKeyboardView.js +11 -1
- package/lib/module/types/BaseKeyboardView.js.map +1 -1
- package/lib/module/utils/withKeyboardFocus.js +25 -1
- package/lib/module/utils/withKeyboardFocus.js.map +1 -1
- package/lib/typescript/src/components/BaseKeyboardView/BaseKeyboardView.d.ts +1 -1
- package/lib/typescript/src/components/BaseKeyboardView/BaseKeyboardView.d.ts.map +1 -1
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.android.d.ts +24 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.android.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.d.ts +1 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.d.ts.map +1 -1
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.d.ts +2 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.d.ts.map +1 -1
- package/lib/typescript/src/context/OrderFocusContext.d.ts +10 -0
- package/lib/typescript/src/context/OrderFocusContext.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpec/ExternalKeyboardViewNativeComponent.d.ts +12 -0
- package/lib/typescript/src/nativeSpec/ExternalKeyboardViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpec/KeyboardFocusGroupNativeComponent.d.ts +1 -0
- package/lib/typescript/src/nativeSpec/KeyboardFocusGroupNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/types/BaseKeyboardView.d.ts +24 -0
- package/lib/typescript/src/types/BaseKeyboardView.d.ts.map +1 -1
- package/lib/typescript/src/utils/withKeyboardFocus.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/BaseKeyboardView/BaseKeyboardView.tsx +77 -4
- package/src/components/KeyboardFocusGroup/KeyboardFocusGroup.android.tsx +39 -0
- package/src/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.tsx +1 -0
- package/src/components/KeyboardFocusGroup/KeyboardFocusGroup.tsx +1 -0
- package/src/context/OrderFocusContext.tsx +25 -0
- package/src/index.tsx +5 -0
- package/src/nativeSpec/ExternalKeyboardViewNativeComponent.ts +12 -0
- package/src/nativeSpec/KeyboardFocusGroupNativeComponent.ts +1 -0
- package/src/types/BaseKeyboardView.ts +26 -0
- package/src/utils/withKeyboardFocus.tsx +24 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
package com.externalkeyboard.helper.Linking;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import java.util.Map;
|
|
6
|
+
import java.util.NavigableMap;
|
|
7
|
+
import java.util.NavigableSet;
|
|
8
|
+
import java.util.TreeMap;
|
|
9
|
+
import java.util.TreeSet;
|
|
10
|
+
|
|
11
|
+
public class LinkingQueue {
|
|
12
|
+
public NavigableSet<Integer> positions = new TreeSet<>();
|
|
13
|
+
public NavigableMap<Integer, View> viewMap = new TreeMap<>();
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
private void linkPosition(View prev, View next) {
|
|
17
|
+
if (prev != null && next != null) {
|
|
18
|
+
prev.setNextFocusForwardId(next.getId());
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private void addWithLinking(int position, View currentView) {
|
|
23
|
+
viewMap.put(position, currentView);
|
|
24
|
+
Map.Entry<Integer, View> nextView = viewMap.higherEntry(position);
|
|
25
|
+
Map.Entry<Integer, View> prevView = viewMap.lowerEntry(position);
|
|
26
|
+
|
|
27
|
+
if (prevView != null) {
|
|
28
|
+
this.linkPosition(prevView.getValue(), currentView);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (nextView != null) {
|
|
32
|
+
this.linkPosition(currentView, nextView.getValue());
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private void unlinkLast() {
|
|
37
|
+
Map.Entry<Integer, View> lastView = viewMap.lastEntry();
|
|
38
|
+
if (lastView != null) {
|
|
39
|
+
lastView.getValue().setNextFocusForwardId(View.NO_ID);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
private void reLinkWithRemove(int position) {
|
|
45
|
+
Map.Entry<Integer, View> nextView = viewMap.higherEntry(position);
|
|
46
|
+
Map.Entry<Integer, View> prevView = viewMap.lowerEntry(position);
|
|
47
|
+
|
|
48
|
+
if (prevView != null && nextView != null) {
|
|
49
|
+
this.linkPosition(prevView.getValue(), nextView.getValue());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
boolean shouldUnlinkLast = nextView == null;
|
|
53
|
+
this.viewMap.remove(position);
|
|
54
|
+
|
|
55
|
+
if (shouldUnlinkLast) {
|
|
56
|
+
this.unlinkLast();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public void addPosition(View view, int position) {
|
|
61
|
+
if (this.viewMap.get(position) == view) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.addWithLinking(position, view);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public void removeFromOrder(int position) {
|
|
69
|
+
if (!this.viewMap.containsKey(position)) return;
|
|
70
|
+
this.reLinkWithRemove(position);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public void refreshIndexes(View view, int position) {
|
|
74
|
+
this.viewMap.put(position, view);
|
|
75
|
+
|
|
76
|
+
for (Map.Entry<Integer, View> positionEntry : this.viewMap.entrySet()) {
|
|
77
|
+
if (positionEntry != null) {
|
|
78
|
+
View currentView = positionEntry.getValue();
|
|
79
|
+
Map.Entry<Integer, View> nextEntry = this.viewMap.higherEntry(positionEntry.getKey());
|
|
80
|
+
|
|
81
|
+
if (nextEntry != null) {
|
|
82
|
+
linkPosition(currentView, nextEntry.getValue());
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
unlinkLast();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public boolean isEmpty() {
|
|
91
|
+
return positions.isEmpty() && viewMap.isEmpty();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package com.externalkeyboard.helper;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.views.textinput.ReactEditText;
|
|
4
|
+
|
|
5
|
+
import java.lang.reflect.Field;
|
|
6
|
+
|
|
7
|
+
public class ReactNativeVersionChecker {
|
|
8
|
+
private static Boolean is80OrLaterVersion = null;
|
|
9
|
+
|
|
10
|
+
public static boolean isReactNative80OrLater() {
|
|
11
|
+
if (is80OrLaterVersion != null) {
|
|
12
|
+
return is80OrLaterVersion;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
Field field = ReactEditText.class.getDeclaredField("dragAndDropFilter");
|
|
17
|
+
is80OrLaterVersion = true;
|
|
18
|
+
} catch (NoSuchFieldException e) {
|
|
19
|
+
is80OrLaterVersion = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return is80OrLaterVersion;
|
|
23
|
+
}
|
|
24
|
+
}
|
package/android/src/main/java/com/externalkeyboard/services/FocusLinkObserver/FocusLinkObserver.java
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
package com.externalkeyboard.services.FocusLinkObserver;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import java.lang.ref.WeakReference;
|
|
6
|
+
import java.util.ArrayList;
|
|
7
|
+
import java.util.HashMap;
|
|
8
|
+
import java.util.List;
|
|
9
|
+
import java.util.Map;
|
|
10
|
+
|
|
11
|
+
public class FocusLinkObserver {
|
|
12
|
+
private final Map<String, View> links;
|
|
13
|
+
private final Map<String, List<Subscriber>> subscribers;
|
|
14
|
+
|
|
15
|
+
public FocusLinkObserver() {
|
|
16
|
+
links = new HashMap<>();
|
|
17
|
+
subscribers = new HashMap<>();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public void emit(String id, View link) {
|
|
21
|
+
if (id == null || link == null) {
|
|
22
|
+
throw new IllegalArgumentException("Both id and link are required");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
links.put(id, link);
|
|
26
|
+
emitLinkUpdated(id, link);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
public void emitRemove(String id) {
|
|
31
|
+
if (links.containsKey(id)) {
|
|
32
|
+
links.remove(id); // Remove the link
|
|
33
|
+
emitLinkRemoved(id); // Notify subscribers
|
|
34
|
+
subscribers.remove(id); // Clean up subscribers for the ID
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public void subscribe(String id, LinkUpdatedCallback onLinkUpdated, LinkRemovedCallback onLinkRemoved) {
|
|
39
|
+
if (id == null || (onLinkUpdated == null && onLinkRemoved == null)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
subscribers.putIfAbsent(id, new ArrayList<>());
|
|
44
|
+
subscribers.get(id).add(new Subscriber(onLinkUpdated, onLinkRemoved));
|
|
45
|
+
|
|
46
|
+
if (onLinkUpdated != null && links.containsKey(id)) {
|
|
47
|
+
onLinkUpdated.onLinkUpdated(links.get(id));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public void unsubscribe(String id, LinkUpdatedCallback onLinkUpdated, LinkRemovedCallback onLinkRemoved) {
|
|
52
|
+
if (id == null || (onLinkUpdated == null && onLinkRemoved == null)) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
List<Subscriber> subscriberList = subscribers.get(id);
|
|
57
|
+
if (subscriberList != null) {
|
|
58
|
+
subscriberList.removeIf(subscriber -> {
|
|
59
|
+
LinkUpdatedCallback updatedCallback = subscriber.onLinkUpdated.get();
|
|
60
|
+
LinkRemovedCallback removedCallback = subscriber.onLinkRemoved.get();
|
|
61
|
+
return updatedCallback == onLinkUpdated && removedCallback == onLinkRemoved;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (subscriberList.isEmpty()) {
|
|
65
|
+
subscribers.remove(id);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private void emitLinkUpdated(String id, View link) {
|
|
71
|
+
List<Subscriber> subscriberList = subscribers.get(id);
|
|
72
|
+
if (subscriberList != null) {
|
|
73
|
+
subscriberList.removeIf(Subscriber::isEmpty);
|
|
74
|
+
|
|
75
|
+
for (Subscriber subscriber : subscriberList) {
|
|
76
|
+
subscriber.notifyLinkUpdated(link);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private void emitLinkRemoved(String id) {
|
|
82
|
+
List<Subscriber> subscriberList = subscribers.get(id);
|
|
83
|
+
if (subscriberList != null) {
|
|
84
|
+
// Remove stale subscribers (whose weak references were garbage-collected)
|
|
85
|
+
subscriberList.removeIf(Subscriber::isEmpty);
|
|
86
|
+
|
|
87
|
+
// Notify all valid subscribers
|
|
88
|
+
for (Subscriber subscriber : subscriberList) {
|
|
89
|
+
subscriber.notifyLinkRemoved();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@FunctionalInterface
|
|
95
|
+
public interface LinkUpdatedCallback {
|
|
96
|
+
void onLinkUpdated(View link);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@FunctionalInterface
|
|
100
|
+
public interface LinkRemovedCallback {
|
|
101
|
+
void onLinkRemoved();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private static class Subscriber {
|
|
105
|
+
private final WeakReference<LinkUpdatedCallback> onLinkUpdated;
|
|
106
|
+
private final WeakReference<LinkRemovedCallback> onLinkRemoved;
|
|
107
|
+
|
|
108
|
+
public Subscriber(LinkUpdatedCallback onLinkUpdated, LinkRemovedCallback onLinkRemoved) {
|
|
109
|
+
this.onLinkUpdated = new WeakReference<>(onLinkUpdated);
|
|
110
|
+
this.onLinkRemoved = new WeakReference<>(onLinkRemoved);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public void notifyLinkUpdated(View link) {
|
|
114
|
+
LinkUpdatedCallback callback = onLinkUpdated.get();
|
|
115
|
+
if (callback != null) {
|
|
116
|
+
callback.onLinkUpdated(link);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public void notifyLinkRemoved() {
|
|
121
|
+
LinkRemovedCallback callback = onLinkRemoved.get();
|
|
122
|
+
if (callback != null) {
|
|
123
|
+
callback.onLinkRemoved();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public boolean isEmpty() {
|
|
128
|
+
return onLinkUpdated.get() == null && onLinkRemoved.get() == null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package com.externalkeyboard.services.FocusLinkObserver;
|
|
2
|
+
|
|
3
|
+
public final class FocusLinkObserverSingleton {
|
|
4
|
+
|
|
5
|
+
private static volatile FocusLinkObserver instance;
|
|
6
|
+
|
|
7
|
+
private FocusLinkObserverSingleton() {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public static FocusLinkObserver getInstance() {
|
|
11
|
+
if (instance == null) {
|
|
12
|
+
synchronized (FocusLinkObserverSingleton.class) {
|
|
13
|
+
if (instance == null) {
|
|
14
|
+
instance = new FocusLinkObserver();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return instance;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
package com.externalkeyboard.views.ExternalKeyboardView;
|
|
2
2
|
|
|
3
3
|
import android.content.Context;
|
|
4
|
+
import android.view.FocusFinder;
|
|
4
5
|
import android.view.KeyEvent;
|
|
5
6
|
import android.view.View;
|
|
6
7
|
import android.view.ViewGroup;
|
|
7
8
|
import android.view.ViewTreeObserver;
|
|
8
9
|
import android.view.accessibility.AccessibilityEvent;
|
|
9
10
|
|
|
11
|
+
import com.externalkeyboard.delegates.FocusOrderDelegate;
|
|
10
12
|
import com.externalkeyboard.events.EventHelper;
|
|
11
13
|
|
|
12
14
|
import com.externalkeyboard.helper.FocusHelper;
|
|
15
|
+
import com.externalkeyboard.helper.ReactNativeVersionChecker;
|
|
13
16
|
import com.externalkeyboard.services.KeyboardKeyPressHandler;
|
|
14
17
|
import com.facebook.react.bridge.ReactContext;
|
|
15
18
|
import com.facebook.react.uimanager.UIManagerHelper;
|
|
@@ -28,20 +31,159 @@ public class ExternalKeyboardView extends ReactViewGroup {
|
|
|
28
31
|
public boolean enableA11yFocus = false;
|
|
29
32
|
public boolean screenAutoA11yFocus = false;
|
|
30
33
|
public int screenAutoA11yFocusDelay = 500;
|
|
34
|
+
public int lockFocus = 0;
|
|
35
|
+
public String orderForward;
|
|
36
|
+
public String orderBackward;
|
|
37
|
+
public String orderId;
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
private FocusOrderDelegate focusOrderDelegate = null;
|
|
31
41
|
private EventDispatcher a11yViewAppearDispatcher = null;
|
|
32
42
|
private EventDispatcherListener eventA11yViewAppearListener = null;
|
|
33
43
|
private final KeyboardKeyPressHandler keyboardKeyPressHandler;
|
|
34
44
|
private final Context context;
|
|
35
45
|
private View listeningView;
|
|
36
46
|
|
|
47
|
+
private Integer orderIndex;
|
|
48
|
+
private String orderGroup;
|
|
49
|
+
private View firstChild;
|
|
50
|
+
|
|
51
|
+
private String orderUp;
|
|
52
|
+
private String orderDown;
|
|
53
|
+
private String orderLeft;
|
|
54
|
+
|
|
55
|
+
public String getOrderRight() {
|
|
56
|
+
return orderRight;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public void setOrderRight(String orderRight) {
|
|
60
|
+
focusOrderDelegate.refreshRight(this.orderRight, orderRight);
|
|
61
|
+
this.orderRight = orderRight;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public String getOrderLeft() {
|
|
65
|
+
return orderLeft;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public void setOrderLeft(String orderLeft) {
|
|
69
|
+
focusOrderDelegate.refreshLeft(this.orderLeft, orderLeft);
|
|
70
|
+
this.orderLeft = orderLeft;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public String getOrderDown() {
|
|
74
|
+
return orderDown;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public void setOrderDown(String orderDown) {
|
|
78
|
+
focusOrderDelegate.refreshDown(this.orderDown, orderDown);
|
|
79
|
+
this.orderDown = orderDown;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public String getOrderUp() {
|
|
83
|
+
return orderUp;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public void setOrderUp(String orderUp) {
|
|
87
|
+
focusOrderDelegate.refreshUp(this.orderUp, orderUp);
|
|
88
|
+
this.orderUp = orderUp;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private String orderRight;
|
|
92
|
+
|
|
37
93
|
public ExternalKeyboardView(Context context) {
|
|
38
94
|
super(context);
|
|
39
95
|
this.context = context;
|
|
96
|
+
this.focusOrderDelegate = new FocusOrderDelegate(this);
|
|
40
97
|
this.keyboardKeyPressHandler = new KeyboardKeyPressHandler();
|
|
41
98
|
}
|
|
42
99
|
|
|
100
|
+
public View getFirstChild() {
|
|
101
|
+
return this.firstChild;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public String getOrderGroup() {
|
|
105
|
+
return this.orderGroup;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public String getOrderId() {
|
|
109
|
+
return this.orderId;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public void setOrderGroup(String orderGroup) {
|
|
113
|
+
focusOrderDelegate.updateOrderGroup(this.orderGroup, orderGroup);
|
|
114
|
+
this.orderGroup = orderGroup;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public Integer getOrderIndex() {
|
|
118
|
+
return this.orderIndex;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public void setOrderIndex(int orderIndex) {
|
|
122
|
+
if (this.orderIndex == null) {
|
|
123
|
+
this.orderIndex = orderIndex;
|
|
124
|
+
} else {
|
|
125
|
+
this.orderIndex = orderIndex;
|
|
126
|
+
focusOrderDelegate.refreshOrder();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public void linkAddView(View child) {
|
|
131
|
+
if (firstChild == null) {
|
|
132
|
+
firstChild = child;
|
|
133
|
+
focusOrderDelegate.link();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public void linkRemoveView(View view) {
|
|
138
|
+
if (view == firstChild) {
|
|
139
|
+
firstChild = null;
|
|
140
|
+
focusOrderDelegate.unlink(view);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@Override
|
|
145
|
+
public View focusSearch(View focused, int direction) {
|
|
146
|
+
if (lockFocus == 0 && orderGroup == null && orderIndex == null && orderForward == null && orderBackward == null) {
|
|
147
|
+
return super.focusSearch(focused, direction);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
boolean isLocked = FocusHelper.isLocked(direction, lockFocus);
|
|
151
|
+
if (isLocked) {
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (direction == FOCUS_FORWARD && orderForward != null) {
|
|
156
|
+
View nextView = this.focusOrderDelegate.getLink(orderForward);
|
|
157
|
+
if (nextView != null) {
|
|
158
|
+
return nextView;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (direction == FOCUS_BACKWARD && orderBackward != null) {
|
|
163
|
+
View prevView = this.focusOrderDelegate.getLink(orderBackward);
|
|
164
|
+
if (prevView != null) {
|
|
165
|
+
return prevView;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if(ReactNativeVersionChecker.isReactNative80OrLater()) {
|
|
170
|
+
if(orderGroup != null && orderIndex != null && (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD)){
|
|
171
|
+
return FocusFinder.getInstance().findNextFocus((ViewGroup) this.getParent(), focused, direction);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return super.focusSearch(focused, direction);
|
|
176
|
+
}
|
|
177
|
+
|
|
43
178
|
@Override
|
|
44
179
|
public boolean dispatchKeyEvent(KeyEvent keyEvent) {
|
|
180
|
+
if(lockFocus != 0) {
|
|
181
|
+
int keyCode = keyEvent.getKeyCode();
|
|
182
|
+
boolean isLocked = FocusHelper.isKeyLocked(keyCode, lockFocus);
|
|
183
|
+
if(isLocked) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
45
187
|
if (!this.hasKeyUpListener && !this.hasKeyDownListener) {
|
|
46
188
|
return super.dispatchKeyEvent(keyEvent);
|
|
47
189
|
}
|
|
@@ -141,6 +283,8 @@ public class ExternalKeyboardView extends ReactViewGroup {
|
|
|
141
283
|
if (this.listeningView != null) {
|
|
142
284
|
this.listeningView.setOnFocusChangeListener(null);
|
|
143
285
|
}
|
|
286
|
+
|
|
287
|
+
// this.focusOrderDelegate.clear(firstChild); // ToDO check how to clean
|
|
144
288
|
}
|
|
145
289
|
|
|
146
290
|
private View getFocusingView() {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
package com.externalkeyboard.views.ExternalKeyboardView;
|
|
2
2
|
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
3
6
|
import androidx.annotation.Nullable;
|
|
4
7
|
|
|
5
8
|
import com.externalkeyboard.events.FocusChangeEvent;
|
|
@@ -13,6 +16,7 @@ import com.facebook.react.views.view.ReactViewGroup;
|
|
|
13
16
|
|
|
14
17
|
import java.util.HashMap;
|
|
15
18
|
import java.util.Map;
|
|
19
|
+
import java.util.Objects;
|
|
16
20
|
|
|
17
21
|
|
|
18
22
|
@ReactModule(name = ExternalKeyboardViewManager.NAME)
|
|
@@ -25,9 +29,23 @@ public class ExternalKeyboardViewManager extends com.externalkeyboard.ExternalKe
|
|
|
25
29
|
return NAME;
|
|
26
30
|
}
|
|
27
31
|
|
|
32
|
+
@NonNull
|
|
28
33
|
@Override
|
|
29
|
-
public ExternalKeyboardView createViewInstance(ThemedReactContext context) {
|
|
30
|
-
|
|
34
|
+
public ExternalKeyboardView createViewInstance(@NonNull ThemedReactContext context) {
|
|
35
|
+
ExternalKeyboardView viewGroup = new ExternalKeyboardView(context);
|
|
36
|
+
|
|
37
|
+
viewGroup.setOnHierarchyChangeListener(new ExternalKeyboardView.OnHierarchyChangeListener() {
|
|
38
|
+
@Override
|
|
39
|
+
public void onChildViewAdded(View parent, View child) {
|
|
40
|
+
viewGroup.linkAddView(child);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Override
|
|
44
|
+
public void onChildViewRemoved(View parent, View child) {
|
|
45
|
+
viewGroup.linkRemoveView(child);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return viewGroup;
|
|
31
49
|
}
|
|
32
50
|
|
|
33
51
|
public static Map<String, Object> buildDirectEventMap(String registrationName) {
|
|
@@ -69,31 +87,41 @@ public class ExternalKeyboardViewManager extends com.externalkeyboard.ExternalKe
|
|
|
69
87
|
@Override
|
|
70
88
|
@ReactProp(name = "enableA11yFocus", defaultBoolean = false)
|
|
71
89
|
public void setEnableA11yFocus(ExternalKeyboardView wrapper, boolean enableA11yFocus) {
|
|
72
|
-
wrapper.enableA11yFocus
|
|
90
|
+
if(wrapper.enableA11yFocus != enableA11yFocus) {
|
|
91
|
+
wrapper.enableA11yFocus = enableA11yFocus;
|
|
92
|
+
}
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
@Override
|
|
76
96
|
@ReactProp(name = "screenAutoA11yFocus", defaultBoolean = false)
|
|
77
97
|
public void setScreenAutoA11yFocus(ExternalKeyboardView wrapper, boolean enableA11yFocus) {
|
|
78
|
-
wrapper.screenAutoA11yFocus
|
|
98
|
+
if(wrapper.screenAutoA11yFocus != enableA11yFocus) {
|
|
99
|
+
wrapper.screenAutoA11yFocus = enableA11yFocus;
|
|
100
|
+
}
|
|
79
101
|
}
|
|
80
102
|
|
|
81
103
|
@Override
|
|
82
104
|
@ReactProp(name = "screenAutoA11yFocusDelay", defaultInt = 500)
|
|
83
105
|
public void setScreenAutoA11yFocusDelay(ExternalKeyboardView wrapper, int value) {
|
|
84
|
-
wrapper.screenAutoA11yFocusDelay
|
|
106
|
+
if(wrapper.screenAutoA11yFocusDelay != value) {
|
|
107
|
+
wrapper.screenAutoA11yFocusDelay = value;
|
|
108
|
+
}
|
|
85
109
|
}
|
|
86
110
|
|
|
87
111
|
@Override
|
|
88
112
|
@ReactProp(name = "hasKeyDownPress")
|
|
89
113
|
public void setHasKeyDownPress(ExternalKeyboardView view, boolean value) {
|
|
90
|
-
view.hasKeyDownListener
|
|
114
|
+
if(view.hasKeyDownListener != value) {
|
|
115
|
+
view.hasKeyDownListener = value;
|
|
116
|
+
}
|
|
91
117
|
}
|
|
92
118
|
|
|
93
119
|
@Override
|
|
94
120
|
@ReactProp(name = "hasKeyUpPress")
|
|
95
121
|
public void setHasKeyUpPress(ExternalKeyboardView view, boolean value) {
|
|
96
|
-
view.hasKeyUpListener
|
|
122
|
+
if(view.hasKeyUpListener != value) {
|
|
123
|
+
view.hasKeyUpListener = value;
|
|
124
|
+
}
|
|
97
125
|
}
|
|
98
126
|
|
|
99
127
|
@Override
|
|
@@ -104,7 +132,9 @@ public class ExternalKeyboardViewManager extends com.externalkeyboard.ExternalKe
|
|
|
104
132
|
@Override
|
|
105
133
|
@ReactProp(name = "autoFocus")
|
|
106
134
|
public void setAutoFocus(ExternalKeyboardView view, @Nullable boolean value) {
|
|
107
|
-
view.autoFocus
|
|
135
|
+
if(view.autoFocus != value) {
|
|
136
|
+
view.autoFocus = value;
|
|
137
|
+
}
|
|
108
138
|
}
|
|
109
139
|
|
|
110
140
|
@Override
|
|
@@ -134,7 +164,97 @@ public class ExternalKeyboardViewManager extends com.externalkeyboard.ExternalKe
|
|
|
134
164
|
@Override
|
|
135
165
|
@ReactProp(name = "tintColor")
|
|
136
166
|
public void setTintColor(ExternalKeyboardView view, @Nullable Integer value) {
|
|
167
|
+
//stub
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@Override
|
|
171
|
+
@ReactProp(name = "orderGroup")
|
|
172
|
+
public void setOrderGroup(ExternalKeyboardView view, @Nullable String value) {
|
|
173
|
+
if(!Objects.equals(view.getOrderGroup(), value)) {
|
|
174
|
+
view.setOrderGroup(value);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@Override
|
|
179
|
+
@ReactProp(name = "orderIndex")
|
|
180
|
+
public void setOrderIndex(ExternalKeyboardView view, int value) {
|
|
181
|
+
if(!Objects.equals(view.getOrderIndex(), value)) {
|
|
182
|
+
view.setOrderIndex(value);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@Override
|
|
187
|
+
@ReactProp(name = "lockFocus")
|
|
188
|
+
public void setLockFocus(ExternalKeyboardView view, int value) {
|
|
189
|
+
if(view.lockFocus != value) {
|
|
190
|
+
view.lockFocus = value;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
137
193
|
|
|
194
|
+
@Override
|
|
195
|
+
@ReactProp(name = "orderId")
|
|
196
|
+
public void setOrderId(ExternalKeyboardView view, @Nullable String value) {
|
|
197
|
+
if(!Objects.equals(view.orderId, value)) {
|
|
198
|
+
view.orderId = value;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@Override
|
|
203
|
+
@ReactProp(name = "orderLeft")
|
|
204
|
+
public void setOrderLeft(ExternalKeyboardView view, @Nullable String value) {
|
|
205
|
+
if(!Objects.equals(view.getOrderLeft(), value)) {
|
|
206
|
+
view.setOrderLeft(value);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@Override
|
|
211
|
+
@ReactProp(name = "orderRight")
|
|
212
|
+
public void setOrderRight(ExternalKeyboardView view, @Nullable String value) {
|
|
213
|
+
if(!Objects.equals(view.getOrderRight(), value)) {
|
|
214
|
+
view.setOrderRight(value);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@Override
|
|
219
|
+
@ReactProp(name = "orderUp")
|
|
220
|
+
public void setOrderUp(ExternalKeyboardView view, @Nullable String value) {
|
|
221
|
+
if(!Objects.equals(view.getOrderUp(), value)) {
|
|
222
|
+
view.setOrderUp(value);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@Override
|
|
227
|
+
@ReactProp(name = "orderDown")
|
|
228
|
+
public void setOrderDown(ExternalKeyboardView view, @Nullable String value) {
|
|
229
|
+
if(!Objects.equals(view.getOrderDown(), value)) {
|
|
230
|
+
view.setOrderDown(value);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@Override
|
|
235
|
+
@ReactProp(name = "orderForward")
|
|
236
|
+
public void setOrderForward(ExternalKeyboardView view, @Nullable String value) {
|
|
237
|
+
if(!Objects.equals(view.orderForward, value)) {
|
|
238
|
+
view.orderForward = value;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
@Override
|
|
243
|
+
@ReactProp(name = "orderBackward")
|
|
244
|
+
public void setOrderBackward(ExternalKeyboardView view, @Nullable String value) {
|
|
245
|
+
if(!Objects.equals(view.orderBackward, value)) {
|
|
246
|
+
view.orderBackward = value;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@Override
|
|
251
|
+
public void setOrderFirst(ExternalKeyboardView view, @Nullable String value) {
|
|
252
|
+
//stub
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@Override
|
|
256
|
+
public void setOrderLast(ExternalKeyboardView view, @Nullable String value) {
|
|
257
|
+
//stub
|
|
138
258
|
}
|
|
139
259
|
|
|
140
260
|
@Override
|
|
@@ -20,10 +20,8 @@ public class KeyboardFocusGroupManager extends com.externalkeyboard.KeyboardFocu
|
|
|
20
20
|
return new KeyboardFocusGroup(context);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
@Override
|
|
25
|
-
|
|
26
|
-
public void setTintColor(KeyboardFocusGroup view, @Nullable Integer value) {
|
|
24
|
+
public void setTintColor(KeyboardFocusGroup view, Integer value) {
|
|
27
25
|
//stub
|
|
28
26
|
}
|
|
29
27
|
|
|
@@ -32,4 +30,10 @@ public class KeyboardFocusGroupManager extends com.externalkeyboard.KeyboardFocu
|
|
|
32
30
|
public void setGroupIdentifier(KeyboardFocusGroup wrapper, String groupIdentifier) {
|
|
33
31
|
//stub
|
|
34
32
|
}
|
|
33
|
+
|
|
34
|
+
@Override
|
|
35
|
+
@ReactProp(name = "orderGroup")
|
|
36
|
+
public void setOrderGroup(KeyboardFocusGroup view, @Nullable String value) {
|
|
37
|
+
//stub
|
|
38
|
+
}
|
|
35
39
|
}
|