├── .gitattributes ├── android ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ ├── reactlibrary │ │ └── RNAllmaxKeyboardPackage.java │ │ └── facebook │ │ └── react │ │ └── uimanager │ │ └── RNAllmaxKeyboardModule.java ├── build.gradle ├── gradlew.bat └── gradlew ├── ios ├── RNAllmaxKeyboard.h ├── RNAllmaxKeyboardEventEmitter.h ├── RNAllmaxKeyboard.podspec ├── RNAllmaxKeyboardEventEmitter.m ├── RNAllmaxKeyboard.m └── RNAllmaxKeyboard.xcodeproj │ └── project.pbxproj ├── package.json ├── .gitignore ├── index.js ├── lib ├── TextField.ios.js └── TextField.android.js └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naxel/react-native-keyboard/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ios/RNAllmaxKeyboard.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @interface RNAllmaxKeyboard : NSObject 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /ios/RNAllmaxKeyboardEventEmitter.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @interface RNAllmaxKeyboardEventEmitter : RCTEventEmitter 6 | 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Aug 29 19:39:44 NOVT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "react-native-allmax-keyboard", 4 | "version": "2.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "react-native" 12 | ], 13 | "author": "", 14 | "license": "", 15 | "peerDependencies": { 16 | "react-native": "^0.47.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | # node.js 7 | # 8 | node_modules/ 9 | npm-debug.log 10 | yarn-error.log 11 | 12 | 13 | # Xcode 14 | # 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | 33 | 34 | # Android/IntelliJ 35 | # 36 | build/ 37 | .idea 38 | .gradle 39 | local.properties 40 | *.iml 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | } 10 | } 11 | 12 | apply plugin: 'com.android.library' 13 | 14 | android { 15 | compileSdkVersion 23 16 | buildToolsVersion '25.0.0' 17 | 18 | defaultConfig { 19 | minSdkVersion 16 20 | targetSdkVersion 22 21 | versionCode 1 22 | versionName "1.0" 23 | } 24 | lintOptions { 25 | abortOnError false 26 | } 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | dependencies { 34 | compile 'com.facebook.react:react-native:+' 35 | } 36 | -------------------------------------------------------------------------------- /ios/RNAllmaxKeyboard.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "RNAllmaxKeyboard" 4 | s.version = "1.0.0" 5 | s.summary = "RNAllmaxKeyboard" 6 | s.description = <<-DESC 7 | RNAllmaxKeyboard 8 | DESC 9 | s.homepage = "" 10 | s.license = "MIT" 11 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 12 | s.author = { "author" => "author@domain.cn" } 13 | s.platform = :ios, "7.0" 14 | s.source = { :git => "https://github.com/author/RNAllmaxKeyboard.git", :tag => "master" } 15 | s.source_files = "RNAllmaxKeyboard/**/*.{h,m}" 16 | s.requires_arc = true 17 | 18 | 19 | s.dependency "React" 20 | #s.dependency "others" 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNAllmaxKeyboardPackage.java: -------------------------------------------------------------------------------- 1 | 2 | package com.reactlibrary; 3 | 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.uimanager.RNAllmaxKeyboardModule; 12 | import com.facebook.react.uimanager.ViewManager; 13 | 14 | public class RNAllmaxKeyboardPackage implements ReactPackage { 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList(new RNAllmaxKeyboardModule(reactContext)); 18 | } 19 | 20 | @Override 21 | public List createViewManagers(ReactApplicationContext reactContext) { 22 | return Collections.emptyList(); 23 | } 24 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { AppRegistry, NativeModules } from 'react-native'; 3 | import TextField from './lib/TextField'; 4 | 5 | const { backSpace, insertText, switchSystemKeyboard, installKeyboard, done, clear, setHeight } = NativeModules.RNAllmaxKeyboard; 6 | 7 | const keyboardTypeRegistry = {}; 8 | 9 | function registerKeyboard (keyboardType, keyboardProvider) { 10 | keyboardTypeRegistry[keyboardType] = keyboardProvider; 11 | } 12 | 13 | class CustomKeyboardContainer extends Component { 14 | render () { 15 | const { tag, keyboardType } = this.props; 16 | const factory = keyboardTypeRegistry[keyboardType]; 17 | if (!factory) { 18 | console.warn(`Custom keyboard type ${keyboardType} not registered.`); 19 | return null; 20 | } 21 | const Keyboard = factory(); 22 | return ; 23 | } 24 | } 25 | 26 | AppRegistry.registerComponent("AllMaxKeyboard", () => CustomKeyboardContainer); 27 | 28 | export { 29 | registerKeyboard, 30 | TextField, 31 | backSpace, 32 | insertText, 33 | done, 34 | clear, // only for Android 35 | installKeyboard, 36 | switchSystemKeyboard, 37 | setHeight 38 | } 39 | -------------------------------------------------------------------------------- /ios/RNAllmaxKeyboardEventEmitter.m: -------------------------------------------------------------------------------- 1 | // 2 | // RNAllmaxKeyboardEventEmitter.m 3 | // RNAllmaxKeyboard 4 | // 5 | // Created by Oleg on 29.08.17. 6 | // Copyright © 2017 Facebook. All rights reserved. 7 | // 8 | 9 | #import "RNAllmaxKeyboardEventEmitter.h" 10 | 11 | @implementation RNAllmaxKeyboardEventEmitter 12 | 13 | @synthesize bridge = _bridge; 14 | 15 | - (instancetype)init 16 | { 17 | self = [super init]; 18 | if (self) { 19 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(touchDownTextFieldWithNotification:) name:@"RNAllMaxKeyboardTouchDownTextField" object:nil]; 20 | } 21 | return self; 22 | } 23 | 24 | - (void)dealloc 25 | { 26 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 27 | } 28 | 29 | - (dispatch_queue_t)methodQueue 30 | { 31 | return dispatch_get_main_queue(); 32 | } 33 | 34 | RCT_EXPORT_MODULE(RNAllmaxKeyboardEventEmitter) 35 | 36 | - (NSArray *)supportedEvents 37 | { 38 | return @[@"TouchDownTextField"]; 39 | } 40 | 41 | - (void)touchDownTextFieldWithNotification: (NSNotification *) notification { 42 | NSLog(@"%@", notification); 43 | [self sendEventWithName:@"TouchDownTextField" body:notification.userInfo]; 44 | } 45 | 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /lib/TextField.ios.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { findNodeHandle, NativeEventEmitter, NativeModules, TextInput } from 'react-native'; 4 | 5 | const { installKeyboard, uninstall } = NativeModules.RNAllmaxKeyboard; 6 | 7 | const keyboardManagerEmitter = new NativeEventEmitter(NativeModules.RNAllmaxKeyboardEventEmitter); 8 | 9 | export default class TextField extends Component { 10 | 11 | static propTypes = { 12 | ...TextInput.propTypes, 13 | customKeyboardType: PropTypes.string.isRequired, 14 | mountInterval: PropTypes.number, 15 | touchOnFocus: PropTypes.func, 16 | onSuccessInstall: PropTypes.func, 17 | }; 18 | 19 | static defaultProps = { 20 | mountInterval: 40, 21 | touchOnFocus: () => {}, 22 | onSuccessInstall: () => {}, 23 | }; 24 | 25 | constructor (props) { 26 | super(props); 27 | this.subscription = keyboardManagerEmitter.addListener( 28 | 'TouchDownTextField', 29 | this.touchDownTextField 30 | ); 31 | } 32 | 33 | touchDownTextField = ({ reactTag }) => { 34 | if (reactTag === findNodeHandle(this.inputRef) && this.props.touchOnFocus) { 35 | this.props.touchOnFocus() 36 | } 37 | }; 38 | 39 | textInputRef = () => this.inputRef; 40 | 41 | componentWillReceiveProps (nextProps) { 42 | if (nextProps.keyboardHeight !== this.props.keyboardHeight) { 43 | installKeyboard(this.props.customKeyboardType, findNodeHandle(this.inputRef), nextProps.keyboardHeight, () => {}); 44 | } 45 | } 46 | 47 | componentDidMount () { 48 | setTimeout(() => installKeyboard( 49 | this.props.customKeyboardType, findNodeHandle(this.inputRef), this.props.keyboardHeight, this.props.onSuccessInstall 50 | ), this.props.mountInterval); 51 | } 52 | 53 | componentWillUnmount () { 54 | uninstall(findNodeHandle(this.inputRef)); 55 | this.subscription.remove(); 56 | } 57 | 58 | render () { 59 | const { ...otherProps } = this.props; 60 | return ( 61 | this.inputRef = ref} 63 | autoCorrect={false} 64 | {...otherProps} 65 | /> 66 | ); 67 | } 68 | } -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /lib/TextField.android.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { findNodeHandle, NativeEventEmitter, NativeModules, TextInput, Alert } from 'react-native'; 4 | 5 | const { installKeyboard, uninstall, setHeight } = NativeModules.RNAllmaxKeyboard; 6 | 7 | let keyboardManagerEmitter; 8 | keyboardManagerEmitter = new NativeEventEmitter(NativeModules.RNAllmaxKeyboard); 9 | 10 | 11 | export default class TextField extends Component { 12 | 13 | static propTypes = { 14 | ...TextInput.propTypes, 15 | customKeyboardType: PropTypes.string.isRequired, 16 | mountInterval: PropTypes.number, 17 | touchOnFocus: PropTypes.func, 18 | onChangeKeyboardHeight: PropTypes.func, 19 | onSuccessInstall: PropTypes.func, 20 | keyboardHeight: PropTypes.number, 21 | }; 22 | 23 | static defaultProps = { 24 | touchOnFocus: () => {}, 25 | onSuccessInstall: () => {}, 26 | mountInterval: 80, 27 | keyboardHeight: 0, 28 | }; 29 | 30 | constructor (props) { 31 | super(props); 32 | this.subscription = keyboardManagerEmitter.addListener( 33 | 'TouchDownTextField', 34 | this.touchDownTextField 35 | ); 36 | this.subscription = keyboardManagerEmitter.addListener( 37 | 'onChangeKeyboardHeight', 38 | this.onChangeKeyboardHeight 39 | ); 40 | this.installInterval = null; 41 | this.installCount = 0; 42 | } 43 | 44 | touchDownTextField = ({ reactTag }) => { 45 | if (reactTag === findNodeHandle(this.inputRef) && this.props.touchOnFocus) { 46 | this.props.touchOnFocus() 47 | } 48 | }; 49 | 50 | onChangeKeyboardHeight = ({ reactTag, height }) => { 51 | if (reactTag === findNodeHandle(this.inputRef) && this.props.onChangeKeyboardHeight) { 52 | this.props.onChangeKeyboardHeight(height) 53 | } 54 | }; 55 | 56 | textInputRef = () => this.inputRef; 57 | 58 | componentWillReceiveProps (nextProps) { 59 | if (nextProps.keyboardHeight !== this.props.keyboardHeight) { 60 | setHeight(findNodeHandle(this.inputRef), nextProps.keyboardHeight); 61 | 62 | } 63 | } 64 | 65 | // successCallback = () => { 66 | // clearInterval(this.installInterval); 67 | // } 68 | // 69 | // errorCallback = () => { 70 | // if (this.installCount > 5) { 71 | // clearInterval(this.installInterval); 72 | // } 73 | // this.installCount++ 74 | // } 75 | 76 | errorCallback = (err) => { 77 | Alert.alert( 78 | 'error', 79 | `${err}` 80 | ) 81 | }; 82 | 83 | componentDidMount () { 84 | // this.installInterval = setInterval(() => { 85 | // installKeyboard(this.props.customKeyboardType, findNodeHandle(this.inputRef), 0, this.successCallback, this.errorCallback) 86 | // }, 10); 87 | installKeyboard(this.props.customKeyboardType, findNodeHandle(this.inputRef), 0, this.props.onSuccessInstall, this.errorCallback) 88 | } 89 | 90 | componentWillUnmount () { 91 | uninstall(findNodeHandle(this.inputRef)); 92 | this.subscription.remove(); 93 | } 94 | 95 | render () { 96 | const { ...otherProps } = this.props; 97 | return ( 98 | this.inputRef = ref} 100 | autoCorrect={false} 101 | {...otherProps} 102 | /> 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # react-native-allmax-keyboard 3 | 4 | ## Getting started 5 | 6 | `$ npm install react-native-allmax-keyboard --save` 7 | 8 | ### Mostly automatic installation 9 | 10 | `$ react-native link react-native-allmax-keyboard` 11 | 12 | ### Manual installation 13 | 14 | 15 | #### iOS 16 | 17 | 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]` 18 | 2. Go to `node_modules` ➜ `react-native-allmax-keyboard` and add `RNAllmaxKeyboard.xcodeproj` 19 | 3. In XCode, in the project navigator, select your project. Add `libRNAllmaxKeyboard.a` to your project's `Build Phases` ➜ `Link Binary With Libraries` 20 | 4. Run your project (`Cmd+R`)< 21 | 22 | #### Android 23 | 24 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java` 25 | - Add `import com.reactlibrary.RNAllmaxKeyboardPackage;` to the imports at the top of the file 26 | - Add `new RNAllmaxKeyboardPackage()` to the list returned by the `getPackages()` method 27 | 2. Append the following lines to `android/settings.gradle`: 28 | ``` 29 | include ':react-native-allmax-keyboard' 30 | project(':react-native-allmax-keyboard').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-allmax-keyboard/android') 31 | ``` 32 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 33 | ``` 34 | compile project(':react-native-allmax-keyboard') 35 | ``` 36 | 37 | ## Usage 38 | ```javascript 39 | import { TextField, setHeight } from 'react-native-allmax-keyboard'; 40 | 41 | ... 42 | { 44 | this.scoutInput = ref; 45 | }} 46 | onSuccessInstall={() => { 47 | this.setState({ androidPreloader: false }); 48 | }} 49 | keyboardHeight={keyboardHeight} 50 | mountInterval={80} 51 | customKeyboardType={'NumPad'} 52 | placeholder="Barcode" 53 | returnKeyType="done" 54 | selectionColor={'rgba(0, 0, 0, .5)'} 55 | spellCheck={false} 56 | onSubmitEditing={() => { 57 | setHeight(findNodeHandle(this.scoutInput.textInputRef()), 0); 58 | if (isFetched !== 1) { 59 | return fetchByBarcode(); 60 | } else if (isFetched === 1) { 61 | return setBarcode(''); 62 | } 63 | return null; 64 | }} 65 | onChangeText={(newBarcode) => { 66 | setBarcode(newBarcode); 67 | }} 68 | value={newBarcode} 69 | style={styles.scan_textInput} 70 | touchOnFocus={() => { 71 | if (keyboardHeight === 0 && !this.state.androidPreloader) { 72 | setKeyboardHeight(this.keyboardHeight); 73 | } 74 | }} 75 | onChangeKeyboardHeight={(height) => { 76 | if (keyboardHeight !== height) { 77 | setKeyboardHeight(height); 78 | } 79 | }} 80 | underlineColorAndroid="transparent" 81 | blurOnSubmit={!externalScanner} 82 | dismissKeyboardAction={setKeyboardHeight} 83 | /> 84 | ... 85 | 86 | ``` 87 | 88 | ## Variables 89 | ``` 90 | touchOnFocus: () => {}, // Input is touched 91 | onSuccessInstall: () => {}, // Callback when keyboard is mounted 92 | mountInterval: 80, // Interval to mount keyboard, only for iOS 93 | keyboardHeight: 0, // Keyboard height, default is 0 94 | ``` 95 | 96 | ## Functions to use 97 | ``` 98 | registerKeyboard, // Register in root container 99 | TextField, // TextInput 100 | backSpace, // Delete action 101 | insertText, // Insert action 102 | done, // Done action 103 | clear, // Clear all nodes, only for Android 104 | installKeyboard, // Don't use it 105 | switchSystemKeyboard, // Switch to system keyboard action 106 | setHeight // Set keyboard height 107 | ``` 108 | 109 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /ios/RNAllmaxKeyboard.m: -------------------------------------------------------------------------------- 1 | #import "RNAllmaxKeyboard.h" 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | @implementation RNAllmaxKeyboard 9 | 10 | @synthesize bridge = _bridge; 11 | 12 | - (dispatch_queue_t)methodQueue 13 | { 14 | return dispatch_get_main_queue(); 15 | } 16 | 17 | RCT_EXPORT_MODULE(RNAllmaxKeyboard) 18 | 19 | RCT_EXPORT_METHOD(installKeyboard:(nonnull NSString *)keyboardType 20 | forTextFieldbyReactTag:(nonnull NSNumber *)reactTag 21 | withHeight:(nonnull NSNumber *)keyboardHeight 22 | number:(RCTResponseSenderBlock)callback) { 23 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 24 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 25 | UIView* keyboardView = [[RCTRootView alloc] 26 | initWithBridge:[self.bridge valueForKey:@"parentBridge"] 27 | moduleName:@"AllMaxKeyboard" 28 | initialProperties:@{ 29 | @"tag": reactTag, 30 | @"keyboardType": keyboardType 31 | } 32 | ]; 33 | 34 | [keyboardView setFrame:CGRectMake(0, 0, 0, [keyboardHeight floatValue])]; 35 | [textField setInputView:keyboardView]; 36 | [textField setReturnKeyType:UIReturnKeyDone]; 37 | [textField reloadInputViews]; 38 | [textField addTarget:self action:@selector(touchDownTextField:) forControlEvents:UIControlEventTouchDown]; 39 | callback(@[[NSNull null], [NSNumber numberWithInt:(10)]]); 40 | } 41 | 42 | RCT_EXPORT_METHOD(uninstall:(nonnull NSNumber *)reactTag) 43 | { 44 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 45 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 46 | 47 | [textField setInputView:nil]; 48 | [textField setInputAccessoryView: nil]; 49 | [textField reloadInputViews]; 50 | } 51 | 52 | RCT_EXPORT_METHOD(setHeight:(nonnull NSNumber *)keyboardHeight 53 | forTextFieldbyReactTag:(nonnull NSNumber *)reactTag) { 54 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 55 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 56 | if (textField.inputView != nil) { 57 | [textField.inputView setFrame:CGRectMake(0, 0, 0, [keyboardHeight floatValue])]; 58 | // [textField reloadInputViews]; 59 | } 60 | } 61 | 62 | RCT_EXPORT_METHOD(insertText:(nonnull NSNumber *)reactTag withText:(NSString*)text) { 63 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 64 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 65 | NSLog(@"%@", textField.inputAccessoryView); 66 | UIView* accessoryView = textField.inputAccessoryView; 67 | [textField replaceRange:textField.selectedTextRange withText:text]; 68 | [textField setInputAccessoryView:accessoryView]; 69 | [textField reloadInputViews]; 70 | } 71 | 72 | RCT_EXPORT_METHOD(backSpace:(nonnull NSNumber *)reactTag) { 73 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 74 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 75 | 76 | UITextRange* range = textField.selectedTextRange; 77 | if ([textField comparePosition:range.start toPosition:range.end] == 0) { 78 | range = [textField textRangeFromPosition:[textField positionFromPosition:range.start offset:-1] toPosition:range.start]; 79 | } 80 | [textField replaceRange:range withText:@""]; 81 | } 82 | 83 | RCT_EXPORT_METHOD(doDelete:(nonnull NSNumber *)reactTag) { 84 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 85 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 86 | 87 | UITextRange* range = textField.selectedTextRange; 88 | if ([textField comparePosition:range.start toPosition:range.end] == 0) { 89 | range = [textField textRangeFromPosition:range.start toPosition:[textField positionFromPosition: range.start offset: 1]]; 90 | } 91 | [textField replaceRange:range withText:@""]; 92 | } 93 | 94 | RCT_EXPORT_METHOD(moveLeft:(nonnull NSNumber *)reactTag) { 95 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 96 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 97 | 98 | UITextRange* range = textField.selectedTextRange; 99 | UITextPosition* position = range.start; 100 | 101 | if ([textField comparePosition:range.start toPosition:range.end] == 0) { 102 | position = [textField positionFromPosition: position offset: -1]; 103 | } 104 | 105 | textField.selectedTextRange = [textField textRangeFromPosition: position toPosition:position]; 106 | } 107 | 108 | RCT_EXPORT_METHOD(moveRight:(nonnull NSNumber *)reactTag) { 109 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 110 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 111 | 112 | UITextRange* range = textField.selectedTextRange; 113 | UITextPosition* position = range.end; 114 | 115 | if ([textField comparePosition:range.start toPosition:range.end] == 0) { 116 | position = [textField positionFromPosition: position offset: 1]; 117 | } 118 | 119 | textField.selectedTextRange = [textField textRangeFromPosition: position toPosition:position]; 120 | } 121 | 122 | RCT_EXPORT_METHOD(switchSystemKeyboard:(nonnull NSNumber*) reactTag) { 123 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 124 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 125 | 126 | UIView* inputView = textField.inputView; 127 | textField.inputView = nil; 128 | [textField reloadInputViews]; 129 | textField.inputView = inputView; 130 | } 131 | 132 | RCT_EXPORT_METHOD(done:(nonnull NSNumber*) reactTag) { 133 | RCTBaseTextInputView *textInputView = (RCTBaseTextInputView*)[_bridge.uiManager viewForReactTag:reactTag]; 134 | UITextField* textField = (UITextField*)[textInputView backedTextInputView]; 135 | 136 | [textField sendActionsForControlEvents:UIControlEventEditingDidEndOnExit]; 137 | [textField endEditing:YES]; 138 | // [textField resignFirstResponder]; 139 | // [textField becomeFirstResponder]; 140 | 141 | 142 | } 143 | 144 | - (void)touchDownTextField: (UITextField *)textField { 145 | NSNumber* reactTag = [textField.superview valueForKey:@"reactTag"]; 146 | [[NSNotificationCenter defaultCenter] postNotificationName:@"RNAllMaxKeyboardTouchDownTextField" object:textField userInfo:@{@"reactTag": reactTag}]; 147 | } 148 | 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /ios/RNAllmaxKeyboard.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B3E7B58A1CC2AC0600A0062D /* RNAllmaxKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNAllmaxKeyboard.m */; }; 11 | CE251E7A1F555A90002FA6DA /* RNAllmaxKeyboardEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = CE251E781F555A90002FA6DA /* RNAllmaxKeyboardEventEmitter.m */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = "include/$(PRODUCT_NAME)"; 19 | dstSubfolderSpec = 16; 20 | files = ( 21 | ); 22 | runOnlyForDeploymentPostprocessing = 0; 23 | }; 24 | /* End PBXCopyFilesBuildPhase section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 134814201AA4EA6300B7C361 /* libRNAllmaxKeyboard.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNAllmaxKeyboard.a; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | B3E7B5881CC2AC0600A0062D /* RNAllmaxKeyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNAllmaxKeyboard.h; sourceTree = ""; }; 29 | B3E7B5891CC2AC0600A0062D /* RNAllmaxKeyboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNAllmaxKeyboard.m; sourceTree = ""; }; 30 | CE251E781F555A90002FA6DA /* RNAllmaxKeyboardEventEmitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNAllmaxKeyboardEventEmitter.m; sourceTree = ""; }; 31 | CE251E791F555A90002FA6DA /* RNAllmaxKeyboardEventEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNAllmaxKeyboardEventEmitter.h; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | 134814211AA4EA7D00B7C361 /* Products */ = { 46 | isa = PBXGroup; 47 | children = ( 48 | 134814201AA4EA6300B7C361 /* libRNAllmaxKeyboard.a */, 49 | ); 50 | name = Products; 51 | sourceTree = ""; 52 | }; 53 | 58B511D21A9E6C8500147676 = { 54 | isa = PBXGroup; 55 | children = ( 56 | CE251E781F555A90002FA6DA /* RNAllmaxKeyboardEventEmitter.m */, 57 | CE251E791F555A90002FA6DA /* RNAllmaxKeyboardEventEmitter.h */, 58 | B3E7B5881CC2AC0600A0062D /* RNAllmaxKeyboard.h */, 59 | B3E7B5891CC2AC0600A0062D /* RNAllmaxKeyboard.m */, 60 | 134814211AA4EA7D00B7C361 /* Products */, 61 | ); 62 | sourceTree = ""; 63 | }; 64 | /* End PBXGroup section */ 65 | 66 | /* Begin PBXNativeTarget section */ 67 | 58B511DA1A9E6C8500147676 /* RNAllmaxKeyboard */ = { 68 | isa = PBXNativeTarget; 69 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNAllmaxKeyboard" */; 70 | buildPhases = ( 71 | 58B511D71A9E6C8500147676 /* Sources */, 72 | 58B511D81A9E6C8500147676 /* Frameworks */, 73 | 58B511D91A9E6C8500147676 /* CopyFiles */, 74 | ); 75 | buildRules = ( 76 | ); 77 | dependencies = ( 78 | ); 79 | name = RNAllmaxKeyboard; 80 | productName = RCTDataManager; 81 | productReference = 134814201AA4EA6300B7C361 /* libRNAllmaxKeyboard.a */; 82 | productType = "com.apple.product-type.library.static"; 83 | }; 84 | /* End PBXNativeTarget section */ 85 | 86 | /* Begin PBXProject section */ 87 | 58B511D31A9E6C8500147676 /* Project object */ = { 88 | isa = PBXProject; 89 | attributes = { 90 | LastUpgradeCheck = 0610; 91 | ORGANIZATIONNAME = Facebook; 92 | TargetAttributes = { 93 | 58B511DA1A9E6C8500147676 = { 94 | CreatedOnToolsVersion = 6.1.1; 95 | }; 96 | }; 97 | }; 98 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNAllmaxKeyboard" */; 99 | compatibilityVersion = "Xcode 3.2"; 100 | developmentRegion = English; 101 | hasScannedForEncodings = 0; 102 | knownRegions = ( 103 | en, 104 | ); 105 | mainGroup = 58B511D21A9E6C8500147676; 106 | productRefGroup = 58B511D21A9E6C8500147676; 107 | projectDirPath = ""; 108 | projectRoot = ""; 109 | targets = ( 110 | 58B511DA1A9E6C8500147676 /* RNAllmaxKeyboard */, 111 | ); 112 | }; 113 | /* End PBXProject section */ 114 | 115 | /* Begin PBXSourcesBuildPhase section */ 116 | 58B511D71A9E6C8500147676 /* Sources */ = { 117 | isa = PBXSourcesBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | B3E7B58A1CC2AC0600A0062D /* RNAllmaxKeyboard.m in Sources */, 121 | CE251E7A1F555A90002FA6DA /* RNAllmaxKeyboardEventEmitter.m in Sources */, 122 | ); 123 | runOnlyForDeploymentPostprocessing = 0; 124 | }; 125 | /* End PBXSourcesBuildPhase section */ 126 | 127 | /* Begin XCBuildConfiguration section */ 128 | 58B511ED1A9E6C8500147676 /* Debug */ = { 129 | isa = XCBuildConfiguration; 130 | buildSettings = { 131 | ALWAYS_SEARCH_USER_PATHS = NO; 132 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 133 | CLANG_CXX_LIBRARY = "libc++"; 134 | CLANG_ENABLE_MODULES = YES; 135 | CLANG_ENABLE_OBJC_ARC = YES; 136 | CLANG_WARN_BOOL_CONVERSION = YES; 137 | CLANG_WARN_CONSTANT_CONVERSION = YES; 138 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 139 | CLANG_WARN_EMPTY_BODY = YES; 140 | CLANG_WARN_ENUM_CONVERSION = YES; 141 | CLANG_WARN_INT_CONVERSION = YES; 142 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 143 | CLANG_WARN_UNREACHABLE_CODE = YES; 144 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 145 | COPY_PHASE_STRIP = NO; 146 | ENABLE_STRICT_OBJC_MSGSEND = YES; 147 | GCC_C_LANGUAGE_STANDARD = gnu99; 148 | GCC_DYNAMIC_NO_PIC = NO; 149 | GCC_OPTIMIZATION_LEVEL = 0; 150 | GCC_PREPROCESSOR_DEFINITIONS = ( 151 | "DEBUG=1", 152 | "$(inherited)", 153 | ); 154 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 155 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 156 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 157 | GCC_WARN_UNDECLARED_SELECTOR = YES; 158 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 159 | GCC_WARN_UNUSED_FUNCTION = YES; 160 | GCC_WARN_UNUSED_VARIABLE = YES; 161 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 162 | MTL_ENABLE_DEBUG_INFO = YES; 163 | ONLY_ACTIVE_ARCH = YES; 164 | SDKROOT = iphoneos; 165 | }; 166 | name = Debug; 167 | }; 168 | 58B511EE1A9E6C8500147676 /* Release */ = { 169 | isa = XCBuildConfiguration; 170 | buildSettings = { 171 | ALWAYS_SEARCH_USER_PATHS = NO; 172 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 173 | CLANG_CXX_LIBRARY = "libc++"; 174 | CLANG_ENABLE_MODULES = YES; 175 | CLANG_ENABLE_OBJC_ARC = YES; 176 | CLANG_WARN_BOOL_CONVERSION = YES; 177 | CLANG_WARN_CONSTANT_CONVERSION = YES; 178 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 179 | CLANG_WARN_EMPTY_BODY = YES; 180 | CLANG_WARN_ENUM_CONVERSION = YES; 181 | CLANG_WARN_INT_CONVERSION = YES; 182 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 183 | CLANG_WARN_UNREACHABLE_CODE = YES; 184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 185 | COPY_PHASE_STRIP = YES; 186 | ENABLE_NS_ASSERTIONS = NO; 187 | ENABLE_STRICT_OBJC_MSGSEND = YES; 188 | GCC_C_LANGUAGE_STANDARD = gnu99; 189 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 190 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 191 | GCC_WARN_UNDECLARED_SELECTOR = YES; 192 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 193 | GCC_WARN_UNUSED_FUNCTION = YES; 194 | GCC_WARN_UNUSED_VARIABLE = YES; 195 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 196 | MTL_ENABLE_DEBUG_INFO = NO; 197 | SDKROOT = iphoneos; 198 | VALIDATE_PRODUCT = YES; 199 | }; 200 | name = Release; 201 | }; 202 | 58B511F01A9E6C8500147676 /* Debug */ = { 203 | isa = XCBuildConfiguration; 204 | buildSettings = { 205 | HEADER_SEARCH_PATHS = ( 206 | "$(inherited)", 207 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 208 | "$(SRCROOT)/../../../React/**", 209 | "$(SRCROOT)/../../react-native/React/**", 210 | ); 211 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 212 | OTHER_LDFLAGS = "-ObjC"; 213 | PRODUCT_NAME = RNAllmaxKeyboard; 214 | SKIP_INSTALL = YES; 215 | }; 216 | name = Debug; 217 | }; 218 | 58B511F11A9E6C8500147676 /* Release */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | HEADER_SEARCH_PATHS = ( 222 | "$(inherited)", 223 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 224 | "$(SRCROOT)/../../../React/**", 225 | "$(SRCROOT)/../../react-native/React/**", 226 | ); 227 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 228 | OTHER_LDFLAGS = "-ObjC"; 229 | PRODUCT_NAME = RNAllmaxKeyboard; 230 | SKIP_INSTALL = YES; 231 | }; 232 | name = Release; 233 | }; 234 | /* End XCBuildConfiguration section */ 235 | 236 | /* Begin XCConfigurationList section */ 237 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNAllmaxKeyboard" */ = { 238 | isa = XCConfigurationList; 239 | buildConfigurations = ( 240 | 58B511ED1A9E6C8500147676 /* Debug */, 241 | 58B511EE1A9E6C8500147676 /* Release */, 242 | ); 243 | defaultConfigurationIsVisible = 0; 244 | defaultConfigurationName = Release; 245 | }; 246 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNAllmaxKeyboard" */ = { 247 | isa = XCConfigurationList; 248 | buildConfigurations = ( 249 | 58B511F01A9E6C8500147676 /* Debug */, 250 | 58B511F11A9E6C8500147676 /* Release */, 251 | ); 252 | defaultConfigurationIsVisible = 0; 253 | defaultConfigurationName = Release; 254 | }; 255 | /* End XCConfigurationList section */ 256 | }; 257 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 258 | } 259 | -------------------------------------------------------------------------------- /android/src/main/java/com/facebook/react/uimanager/RNAllmaxKeyboardModule.java: -------------------------------------------------------------------------------- 1 | package com.facebook.react.uimanager; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.os.ResultReceiver; 8 | import android.support.annotation.Nullable; 9 | import android.util.Log; 10 | import android.view.KeyEvent; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.view.inputmethod.InputMethodManager; 14 | import android.widget.EditText; 15 | import android.widget.RelativeLayout; 16 | 17 | import com.facebook.react.ReactApplication; 18 | import com.facebook.react.ReactRootView; 19 | import com.facebook.react.bridge.Arguments; 20 | import com.facebook.react.bridge.Callback; 21 | import com.facebook.react.bridge.ReactApplicationContext; 22 | import com.facebook.react.bridge.ReactContext; 23 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 24 | import com.facebook.react.bridge.ReactMethod; 25 | import com.facebook.react.bridge.WritableMap; 26 | import com.facebook.react.modules.core.DeviceEventManagerModule; 27 | import com.facebook.react.views.textinput.ReactEditText; 28 | import com.facebook.react.ReactInstanceManager; 29 | 30 | import java.lang.reflect.Method; 31 | import java.util.Map; 32 | import java.util.concurrent.ConcurrentHashMap; 33 | 34 | public class RNAllmaxKeyboardModule extends ReactContextBaseJavaModule { 35 | private static final String TAG = "RNAllmaxKeyboardModule"; 36 | private static final int DEFAULT_TIMEOUT = 300; 37 | private final ReactApplicationContext reactContext; 38 | 39 | private Method setShowSoftInputOnFocusMethod; 40 | private Method setSoftInputShownOnFocusMethod; 41 | 42 | private ConcurrentHashMap edits = new ConcurrentHashMap(); 43 | private ConcurrentHashMap keyboardLayouts = new ConcurrentHashMap(); 44 | private Handler mHandler = new Handler(Looper.getMainLooper()); 45 | 46 | public RNAllmaxKeyboardModule(ReactApplicationContext reactContext) { 47 | super(reactContext); 48 | this.reactContext = reactContext; 49 | initReflectMethod(); 50 | } 51 | 52 | private void initReflectMethod () { 53 | Class cls = ReactEditText.class; 54 | try { 55 | setShowSoftInputOnFocusMethod = cls.getMethod("setShowSoftInputOnFocus", boolean.class); 56 | setShowSoftInputOnFocusMethod.setAccessible(true); 57 | } catch (Exception e) { 58 | Log.i(TAG, "initReflectMethod 1 err=" + e.getMessage()); 59 | } 60 | try { 61 | setSoftInputShownOnFocusMethod = cls.getMethod("setSoftInputShownOnFocus", boolean.class); 62 | setSoftInputShownOnFocusMethod.setAccessible(true); 63 | } catch (Exception e) { 64 | Log.i(TAG, "initReflectMethod 2 err=" + e.getMessage()); 65 | } 66 | } 67 | 68 | private ReactEditText getEditById(int id) throws IllegalViewOperationException { 69 | UIViewOperationQueue uii = this.getReactApplicationContext().getNativeModule(UIManagerModule.class).getUIImplementation().getUIViewOperationQueue(); 70 | return (ReactEditText) uii.getNativeViewHierarchyManager().resolveView(id); 71 | } 72 | 73 | private void showKeyboard (final Activity activity, final int tag) { 74 | final ResultReceiver receiver = new ResultReceiver(mHandler) { 75 | @Override 76 | protected void onReceiveResult(int resultCode, Bundle resultData) { 77 | if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN || resultCode == InputMethodManager.RESULT_HIDDEN) { 78 | mHandler.postDelayed(new Runnable() { 79 | @Override 80 | public void run() { 81 | final ReactEditText edit = edits.get(String.valueOf(tag)); 82 | final RelativeLayout keyboardLayout = keyboardLayouts.get(String.valueOf(tag)); 83 | 84 | if (keyboardLayout != null && edit != null && edit.isFocused()) { 85 | if (keyboardLayout.getParent() != null) { 86 | ((ViewGroup)keyboardLayout.getParent()).removeView(keyboardLayout); 87 | } 88 | activity.addContentView(keyboardLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 89 | } 90 | } 91 | }, 5); 92 | } 93 | } 94 | }; 95 | 96 | mHandler.post(new Runnable() { 97 | @Override 98 | public void run() { 99 | InputMethodManager im = ((InputMethodManager) getReactApplicationContext().getSystemService(Activity.INPUT_METHOD_SERVICE)); 100 | im.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0, receiver); 101 | } 102 | }); 103 | } 104 | 105 | public void disableShowSoftInput(ReactEditText editText) { 106 | try { 107 | setShowSoftInputOnFocusMethod.invoke(editText, false); 108 | } catch (Exception e) { 109 | Log.i(TAG, "disableShowSoftInput 1 err=" + e.getMessage()); 110 | } 111 | 112 | try { 113 | setSoftInputShownOnFocusMethod.invoke(editText, false); 114 | } catch (Exception e) { 115 | Log.i(TAG, "disableShowSoftInput 2 err=" + e.getMessage()); 116 | } 117 | } 118 | 119 | private void setEditTextTagAndListener (final ReactEditText edit, final int tag, final String type, final int keyboardHeight) { 120 | final Activity activity = getCurrentActivity(); 121 | if (edit == null || activity == null) { 122 | Log.e(TAG, "setEditTextListener error null, edit=" + edit); 123 | return; 124 | } 125 | disableShowSoftInput(edit); 126 | final RelativeLayout keyboardLayout = createCustomKeyboard(activity, tag, type, keyboardHeight); 127 | 128 | edits.put(String.valueOf(tag), edit); 129 | keyboardLayouts.put(String.valueOf(tag), keyboardLayout); 130 | 131 | final View.OnFocusChangeListener oldOnFocusChangeListener = edit.getOnFocusChangeListener(); 132 | edit.setOnFocusChangeListener(new View.OnFocusChangeListener() { 133 | @Override 134 | public void onFocusChange(final View v, boolean hasFocus) { 135 | Log.i(TAG, "onFocusChange hasFocus=" + hasFocus ); 136 | if (hasFocus) { 137 | showKeyboard(activity, tag); 138 | } else { 139 | if (keyboardLayout.getParent() != null) { 140 | ((ViewGroup) keyboardLayout.getParent()).removeView(keyboardLayout); 141 | } 142 | } 143 | oldOnFocusChangeListener.onFocusChange(v, hasFocus); 144 | } 145 | }); 146 | 147 | edit.setOnClickListener(new View.OnClickListener(){ 148 | @Override 149 | public void onClick(final View v) { 150 | WritableMap params = Arguments.createMap(); 151 | params.putInt("reactTag", tag); 152 | sendEvent(reactContext, "TouchDownTextField", params); 153 | } 154 | }); 155 | } 156 | 157 | @ReactMethod 158 | public void installKeyboard(final String type, final int tag, final int keyboardHeight, final @Nullable Callback successCallback, final @Nullable Callback errorCallback) { 159 | mHandler.post(new Runnable() { 160 | @Override 161 | public void run() { 162 | try { 163 | ReactEditText edit = getEditById(tag); 164 | setEditTextTagAndListener(edit, tag, type, keyboardHeight); 165 | if (successCallback != null) { 166 | successCallback.invoke(); 167 | } 168 | } catch (IllegalViewOperationException e) { 169 | mHandler.postDelayed(new Runnable() { 170 | @Override 171 | public void run() { 172 | try { 173 | final ReactEditText edit = getEditById(tag); 174 | setEditTextTagAndListener(edit, tag, type, keyboardHeight); 175 | if (successCallback != null) { 176 | successCallback.invoke(); 177 | } 178 | } catch (IllegalViewOperationException err) { 179 | Log.e(TAG, err.toString()); 180 | if (errorCallback != null) { 181 | errorCallback.invoke(err.getMessage()); 182 | } 183 | } 184 | } 185 | }, DEFAULT_TIMEOUT); 186 | } 187 | } 188 | }); 189 | } 190 | 191 | private RelativeLayout createCustomKeyboard(Activity activity, int tag, String type, int keyboardHeight) { 192 | RelativeLayout keyboardLayout = new RelativeLayout(activity); 193 | ReactRootView rootView = new ReactRootView(this.getReactApplicationContext()); 194 | 195 | Bundle bundle = new Bundle(); 196 | bundle.putInt("tag", tag); 197 | bundle.putString("keyboardType", type); 198 | rootView.startReactApplication( 199 | ((ReactApplication) activity.getApplication()).getReactNativeHost().getReactInstanceManager(), 200 | "AllMaxKeyboard", 201 | bundle); 202 | 203 | final float scale = activity.getResources().getDisplayMetrics().density; 204 | RelativeLayout.LayoutParams lParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Math.round(keyboardHeight * scale)); 205 | lParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); 206 | if (rootView.getParent() != null) { 207 | ((ViewGroup)rootView.getParent()).removeView(rootView); 208 | } 209 | keyboardLayout.addView(rootView, lParams); 210 | 211 | WritableMap params = Arguments.createMap(); 212 | params.putInt("reactTag", tag); 213 | params.putInt("height", keyboardHeight); 214 | sendEvent(reactContext, "onChangeKeyboardHeight", params); 215 | 216 | return keyboardLayout; 217 | } 218 | 219 | @ReactMethod 220 | public void uninstall(final int tag) { 221 | Log.v(TAG, String.format("uninstall: %d", tag)); 222 | // mHandler.removeCallbacksAndMessages(null); 223 | mHandler.post(new Runnable() { 224 | @Override 225 | public void run() { 226 | final Activity activity = getCurrentActivity(); 227 | 228 | if (!edits.containsKey(String.valueOf(tag))) { 229 | return; 230 | } 231 | 232 | ReactEditText edit = edits.get(String.valueOf(tag)); 233 | RelativeLayout keyboardLayout = keyboardLayouts.get(String.valueOf(tag)); 234 | ReactRootView rootView = (ReactRootView)keyboardLayout.getChildAt(0); 235 | edit.setOnFocusChangeListener(null); 236 | edit.setOnClickListener(null); 237 | 238 | if (keyboardLayout != null && keyboardLayout.getParent() != null) { 239 | ((ViewGroup) keyboardLayout.getParent()).removeView(keyboardLayout); 240 | } 241 | 242 | if (rootView != null/* && activity != null*/) { 243 | rootView.unmountReactApplication(); 244 | // ((ReactApplication) activity.getApplication()).getReactNativeHost().getReactInstanceManager().detachRootView(rootView); 245 | } 246 | edits.remove(String.valueOf(tag)); 247 | keyboardLayouts.remove(String.valueOf(tag)); 248 | } 249 | }); 250 | } 251 | 252 | @ReactMethod 253 | public void clear(final Callback successCallback, final Callback errorCallback) { 254 | mHandler.removeCallbacksAndMessages(null); 255 | mHandler.post(new Runnable() { 256 | @Override 257 | public void run() { 258 | try { 259 | for(Map.Entry entry : keyboardLayouts.entrySet()) { 260 | RelativeLayout keyboardLayout = entry.getValue(); 261 | ReactRootView rootView = (ReactRootView)keyboardLayout.getChildAt(0); 262 | if (keyboardLayout != null && keyboardLayout.getParent() != null) { 263 | ((ViewGroup) keyboardLayout.getParent()).removeView(keyboardLayout); 264 | } 265 | if (rootView != null) { 266 | rootView.unmountReactApplication(); 267 | } 268 | } 269 | for(Map.Entry entry : edits.entrySet()) { 270 | ReactEditText edit = entry.getValue(); 271 | if (edit != null) { 272 | edit.setOnFocusChangeListener(null); 273 | edit.setOnClickListener(null); 274 | } 275 | } 276 | keyboardLayouts.clear(); 277 | edits.clear(); 278 | successCallback.invoke(); 279 | } catch ( Exception e) { 280 | errorCallback.invoke(e.getMessage()); 281 | } 282 | } 283 | }); 284 | } 285 | 286 | @ReactMethod 287 | public void setHeight(final int tag, final int keyboardHeight) { 288 | Log.v(TAG, "setHeight"); 289 | mHandler.post(new Runnable() { 290 | @Override 291 | public void run() { 292 | 293 | if (!edits.containsKey(String.valueOf(tag))) { 294 | return; 295 | } 296 | if (!keyboardLayouts.containsKey(String.valueOf(tag))) { 297 | return; 298 | } 299 | final Activity activity = getCurrentActivity(); 300 | if (activity == null) { 301 | return; 302 | } 303 | final float scale = activity.getResources().getDisplayMetrics().density; 304 | RelativeLayout keyboardLayout = keyboardLayouts.get(String.valueOf(tag)); 305 | 306 | 307 | RelativeLayout.LayoutParams lParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Math.round(keyboardHeight*scale)); 308 | lParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); 309 | 310 | if (keyboardLayout != null && keyboardLayout.getChildAt(0) != null) { 311 | keyboardLayout.updateViewLayout(keyboardLayout.getChildAt(0), lParams); 312 | 313 | WritableMap params = Arguments.createMap(); 314 | params.putInt("reactTag", tag); 315 | params.putInt("height", keyboardHeight); 316 | sendEvent(reactContext, "onChangeKeyboardHeight", params); 317 | } 318 | } 319 | }); 320 | } 321 | 322 | @ReactMethod 323 | public void insertText(final int tag, final String text) { 324 | mHandler.post(new Runnable() { 325 | @Override 326 | public void run() { 327 | final Activity activity = getCurrentActivity(); 328 | if (!edits.containsKey(String.valueOf(tag))) { 329 | return; 330 | } 331 | 332 | final ReactEditText edit = edits.get(String.valueOf(tag)); 333 | 334 | int start = Math.max(edit.getSelectionStart(), 0); 335 | int end = Math.max(edit.getSelectionEnd(), 0); 336 | edit.getText().replace(Math.min(start, end), Math.max(start, end), 337 | text, 0, text.length()); 338 | } 339 | }); 340 | } 341 | 342 | @ReactMethod 343 | public void backSpace(final int tag) { 344 | mHandler.post(new Runnable() { 345 | @Override 346 | public void run() { 347 | final Activity activity = getCurrentActivity(); 348 | if (!edits.containsKey(String.valueOf(tag))) { 349 | return; 350 | } 351 | 352 | final ReactEditText edit = edits.get(String.valueOf(tag)); 353 | 354 | int start = Math.max(edit.getSelectionStart(), 0); 355 | int end = Math.max(edit.getSelectionEnd(), 0); 356 | if (start != end) { 357 | edit.getText().delete(start, end); 358 | } else if (start > 0) { 359 | edit.getText().delete(start - 1, end); 360 | } 361 | } 362 | }); 363 | } 364 | 365 | @ReactMethod 366 | public void doDelete(final int tag) { 367 | mHandler.post(new Runnable() { 368 | @Override 369 | public void run() { 370 | if (!edits.containsKey(String.valueOf(tag))) { 371 | return; 372 | } 373 | 374 | final ReactEditText edit = edits.get(String.valueOf(tag)); 375 | 376 | int start = Math.max(edit.getSelectionStart(), 0); 377 | int end = Math.max(edit.getSelectionEnd(), 0); 378 | if (start != end) { 379 | edit.getText().delete(start, end); 380 | } else if (start > 0) { 381 | edit.getText().delete(start, end + 1); 382 | } 383 | } 384 | }); 385 | } 386 | 387 | @ReactMethod 388 | public void moveLeft(final int tag) { 389 | mHandler.post(new Runnable() { 390 | @Override 391 | public void run() { 392 | final Activity activity = getCurrentActivity(); 393 | if (!edits.containsKey(String.valueOf(tag))) { 394 | return; 395 | } 396 | 397 | final ReactEditText edit = edits.get(String.valueOf(tag)); 398 | 399 | int start = Math.max(edit.getSelectionStart(), 0); 400 | int end = Math.max(edit.getSelectionEnd(), 0); 401 | if (start != end) { 402 | edit.setSelection(start, start); 403 | } else { 404 | edit.setSelection(start - 1, start - 1); 405 | } 406 | } 407 | }); 408 | } 409 | 410 | @ReactMethod 411 | public void moveRight(final int tag) { 412 | mHandler.post(new Runnable() { 413 | @Override 414 | public void run() { 415 | final Activity activity = getCurrentActivity(); 416 | if (!edits.containsKey(String.valueOf(tag))) { 417 | return; 418 | } 419 | 420 | final ReactEditText edit = edits.get(String.valueOf(tag)); 421 | 422 | int start = Math.max(edit.getSelectionStart(), 0); 423 | int end = Math.max(edit.getSelectionEnd(), 0); 424 | if (start != end) { 425 | edit.setSelection(end, end); 426 | } else if (start > 0) { 427 | edit.setSelection(end + 1, end + 1); 428 | } 429 | } 430 | }); 431 | } 432 | 433 | @ReactMethod 434 | public void switchSystemKeyboard(final int tag) { 435 | mHandler.post(new Runnable() { 436 | @Override 437 | public void run() { 438 | final Activity activity = getCurrentActivity(); 439 | if (!edits.containsKey(String.valueOf(tag))) { 440 | return; 441 | } 442 | if (!keyboardLayouts.containsKey(String.valueOf(tag))) { 443 | return; 444 | } 445 | final ReactEditText edit = edits.get(String.valueOf(tag)); 446 | final RelativeLayout keyboardLayout = keyboardLayouts.get(String.valueOf(tag)); 447 | 448 | if (keyboardLayout.getParent() != null) { 449 | ((ViewGroup) keyboardLayout.getParent()).removeView(keyboardLayout); 450 | } 451 | mHandler.post(new Runnable() { 452 | 453 | @Override 454 | public void run() { 455 | ((InputMethodManager) getReactApplicationContext().getSystemService(Activity.INPUT_METHOD_SERVICE)).showSoftInput(edit, InputMethodManager.SHOW_IMPLICIT); 456 | } 457 | }); 458 | } 459 | }); 460 | } 461 | 462 | @ReactMethod 463 | public void done(final int tag) { 464 | Log.v(TAG, "done"); 465 | mHandler.post(new Runnable() { 466 | @Override 467 | public void run() { 468 | final Activity activity = getCurrentActivity(); 469 | if (!edits.containsKey(String.valueOf(tag))) { 470 | return; 471 | } 472 | 473 | final ReactEditText edit = edits.get(String.valueOf(tag)); 474 | 475 | edit.dispatchKeyEvent(new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, 476 | KeyEvent.KEYCODE_ENTER, 0)); 477 | 478 | } 479 | }); 480 | } 481 | 482 | private void sendEvent(ReactContext reactContext, 483 | String eventName, 484 | @Nullable WritableMap params) { 485 | reactContext 486 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 487 | .emit(eventName, params); 488 | } 489 | 490 | @Override 491 | public String getName() { 492 | return "RNAllmaxKeyboard"; 493 | } 494 | } --------------------------------------------------------------------------------