CustomKeyboardHandler Module

Use the CustomKeyboardHandler module to support your own custom keyboard implementation in your application. This module acts as a bridge between the RN/JS layer and the native layer. When enabled, it blocks the native device’s software keyboard, if one is available on the device, and instead surfaces the keyboard requests to the JavaScript (JS) layer via CustomKeyboardHandler, to be handled by your custom keyboard implementation. It also allows text input to be passed back to the current target keyboard input receiver.

This allows your application to specify its own keyboard implementation for devices that don’t have their own keyboard implementation, as well as allowing you to replace any existing platform keyboard, if desired.

You can enable and disable your custom keyboard as needed. Toggling between the native software keyboard and your own, as needed.

Methods


CustomKeyboardEvent

  • Description: List of valid custom keyboard event names.
  • Return Type: Enum
  • Parameters/Events: SHOW_CUSTOM_KEYBOARD_EVENT: string

    Emitted when a view/input receiver is requesting the keyboard to be shown and expecting text. The parameters include:

    • string receiverText - The text currently within the receiver requesting the keyboard.
    • number receiverMaxCharacterCount - Max character count of the receiver requesting the keyboard
    • number cursorPositionInText - The current position of the cursor in the text of the receiver.
    • object receiverScreenRect - Represents a RECT structure of the pos and dimensions of the receiver.
  • Parameters/Events: HIDE_CUSTOM_KEYBOARD_EVENT: string

    Emitted when the keyboard is being requested to be closed.


enableCustomKeyboard()

  • Description: Inform CustomKeyboardHandler whether the application is using custom keyboard or not. This must be called for custom keyboard events to be surfaced to this handler. Otherwise, the platform specific keyboard, if available, will be used.
  • Method Usage Example: CustomKeyboardHandlerModule.enableCustomKeyboard(enableCustomKeyboard);
  • Parameters: enableCustomKeyboard : boolean

addEventListener()

  • Description: Adds an event listener.
  • Method Usage Example: addEventListener(type: CustomKeyboardEventName, handler: Function)
  • Parameters/Events: type: CustomKeyboardEventName

    The name of the custom keyboard event being listened to.

  • Parameters/Events: handler: Function

    The function that is called to handle the event.


removeEventListener()

  • Description: Removes an event listener.
  • Method Usage Example: removeEventListener(type: CustomKeyboardEventName, handler: Function)
  • Parameters/Events: type: CustomKeyboardEventName

    The name of the custom keyboard event being listened to.

  • Parameters/Events: handler: Function

    The function that is called to handle the event.


setTextToCurrentReceiver()

  • Description: Notify CustomKeyboardHandler that the custom keyboard has compiled text to apply to the currently targeted input receiver. Note that this text will overwrite any existing text currently in the input receiver.
  • Method Usage Example: setTextToCurrentReceiver(inputText: string)
  • Parameters/Events: inputText: string

    The text string to apply to the current input receiver connected to the custom keyboard.


closeCustomKeyboard()

  • Description: Notify CustomKeyboardHandler that the custom keyboard should be closed. This will allow the native layer to perform any required operations before calling a HIDE_CUSTOM_KEYBOARD_EVENT to close the keyboard.
  • Method Usage Example: closeCustomKeyboard()

Example

The following is a simple example showing a very basic integration to set up a custom keyboard implementation by tying into the events and methods provided by CustomKeyboardHandler to launch your keyboard when needed and to set the keyboard’s generated text to the target input receiver:

import React, { Component } from 'react';
import { 
  AppRegistry,
  StyleSheet,
  Text,
  TextInput,
  View,
} from 'react-native'
import { 
  ButtonRef, 
  Composition,
  CustomKeyboardHandler,
  FocusManager,
  TextInputRef,
  TextRef,
  ViewRef 
} from '@youi/react-native-youi'

 
const buttons = [
  {
    name: 'OneKey',
    char: '1',
  },
  {
    name: 'TwoKey',
    char: '2',
  },
  {
     name: 'ThreeKey',
     char: '3',
  },
  {
     name: 'AKey',
     char: 'A',
  },
  {
    name: 'BKey',
    char: 'B',
  },
  {
     name: 'CKey',
     char: 'C',
  },
  {
     name: 'DKey',
     char: 'D',
  },
  {
     name: 'EKey',
     char: 'E',
  },
  {
     name: 'FKey',
     char: 'F',
  },
];

class MyKeyboard extends Component {
  state = {
    value: this.props.value,
    receiverText: this.props.receiverText,
    receiverMaxCharacterCount: this.props.receiverMaxCharacterCount,
    cursorPositionInText: this.props.cursorPositionInText,
    receiverPosX: this.props.receiverPosX,
    receiverPosY: this.props.receiverPosY,
    receiverWidth: this.props.receiverWidth,
    receiverHeight: this.props.receiverHeight,
  };

  componentDidMount() {
    setTimeout(() => {
      FocusManager.setFocusable(this.root, true);
      FocusManager.enableFocus(this.root, true);
      FocusManager.setFocusRoot(this.root, true);
      FocusManager.focus(this.AKey);
    });
  }

  render() {
    const charButtons = buttons.map((button) => {
      return (
        <ButtonRef
          name={button.name}
          onClick={() => {
            this.setState({
              value: this.state.value + button.char,
            });
          }}
        />
      );
    });
    return (
      <View style={styles.keyboard}>
        <View style={styles.eventLogsContainer}>
          <Text style={styles.eventLogText}>{"receiverText: \"" + this.state.receiverText + "\""}</Text>
          <Text style={styles.eventLogText}>{"receiverMaxCharLimit: " + this.state.receiverMaxCharacterCount}</Text>               
          <Text style={styles.eventLogText}>{"receiverCursorTextPos: " + this.state.cursorPositionInText}</Text>
          <Text style={styles.eventLogText}>{"receiverViewPos: (" + this.state.receiverPosX + "," + this.state.receiverPosY + ")"}</Text>
          <Text style={styles.eventLogText}>{"receiverViewDimensions: (" + this.state.receiverWidth + "," + this.state.receiverHeight + ")"}</Text>
        </View>
        <Composition source="Keyboard_MainComp">
          <TextRef name="PLACEHOLDER" text={this.state.value} />
          {charButtons}
          <ButtonRef
            name="BackspaceKey"
            onClick={() => {
              if (this.state.value.length > 0) {
                this.setState({
                  value: this.state.value.substr(0, this.state.value.length -1),
                });
              }
            }}
          />
          <ButtonRef
            name="ClearKey"
            onClick={() => {
              this.setState({
                value: '',
              });
            }}
          />
          <ButtonRef
            name="DoneKey"
            onClick={() => {
              console.log("Done! Send '" + this.state.value + "' to the Keyboard manager.");
              this.props.onDone(this.state.value);
            }}
          />
          <ButtonRef
            name="CancelKey"
            onClick={() => {
              console.log("Cancel! Tell the Keyboard manager to close us.");
              this.setState({
                value: ''
              });
              this.props.onCancel();
            }}
          />         
        </Composition>
      </View>
    );
  }
}

export default class TestCustomKeyboard extends Component {
  constructor(props){
    super(props);

    this.state = {
      keyboardVisible: false,
      inputText: '',
      text: 'Useless Placeholder. isFocused should print true.',
      text2: 'This text should never change.', 
      text3: '',
      text4: 'onKeyPress tester.',
      text5: 'This text field will not be editable. You will not be able to focus it or enter text.',
      text6: '',
      currentReceiverData: {
        receiverText:'',
        receiverMaxCharacterCount: 0,
        cursorPositionInText: 0,
        receiverScreenRect : {
          x: 0,
          y: 0,
          width: 0,
          height: 0
        }
      },
    }
 
    CustomKeyboardHandler.enableCustomKeyboard(true);
    CustomKeyboardHandler.addEventListener('SHOW_CUSTOM_KEYBOARD_EVENT', this.onShowCustomKeyboard);
    CustomKeyboardHandler.addEventListener('HIDE_CUSTOM_KEYBOARD_EVENT', this.onHideCustomKeyboard);
  }
  
  onShowCustomKeyboard = (args) => {
    this.setState({keyboardVisible: true,
                   currentReceiverData: args});
  }
  
  onHideCustomKeyboard = (args) => {
    this.setState({keyboardVisible: false});
  }
  
  handleKeyboardDone = (enteredText) => {
    CustomKeyboardHandler.setTextToCurrentReceiver(enteredText);
    this.setState({
      keyboardVisible: false,
      inputText: enteredText,
    });
    CustomKeyboardHandler.closeCustomKeyboard();
  }
  
  render() {
    let keyboard = this.state.keyboardVisible ? <MyKeyboard
      onDone={this.handleKeyboardDone}
      onCancel={() => {this.setState({keyboardVisible: false});}}
      value={this.state.currentReceiverData.receiverText}
      receiverText = {this.state.currentReceiverData.receiverText}
      receiverMaxCharacterCount = {this.state.currentReceiverData.receiverMaxCharacterCount}
      cursorPositionInText = {this.state.currentReceiverData.cursorPositionInText}
      receiverPosX = {this.state.currentReceiverData.receiverScreenRect.x}
      receiverPosY = {this.state.currentReceiverData.receiverScreenRect.y}
      receiverWidth = {this.state.currentReceiverData.receiverScreenRect.width}
      receiverHeight = {this.state.currentReceiverData.receiverScreenRect.height}
    /> : <View />;
  
    return (
      <View style={styles.mainContainer}>
        <View style={{backgroundColor: 'gray'}}>
          <View style={{backgroundColor: 'transparent'}}>
            <TextInput ref={(a) => {this.textinput = a;}}
              style={{height: 40, borderColor: 'gray', borderWidth: 1}}
              onChangeText={(t) => {
                this.setState({text: t});
                console.log("isFocused? " + this.textinput.isFocused());
              }}
              onChange={() => console.log("OnChange called.")}
              onFocus={() => {
                console.log("onFocus called.")
                CustomKeyboardHandler.setTextReceivedHandler((enteredText) => {
                  this.setState({text: enteredText});
                });
              }}
              onEndEditing={() => console.log("onEndEditing called.")}
              onSubmitEditing={() => console.log("onSubmitEditing called.")}
              value={this.state.text}
            />
            <TextInput
              style={{height: 40, borderColor: 'gray', borderWidth: 1}}
              value={this.state.text2}
            />
            <TextInput
              style={{height: 40, borderColor: 'gray', borderWidth: 1}}
              onChangeText={(t) => {
                this.setState({text3: t})
              }}
              onFocus={() => {
                CustomKeyboardHandler.setTextReceivedHandler((enteredText) => {
                  this.setState({text3: enteredText});
                });
              }}
              value={this.state.text3}
              placeholder={'This is placeholder text.'}
              placeholderTextColor={'blue'}
            />
            <TextInput
              style={{height: 40, color: 'red', backgroundColor: 'yellow'}}
              value={'This text should be red and the background should be yellow.'}
            />
            <TextInput
              style={{height: 40, fontSize: 20}}
              value={'This text should be size 20.'}
            />
            <TextInput
              style={{height: 40, fontFamily: 'yi_Futura-Regular.ttf'}}
              value={'This text should display Futura.'}
            />
            <TextInput
              style={{height: 40, fontSize: 20}}
              value={this.state.text4}
              onKeyPress={(k) =>{
                console.log("onKeyPress called with key [" + k.nativeEvent.key + "]");
              }}
              onChangeText={(t) => {
                this.setState({text4: t})
              }}
              onFocus={() => {
                CustomKeyboardHandler.setTextReceivedHandler((enteredText) => {
                  this.setState({text4: enteredText});
                });
              }}
            />
            <TextInput
              style={{height: 40, fontSize: 20}}
              defaultValue={'The text here is the default entry. isFocused should print false.'}
              onChangeText={(t) => {
                console.log("isFocused? " + this.textinput.isFocused());
              }}
            />
            <TextInput
              style={{height: 40, fontSize: 20}}
              value={'This text field will not have a caret.'}
              caretHidden={true}
            />
            <TextInput
              style={{height: 40, fontSize: 20}}
              value={this.state.text5}
              editable={false}
              onChangeText={(t) => {
                this.setState({text5: t})
              }}
              onFocus={() => {
                CustomKeyboardHandler.setTextReceivedHandler((enteredText) => {
                  this.setState({text5: enteredText});
                });
              }}
            />
            <TextInput
              style={{height: 40, borderColor: 'gray', borderWidth: 1}}
              onChangeText={(t) => {
                this.setState({text6: t})
              }}
              onFocus={() => {
                CustomKeyboardHandler.setTextReceivedHandler((enteredText) => {
                  this.setState({text6: enteredText});
                });
              }}
              value={this.state.text6}
              placeholder={'This is a password field'}
              placeholderTextColor={'blue'}
              secureTextEntry={true}
            />
            <TextInput
              style={{height: 40, fontFamily: 'Charter'}}
              value={'This text should display Charter Bold.'}
            />
            <TextInput
              style={{height: 40, fontSize: 20}}
              value={'clearTextOnFocus - This text field will clear on focus. Text will reappear after typing.'}
              clearTextOnFocus={true}
            />
            <TextInput
              ref={(a) => {this.textinput2 = a;}}
              style={{height: 40, fontSize: 20}}
              value={'clear() - This text field will clear on focus. Text will reappear after typing.'}
              onFocus={() => 
                this.textinput2.clear()
              }
            />
          </View>
        </View>          
      {keyboard}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  mainContainer: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'flex-start',
    backgroundColor: '#d0d0d0'
  },
  container: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#d0d0d0',
  }, 
  keyboard: {
    backgroundColor: 'black',
    position: 'absolute',
    top: 0,
    left: 0,
  },
  eventLogText: {
    fontSize: 20,
    textAlign: 'center',
    margin: 0,
    color: '#000',
  },
  eventLogsContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#d0d0d0'
  },
});

AppRegistry.registerComponent('TestCaseApp', () => TestCustomKeyboard);