Skip to content

Commit

Permalink
Mobile chat: Pressing enter on a hardware keyboard should send chat m…
Browse files Browse the repository at this point in the history
…essage, shift-enter should add newline (keybase#23430)

* Mobile: Pressing enter on a hardware keyboard should send chat message, shift-enter should add newline

* check if a hardware keyboard is connected before dispatching <enter> keydown events

* use isOpen to determine whether we're using the virtual keyboard or not

Co-authored-by: John Zila <[email protected]>
  • Loading branch information
cjb and jzila authored Apr 3, 2020
1 parent 8a82fbf commit c23b405
Show file tree
Hide file tree
Showing 14 changed files with 7,972 additions and 7,510 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

import android.view.KeyEvent;
import com.github.emilioicai.hwkeyboardevent.HWKeyboardEventModule;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -69,6 +72,7 @@
public class MainActivity extends ReactActivity {
private static final String TAG = MainActivity.class.getName();
private PermissionListener listener;
private boolean isUsingHardwareKeyboard = false;
static boolean createdReact = false;

@Override
Expand Down Expand Up @@ -168,6 +172,8 @@ public void run() {
}, 300);

KeybasePushNotificationListenerService.createNotificationChannel(this);

updateIsUsingHardwareKeyboard();
}

@Override
Expand Down Expand Up @@ -428,8 +434,12 @@ public void onConfigurationChanged(Configuration newConfig) {

try {
setBackgroundColor(GuiConfig.getInstance(getFilesDir()).getDarkMode());
} catch (Exception e) {
} catch (Exception e) {}

if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
isUsingHardwareKeyboard = true;
} else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
isUsingHardwareKeyboard = false;
}
}

Expand All @@ -449,4 +459,26 @@ public void setBackgroundColor(DarkModePreference pref) {
mainWindow.setBackgroundDrawableResource(bgColor);
});
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (isUsingHardwareKeyboard && event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
// Detects user pressing the enter key
if (event.getAction() == KeyEvent.ACTION_DOWN && !event.isShiftPressed()) {
// Enter is pressed
HWKeyboardEventModule.getInstance().keyPressed("enter");
return true;
}
if (event.getAction() == KeyEvent.ACTION_DOWN && event.isShiftPressed()) {
// Shift-Enter is pressed
HWKeyboardEventModule.getInstance().keyPressed("shift-enter");
return true;
}
}
return super.dispatchKeyEvent(event);
}

private void updateIsUsingHardwareKeyboard() {
isUsingHardwareKeyboard = getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {parseUri, launchCameraAsync, launchImageLibraryAsync} from '../../../../
import {BotCommandUpdateStatus} from './shared'
import {formatDurationShort} from '../../../../util/timestamp'
import {indefiniteArticle} from '../../../../util/string'
import {isOpen} from '../../../../util/keyboard'
import AudioRecorder from '../../../audio/audio-recorder.native'
import {
AnimatedBox2,
Expand All @@ -25,6 +26,7 @@ import {
runToggle,
runRotateToggle,
} from './platform-input-animation.native'
import HWKeyboardEvent from 'react-native-hw-keyboard-event'

type menuType = 'exploding' | 'filepickerpopup' | 'moremenu'

Expand Down Expand Up @@ -97,6 +99,26 @@ class _PlatformInput extends React.PureComponent<PlatformInputPropsInternal, Sta
}
}

// Enter should send a message like on desktop, when a hardware keyboard's attached.
private handleHardwareEnterPress = (hwKeyEvent: {pressedKey: string}) => {
switch (hwKeyEvent.pressedKey) {
case 'enter':
!isOpen() ? this.onSubmit() : this.insertText('\n')
break
case 'shift-enter':
this.insertText('\n')
}
}

componentDidMount() {
// @ts-ignore supplied type seems incorrect, has the onHWKeyPressed param as an object
HWKeyboardEvent.onHWKeyPressed(this.handleHardwareEnterPress)
}

componentWillUnmount() {
HWKeyboardEvent.removeOnHWKeyPressed()
}

private getText = () => {
return this.lastText || ''
}
Expand Down
25 changes: 25 additions & 0 deletions shared/ios/Keybase/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#import <UMCore/UMModuleRegistry.h>
#import <UMReactNativeAdapter/UMNativeModulesProxy.h>
#import <UMReactNativeAdapter/UMModuleRegistryAdapter.h>
#import <RNHWKeyboardEvent.h>

@interface AppDelegate ()
@property UIBackgroundTaskIdentifier backgroundTask;
Expand Down Expand Up @@ -298,4 +299,28 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
return extraModules;
}

RNHWKeyboardEvent *hwKeyEvent = nil;
- (NSMutableArray<UIKeyCommand *> *)keyCommands {
NSMutableArray *keys = [NSMutableArray new];
if (hwKeyEvent == nil) {
hwKeyEvent = [[RNHWKeyboardEvent alloc] init];
}
if ([hwKeyEvent isListening]) {
[keys addObject: [UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:0 action:@selector(sendEnter:)]];
[keys addObject: [UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:UIKeyModifierShift action:@selector(sendShiftEnter:)]];
}
return keys;
}

- (void)sendEnter:(UIKeyCommand *)sender {
// Detects user pressing the enter key
NSString *selected = sender.input;
[hwKeyEvent sendHWKeyEvent:@"enter"];
}
- (void)sendShiftEnter:(UIKeyCommand *)sender {
// Detects user pressing the shift-enter combination
NSString *selected = sender.input;
[hwKeyEvent sendHWKeyEvent:@"shift-enter"];
}

@end
8 changes: 7 additions & 1 deletion shared/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ PODS:
- React
- react-native-geolocation (2.0.2):
- React
- react-native-hw-keyboard-event (0.0.4):
- React
- react-native-netinfo (5.6.2):
- React
- react-native-safe-area-context (0.7.3):
Expand Down Expand Up @@ -349,6 +351,7 @@ DEPENDENCIES:
- "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)"
- react-native-contacts (from `../node_modules/react-native-contacts`)
- "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
- react-native-hw-keyboard-event (from `../node_modules/react-native-hw-keyboard-event`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-video (from `../node_modules/react-native-video`)
Expand Down Expand Up @@ -457,6 +460,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-contacts"
react-native-geolocation:
:path: "../node_modules/@react-native-community/geolocation"
react-native-hw-keyboard-event:
:path: "../node_modules/react-native-hw-keyboard-event"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-safe-area-context:
Expand Down Expand Up @@ -569,6 +574,7 @@ SPEC CHECKSUMS:
react-native-cameraroll: 3e5e34d36d93548ae7770ee8ab7b2ae9e778f571
react-native-contacts: be6cde1ffc9c0196fbb57d987b9d40f12b85989c
react-native-geolocation: c956aeb136625c23e0dce0467664af2c437888c9
react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53
react-native-netinfo: 73303369946c2487c600418961bfdc87748b832f
react-native-safe-area-context: e200d4433aba6b7e60b52da5f37af11f7a0b0392
react-native-video: d01ed7ff1e38fa7dcc6c15c94cf505e661b7bfd0
Expand Down Expand Up @@ -608,4 +614,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 843dc6df133334007d13b5c34a0fd83194e7fa0e

COCOAPODS: 1.8.4
COCOAPODS: 1.9.1
8 changes: 7 additions & 1 deletion shared/ios/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c23b405

Please sign in to comment.