Shoot from the volume keys, while the camera is up
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'expo-module-gradle-plugin'
|
||||
}
|
||||
|
||||
group = 'com.locphamtran.recipescamera'
|
||||
version = '0.1.0'
|
||||
|
||||
android {
|
||||
namespace "com.locphamtran.recipescamera.volume"
|
||||
defaultConfig {
|
||||
versionCode 1
|
||||
versionName "0.1.0"
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.locphamtran.recipescamera.volume
|
||||
|
||||
import android.view.KeyEvent
|
||||
import expo.modules.kotlin.modules.Module
|
||||
import expo.modules.kotlin.modules.ModuleDefinition
|
||||
|
||||
/**
|
||||
* Volume keys as a shutter release.
|
||||
*
|
||||
* Android exposes no key stream to JS, and the volume keys never reach a view -
|
||||
* the window (PhoneWindow.OnKeyListener) turns them into a stream-volume change
|
||||
* before any view sees them. The one place that runs first is the activity's
|
||||
* dispatchKeyEvent, so MainActivity hands every key here and only passes on
|
||||
* what comes back false.
|
||||
*
|
||||
* Enabled from JS only while the camera screen is up: with the flag off the keys
|
||||
* go straight back to the window, so volume still works in the library.
|
||||
*/
|
||||
class VolumeShutterModule : Module() {
|
||||
override fun definition() = ModuleDefinition {
|
||||
Name("RecipesCamVolumeShutter")
|
||||
|
||||
Events("onShutter")
|
||||
|
||||
// The activity is the one dispatching, but it does not own the module -
|
||||
// publish the single live instance so it can be reached from there.
|
||||
OnCreate { instance = this@VolumeShutterModule }
|
||||
OnDestroy { if (instance === this@VolumeShutterModule) instance = null }
|
||||
|
||||
Function("setEnabled") { enabled: Boolean -> VolumeShutterModule.enabled = enabled }
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Volatile private var instance: VolumeShutterModule? = null
|
||||
|
||||
@Volatile private var enabled = false
|
||||
|
||||
/**
|
||||
* Every key event of the activity goes through here first. Returns true when
|
||||
* the key is ours and has been consumed - that consumption is what keeps the
|
||||
* press from also changing the media volume, the way a stock camera app
|
||||
* behaves.
|
||||
*
|
||||
* Only ACTION_DOWN with repeatCount 0 fires: the UP and the auto-repeat of a
|
||||
* held button are still swallowed (so holding it does not leak a volume
|
||||
* change on release) but produce no second frame.
|
||||
*/
|
||||
fun onKeyEvent(event: KeyEvent): Boolean {
|
||||
if (!enabled) return false
|
||||
if (event.keyCode != KeyEvent.KEYCODE_VOLUME_UP && event.keyCode != KeyEvent.KEYCODE_VOLUME_DOWN) {
|
||||
return false
|
||||
}
|
||||
if (event.action == KeyEvent.ACTION_DOWN && event.repeatCount == 0) {
|
||||
instance?.sendEvent("onShutter")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"platforms": ["android"],
|
||||
"android": {
|
||||
"modules": [
|
||||
"com.locphamtran.recipescamera.volume.VolumeShutterModule"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { requireNativeModule } from 'expo-modules-core';
|
||||
|
||||
export interface VolumeShutterModule {
|
||||
/**
|
||||
* Claims the volume keys while true; while false every key is handed back to
|
||||
* the window, so they stay volume keys everywhere but the camera screen.
|
||||
*/
|
||||
setEnabled(enabled: boolean): void;
|
||||
/** Fired once per press (a held key does not auto-repeat). */
|
||||
addListener(event: 'onShutter', listener: () => void): { remove(): void };
|
||||
}
|
||||
|
||||
export default requireNativeModule<VolumeShutterModule>('RecipesCamVolumeShutter');
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "recipescam-volume",
|
||||
"version": "0.1.0",
|
||||
"description": "Volume keys as a shutter release for Recipescam.",
|
||||
"main": "index.ts",
|
||||
"license": "MIT",
|
||||
"private": true
|
||||
}
|
||||
Reference in New Issue
Block a user