diff --git a/packages/react-native-global-keyevent/.eslintrc.js b/packages/react-native-global-keyevent/.eslintrc.js new file mode 100644 index 0000000..2720197 --- /dev/null +++ b/packages/react-native-global-keyevent/.eslintrc.js @@ -0,0 +1,2 @@ +// @generated by expo-module-scripts +module.exports = require('expo-module-scripts/eslintrc.base.js'); diff --git a/packages/react-native-global-keyevent/README.md b/packages/react-native-global-keyevent/README.md new file mode 100644 index 0000000..1bce843 --- /dev/null +++ b/packages/react-native-global-keyevent/README.md @@ -0,0 +1,47 @@ +# @config-plugins/react-native-global-keyevent + +Expo Config Plugin to auto-configure [`react-native-global-keyevent`](https://www.npmjs.com/package/react-native-global-keyevent) when the native code is generated (`npx expo prebuild`). + +## Versioning + +| `expo` | `react-native-global-keyevent` | `@config-plugins/react-native-global-keyevent` | +|--------|--------------------------------|------------------------------------------------| +| 51.0.0 | 0.1.4 | 0.1.4 | + +## Expo installation + +> This package cannot be used in the "Expo Go" app because [it requires custom native code](https://docs.expo.io/workflow/customizing/). + +First install the package with yarn, npm, or [`npx expo install`](https://docs.expo.io/workflow/expo-cli/#expo-install). + +```sh +npx expo install react-native-global-keyevent @config-plugins/react-native-global-keyevent +``` + +After installing this npm package, add the [config plugin](https://docs.expo.io/guides/config-plugins/) to the [`plugins`](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`: + +```json +{ + "expo": { + "plugins": ["@config-plugins/react-native-global-keyevent"] + } +} +``` + +Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.io/workflow/customizing/) guide. + +## API + +The plugin does not provide any props for extra customization. + +#### Example + +```json +{ + "expo": { + "plugins": [ + "@config-plugins/react-native-global-keyevent" + ] + } +} +``` diff --git a/packages/react-native-global-keyevent/app.plugin.js b/packages/react-native-global-keyevent/app.plugin.js new file mode 100644 index 0000000..e0abfdf --- /dev/null +++ b/packages/react-native-global-keyevent/app.plugin.js @@ -0,0 +1 @@ +module.exports = require("./build/withReactNativeGlobalKeyevent"); \ No newline at end of file diff --git a/packages/react-native-global-keyevent/package.json b/packages/react-native-global-keyevent/package.json new file mode 100644 index 0000000..aeb8113 --- /dev/null +++ b/packages/react-native-global-keyevent/package.json @@ -0,0 +1,37 @@ +{ + "name": "@config-plugins/react-native-global-keyevent", + "version": "0.1.4", + "description": "Config plugin for react-native-global-keyevent package", + "main": "build/withReactNativeGlobalKeyevent.js", + "types": "build/withReactNativeGlobalKeyevent.d.ts", + "sideEffects": false, + "homepage": "https://github.com/mybigday/react-native-global-keyevent", + "repository": { + "type": "git", + "url": "https://github.com/expo/config-plugins.git", + "directory": "packages/react-native-global-keyevent" + }, + "scripts": { + "build": "expo-module build", + "clean": "expo-module clean", + "lint": "expo-module lint", + "test": "expo-module test", + "prepare": "expo-module prepare", + "prepublishOnly": "expo-module prepublishOnly", + "expo-module": "expo-module" + }, + "keywords": [ + "react", + "expo", + "config-plugins", + "prebuild", + "react-native-global-keyevent", + "expo-51" + ], + "peerDependencies": { + "expo": "^51" + }, + "devDependencies": { + "expo-module-scripts": "^3.5.1" + } +} diff --git a/packages/react-native-global-keyevent/src/withReactNativeGlobalKeyevent.ts b/packages/react-native-global-keyevent/src/withReactNativeGlobalKeyevent.ts new file mode 100644 index 0000000..d014ea8 --- /dev/null +++ b/packages/react-native-global-keyevent/src/withReactNativeGlobalKeyevent.ts @@ -0,0 +1,112 @@ +import { + ConfigPlugin, + createRunOncePlugin, + withMainActivity, +} from "@expo/config-plugins"; +import { addImports } from "@expo/config-plugins/build/android/codeMod"; +import { mergeContents } from "@expo/config-plugins/build/utils/generateCode"; + +const MAIN_ACTIVITY_LANGUAGES: Record< + string, + { code: string; anchor: RegExp } +> = { + java: { + code: ` + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + GlobalKeyEventModule instance = GlobalKeyEventModule.getInstance(); + if (instance != null) instance.onKeyDownEvent(keyCode, event); + return super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + GlobalKeyEventModule instance = GlobalKeyEventModule.getInstance(); + if (instance != null) instance.onKeyUpEvent(keyCode, event); + return super.onKeyUp(keyCode, event); + } +`, + anchor: /return "main";\n\s*};/, + }, + kt: { + code: ` + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + val instance = GlobalKeyEventModule.getInstance(); + if (instance != null) instance.onKeyDownEvent(keyCode, event); + return super.onKeyDown(keyCode, event); + } + + override fun onKeyUp(keyCode: Int , event: KeyEvent): Boolean { + val instance = GlobalKeyEventModule.getInstance(); + if (instance != null) instance.onKeyUpEvent(keyCode, event); + return super.onKeyUp(keyCode, event); + } +`, + anchor: /override\sfun\sgetMainComponentName\(\).*/, + }, +}; + +const addKeyBindings = (src: string, language: string) => { + const mainActivity = MAIN_ACTIVITY_LANGUAGES[language]; + if (!mainActivity) { + throw new Error( + `react-native-global-keyevent config plugin does not support MainActivity.${language} yet`, + ); + } + + const newSrc = []; + newSrc.push(` ${mainActivity.code}`); + + return mergeContents({ + tag: "react-native-global-keyevent-onKey", + src, + newSrc: newSrc.join("\n"), + anchor: mainActivity.anchor, + offset: 1, + comment: "//", + }); +}; + +const withAndroidMainActivityKeyboardEvents: ConfigPlugin = (config) => { + return withMainActivity(config, async (config) => { + const src = addImports( + config.modResults.contents, + ["android.view.KeyEvent", "com.globalkeyevent.GlobalKeyEventModule"], + config.modResults.language === "java", + ); + + config.modResults.contents = addKeyBindings( + src, + config.modResults.language, + ).contents; + + return config; + }); +}; + +/** + * Apply react-native-global-keyevent configuration for Expo SDK 51 projects. + */ +const withReactNativeGlobalKeyevent: ConfigPlugin = (config) => { + config = withAndroidMainActivityKeyboardEvents(config); + + // Return the modified config. + return config; +}; + +const pkg = { + // Prevent this plugin from being run more than once. + // This pattern enables users to safely migrate off of this + // out-of-tree `@config-plugins/react-native-global-keyevent` to a future + // upstream plugin in `react-native-global-keyevent` + name: "react-native-global-keyevent", + // Indicates that this plugin is dangerously linked to a module, + // and might not work with the latest version of that module. + version: "UNVERSIONED", +}; + +export default createRunOncePlugin( + withReactNativeGlobalKeyevent, + pkg.name, + pkg.version, +); diff --git a/packages/react-native-global-keyevent/tsconfig.json b/packages/react-native-global-keyevent/tsconfig.json new file mode 100644 index 0000000..901571e --- /dev/null +++ b/packages/react-native-global-keyevent/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "expo-module-scripts/tsconfig.plugin", + "compilerOptions": { + "outDir": "./build" + }, + "include": ["./src"], + "exclude": ["**/__mocks__/*", "**/__tests__/*"] +}