├── .gitignore ├── app.plugin.js ├── .eslintrc.js ├── tsconfig.json ├── README.md ├── package.json └── src └── withReactNativeKeyevent.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /app.plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./build/withReactNativeKeyevent"); -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // @generated by expo-module-scripts 2 | module.exports = require('expo-module-scripts/eslintrc.base.js'); 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo-module-scripts/tsconfig.plugin", 3 | "compilerOptions": { 4 | "outDir": "build", 5 | "rootDir": "src" 6 | }, 7 | "include": ["./src"], 8 | "exclude": ["**/__mocks__/*", "**/__tests__/*"] 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-keyevent 2 | 3 | Config plugin to auto configure react-native-keyevent on prebuild 4 | ### Add the package to your npm dependencies 5 | 6 | ``` 7 | yarn add react-native-keyevent 8 | yarn add --dev react-native-keyevent-expo-config-plugin 9 | ``` 10 | 11 | In your `app.json` or equivalent, add the following; 12 | ```js 13 | { 14 | expo: { 15 | /* ... */ 16 | plugins: ['react-native-keyevent-expo-config-plugin'], 17 | }, 18 | } 19 | ``` 20 | 21 | # Contributing 22 | 23 | Contributions are very welcome! Please refer to guidelines described in the [contributing guide]( https://github.com/expo/expo#contributing). 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-keyevent-expo-config-plugin", 3 | "version": "1.0.49", 4 | "description": "Config plugin to auto configure react-native-keyevent on prebuild", 5 | "main": "build/withReactNativeKeyevent.js", 6 | "types": "build/withReactNativeKeyevent.d.ts", 7 | "sideEffects": false, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/chronsyn/react-native-keyevent-expo-config-plugin.git" 11 | }, 12 | "scripts": { 13 | "build": "expo-module build", 14 | "clean": "expo-module clean", 15 | "lint": "expo-module lint", 16 | "test": "expo-module test", 17 | "prepare": "expo-module prepare", 18 | "prepublishOnly": "expo-module prepublishOnly", 19 | "expo-module": "expo-module" 20 | }, 21 | "files": [ 22 | "build", 23 | "app.plugin.js" 24 | ], 25 | "author": "Scott Pritchard", 26 | "devDependencies": { 27 | "expo-module-scripts": "^3.1.0" 28 | }, 29 | "peerDependencies": { 30 | "expo": "^49.0.0" 31 | }, 32 | "dependencies": { 33 | "@expo/config-plugins": "^7.2.5" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/withReactNativeKeyevent.ts: -------------------------------------------------------------------------------- 1 | import { ConfigPlugin, withAppDelegate, withMainActivity } from "@expo/config-plugins"; 2 | import { mergeContents } from "@expo/config-plugins/build/utils/generateCode"; 3 | 4 | const withIosAppDelegateImport: ConfigPlugin = (config) => { 5 | // @ts-ignore 6 | const newConfig = withAppDelegate(config, (config) => { 7 | const newSrc = ['#import ']; 8 | const newConfig = mergeContents({ 9 | tag: 'react-native-keyevent-import', 10 | src: config.modResults.contents, 11 | newSrc: newSrc.join('\n'), 12 | anchor: `#import "AppDelegate.h"`, 13 | offset: 1, 14 | comment: '//', 15 | }); 16 | return { 17 | ...config, 18 | modResults: newConfig, 19 | }; 20 | }); 21 | return newConfig; 22 | }; 23 | const withIosAppDelegateBody: ConfigPlugin = (config) => { 24 | // @ts-ignore 25 | const newConfig = withAppDelegate(config, (config) => { 26 | const newSrc = [ 27 | 'RNKeyEvent *keyEvent = nil;', 28 | ' ', 29 | '- (NSMutableArray *)keyCommands {', 30 | ' NSMutableArray *keys = [NSMutableArray new];', 31 | ' ', 32 | ' if (keyEvent == nil) {', 33 | ' keyEvent = [[RNKeyEvent alloc] init];', 34 | ' }', 35 | ' ', 36 | ' if ([keyEvent isListening]) {', 37 | ' NSArray *namesArray = [[keyEvent getKeys] componentsSeparatedByString:@","];', 38 | ' ', 39 | ' NSCharacterSet *validChars = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZ"];', 40 | ' ', 41 | ' for (NSString* names in namesArray) {', 42 | ' NSRange range = [names rangeOfCharacterFromSet:validChars];', 43 | ' ', 44 | ' if (NSNotFound != range.location) {', 45 | ' [keys addObject: [UIKeyCommand keyCommandWithInput:names modifierFlags:UIKeyModifierShift action:@selector(keyInput:)]];', 46 | ' } else {', 47 | ' [keys addObject: [UIKeyCommand keyCommandWithInput:names modifierFlags:0 action:@selector(keyInput:)]];', 48 | ' }', 49 | ' }', 50 | ' }', 51 | ' ', 52 | ' return keys;', 53 | '}', 54 | '', 55 | '- (void)keyInput:(UIKeyCommand *)sender {', 56 | ' NSString *selected = sender.input;', 57 | ' [keyEvent sendKeyEvent:selected];', 58 | '}', 59 | ]; 60 | const newConfig = mergeContents({ 61 | tag: 'react-native-keyevent-body', 62 | src: config.modResults.contents, 63 | newSrc: newSrc.join('\n'), 64 | anchor: `@implementation AppDelegate`, // /#import "AppDelegate\.h"/g, 65 | offset: 1, 66 | comment: '//', 67 | }); 68 | return { 69 | ...config, 70 | modResults: newConfig, 71 | }; 72 | }); 73 | return newConfig; 74 | }; 75 | 76 | const withAndroidMainActivityImport: ConfigPlugin = (config) => { 77 | // @ts-ignore 78 | const newConfig = withMainActivity(config, (config) => { 79 | const newSrc = [ 80 | 'import android.view.KeyEvent;', 81 | 'import com.github.kevinejohn.keyevent.KeyEventModule;', 82 | ]; 83 | const newConfig = mergeContents({ 84 | tag: 'react-native-keyevent-import', 85 | src: config.modResults.contents, 86 | newSrc: newSrc.join('\n'), 87 | anchor: `;`, 88 | offset: 1, 89 | comment: '//', 90 | }); 91 | return { 92 | ...config, 93 | modResults: newConfig, 94 | }; 95 | }); 96 | return newConfig; 97 | }; 98 | const withAndroidMainActivityBody: ConfigPlugin = (config) => { 99 | // @ts-ignore 100 | const newConfig = withMainActivity(config, (config) => { 101 | const newSrc = [ 102 | '@Override', 103 | 'public boolean onKeyDown(int keyCode, KeyEvent event) {', 104 | '', 105 | ' // // Uncomment this is key events should only trigger once when key is held down', 106 | ' // if (event.getRepeatCount() == 0) {', 107 | ' // KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);', 108 | ' // }', 109 | '', 110 | ' // // This will trigger the key repeat if the key is held down', 111 | ' // // Comment this out if uncommenting the above', 112 | ' KeyEventModule.getInstance().onKeyDownEvent(keyCode, event);', 113 | '', 114 | ' // // Uncomment this if you want the default keyboard behavior', 115 | ' // return super.onKeyDown(keyCode, event);', 116 | '', 117 | ' // // The default keyboard behaviour wll be overridden', 118 | ' // // This is similar to what e.preventDefault() does in a browser', 119 | ' // // comment this if uncommenting the above', 120 | ' super.onKeyDown(keyCode, event);', 121 | ' return true;', 122 | '}', 123 | '', 124 | '@Override', 125 | 'public boolean onKeyUp(int keyCode, KeyEvent event) {', 126 | ' KeyEventModule.getInstance().onKeyUpEvent(keyCode, event);', 127 | '', 128 | ' // // Uncomment this if you want the default keyboard behavior', 129 | ' // return super.onKeyUp(keyCode, event);', 130 | '', 131 | ' // // The default keyboard behaviour wll be overridden', 132 | ' // // This is similar to what e.preventDefault() does in a browser', 133 | ' // // comment this if uncommenting the above', 134 | ' super.onKeyUp(keyCode, event);', 135 | ' return true;', 136 | '}', 137 | '', 138 | '@Override', 139 | 'public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {', 140 | ' KeyEventModule.getInstance().onKeyMultipleEvent(keyCode, repeatCount, event);', 141 | ' return super.onKeyMultiple(keyCode, repeatCount, event);', 142 | '}', 143 | ]; 144 | const newConfig = mergeContents({ 145 | tag: 'react-native-keyevent-body', 146 | src: config.modResults.contents, 147 | newSrc: newSrc.join('\n'), 148 | anchor: `public class MainActivity extends ReactActivity {`, 149 | offset: 1, 150 | comment: '//', 151 | }); 152 | return { 153 | ...config, 154 | modResults: newConfig, 155 | }; 156 | }); 157 | return newConfig; 158 | }; 159 | 160 | const initPlugin: ConfigPlugin = (config) => { 161 | config = withIosAppDelegateImport(config); 162 | config = withIosAppDelegateBody(config); 163 | config = withAndroidMainActivityImport(config); 164 | config = withAndroidMainActivityBody(config); 165 | return config; 166 | }; 167 | 168 | export default initPlugin; --------------------------------------------------------------------------------