7
7
import android .app .Activity ;
8
8
import android .app .Dialog ;
9
9
import android .content .DialogInterface ;
10
+ import android .content .Intent ;
10
11
import android .os .Bundle ;
11
12
import android .text .InputFilter ;
12
13
import android .text .Spanned ;
13
14
import android .view .ViewGroup ;
14
15
import android .widget .EditText ;
15
16
import android .widget .FrameLayout ;
16
-
17
17
import androidx .annotation .NonNull ;
18
18
import androidx .annotation .Nullable ;
19
19
import androidx .appcompat .app .AlertDialog ;
20
20
import androidx .fragment .app .DialogFragment ;
21
-
22
21
import com .google .android .material .dialog .MaterialAlertDialogBuilder ;
23
-
22
+ import java . util . Objects ;
24
23
import org .citra .citra_emu .CitraApplication ;
25
24
import org .citra .citra_emu .NativeLibrary ;
26
25
import org .citra .citra_emu .R ;
27
26
import org .citra .citra_emu .activities .EmulationActivity ;
28
27
import org .citra .citra_emu .utils .Log ;
28
+ import org .citra .citra_emu .vr .VrActivity ;
29
+ import org .citra .citra_emu .vr .VrKeyboardActivity ;
29
30
30
- import java .util .Objects ;
31
31
32
+ // Warning (amwatson): I had to tear through this pretty quickly because I didn't realize
33
+ // there was a system keyboard. This is a pretty hack solution that will not
34
+ // merge well.
32
35
public final class SoftwareKeyboard {
33
36
/// Corresponds to Frontend::ButtonConfig
34
- private interface ButtonConfig {
37
+ public interface ButtonConfig {
35
38
int Single = 0 ; /// Ok button
36
39
int Dual = 1 ; /// Cancel | Ok buttons
37
40
int Triple = 2 ; /// Cancel | I Forgot | Ok buttons
@@ -62,8 +65,7 @@ public static class KeyboardConfig implements java.io.Serializable {
62
65
public int max_text_length ;
63
66
public boolean multiline_mode ; /// True if the keyboard accepts multiple lines of input
64
67
public String hint_text ; /// Displayed in the field as a hint before
65
- @ Nullable
66
- public String [] button_text ; /// Contains the button text that the caller provides
68
+ @ Nullable public String [] button_text ; /// Contains the button text that the caller provides
67
69
}
68
70
69
71
/// Corresponds to Frontend::KeyboardData
@@ -77,13 +79,13 @@ private KeyboardData(int button, String text) {
77
79
}
78
80
}
79
81
80
- private static class Filter implements InputFilter {
82
+ public static class Filter implements InputFilter {
81
83
@ Override
82
84
public CharSequence filter (CharSequence source , int start , int end , Spanned dest ,
83
85
int dstart , int dend ) {
84
86
String text = new StringBuilder (dest )
85
- .replace (dstart , dend , source .subSequence (start , end ).toString ())
86
- .toString ();
87
+ .replace (dstart , dend , source .subSequence (start , end ).toString ())
88
+ .toString ();
87
89
if (ValidateFilters (text ) == ValidationError .None ) {
88
90
return null ; // Accept replacement
89
91
}
@@ -107,52 +109,52 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
107
109
assert emulationActivity != null ;
108
110
109
111
FrameLayout .LayoutParams params = new FrameLayout .LayoutParams (
110
- ViewGroup .LayoutParams .MATCH_PARENT , ViewGroup .LayoutParams .WRAP_CONTENT );
112
+ ViewGroup .LayoutParams .MATCH_PARENT , ViewGroup .LayoutParams .WRAP_CONTENT );
111
113
params .leftMargin = params .rightMargin =
112
- CitraApplication .getAppContext ().getResources ().getDimensionPixelSize (
113
- R .dimen .dialog_margin );
114
+ CitraApplication .getAppContext ().getResources ().getDimensionPixelSize (
115
+ R .dimen .dialog_margin );
114
116
115
117
KeyboardConfig config = Objects .requireNonNull (
116
- (KeyboardConfig ) Objects .requireNonNull (getArguments ()).getSerializable ("config" ));
118
+ (KeyboardConfig )Objects .requireNonNull (getArguments ()).getSerializable ("config" ));
117
119
118
120
// Set up the input
119
121
EditText editText = new EditText (CitraApplication .getAppContext ());
120
122
editText .setHint (config .hint_text );
121
123
editText .setSingleLine (!config .multiline_mode );
122
124
editText .setLayoutParams (params );
123
- editText .setFilters (new InputFilter []{
124
- new Filter (), new InputFilter .LengthFilter (config .max_text_length )});
125
+ editText .setFilters (new InputFilter [] {
126
+ new Filter (), new InputFilter .LengthFilter (config .max_text_length )});
125
127
126
128
FrameLayout container = new FrameLayout (emulationActivity );
127
129
container .addView (editText );
128
130
129
131
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder (emulationActivity )
130
- .setTitle (R .string .software_keyboard )
131
- .setView (container );
132
+ .setTitle (R .string .software_keyboard )
133
+ .setView (container );
132
134
setCancelable (false );
133
135
134
136
switch (config .button_config ) {
135
- case ButtonConfig .Triple : {
136
- final String text = config .button_text [1 ].isEmpty ()
137
- ? emulationActivity .getString (R .string .i_forgot )
138
- : config .button_text [1 ];
139
- builder .setNeutralButton (text , null );
140
- }
141
- // fallthrough
142
- case ButtonConfig .Dual : {
143
- final String text = config .button_text [0 ].isEmpty ()
144
- ? emulationActivity .getString (android .R .string .cancel )
145
- : config .button_text [0 ];
146
- builder .setNegativeButton (text , null );
147
- }
148
- // fallthrough
149
- case ButtonConfig .Single : {
150
- final String text = config .button_text [2 ].isEmpty ()
151
- ? emulationActivity .getString (android .R .string .ok )
152
- : config .button_text [2 ];
153
- builder .setPositiveButton (text , null );
154
- break ;
155
- }
137
+ case ButtonConfig .Triple : {
138
+ final String text = config .button_text [1 ].isEmpty ()
139
+ ? emulationActivity .getString (R .string .i_forgot )
140
+ : config .button_text [1 ];
141
+ builder .setNeutralButton (text , null );
142
+ }
143
+ // fallthrough
144
+ case ButtonConfig .Dual : {
145
+ final String text = config .button_text [0 ].isEmpty ()
146
+ ? emulationActivity .getString (android .R .string .cancel )
147
+ : config .button_text [0 ];
148
+ builder .setNegativeButton (text , null );
149
+ }
150
+ // fallthrough
151
+ case ButtonConfig .Single : {
152
+ final String text = config .button_text [2 ].isEmpty ()
153
+ ? emulationActivity .getString (android .R .string .ok )
154
+ : config .button_text [2 ];
155
+ builder .setPositiveButton (text , null );
156
+ break ;
157
+ }
156
158
}
157
159
158
160
final AlertDialog dialog = builder .create ();
@@ -209,31 +211,65 @@ private static void ExecuteImpl(KeyboardConfig config) {
209
211
fragment .show (emulationActivity .getSupportFragmentManager (), "keyboard" );
210
212
}
211
213
212
- private static void HandleValidationError (KeyboardConfig config , ValidationError error ) {
214
+ public static void HandleValidationError (KeyboardConfig config , ValidationError error ) {
213
215
final EmulationActivity emulationActivity = NativeLibrary .sEmulationActivity .get ();
214
216
String message = "" ;
215
217
switch (error ) {
216
- case FixedLengthRequired :
217
- message =
218
- emulationActivity .getString (R .string .fixed_length_required , config .max_text_length );
219
- break ;
220
- case MaxLengthExceeded :
221
- message =
222
- emulationActivity .getString (R .string .max_length_exceeded , config .max_text_length );
223
- break ;
224
- case BlankInputNotAllowed :
225
- message = emulationActivity .getString (R .string .blank_input_not_allowed );
226
- break ;
227
- case EmptyInputNotAllowed :
228
- message = emulationActivity .getString (R .string .empty_input_not_allowed );
229
- break ;
218
+ case FixedLengthRequired :
219
+ message =
220
+ emulationActivity .getString (R .string .fixed_length_required , config .max_text_length );
221
+ break ;
222
+ case MaxLengthExceeded :
223
+ message =
224
+ emulationActivity .getString (R .string .max_length_exceeded , config .max_text_length );
225
+ break ;
226
+ case BlankInputNotAllowed :
227
+ message = emulationActivity .getString (R .string .blank_input_not_allowed );
228
+ break ;
229
+ case EmptyInputNotAllowed :
230
+ message = emulationActivity .getString (R .string .empty_input_not_allowed );
231
+ break ;
230
232
}
231
233
232
- new MaterialAlertDialogBuilder (emulationActivity )
233
- .setTitle (R .string .software_keyboard )
234
- .setMessage (message )
235
- .setPositiveButton (android .R .string .ok , null )
236
- .show ();
234
+ // TODO show error dialog
235
+ Log .warning ("Keyboard error: " + message );
236
+ /* new MaterialAlertDialogBuilder(emulationActivity)
237
+ .setTitle(R.string.software_keyboard)
238
+ .setMessage(message)
239
+ .setPositiveButton(android.R.string.ok, null)
240
+ .show();*/
241
+ }
242
+
243
+ public static void onFinishVrKeyboardPositive (final String text , final KeyboardConfig config ) {
244
+ data = new KeyboardData (0 , "" );
245
+ data .button = config .button_config ;
246
+ data .text = text ;
247
+ final ValidationError error = ValidateInput (data .text );
248
+ if (error != ValidationError .None ) {
249
+ HandleValidationError (config , error );
250
+ final EmulationActivity emulationActivity = NativeLibrary .sEmulationActivity .get ();
251
+ onFinishVrKeyboardNegative ();
252
+ return ;
253
+ }
254
+ synchronized (finishLock ) {
255
+ finishLock .notifyAll ();
256
+ }
257
+ }
258
+
259
+ public static void onFinishVrKeyboardNeutral () {
260
+ data = new KeyboardData (0 , "" );
261
+ data .button = 1 ;
262
+ synchronized (finishLock ) {
263
+ finishLock .notifyAll ();
264
+ }
265
+ }
266
+
267
+ public static void onFinishVrKeyboardNegative () {
268
+ data = new KeyboardData (0 , "" );
269
+ data .button = 0 ;
270
+ synchronized (finishLock ) {
271
+ finishLock .notifyAll ();
272
+ }
237
273
}
238
274
239
275
public static KeyboardData Execute (KeyboardConfig config ) {
@@ -242,7 +278,12 @@ public static KeyboardData Execute(KeyboardConfig config) {
242
278
return new KeyboardData (0 , "" );
243
279
}
244
280
245
- NativeLibrary .sEmulationActivity .get ().runOnUiThread (() -> ExecuteImpl (config ));
281
+ final EmulationActivity emulationActivity = NativeLibrary .sEmulationActivity .get ();
282
+ if (emulationActivity instanceof VrActivity ) {
283
+ ((VrActivity )emulationActivity ).mVrKeyboardLauncher .launch (config );
284
+ } else {
285
+ NativeLibrary .sEmulationActivity .get ().runOnUiThread (() -> ExecuteImpl (config ));
286
+ }
246
287
247
288
synchronized (finishLock ) {
248
289
try {
@@ -256,11 +297,11 @@ public static KeyboardData Execute(KeyboardConfig config) {
256
297
257
298
public static void ShowError (String error ) {
258
299
NativeLibrary .displayAlertMsg (
259
- CitraApplication .getAppContext ().getResources ().getString (R .string .software_keyboard ),
260
- error , false );
300
+ CitraApplication .getAppContext ().getResources ().getString (R .string .software_keyboard ),
301
+ error , false );
261
302
}
262
303
263
- private static native ValidationError ValidateFilters (String text );
304
+ public static native ValidationError ValidateFilters (String text );
264
305
265
- private static native ValidationError ValidateInput (String text );
306
+ public static native ValidationError ValidateInput (String text );
266
307
}
0 commit comments