This commit is contained in:
2020-07-04 14:41:25 +08:00
parent 70c346d2c1
commit a8f02e4da5
3748 changed files with 587372 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6a3216a95bc7b4f0180c3a6f894801b3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 00a90c1899af344a9aa30073a5c9e74f
folderAsset: yes
timeCreated: 1522829902
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="ru.mopsicus.UnityMobileInput" xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" android:hardwareAccelerated="true" android:versionCode="1" android:versionName="1.0.0">
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="26" />
<application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name" android:launchMode="singleTask" android:process=":unityplayer" android:windowSoftInputMode="adjustNothing">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true"/>
</activity>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 0e1851b1f877a40ed8adffd0479dfda3
timeCreated: 1522835512
licenseType: Pro
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
fileFormatVersion: 2
guid: ba1124b09225a4b35941439492d17c35
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
fileFormatVersion: 2
guid: 6473dfeb66d4b423e8c49d8286c56396
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9e5fed99659a84ac5b32bcf1c8e8750f
folderAsset: yes
timeCreated: 1522829897
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
// ----------------------------------------------------------------------------
// The MIT License
// UnityMobileInput https://github.com/mopsicus/UnityMobileInput
// Copyright (c) 2018 Mopsicus <mail@mopsicus.ru>
// ----------------------------------------------------------------------------
#import <Foundation/Foundation.h>
extern void UnitySendMessage(const char *obj, const char *method, const char *msg); // to send data in Unity app
extern UIViewController *UnityGetGLViewController(); // main controller Unity
extern void pluginsInit(const char *data);
@interface Common : NSObject
+ (NSDictionary *)jsonToDict:(NSString *)json;
+ (NSString *)dictToJson:(NSDictionary *)dict;
+ (void)initialize:(NSString *)data;
+ (void)sendData:(NSString *)plugin data:(NSString *)data;
+ (void)sendError:(NSString *)plugin code:(NSString *)code;
+ (void)sendError:(NSString *)plugin code:(NSString *)code data:(NSString *)data;
@end

View File

@@ -0,0 +1,30 @@
fileFormatVersion: 2
guid: 941120bca5d8a47239a903e74f6949ed
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
// ----------------------------------------------------------------------------
// The MIT License
// UnityMobileInput https://github.com/mopsicus/UnityMobileInput
// Copyright (c) 2018 Mopsicus <mail@mopsicus.ru>
// ----------------------------------------------------------------------------
#import "Common.h"
@implementation Common
static NSString *object;
static NSString *receiver;
// Convert JSON string to NSDictionary
+ (NSDictionary *)jsonToDict:(NSString *)json {
NSError *error;
NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding];
return (error) ? NULL : [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
}
// Convert NSDictionary to JSON string
+ (NSString *)dictToJson:(NSDictionary *)dict {
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
return (error) ? NULL : [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
// Plugins initialize
+ (void)initialize:(NSString *)data {
NSDictionary *params = [self jsonToDict:data];
object = [params valueForKey:@"object"];
receiver = [params valueForKey:@"receiver"];
}
// Send data in JSON format to Unity
+ (void)sendData:(NSString *)plugin data:(NSString *)data {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:plugin forKey:@"name"];
[dict setValue:data forKey:@"data"];
NSString *result = [self dictToJson:dict];
UnitySendMessage([object cStringUsingEncoding:NSUTF8StringEncoding], [receiver cStringUsingEncoding:NSUTF8StringEncoding], [result cStringUsingEncoding:NSUTF8StringEncoding]);
}
// Send error
+ (void)sendError:(NSString *)plugin code:(NSString *)code {
[self sendError:plugin code:code data:NULL];
}
// Send error in JSON format to Unity
+ (void)sendError:(NSString *)plugin code:(NSString *)code data:(NSString *)data {
NSDictionary *error = [NSDictionary dictionaryWithObjectsAndKeys:code, @"code", data, @"message", nil];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:plugin forKey:@"name"];
[dict setValue:error forKey:@"error"];
NSString *result = [self dictToJson:dict];
UnitySendMessage([object cStringUsingEncoding:NSUTF8StringEncoding], [receiver cStringUsingEncoding:NSUTF8StringEncoding], [result cStringUsingEncoding:NSUTF8StringEncoding]);
}
// Init plugins system
void pluginsInit(const char *data) {
[Common initialize:[NSString stringWithUTF8String:data]];
}
@end

View File

@@ -0,0 +1,30 @@
fileFormatVersion: 2
guid: 295300052141d45259ecd1fa4452c3ee
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,616 @@
// ----------------------------------------------------------------------------
// The MIT License
// UnityMobileInput https://github.com/mopsicus/UnityMobileInput
// Copyright (c) 2018-2020 Mopsicus <mail@mopsicus.ru>
// ----------------------------------------------------------------------------
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "UnityForwardDecls.h"
#import <MobileCoreServices/UTCoreTypes.h>
#import "Common.h"
#define CREATE @"CREATE_EDIT"
#define REMOVE @"REMOVE_EDIT"
#define SET_TEXT @"SET_TEXT"
#define SET_RECT @"SET_RECT"
#define ON_FOCUS @"ON_FOCUS"
#define ON_UNFOCUS @"ON_UNFOCUS"
#define SET_FOCUS @"SET_FOCUS"
#define SET_VISIBLE @"SET_VISIBLE"
#define TEXT_CHANGE @"TEXT_CHANGE"
#define TEXT_END_EDIT @"TEXT_END_EDIT"
#define RETURN_PRESSED @"RETURN_PRESSED"
#define KEYBOARD_ACTION @"KEYBOARD_ACTION"
#define KEYBOARD_PREPARE @"KEYBOARD_PREPARE"
#define READY @"READY"
UIViewController *mainViewController = nil;
NSMutableDictionary *mobileInputList = nil;
NSString *plugin;
//
//
//
@interface PlaceholderTextView : UITextView
@property(nonatomic, strong) NSString *placeholder;
@property(nonatomic, strong) UIColor *realTextColor UI_APPEARANCE_SELECTOR;
@property(nonatomic, strong) UIColor *placeholderColor UI_APPEARANCE_SELECTOR;
@end
@interface MobileInput : NSObject <UITextFieldDelegate, UITextViewDelegate> {
int inputId;
int characterLimit;
CGRect rectKeyboardFrame;
UIView *editView;
UIViewController *viewController;
UIToolbar *keyboardDoneButtonView;
UIBarButtonItem *doneButton;
}
+ (void)init:(UIViewController *)viewController;
+ (void)processMessage:(int)inputId data:(NSString *)data;
+ (void)destroy;
- (id)initWith:(UIViewController *)controller andTag:(int)inputId;
- (void)create:(NSDictionary *)data;
- (void)processData:(NSDictionary *)data;
- (void)showKeyboard:(BOOL)value;
- (BOOL)isFocused;
@end
@interface PlaceholderTextView ()
@property(unsafe_unretained, nonatomic, readonly) NSString *realText;
- (void)beginEditing:(NSNotification *)notification;
- (void)endEditing:(NSNotification *)notification;
@end
//
//
//
@implementation PlaceholderTextView
@synthesize realTextColor;
@synthesize placeholder;
@synthesize placeholderColor;
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self awakeFromNib];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginEditing:) name:UITextViewTextDidBeginEditingNotification object:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endEditing:) name:UITextViewTextDidEndEditingNotification object:self];
self.realTextColor = self.textColor;
self.placeholderColor = [UIColor lightGrayColor];
}
- (void)setPlaceholder:(NSString *)textPlaceholder {
if ([self.realText isEqualToString:placeholder] && ![self isFirstResponder]) {
self.text = textPlaceholder;
}
if (textPlaceholder != placeholder) {
placeholder = textPlaceholder;
}
[self endEditing:nil];
}
- (void)setPlaceholderColor:(UIColor *)colorPlaceholder {
placeholderColor = colorPlaceholder;
if ([super.text isEqualToString:self.placeholder]) {
self.textColor = self.placeholderColor;
}
}
- (NSString *)text {
NSString *text = [super text];
return ([text isEqualToString:self.placeholder]) ? @"" : text;
}
- (void)setText:(NSString *)text {
if (([text isEqualToString:@""] || text == nil) && ![self isFirstResponder]) {
super.text = self.placeholder;
} else {
super.text = text;
}
if ([text isEqualToString:self.placeholder] || text == nil) {
self.textColor = self.placeholderColor;
} else {
self.textColor = self.realTextColor;
}
}
- (NSString *)realText {
return [super text];
}
- (void)beginEditing:(NSNotification *)notification {
if ([self.realText isEqualToString:self.placeholder]) {
super.text = nil;
self.textColor = self.realTextColor;
}
}
- (void)endEditing:(NSNotification *)notification {
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
if ([self.realText isEqualToString:@""] || self.realText == nil) {
super.text = self.placeholder;
self.textColor = self.placeholderColor;
}
}
- (void)setTextColor:(UIColor *)textColor {
if ([self.realText isEqualToString:self.placeholder]) {
if ([textColor isEqual:self.placeholderColor]) {
[super setTextColor:textColor];
} else {
self.realTextColor = textColor;
}
} else {
self.realTextColor = textColor;
[super setTextColor:textColor];
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
@implementation MobileInput
+ (void)init:(UIViewController *)viewController {
mainViewController = viewController;
mobileInputList = [[NSMutableDictionary alloc] init];
}
+ (void)processMessage:(int)inputId data:(NSString *)data {
NSDictionary *message = [Common jsonToDict:data];
NSString *msg = [message valueForKey:@"msg"];
if ([msg isEqualToString:CREATE]) {
MobileInput *input = [[MobileInput alloc] initWith:mainViewController andTag:inputId];
[input create:message];
[mobileInputList setObject:input forKey:[NSNumber numberWithInt:inputId]];
} else {
MobileInput *input = [mobileInputList objectForKey:[NSNumber numberWithInt:inputId]];
if (input) {
[input processData:message];
}
}
}
+ (void)destroy {
NSArray *list = [mobileInputList allValues];
for (MobileInput *input in list) {
[input remove];
}
mobileInputList = nil;
}
+ (void)setPlugin:(NSString *)name {
plugin = name;
}
- (id)initWith:(UIViewController *)controller andTag:(int)idInput {
if (self = [super init]) {
viewController = controller;
inputId = idInput;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
return self;
}
- (BOOL)isFocused {
return editView.isFirstResponder;
}
- (void)sendData:(NSMutableDictionary *)data {
[data setValue:[NSNumber numberWithInt:inputId] forKey:@"id"];
NSString *result = [Common dictToJson:data];
[Common sendData:plugin data:result];
}
- (void)processData:(NSDictionary *)data {
NSString *msg = [data valueForKey:@"msg"];
if ([msg isEqualToString:REMOVE]) {
[self remove];
} else if ([msg isEqualToString:SET_TEXT]) {
NSString *text = [data valueForKey:@"text"];
[self setText:text];
} else if ([msg isEqualToString:SET_RECT]) {
[self setRect:data];
} else if ([msg isEqualToString:SET_FOCUS]) {
BOOL isFocus = [[data valueForKey:@"is_focus"] boolValue];
[self setFocus:isFocus];
} else if ([msg isEqualToString:SET_VISIBLE]) {
BOOL isVisible = [[data valueForKey:@"is_visible"] boolValue];
[self setVisible:isVisible];
}
}
- (void)setRect:(NSDictionary *)data {
float x = [[data valueForKey:@"x"] floatValue] * viewController.view.bounds.size.width;
float y = [[data valueForKey:@"y"] floatValue] * viewController.view.bounds.size.height;
float width = [[data valueForKey:@"width"] floatValue] * viewController.view.bounds.size.width;
float height = [[data valueForKey:@"height"] floatValue] * viewController.view.bounds.size.height;
x -= editView.superview.frame.origin.x;
y -= editView.superview.frame.origin.y;
editView.frame = CGRectMake(x, y, width, height);
}
BOOL multiline;
- (void)create:(NSDictionary *)data {
NSString *placeholder = [data valueForKey:@"placeholder"];
float fontSize = [[data valueForKey:@"font_size"] floatValue];
float x = [[data valueForKey:@"x"] floatValue] * viewController.view.bounds.size.width;
float y = [[data valueForKey:@"y"] floatValue] * viewController.view.bounds.size.height;
float width = [[data valueForKey:@"width"] floatValue] * viewController.view.bounds.size.width;
float height = [[data valueForKey:@"height"] floatValue] * viewController.view.bounds.size.height;
characterLimit = [[data valueForKey:@"character_limit"] intValue];
float textColor_r = [[data valueForKey:@"text_color_r"] floatValue];
float textColor_g = [[data valueForKey:@"text_color_g"] floatValue];
float textColor_b = [[data valueForKey:@"text_color_b"] floatValue];
float textColor_a = [[data valueForKey:@"text_color_a"] floatValue];
UIColor *textColor = [UIColor colorWithRed:textColor_r green:textColor_g blue:textColor_b alpha:textColor_a];
float backColor_r = [[data valueForKey:@"back_color_r"] floatValue];
float backColor_g = [[data valueForKey:@"back_color_g"] floatValue];
float backColor_b = [[data valueForKey:@"back_color_b"] floatValue];
float backColor_a = [[data valueForKey:@"back_color_a"] floatValue];
UIColor *backgroundColor = [UIColor colorWithRed:backColor_r green:backColor_g blue:backColor_b alpha:backColor_a];
float placeHolderColor_r = [[data valueForKey:@"placeholder_color_r"] floatValue];
float placeHolderColor_g = [[data valueForKey:@"placeholder_color_g"] floatValue];
float placeHolderColor_b = [[data valueForKey:@"placeholder_color_b"] floatValue];
float placeHolderColor_a = [[data valueForKey:@"placeholder_color_a"] floatValue];
UIColor *placeHolderColor = [UIColor colorWithRed:placeHolderColor_r green:placeHolderColor_g blue:placeHolderColor_b alpha:placeHolderColor_a];
NSString *contentType = [data valueForKey:@"content_type"];
NSString *alignment = [data valueForKey:@"align"];
BOOL withDoneButton = [[data valueForKey:@"with_done_button"] boolValue];
BOOL withClearButton = [[data valueForKey:@"with_clear_button"] boolValue];
multiline = [[data valueForKey:@"multiline"] boolValue];
BOOL autoCorrection = NO;
BOOL password = NO;
NSString *inputType = [data valueForKey:@"input_type"];
NSString *keyboardType = [data valueForKey:@"keyboard_type"];
UIKeyboardType keyType = UIKeyboardTypeDefault;
if ([contentType isEqualToString:@"Autocorrected"]) {
autoCorrection = YES;
} else if ([contentType isEqualToString:@"IntegerNumber"]) {
keyType = UIKeyboardTypeNumberPad;
} else if ([contentType isEqualToString:@"DecimalNumber"]) {
keyType = UIKeyboardTypeDecimalPad;
} else if ([contentType isEqualToString:@"Alphanumeric"]) {
keyType = UIKeyboardTypeAlphabet;
} else if ([contentType isEqualToString:@"Name"]) {
keyType = UIKeyboardTypeNamePhonePad;
} else if ([contentType isEqualToString:@"EmailAddress"]) {
keyType = UIKeyboardTypeEmailAddress;
} else if ([contentType isEqualToString:@"Password"]) {
password = YES;
} else if ([contentType isEqualToString:@"Pin"]) {
keyType = UIKeyboardTypePhonePad;
} else if ([contentType isEqualToString:@"Custom"]) {
if ([keyboardType isEqualToString:@"ASCIICapable"]) {
keyType = UIKeyboardTypeASCIICapable;
} else if ([keyboardType isEqualToString:@"NumbersAndPunctuation"]) {
keyType = UIKeyboardTypeNumbersAndPunctuation;
} else if ([keyboardType isEqualToString:@"URL"]) {
keyType = UIKeyboardTypeURL;
} else if ([keyboardType isEqualToString:@"NumberPad"]) {
keyType = UIKeyboardTypeNumberPad;
} else if ([keyboardType isEqualToString:@"PhonePad"]) {
keyType = UIKeyboardTypePhonePad;
} else if ([keyboardType isEqualToString:@"NamePhonePad"]) {
keyType = UIKeyboardTypeNamePhonePad;
} else if ([keyboardType isEqualToString:@"EmailAddress"]) {
keyType = UIKeyboardTypeEmailAddress;
} else if ([keyboardType isEqualToString:@"Social"]) {
keyType = UIKeyboardTypeTwitter;
} else if ([keyboardType isEqualToString:@"Search"]) {
keyType = UIKeyboardTypeWebSearch;
} else {
keyType = UIKeyboardTypeDefault;
}
if ([inputType isEqualToString:@"Standard"]) {
} else if ([inputType isEqualToString:@"AutoCorrect"]) {
autoCorrection = YES;
} else if ([inputType isEqualToString:@"Password"]) {
password = YES;
}
}
UIControlContentHorizontalAlignment halign = UIControlContentHorizontalAlignmentLeft;
UIControlContentVerticalAlignment valign = UIControlContentVerticalAlignmentCenter;
NSTextAlignment textAlign = NSTextAlignmentCenter;
if ([alignment isEqualToString:@"UpperLeft"]) {
valign = UIControlContentVerticalAlignmentTop;
halign = UIControlContentHorizontalAlignmentLeft;
textAlign = NSTextAlignmentLeft;
} else if ([alignment isEqualToString:@"UpperCenter"]) {
valign = UIControlContentVerticalAlignmentTop;
halign = UIControlContentHorizontalAlignmentCenter;
textAlign = NSTextAlignmentCenter;
} else if ([alignment isEqualToString:@"UpperRight"]) {
valign = UIControlContentVerticalAlignmentTop;
halign = UIControlContentHorizontalAlignmentRight;
textAlign = NSTextAlignmentRight;
} else if ([alignment isEqualToString:@"MiddleLeft"]) {
valign = UIControlContentVerticalAlignmentCenter;
halign = UIControlContentHorizontalAlignmentLeft;
textAlign = NSTextAlignmentLeft;
} else if ([alignment isEqualToString:@"MiddleCenter"]) {
valign = UIControlContentVerticalAlignmentCenter;
halign = UIControlContentHorizontalAlignmentCenter;
textAlign = NSTextAlignmentCenter;
} else if ([alignment isEqualToString:@"MiddleRight"]) {
valign = UIControlContentVerticalAlignmentCenter;
halign = UIControlContentHorizontalAlignmentRight;
textAlign = NSTextAlignmentRight;
} else if ([alignment isEqualToString:@"LowerLeft"]) {
valign = UIControlContentVerticalAlignmentBottom;
halign = UIControlContentHorizontalAlignmentLeft;
textAlign = NSTextAlignmentLeft;
} else if ([alignment isEqualToString:@"LowerCenter"]) {
valign = UIControlContentVerticalAlignmentBottom;
halign = UIControlContentHorizontalAlignmentCenter;
textAlign = NSTextAlignmentCenter;
} else if ([alignment isEqualToString:@"LowerRight"]) {
valign = UIControlContentVerticalAlignmentBottom;
halign = UIControlContentHorizontalAlignmentRight;
textAlign = NSTextAlignmentRight;
}
if (withDoneButton) {
keyboardDoneButtonView = [[UIToolbar alloc] init];
[keyboardDoneButtonView sizeToFit];
doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneClicked:)];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[keyboardDoneButtonView setItems:[NSArray arrayWithObjects:flexibleSpace, flexibleSpace, doneButton, nil]];
} else {
keyboardDoneButtonView = nil;
}
UIReturnKeyType returnKeyType = UIReturnKeyDefault;
NSString *returnKeyTypeString = [data valueForKey:@"return_key_type"];
if ([returnKeyTypeString isEqualToString:@"Next"]) {
returnKeyType = UIReturnKeyNext;
} else if ([returnKeyTypeString isEqualToString:@"Done"]) {
returnKeyType = UIReturnKeyDone;
} else if ([returnKeyTypeString isEqualToString:@"Search"]) {
returnKeyType = UIReturnKeySearch;
}
fontSize = fontSize / [UIScreen mainScreen].scale;
UIFont *uiFont = [UIFont systemFontOfSize:fontSize];
if (multiline) {
PlaceholderTextView *textView = [[PlaceholderTextView alloc] initWithFrame:CGRectMake(x, y, width, height)];
textView.keyboardType = keyType;
[textView setFont:uiFont];
textView.scrollEnabled = TRUE;
textView.delegate = self;
textView.tag = inputId;
textView.text = @"";
textView.textColor = textColor;
textView.backgroundColor = backgroundColor;
textView.returnKeyType = returnKeyType;
textView.textAlignment = textAlign;
textView.autocorrectionType = autoCorrection ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo;
textView.contentInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
textView.placeholder = placeholder;
textView.placeholderColor = placeHolderColor;
textView.delegate = self;
if (keyType == UIKeyboardTypeEmailAddress) {
textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
}
[textView setSecureTextEntry:password];
if (keyboardDoneButtonView != nil) {
textView.inputAccessoryView = keyboardDoneButtonView;
}
editView = textView;
} else {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(x, y, width, height)];
textField.keyboardType = keyType;
[textField setFont:uiFont];
textField.delegate = self;
textField.tag = inputId;
textField.text = @"";
textField.textColor = textColor;
textField.backgroundColor = backgroundColor;
textField.returnKeyType = returnKeyType;
textField.autocorrectionType = autoCorrection ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo;
textField.contentVerticalAlignment = valign;
textField.contentHorizontalAlignment = halign;
textField.textAlignment = textAlign;
if (withClearButton) {
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
}
NSMutableParagraphStyle *setting = [[NSMutableParagraphStyle alloc] init];
setting.alignment = textAlign;
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName: placeHolderColor, NSParagraphStyleAttributeName : setting}];
textField.delegate = self;
if (keyType == UIKeyboardTypeEmailAddress) {
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
}
[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[textField addTarget:self action:@selector(textFieldActive:) forControlEvents:UIControlEventEditingDidBegin];
[textField addTarget:self action:@selector(textFieldInActive:) forControlEvents:UIControlEventEditingDidEnd];
[textField setSecureTextEntry:password];
if (keyboardDoneButtonView != nil) {
textField.inputAccessoryView = keyboardDoneButtonView;
}
editView = textField;
}
[mainViewController.view addSubview:editView];
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:READY forKey:@"msg"];
[self sendData:msg];
}
- (void)setText:(NSString *)text {
if ([editView isKindOfClass:[UITextField class]]) {
[((UITextField *) editView) setText:text];
} else if ([editView isKindOfClass:[UITextView class]]) {
[((UITextView *) editView) setText:text];
}
}
- (IBAction) doneClicked:(id)sender {
[self showKeyboard:false];
}
- (void)remove {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[editView resignFirstResponder];
[editView removeFromSuperview];
if (keyboardDoneButtonView != nil) {
doneButton = nil;
keyboardDoneButtonView = nil;
}
}
- (void)setFocus:(BOOL)isFocus {
if (isFocus) {
[editView becomeFirstResponder];
} else {
[editView resignFirstResponder];
}
}
- (void)showKeyboard:(BOOL)isShow {
[editView endEditing:(isShow ? YES : NO)];
}
- (void)setVisible:(BOOL)isVisible {
editView.hidden = (isVisible ? NO : YES);
}
- (void)onTextChange:(NSString *)text {
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:TEXT_CHANGE forKey:@"msg"];
[msg setValue:text forKey:@"text"];
[self sendData:msg];
}
- (void)onTextEditEnd:(NSString *)text {
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:TEXT_END_EDIT forKey:@"msg"];
[msg setValue:text forKey:@"text"];
[self sendData:msg];
}
- (void)textViewDidChange:(UITextView *)textView {
[self onTextChange:textView.text];
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
if (multiline) {
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:ON_FOCUS forKey:@"msg"];
[self sendData:msg];
}
}
- (void)textViewDidEndEditing:(UITextView *)textView {
if (multiline) {
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:ON_UNFOCUS forKey:@"msg"];
[self sendData:msg];
}
[self onTextEditEnd:textView.text];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (![editView isFirstResponder]) {
return YES;
}
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:RETURN_PRESSED forKey:@"msg"];
[self sendData:msg];
return YES;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (range.length + range.location > textField.text.length) {
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
if (characterLimit > 0) {
return newLength <= characterLimit;
} else {
return YES;
}
}
- (void)textFieldActive:(UITextField *)theTextField {
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:ON_FOCUS forKey:@"msg"];
[self sendData:msg];
}
- (void)textFieldInActive:(UITextField *)theTextField {
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:ON_UNFOCUS forKey:@"msg"];
[self sendData:msg];
}
- (void)textFieldDidChange:(UITextField *)theTextField {
[self onTextChange:theTextField.text];
}
- (void)keyboardWillShow:(NSNotification *)notification {
if (![editView isFirstResponder]) {
return;
}
NSMutableDictionary *tmp = [[NSMutableDictionary alloc] init];
[tmp setValue:KEYBOARD_PREPARE forKey:@"msg"];
[self sendData:tmp];
NSDictionary *keyboardInfo = [notification userInfo];
NSValue *keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
rectKeyboardFrame = [keyboardFrameBegin CGRectValue];
CGFloat screenScale = [[UIScreen mainScreen] scale];
CGFloat height = screenScale * rectKeyboardFrame.size.height;
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:KEYBOARD_ACTION forKey:@"msg"];
[msg setValue:[NSNumber numberWithBool:YES] forKey:@"show"];
[msg setValue:[NSNumber numberWithFloat:height] forKey:@"height"];
[self sendData:msg];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSMutableDictionary *msg = [[NSMutableDictionary alloc] init];
[msg setValue:KEYBOARD_ACTION forKey:@"msg"];
[msg setValue:[NSNumber numberWithBool:NO] forKey:@"show"];
[msg setValue:[NSNumber numberWithFloat:0] forKey:@"height"];
[self sendData:msg];
}
@end
extern "C" {
void inputExecute(int inputId, const char *data) {
[MobileInput processMessage:inputId data:[NSString stringWithUTF8String:data]];
}
void inputDestroy() {
[MobileInput destroy];
}
void inputInit() {
[MobileInput setPlugin:@"mobileinput"];
[MobileInput init:UnityGetGLViewController()];
}
}

View File

@@ -0,0 +1,30 @@
fileFormatVersion: 2
guid: c9745b7883f2e4d8f932044cda1b7886
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8fa210ba3e804458181b9dd1bb5e5c42
folderAsset: yes
timeCreated: 1522829876
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: c54bd4360ae694d8e9375671e7564f20
timeCreated: 1522829870
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 235d42526991144bcb974eca34a7dc59
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 162f324e2772d44c9a31e65df128e4a1
folderAsset: yes
timeCreated: 1522829883
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using Mopsicus.Plugins;
using UnityEngine;
using UnityEngine.UI;
public class Demo : MonoBehaviour {
public MobileInputField InputText;
void Start () {
MobileInput.OnPrepareKeyboard += OnPrepareKeyboard;
MobileInput.OnShowKeyboard += OnShowKeyboard;
}
public void OnReturn () {
Debug.Log ("OnReturn action");
}
public void OnEdit (string text) {
Debug.LogFormat ("OnEdit action. Text: {0}", text);
}
public void OnEndEdit (string text) {
Debug.LogFormat ("OnEdit action. Text: {0}", text);
}
public void SetTextData () {
InputText.Text = "Text by script";
}
void OnPrepareKeyboard () {
Debug.LogFormat ("Keyboad will show");
}
void OnShowKeyboard (bool isShow, int height) {
Debug.LogFormat ("Keyboad action, show = {0}, height = {1}", isShow, height);
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 053f12a21060a4074af5416ef1101ff4
timeCreated: 1522834416
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,956 @@
/*
NiceJson 1.3.1 (2017-07-26)
MIT License
===========
Copyright (C) 2015 Ángel Quiroga Mendoza <me@angelqm.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Appreciation Contributions:
Rayco Sánchez García <raycosanchezgarcia@gmail.com>
*/
using System;
using System.Collections.Generic;
using System.Collections;
using System.Globalization;
using System.Text;
namespace NiceJson
{
[Serializable]
public abstract class JsonNode
{
protected const char PP_IDENT_CHAR = '\t'; //Modify this to spaces or whatever char you want to be the ident one
protected const int PP_IDENT_COUNT = 1; //Modify this to be the numbers of IDENT_CHAR x identation
protected const bool ESCAPE_SOLIDUS = false; //If you are going to to embed this json in html, you can turn this on ref: http://andowebsit.es/blog/noteslog.com/post/the-solidus-issue/
protected const char CHAR_CURLY_OPEN = '{';
protected const char CHAR_CURLY_CLOSED = '}';
protected const char CHAR_SQUARED_OPEN = '[';
protected const char CHAR_SQUARED_CLOSED = ']';
protected const char CHAR_COLON = ':';
protected const char CHAR_COMMA = ',';
protected const char CHAR_QUOTE = '"';
protected const char CHAR_NULL_LITERAL = 'n';
protected const char CHAR_TRUE_LITERAL = 't';
protected const char CHAR_FALSE_LITERAL = 'f';
protected const char CHAR_SPACE = ' ';
protected const char CHAR_BS = '\b';
protected const char CHAR_FF = '\f';
protected const char CHAR_RF = '\r';
protected const char CHAR_NL = '\n';
protected const char CHAR_HT = '\t';
protected const char CHAR_ESCAPE = '\\';
protected const char CHAR_SOLIDUS = '/';
protected const char CHAR_ESCAPED_QUOTE = '\"';
protected const char CHAR_N = 'n';
protected const char CHAR_R = 'r';
protected const char CHAR_B = 'b';
protected const char CHAR_T = 't';
protected const char CHAR_F = 'f';
protected const char CHAR_U = 'u';
protected const string STRING_ESCAPED_BS = "\\b";
protected const string STRING_ESCAPED_FF = "\\f";
protected const string STRING_ESCAPED_RF = "\\r";
protected const string STRING_ESCAPED_NL = "\\n";
protected const string STRING_ESCAPED_TAB = "\\t";
protected const string STRING_ESCAPED_ESCAPE = "\\\\";
protected const string STRING_ESCAPED_SOLIDUS = "\\/";
protected const string STRING_ESCAPED_ESCAPED_QUOTE = "\\\"";
protected const string STRING_SPACE = " ";
protected const string STRING_LITERAL_NULL = "null";
protected const string STRING_LITERAL_TRUE = "true";
protected const string STRING_LITERAL_FALSE = "false";
protected const string STRING_ESCAPED_UNICODE_INIT = "\\u00";
//Indexers and accesors
public JsonNode this[string key]
{
get
{
if (this is JsonObject)
{
return ((JsonObject)this)[key];
}
else
{
return null;
}
}
set
{
if (this is JsonObject)
{
((JsonObject)this)[key] = value;
}
}
}
public JsonNode this[int index]
{
get
{
if (this is JsonArray)
{
return ((JsonArray)this)[index];
}
else
{
return null;
}
}
set
{
if (this is JsonArray)
{
((JsonArray)this)[index] = value;
}
}
}
public bool ContainsKey (string key)
{
if (this is JsonObject)
{
return ((JsonObject)this).ContainsKey(key);
}
else
{
return false;
}
}
//escaping logic
//Escaping/Unescaping logic
protected static string EscapeString(string s)
{
StringBuilder result = new StringBuilder();
foreach (char c in s)
{
switch (c)
{
case CHAR_ESCAPE:
{
result.Append(STRING_ESCAPED_ESCAPE);
}
break;
case CHAR_SOLIDUS:
{
#pragma warning disable
if (ESCAPE_SOLIDUS)
{
result.Append(STRING_ESCAPED_SOLIDUS);
}
else
{
result.Append(c);
}
#pragma warning restore
}
break;
case CHAR_ESCAPED_QUOTE:
{
result.Append (STRING_ESCAPED_ESCAPED_QUOTE);
}
break;
case CHAR_NL:
{
result.Append (STRING_ESCAPED_NL);
}
break;
case CHAR_RF:
{
result.Append (STRING_ESCAPED_RF);
}
break;
case CHAR_HT:
{
result.Append (STRING_ESCAPED_TAB);
}
break;
case CHAR_BS:
{
result.Append (STRING_ESCAPED_BS);
}
break;
case CHAR_FF:
{
result.Append (STRING_ESCAPED_FF);
}
break;
default:
if (c < CHAR_SPACE)
{
result.Append (STRING_ESCAPED_UNICODE_INIT + Convert.ToByte(c).ToString("x2").ToUpper());
}
else
{
result.Append(c);
}
break;
}
}
return result.ToString();
}
protected static string UnescapeString(string s)
{
StringBuilder result = new StringBuilder(s.Length);
for (int i=0;i<s.Length;i++)
{
if (s[i] == CHAR_ESCAPE)
{
i++;
switch(s[i])
{
case CHAR_ESCAPE:
{
result.Append(s[i]);
}
break;
case CHAR_SOLIDUS:
{
result.Append(s[i]);
}
break;
case CHAR_ESCAPED_QUOTE:
{
result.Append(s[i]);
}
break;
case CHAR_N:
{
result.Append(CHAR_NL);
}
break;
case CHAR_R:
{
result.Append(CHAR_RF);
}
break;
case CHAR_T:
{
result.Append(CHAR_HT);
}
break;
case CHAR_B:
{
result.Append(CHAR_BS);
}
break;
case CHAR_F:
{
result.Append(CHAR_FF);
}
break;
case CHAR_U:
{
result.Append((char) int.Parse(s.Substring(i+1,4),NumberStyles.AllowHexSpecifier));
i = i + 4;
}
break;
default:
{
result.Append(s[i]);
}
break;
}
}
else
{
result.Append(s[i]);
}
}
return result.ToString();
}
//setter implicit casting
public static implicit operator JsonNode(string value)
{
return new JsonBasic(value);
}
public static implicit operator JsonNode(int value)
{
return new JsonBasic(value);
}
public static implicit operator JsonNode(long value)
{
return new JsonBasic(value);
}
public static implicit operator JsonNode(float value)
{
return new JsonBasic(value);
}
public static implicit operator JsonNode(double value)
{
return new JsonBasic(value);
}
public static implicit operator JsonNode(decimal value)
{
return new JsonBasic(value);
}
public static implicit operator JsonNode(bool value)
{
return new JsonBasic(value);
}
//getter implicit casting
public static implicit operator string(JsonNode value)
{
if (value != null)
{
return value.ToString();
}
else
{
return null;
}
}
public static implicit operator int(JsonNode value)
{
return (int) Convert.ChangeType(((JsonBasic)value).ValueObject,typeof(int));
}
public static implicit operator long (JsonNode value)
{
return (long) Convert.ChangeType(((JsonBasic)value).ValueObject, typeof(long));
}
public static implicit operator float(JsonNode value)
{
return (float) Convert.ChangeType(((JsonBasic)value).ValueObject, typeof(float));
}
public static implicit operator double(JsonNode value)
{
return (double) Convert.ChangeType(((JsonBasic)value).ValueObject, typeof(double));
}
public static implicit operator decimal (JsonNode value)
{
return (decimal) Convert.ChangeType(((JsonBasic)value).ValueObject, typeof(decimal));
}
public static implicit operator bool(JsonNode value)
{
return (bool) Convert.ChangeType(((JsonBasic)value).ValueObject, typeof(bool));
}
//Parsing logic
public static JsonNode ParseJsonString(string jsonString)
{
return ParseJsonPart(RemoveNonTokenChars(jsonString));
}
private static JsonNode ParseJsonPart(string jsonPart)
{
JsonNode jsonPartValue = null;
if (jsonPart.Length == 0)
{
return jsonPartValue;
}
switch (jsonPart[0])
{
case JsonNode.CHAR_CURLY_OPEN:
{
JsonObject jsonObject = new JsonObject();
List<string> splittedParts = SplitJsonParts(jsonPart.Substring(1, jsonPart.Length - 2));
string[] keyValueParts = new string[2];
foreach (string keyValuePart in splittedParts)
{
keyValueParts = SplitKeyValuePart (keyValuePart);
if (keyValueParts [0] != null)
{
jsonObject [JsonNode.UnescapeString (keyValueParts [0])] = ParseJsonPart (keyValueParts [1]);
}
}
jsonPartValue = jsonObject;
}
break;
case JsonNode.CHAR_SQUARED_OPEN:
{
JsonArray jsonArray = new JsonArray();
List<string> splittedParts = SplitJsonParts(jsonPart.Substring(1, jsonPart.Length - 2));
foreach (string part in splittedParts)
{
if (part.Length > 0)
{
jsonArray.Add (ParseJsonPart (part));
}
}
jsonPartValue = jsonArray;
}
break;
case JsonNode.CHAR_QUOTE:
{
jsonPartValue = new JsonBasic(JsonNode.UnescapeString(jsonPart.Substring(1, jsonPart.Length - 2)));
}
break;
case JsonNode.CHAR_FALSE_LITERAL://false
{
jsonPartValue = new JsonBasic(false);
}
break;
case JsonNode.CHAR_TRUE_LITERAL://true
{
jsonPartValue = new JsonBasic(true);
}
break;
case JsonNode.CHAR_NULL_LITERAL://null
{
jsonPartValue = null;
}
break;
default://it must be a number or it will fail
{
long longValue = 0;
if (long.TryParse(jsonPart, NumberStyles.Any, CultureInfo.InvariantCulture, out longValue))
{
if (longValue > int.MaxValue || longValue < int.MinValue)
{
jsonPartValue = new JsonBasic(longValue);
}
else
{
jsonPartValue = new JsonBasic((int)longValue);
}
}
else
{
decimal decimalValue = 0;
if (decimal.TryParse(jsonPart, NumberStyles.Any, CultureInfo.InvariantCulture, out decimalValue))
{
jsonPartValue = new JsonBasic(decimalValue);
}
}
}
break;
}
return jsonPartValue;
}
private static List<string> SplitJsonParts(string json)
{
List<string> jsonParts = new List<string>();
int identLevel = 0;
int lastPartChar = 0;
bool inString = false;
for (int i = 0; i < json.Length; i++)
{
switch (json[i])
{
case JsonNode.CHAR_COMMA:
{
if (!inString && identLevel == 0)
{
jsonParts.Add(json.Substring(lastPartChar, i - lastPartChar));
lastPartChar = i + 1;
}
}
break;
case JsonNode.CHAR_QUOTE:
{
if (i == 0 || (json[i - 1] != JsonNode.CHAR_ESCAPE))
{
inString = !inString;
}
}
break;
case JsonNode.CHAR_CURLY_OPEN:
case JsonNode.CHAR_SQUARED_OPEN:
{
if (!inString)
{
identLevel++;
}
}
break;
case JsonNode.CHAR_CURLY_CLOSED:
case JsonNode.CHAR_SQUARED_CLOSED:
{
if (!inString)
{
identLevel--;
}
}
break;
}
}
jsonParts.Add(json.Substring(lastPartChar));
return jsonParts;
}
private static string[] SplitKeyValuePart(string json)
{
string[] parts = new string[2];
bool inString = false;
bool found = false;
int index = 0;
while (index < json.Length && !found)
{
if (json[index] == JsonNode.CHAR_QUOTE && (index == 0 || (json[index - 1] != JsonNode.CHAR_ESCAPE)))
{
if (!inString)
{
inString = true;
index++;
}
else
{
parts[0] = json.Substring(1, index - 1);
parts[1] = json.Substring(index + 2);//+2 because of the :
found = true;
}
}
else
{
index++;
}
}
return parts;
}
private static string RemoveNonTokenChars(string s)
{
int len = s.Length;
char[] s2 = new char[len];
int currentPos = 0;
bool outString = true;
for (int i = 0; i < len; i++)
{
char c = s[i];
if (c == JsonNode.CHAR_QUOTE)
{
if (i == 0 || (s[i - 1] != JsonNode.CHAR_ESCAPE))
{
outString = !outString;
}
}
if (!outString || (
(c != JsonNode.CHAR_SPACE) &&
(c != JsonNode.CHAR_RF) &&
(c != JsonNode.CHAR_NL) &&
(c != JsonNode.CHAR_HT) &&
(c != JsonNode.CHAR_BS) &&
(c != JsonNode.CHAR_FF)
))
{
s2[currentPos++] = c;
}
}
return new String(s2, 0, currentPos);
}
//Object logic
public abstract string ToJsonString();
public string ToJsonPrettyPrintString()
{
string jsonString = this.ToJsonString();
string identStep = string.Empty;
for (int i = 0; i < PP_IDENT_COUNT; i++)
{
identStep += PP_IDENT_CHAR;
}
bool inString = false;
string currentIdent = string.Empty;
for (int i = 0; i < jsonString.Length; i++)
{
switch (jsonString[i])
{
case CHAR_COLON:
{
if (!inString)
{
jsonString = jsonString.Insert(i + 1, STRING_SPACE);
}
}
break;
case CHAR_QUOTE:
{
if (i == 0 || (jsonString[i - 1] != CHAR_ESCAPE))
{
inString = !inString;
}
}
break;
case CHAR_COMMA:
{
if (!inString)
{
jsonString = jsonString.Insert(i + 1, CHAR_NL + currentIdent);
}
}
break;
case CHAR_CURLY_OPEN:
case CHAR_SQUARED_OPEN:
{
if (!inString)
{
currentIdent += identStep;
jsonString = jsonString.Insert(i + 1, CHAR_NL + currentIdent);
}
}
break;
case CHAR_CURLY_CLOSED:
case CHAR_SQUARED_CLOSED:
{
if (!inString)
{
currentIdent = currentIdent.Substring(0, currentIdent.Length - identStep.Length);
jsonString = jsonString.Insert(i, CHAR_NL + currentIdent);
i += currentIdent.Length + 1;
}
}
break;
}
}
return jsonString;
}
}
[Serializable]
public class JsonBasic : JsonNode
{
public object ValueObject
{
get
{
return m_value;
}
}
private object m_value;
public JsonBasic(object value)
{
m_value = value;
}
public override string ToString()
{
return m_value.ToString();
}
public override string ToJsonString ()
{
if (m_value == null)
{
return STRING_LITERAL_NULL;
}
else if (m_value is string)
{
return CHAR_QUOTE + EscapeString(m_value.ToString()) + CHAR_QUOTE;
}
else if (m_value is bool)
{
if ((bool) m_value)
{
return STRING_LITERAL_TRUE;
}
else
{
return STRING_LITERAL_FALSE;
}
}
else
{
return m_value.ToString();
}
}
}
[Serializable]
public class JsonObject : JsonNode, IEnumerable
{
private Dictionary<string,JsonNode> m_dictionary = new Dictionary<string, JsonNode>();
public Dictionary<string,JsonNode>.KeyCollection Keys
{
get
{
return m_dictionary.Keys;
}
}
public Dictionary<string, JsonNode>.ValueCollection Values
{
get
{
return m_dictionary.Values;
}
}
public new JsonNode this[string key]
{
get
{
return m_dictionary[key];
}
set
{
m_dictionary[key] = value;
}
}
public void Add(string key, JsonNode value)
{
m_dictionary.Add(key, value);
}
public bool Remove(string key)
{
return m_dictionary.Remove(key);
}
public new bool ContainsKey(string key)
{
return m_dictionary.ContainsKey(key);
}
public bool ContainsValue(JsonNode value)
{
return m_dictionary.ContainsValue(value);
}
public void Clear()
{
m_dictionary.Clear();
}
public int Count
{
get
{
return m_dictionary.Count;
}
}
public IEnumerator GetEnumerator()
{
foreach (KeyValuePair<string, JsonNode> jsonKeyValue in m_dictionary)
{
yield return jsonKeyValue;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override string ToJsonString ()
{
if (m_dictionary == null)
{
return STRING_LITERAL_NULL;
}
else
{
StringBuilder jsonString = new StringBuilder();
jsonString.Append(CHAR_CURLY_OPEN);
foreach (string key in m_dictionary.Keys)
{
jsonString.Append(CHAR_QUOTE);
jsonString.Append(EscapeString(key));
jsonString.Append(CHAR_QUOTE);
jsonString.Append(CHAR_COLON);
if (m_dictionary[key] != null)
{
jsonString.Append(m_dictionary[key].ToJsonString());
}
else
{
jsonString.Append(STRING_LITERAL_NULL);
}
jsonString.Append(CHAR_COMMA);
}
if (jsonString[jsonString.Length -1] == CHAR_COMMA)
{
jsonString.Remove(jsonString.Length -1,1);
}
jsonString.Append(CHAR_CURLY_CLOSED);
return jsonString.ToString();
}
}
}
[Serializable]
public class JsonArray : JsonNode, IEnumerable<JsonNode>
{
private List<JsonNode> m_list = new List<JsonNode>();
public int Count
{
get
{
return m_list.Count;
}
}
public new JsonNode this[int index]
{
get
{
return m_list[index];
}
set
{
m_list[index] = value;
}
}
public IEnumerator<JsonNode> GetEnumerator()
{
foreach (JsonNode value in m_list)
{
yield return value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
//expose some methods of list extends with needs
public void Add(JsonNode item)
{
m_list.Add(item);
}
public void AddRange(IEnumerable<JsonNode> collection)
{
m_list.AddRange(collection);
}
public void Insert(int index,JsonNode item)
{
m_list.Insert(index,item);
}
public void InsertRange(int index,IEnumerable<JsonNode> collection)
{
m_list.InsertRange(index,collection);
}
public void RemoveAt(int index)
{
m_list.RemoveAt(index);
}
public bool Remove(JsonNode item)
{
return m_list.Remove(item);
}
public void Clear()
{
m_list.Clear();
}
//end exposed methods
public override string ToJsonString ()
{
if (m_list == null)
{
return STRING_LITERAL_NULL;
}
else
{
StringBuilder jsonString = new StringBuilder();
jsonString.Append (CHAR_SQUARED_OPEN);
foreach (JsonNode value in m_list)
{
if (value != null)
{
jsonString.Append (value.ToJsonString());
}
else
{
jsonString.Append (STRING_LITERAL_NULL);
}
jsonString.Append (CHAR_COMMA);
}
if (jsonString[jsonString.Length-1] == CHAR_COMMA)
{
jsonString.Remove(jsonString.Length -1,1);
}
jsonString.Append (CHAR_SQUARED_CLOSED);
return jsonString.ToString();
}
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: e4f694d670baf414b9018735af14a6a7
timeCreated: 1522830148
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 82bab59c0aaa34beaa1f3397c03a32a3
folderAsset: yes
timeCreated: 1522830104
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aa35a23a042f14b12ae57cd621e8a6e8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
// ----------------------------------------------------------------------------
// The MIT License
// UnityMobileInput https://github.com/mopsicus/UnityMobileInput
// Copyright (c) 2018 Mopsicus <mail@mopsicus.ru>
// ----------------------------------------------------------------------------
using UnityEditor;
using UnityEngine;
namespace Mopsicus.Plugins {
/// <summary>
/// Custom editor for MobileInput
/// </summary>
[CustomEditor (typeof (MobileInputField))]
public class MobileInputEditor : Editor {
/// <summary>
/// Offset size
/// </summary>
const int OFFSET = 20;
/// <summary>
/// Space between labels
/// </summary>
const int SPACE = 5;
/// <summary>
/// MobileInput target
/// </summary>
private MobileInputField _target;
/// <summary>
/// Serialized target object
/// </summary>
private SerializedObject _object;
/// <summary>
/// Return press event
/// </summary>
private SerializedProperty _onReturnPressedEvent;
#if UNITY_IOS
/// <summary>
/// Visible Done button
/// </summary>
private SerializedProperty _isWithDoneButton;
/// <summary>
/// Visible Clear buttonƒ
/// </summary>
private SerializedProperty _isWithClearButton;
#endif
/// <summary>
/// Init data
/// </summary>
private void OnEnable () {
_target = (MobileInputField) target;
_object = new SerializedObject (target);
_onReturnPressedEvent = _object.FindProperty ("OnReturnPressedEvent");
#if UNITY_IOS
_isWithDoneButton = _object.FindProperty ("IsWithDoneButton");
_isWithClearButton = _object.FindProperty ("IsWithClearButton");
#endif
}
/// <summary>
/// Draw inspector
/// </summary>
public override void OnInspectorGUI () {
_object.Update ();
EditorGUI.BeginChangeCheck ();
GUILayout.Space (OFFSET);
GUILayout.Label ("Select type for Return button:");
_target.ReturnKey = (MobileInputField.ReturnKeyType) GUILayout.Toolbar ((int) _target.ReturnKey, new string[] { "Default", "Next", "Done", "Search" });
GUILayout.Space (OFFSET);
#if UNITY_IOS
GUILayout.Label ("Options:");
_target.IsWithDoneButton = GUILayout.Toggle (_target.IsWithDoneButton, " Show \"Done\" button");
GUILayout.Space (SPACE);
_target.IsWithClearButton = GUILayout.Toggle (_target.IsWithClearButton, " Show \"Clear\" button");
GUILayout.Space (OFFSET);
#endif
EditorGUILayout.PropertyField (_onReturnPressedEvent);
if (EditorGUI.EndChangeCheck ()) {
_object.ApplyModifiedProperties ();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd55cea5e8ce949a395e88966d10f0bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,320 @@
// ----------------------------------------------------------------------------
// The MIT License
// UnityMobileInput https://github.com/mopsicus/UnityMobileInput
// Copyright (c) 2018 Mopsicus <mail@mopsicus.ru>
// ----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using NiceJson;
using UnityEngine;
#if UNITY_IOS
using System.Runtime.InteropServices;
#endif
namespace Mopsicus.Plugins {
/// <summary>
/// Base class for InputField
/// </summary>
public abstract class MobileInputReceiver : MonoBehaviour {
/// <summary>
/// Current input id
/// </summary>
private int _id;
/// <summary>
/// Init input and register interface
/// </summary>
protected virtual void Start () {
_id = MobileInput.Register (this);
}
/// <summary>
/// Action on destroy
/// </summary>
protected virtual void OnDestroy () {
MobileInput.RemoveReceiver (_id);
}
/// <summary>
/// Send data to plugin
/// </summary>
/// <param name="data">Data</param>
protected void Execute (JsonObject data) {
MobileInput.Execute (_id, data);
}
/// <summary>
/// Send data to plugin manually
/// </summary>
/// <param name="data">Data</param>
public abstract void Send (JsonObject data);
/// <summary>
/// Hide input
/// </summary>
public abstract void Hide ();
}
/// <summary>
/// Mobile native input plugin
/// </summary>
public class MobileInput : MonoBehaviour, IPlugin {
/// <summary>
/// Event name for keyboard prepare to change
/// </summary>
const string KEYBOARD_PREPARE = "KEYBOARD_PREPARE";
/// <summary>
/// Event name for keyboard show/hide
/// </summary>
const string KEYBOARD_ACTION = "KEYBOARD_ACTION";
/// <summary>
/// Delegate for show/hide keyboard action
/// </summary>
public delegate void ShowDelegate (bool isShow, int height);
/// <summary>
/// Delegate for prepare show keyboard
/// </summary>
public delegate void PrepareDelegate ();
/// <summary>
/// Handler for ShowDelegate
/// </summary>
public static ShowDelegate OnShowKeyboard = delegate { };
/// <summary>
/// Handler for PrepareDelegate
/// </summary>
public static PrepareDelegate OnPrepareKeyboard = delegate { };
/// <summary>
/// Mobile fields dictionary
/// </summary>
private Dictionary<int, MobileInputReceiver> _inputs = new Dictionary<int, MobileInputReceiver> ();
/// <summary>
/// Current instance
/// </summary>
private static MobileInput _instance;
/// <summary>
/// Cache data for hidden app state
/// </summary>
private JsonObject _data;
/// <summary>
/// Cache error for hidden app state
/// </summary>
private JsonObject _error;
/// <summary>
/// MobileInput counter
/// </summary>
private int _counter = 0;
#if UNITY_IOS
/// <summary>
/// Send data to plugin input
/// </summary>
[DllImport ("__Internal")]
private static extern void inputExecute (int id, string json);
/// <summary>
/// Init MobileInput plugin
/// </summary>
[DllImport ("__Internal")]
private static extern void inputInit ();
/// <summary>
/// Destroy MobileInput plugin
/// </summary>
[DllImport ("__Internal")]
private static extern void inputDestroy ();
#endif
/// <summary>
/// Constructor
/// </summary>
private void Awake () {
if ((object) _instance == null) {
_instance = GetComponent<MobileInput> ();
Init ();
}
}
/// <summary>
/// Plugin name
/// </summary>
public string Name {
get {
return GetType ().Name.ToLower ();
}
}
/// <summary>
/// Current instance for external access
/// </summary>
public static MobileInput Plugin {
get {
return _instance;
}
}
/// <summary>
/// Callback on data
/// </summary>
public void OnData (JsonObject data) {
Debug.Log (string.Format ("{0} plugin OnData: {1}", GetType ().Name, data.ToJsonPrettyPrintString ()));
_data = data;
try {
JsonObject response = (JsonObject) JsonNode.ParseJsonString (data["data"]);
string code = response["msg"];
switch (code) {
case KEYBOARD_PREPARE:
OnPrepareKeyboard ();
break;
case KEYBOARD_ACTION:
bool isShow = response["show"];
int height = 0;
#if UNITY_ANDROID
height = (int) (response["height"] * (float) Screen.height);
#elif UNITY_IOS
height = response["height"];
#endif
OnShowKeyboard (isShow, height);
break;
default:
int id = response["id"];
if (_inputs.ContainsKey (id)) {
GetReceiver (id).Send (response);
}
break;
}
_data = null;
} catch (Exception e) {
Debug.LogError (string.Format ("{0} plugin OnData error: {1}", GetType ().Name, e.Message));
}
}
/// <summary>
/// Callback on error
/// </summary>
public void OnError (JsonObject data) {
Debug.LogError (string.Format ("{0} plugin OnError: {0}", GetType ().Name, data.ToJsonPrettyPrintString ()));
_error = data;
try {
_error = null;
} catch (Exception e) {
Debug.LogError (string.Format ("{0} plugin OnError error: {1}", GetType ().Name, e.Message));
}
}
/// <summary>
/// Init and save new MobileInput
/// </summary>
/// <param name="receiver">Receiver</param>
/// <returns>Id</returns>
public static int Register (MobileInputReceiver receiver) {
int index = _instance._counter;
_instance._counter++;
_instance._inputs[index] = receiver;
return index;
}
/// <summary>
/// Remove MobileInput
/// </summary>
/// <param name="id">Input id</param>
public static void RemoveReceiver (int id) {
_instance._inputs.Remove (id);
}
/// <summary>
/// Get MobileInput by index
/// </summary>
/// <param name="id">Input id</param>
/// <returns>Receiver</returns>
public static MobileInputReceiver GetReceiver (int id) {
return _instance._inputs[id];
}
/// <summary>
/// Send data to plugin
/// </summary>
/// <param name="id">id</param>
/// <param name="data">json</param>
public static void Execute (int id, JsonObject data) {
data["id"] = id;
string json = data.ToJsonString ();
#if UNITY_EDITOR
Debug.Log ("MobileInput execute " + json);
#elif UNITY_ANDROID
using (AndroidJavaClass plugin = new AndroidJavaClass (string.Format (Plugins.ANDROID_CLASS_MASK, _instance.Name))) {
plugin.CallStatic ("execute", id, json);
}
#elif UNITY_IOS
inputExecute (id, json);
#endif
}
/// <summary>
/// Init plugin
/// </summary>
public static void Init () {
#if UNITY_EDITOR
#elif UNITY_ANDROID
using (AndroidJavaClass plugin = new AndroidJavaClass (string.Format (Plugins.ANDROID_CLASS_MASK, _instance.Name))) {
plugin.CallStatic ("init");
}
#elif UNITY_IOS
inputInit ();
#endif
}
/// <summary>
/// Destructor
/// </summary>
public static void Destroy () {
#if UNITY_EDITOR
#elif UNITY_ANDROID
using (AndroidJavaClass plugin = new AndroidJavaClass (string.Format (Plugins.ANDROID_CLASS_MASK, _instance.Name))) {
plugin.CallStatic ("destroy");
}
#elif UNITY_IOS
inputDestroy ();
#endif
}
/// <summary>
/// Handler to check data on focus change
/// </summary>
private void OnApplicationPause (bool pauseStatus) {
if (!pauseStatus) {
if (_data != null) {
OnData (_data);
} else if (_error != null) {
OnError (_error);
}
}
}
/// <summary>
/// Handler on app focus
/// </summary>
void OnApplicationFocus (bool focusStatus) {
if (!focusStatus) {
foreach (var item in _instance._inputs.Values) {
item.Hide ();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ec5c22f648534b2490352b23199aae1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,621 @@
// ----------------------------------------------------------------------------
// The MIT License
// UnityMobileInput https://github.com/mopsicus/UnityMobileInput
// Copyright (c) 2018 Mopsicus <mail@mopsicus.ru>
// ----------------------------------------------------------------------------
using System;
using System.Collections;
using NiceJson;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace Mopsicus.Plugins {
/// <summary>
/// Wrapper for Unity InputField
/// Add this component on your InputField
/// </summary>
[RequireComponent (typeof (InputField))]
public class MobileInputField : MobileInputReceiver {
/// <summary>
/// Config structure
/// </summary>
private struct MobileInputConfig {
public bool Multiline;
public Color TextColor;
public Color BackgroundColor;
public string ContentType;
public string InputType;
public string KeyboardType;
public float FontSize;
public string Align;
public string Placeholder;
public Color PlaceholderColor;
public int CharacterLimit;
}
/// <summary>
/// Button type
/// </summary>
public enum ReturnKeyType {
Default,
Next,
Done,
Search
}
/// <summary>
/// "Done" button visible (for iOS)
/// </summary>
public bool IsWithDoneButton = true;
/// <summary>
/// "(x)" button visible (for iOS)
/// </summary>
public bool IsWithClearButton = true;
/// <summary>
/// Type for return button
/// </summary>
public ReturnKeyType ReturnKey;
/// <summary>
/// Action when Return pressed, for subscribe
/// </summary>
public Action OnReturnPressed = delegate { };
/// <summary>
/// Action when Focus changed
/// </summary>
public Action<bool> OnFocusChanged = delegate { };
/// <summary>
/// Event when Return pressed, for Unity inspector
/// </summary>
public UnityEvent OnReturnPressedEvent;
/// <summary>
/// Mobile input creation flag
/// </summary>
private bool _isMobileInputCreated = false;
/// <summary>
/// InputField object
/// </summary>
private InputField _inputObject;
/// <summary>
/// Text object from _inputObject
/// </summary>
private Text _inputObjectText;
/// <summary>
/// Set focus on create flag
/// </summary>
private bool _isFocusOnCreate;
/// <summary>
/// Set visible on create flag
/// </summary>
private bool _isVisibleOnCreate = true;
/// <summary>
/// Last field position cache
/// </summary>
private Rect _lastRect;
/// <summary>
/// Current config
/// </summary>
private MobileInputConfig _config;
/// <summary>
/// InputField create event
/// </summary>
const string CREATE = "CREATE_EDIT";
/// <summary>
/// InputField remove event
/// </summary>
const string REMOVE = "REMOVE_EDIT";
/// <summary>
/// Set text to InputField
/// </summary>
const string SET_TEXT = "SET_TEXT";
/// <summary>
/// Set new Rect, position, size
/// </summary>
const string SET_RECT = "SET_RECT";
/// <summary>
/// Set focus to InputField
/// </summary>
const string SET_FOCUS = "SET_FOCUS";
/// <summary>
/// Event when InputField is focused
/// </summary>
const string ON_FOCUS = "ON_FOCUS";
/// <summary>
/// Event when InputField is unfocused
/// </summary>
const string ON_UNFOCUS = "ON_UNFOCUS";
/// <summary>
/// Set visible to InputField
/// </summary>
const string SET_VISIBLE = "SET_VISIBLE";
/// <summary>
/// Event when text changing in InputField
/// </summary>
const string TEXT_CHANGE = "TEXT_CHANGE";
/// <summary>
/// Event when text end changing in InputField
/// </summary>
const string TEXT_END_EDIT = "TEXT_END_EDIT";
/// <summary>
/// Event for Android
/// </summary>
const string ANDROID_KEY_DOWN = "ANDROID_KEY_DOWN";
/// <summary>
/// Event when Return key pressed
/// </summary>
const string RETURN_PRESSED = "RETURN_PRESSED";
/// <summary>
/// Ready event
/// </summary>
const string READY = "READY";
/// <summary>
/// Constructor
/// </summary>
private void Awake () {
_inputObject = this.GetComponent<InputField> ();
if ((object) _inputObject == null) {
Debug.LogError (string.Format ("No found InputField for {0} MobileInput", this.name));
throw new MissingComponentException ();
}
_inputObjectText = _inputObject.textComponent;
}
/// <summary>
/// Create mobile input on Start with coroutine
/// </summary>
protected override void Start () {
base.Start ();
StartCoroutine (InitialzieOnNextFrame ());
}
/// <summary>
/// Show native on enable
/// </summary>
private void OnEnable () {
if (_isMobileInputCreated) {
this.SetVisible (true);
}
}
/// <summary>
/// Hide native on disable
/// </summary>
private void OnDisable () {
if (_isMobileInputCreated) {
this.SetFocus (false);
this.SetVisible (false);
}
}
/// <summary>
/// Destructor
/// </summary>
protected override void OnDestroy () {
RemoveNative ();
base.OnDestroy ();
}
/// <summary>
/// Handler for app focus lost
/// </summary>
private void OnApplicationFocus (bool hasFocus) {
if (!_isMobileInputCreated || !this.Visible) {
return;
}
this.SetVisible (hasFocus);
}
/// <summary>
/// Current InputField for external access
/// </summary>
public InputField InputField {
get {
return _inputObject;
}
}
/// <summary>
/// MobileInput visible
/// </summary>
public bool Visible {
get;
private set;
}
/// <summary>
/// MobileInput text
/// </summary>
public string Text {
get {
return _inputObject.text;
}
set {
_inputObject.text = value;
SetTextNative (value);
}
}
/// <summary>
/// Initialization coroutine
/// </summary>
private IEnumerator InitialzieOnNextFrame () {
yield return null;
this.PrepareNativeEdit ();
#if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR
this.CreateNativeEdit ();
this.SetTextNative (this._inputObjectText.text);
_inputObject.placeholder.gameObject.SetActive (false);
_inputObject.enabled = false;
_inputObjectText.enabled = false;
#endif
}
/// <summary>
/// Check position on each frame
/// If changed - send to plugin
/// It's need when app rotate on input field chage position
/// </summary>
private void Update () {
#if UNITY_ANDROID && !UNITY_EDITOR
this.UpdateForceKeyeventForAndroid ();
#endif
if (this._inputObject != null && _isMobileInputCreated) {
#if !UNITY_EDITOR
if (Input.touchCount > 0) {
for (int i = 0; i < Input.touches.Length; i++) {
if (!this._inputObjectText.rectTransform.rect.Contains (Input.touches[i].position)) {
Hide ();
return;
}
}
}
#endif
SetRectNative (this._inputObjectText.rectTransform);
}
}
/// <summary>
/// Get sizes and convert to current screen size
/// </summary>
/// <param name="rect">RectTranform from Gameobject</param>
/// <returns>Rect</returns>
public static Rect GetScreenRectFromRectTransform (RectTransform rect) {
Vector3[] corners = new Vector3[4];
rect.GetWorldCorners (corners);
float xMin = float.PositiveInfinity;
float xMax = float.NegativeInfinity;
float yMin = float.PositiveInfinity;
float yMax = float.NegativeInfinity;
for (int i = 0; i < 4; i++) {
Vector3 screenCoord;
if (rect.GetComponentInParent<Canvas> ().renderMode == RenderMode.ScreenSpaceOverlay) {
screenCoord = corners[i];
} else {
screenCoord = RectTransformUtility.WorldToScreenPoint (Camera.main, corners[i]);
}
if (screenCoord.x < xMin) {
xMin = screenCoord.x;
}
if (screenCoord.x > xMax) {
xMax = screenCoord.x;
}
if (screenCoord.y < yMin) {
yMin = screenCoord.y;
}
if (screenCoord.y > yMax) {
yMax = screenCoord.y;
}
}
Rect result = new Rect (xMin, Screen.height - yMax, xMax - xMin, yMax - yMin);
return result;
}
/// <summary>
/// Prepare config
/// </summary>
private void PrepareNativeEdit () {
Text placeHolder = _inputObject.placeholder.GetComponent<Text> ();
_config.Placeholder = placeHolder.text;
_config.PlaceholderColor = placeHolder.color;
_config.CharacterLimit = _inputObject.characterLimit;
Rect rect = GetScreenRectFromRectTransform (this._inputObjectText.rectTransform);
float ratio = rect.height / _inputObjectText.rectTransform.rect.height;
_config.FontSize = ((float) _inputObjectText.fontSize) * ratio;
_config.TextColor = _inputObjectText.color;
_config.Align = _inputObjectText.alignment.ToString ();
_config.ContentType = _inputObject.contentType.ToString ();
_config.BackgroundColor = _inputObject.colors.normalColor;
_config.Multiline = (_inputObject.lineType == InputField.LineType.SingleLine) ? false : true;
_config.KeyboardType = _inputObject.keyboardType.ToString ();
_config.InputType = _inputObject.inputType.ToString ();
}
/// <summary>
/// Text change callback
/// </summary>
/// <param name="text">new text</param>
private void OnTextChange (string text) {
if (text == this._inputObject.text) {
return;
}
this._inputObject.text = text;
if (this._inputObject.onValueChanged != null) {
this._inputObject.onValueChanged.Invoke (text);
}
}
/// <summary>
/// Text change end callback
/// </summary>
/// <param name="text">text</param>
private void OnTextEditEnd (string text) {
this._inputObject.text = text;
if (this._inputObject.onEndEdit != null) {
this._inputObject.onEndEdit.Invoke (text);
}
SetFocus (false);
}
/// <summary>
/// Sending data to plugin
/// </summary>
/// <param name="data">JSON</param>
public override void Send (JsonObject data) {
MobileInput.Plugin.StartCoroutine (PluginsMessageRoutine (data));
}
/// <summary>
/// Remove focus, keyboard when app lose focus
/// </summary>
public override void Hide () {
this.SetFocus (false);
}
/// <summary>
/// Coroutine for send, so its not freeze main thread
/// </summary>
/// <param name="data">JSON</param>
private IEnumerator PluginsMessageRoutine (JsonObject data) {
yield return null;
string msg = data["msg"];
if (msg.Equals (TEXT_CHANGE)) {
string text = data["text"];
this.OnTextChange (text);
} else if (msg.Equals (READY)) {
this.Ready ();
} else if (msg.Equals (ON_FOCUS)) {
OnFocusChanged (true);
} else if (msg.Equals (ON_UNFOCUS)) {
OnFocusChanged (false);
} else if (msg.Equals (TEXT_END_EDIT)) {
string text = data["text"];
this.OnTextEditEnd (text);
} else if (msg.Equals (RETURN_PRESSED)) {
OnReturnPressed ();
if (OnReturnPressedEvent != null) {
OnReturnPressedEvent.Invoke ();
}
}
}
/// <summary>
/// Convert float value to InvariantCulture string
/// </summary>
/// <param name="value">float value</param>
/// <returns></returns>
private string InvariantCultureString (float value){
return value.ToString ("G", System.Globalization.CultureInfo.InvariantCulture);
}
/// <summary>
/// Create native input field
/// </summary>
private void CreateNativeEdit () {
Rect rect = GetScreenRectFromRectTransform (this._inputObjectText.rectTransform);
JsonObject data = new JsonObject ();
data["msg"] = CREATE;
data["x"] = InvariantCultureString(rect.x / Screen.width);
data["y"] = InvariantCultureString(rect.y / Screen.height);
data["width"] = InvariantCultureString(rect.width / Screen.width);
data["height"] = InvariantCultureString(rect.height / Screen.height);
data["character_limit"] = _config.CharacterLimit;
data["text_color_r"] = InvariantCultureString(_config.TextColor.r);
data["text_color_g"] = InvariantCultureString(_config.TextColor.g);
data["text_color_b"] = InvariantCultureString(_config.TextColor.b);
data["text_color_a"] = InvariantCultureString(_config.TextColor.a);
data["back_color_r"] = InvariantCultureString(_config.BackgroundColor.r);
data["back_color_g"] = InvariantCultureString(_config.BackgroundColor.g);
data["back_color_b"] = InvariantCultureString(_config.BackgroundColor.b);
data["back_color_a"] = InvariantCultureString(_config.BackgroundColor.a);
data["font_size"] = InvariantCultureString(_config.FontSize);
data["content_type"] = _config.ContentType;
data["align"] = _config.Align;
data["with_done_button"] = this.IsWithDoneButton;
data["with_clear_button"] = this.IsWithClearButton;
data["placeholder"] = _config.Placeholder;
data["placeholder_color_r"] = InvariantCultureString(_config.PlaceholderColor.r);
data["placeholder_color_g"] = InvariantCultureString(_config.PlaceholderColor.g);
data["placeholder_color_b"] = InvariantCultureString(_config.PlaceholderColor.b);
data["placeholder_color_a"] = InvariantCultureString(_config.PlaceholderColor.a);
data["multiline"] = _config.Multiline;
data["input_type"] = _config.InputType;
data["keyboard_type"] = _config.KeyboardType;
switch (ReturnKey) {
case ReturnKeyType.Next:
data["return_key_type"] = "Next";
break;
case ReturnKeyType.Done:
data["return_key_type"] = "Done";
break;
case ReturnKeyType.Search:
data["return_key_type"] = "Search";
break;
default:
data["return_key_type"] = "Default";
break;
}
this.Execute (data);
}
/// <summary>
/// New field successfully added
/// </summary>
void Ready () {
_isMobileInputCreated = true;
if (!_isVisibleOnCreate) {
SetVisible (false);
}
if (_isFocusOnCreate) {
SetFocus (true);
}
}
/// <summary>
/// Set text to field
/// </summary>
/// <param name="text">New text</param>
void SetTextNative (string text) {
JsonObject data = new JsonObject ();
data["msg"] = SET_TEXT;
data["text"] = text;
this.Execute (data);
}
/// <summary>
/// Remove field
/// </summary>
private void RemoveNative () {
JsonObject data = new JsonObject ();
data["msg"] = REMOVE;
this.Execute (data);
}
/// <summary>
/// Set new size and position
/// </summary>
/// <param name="inputRect">RectTransform</param>
public void SetRectNative (RectTransform inputRect) {
Rect rect = GetScreenRectFromRectTransform (inputRect);
if (_lastRect == rect) {
return;
}
_lastRect = rect;
JsonObject data = new JsonObject ();
data["msg"] = SET_RECT;
data["x"] = InvariantCultureString(rect.x / Screen.width);
data["y"] = InvariantCultureString(rect.y / Screen.height);
data["width"] = InvariantCultureString(rect.width / Screen.width);
data["height"] = InvariantCultureString(rect.height / Screen.height);
this.Execute (data);
}
/// <summary>
/// Set focus on field
/// </summary>
/// <param name="isFocus">true | false</param>
public void SetFocus (bool isFocus) {
#if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR
if (!_isMobileInputCreated) {
_isFocusOnCreate = isFocus;
return;
}
JsonObject data = new JsonObject ();
data["msg"] = SET_FOCUS;
data["is_focus"] = isFocus;
this.Execute (data);
#else
if (gameObject.activeInHierarchy) {
if (isFocus) {
_inputObject.ActivateInputField ();
} else {
_inputObject.DeactivateInputField ();
}
} else {
_isFocusOnCreate = isFocus;
}
#endif
}
/// <summary>
/// Set field visible
/// </summary>
/// <param name="isVisible">true | false</param>
public void SetVisible (bool isVisible) {
if (!_isMobileInputCreated) {
_isVisibleOnCreate = isVisible;
return;
}
JsonObject data = new JsonObject ();
data["msg"] = SET_VISIBLE;
data["is_visible"] = isVisible;
this.Execute (data);
this.Visible = isVisible;
}
#if UNITY_ANDROID && !UNITY_EDITOR
/// <summary>
/// Send android button state
/// </summary>
/// <param name="key">Code</param>
private void ForceSendKeydownAndroid (string key) {
JsonObject data = new JsonObject ();
data["msg"] = ANDROID_KEY_DOWN;
data["key"] = key;
this.Execute (data);
}
/// <summary>
/// Keyboard handler
/// </summary>
private void UpdateForceKeyeventForAndroid () {
if (UnityEngine.Input.anyKeyDown) {
if (UnityEngine.Input.GetKeyDown (KeyCode.Backspace)) {
this.ForceSendKeydownAndroid ("backspace");
} else {
foreach (char c in UnityEngine.Input.inputString) {
if (c == '\n') {
this.ForceSendKeydownAndroid ("enter");
} else {
this.ForceSendKeydownAndroid (Input.inputString);
}
}
}
}
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7efa08dd091db4556b539d69d5505878
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,132 @@
// ----------------------------------------------------------------------------
// The MIT License
// UnityMobileInput https://github.com/mopsicus/UnityMobileInput
// Copyright (c) 2018 Mopsicus <mail@mopsicus.ru>
// ----------------------------------------------------------------------------
using UnityEngine;
using System;
using System.Collections.Generic;
using NiceJson;
#if UNITY_IOS
using System.Runtime.InteropServices;
#endif
namespace Mopsicus.Plugins {
/// <summary>
/// Mobile plugin interface
/// Each plugin must implement it
/// </summary>
public interface IPlugin {
/// <summary>
/// Plaugin name
/// </summary>
string Name { get; }
/// <summary>
/// Callback on get data
/// </summary>
void OnData (JsonObject data);
/// <summary>
/// Callback on get error
/// </summary>
void OnError (JsonObject data);
}
/// <summary>
/// Plugin service to manager all mobile plugins
/// </summary>
public class Plugins : MonoBehaviour {
#if UNITY_ANDROID
/// <summary>
/// Mask for Java classes
/// </summary>
public const string ANDROID_CLASS_MASK = "ru.mopsicus.{0}.Plugin";
#elif UNITY_IOS
/// <summary>
/// Init iOS plugins
/// </summary>
[DllImport ("__Internal")]
private static extern void pluginsInit (string data);
#endif
/// <summary>
/// Gameobject name on scene to receive data
/// ACHTUNG! Do not change it
/// </summary>
const string _dataObject = "Plugins";
/// <summary>
/// Function name to receive data
/// ACHTUNG! Do not change it
/// </summary>
const string _dataReceiver = "OnDataReceive";
/// <summary>
/// Dictionary of plugins
/// </summary>
private Dictionary<string, IPlugin> _plugins;
private void Awake () {
name = _dataObject;
DontDestroyOnLoad (gameObject);
InitPlugins ();
}
private void OnDestroy () {
_plugins = null;
}
/// <summary>
/// Init all plugins in app
/// </summary>
void InitPlugins () {
gameObject.AddComponent<MobileInput> ();
//
// other plugins
//
IPlugin[] plugins = GetComponents<IPlugin> ();
_plugins = new Dictionary<string, IPlugin> (plugins.Length);
foreach (var item in plugins) {
_plugins.Add (item.Name, item);
}
JsonObject data = new JsonObject ();
data["object"] = _dataObject;
data["receiver"] = _dataReceiver;
#if UNITY_IOS
pluginsInit (data.ToJsonString ());
#endif
Debug.Log ("Plugins init");
}
/// <summary>
/// Handler to process data to plugin
/// </summary>
/// <param name="data">data from plugin</param>
void OnDataReceive (string data) {
Debug.Log ("Plugins receive data: " + data);
try {
JsonObject info = (JsonObject) JsonNode.ParseJsonString (data);
if (_plugins.ContainsKey (info["name"])) {
IPlugin plugin = _plugins[info["name"]];
if (info.ContainsKey ("error")) {
plugin.OnError (info);
} else {
plugin.OnData (info);
}
} else {
Debug.LogError (string.Format ("{0} plugin does not exists", info["name"]));
}
} catch (Exception e) {
Debug.LogError (string.Format ("Plugins receive error: {0}, stack: {1}", e.Message, e.StackTrace));
}
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: af391257446ba4bc6b9124b683ceb46a
timeCreated: 1522834071
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: