microsoft / react-native-macos

A framework for building native macOS apps with React.
https://microsoft.github.io/react-native-windows/
MIT License
3.39k stars 130 forks source link

Keyboard shortcuts (copy, paste, select) not working in TextInput #2075

Closed AdrianFahrbach closed 5 months ago

AdrianFahrbach commented 5 months ago

Environment

react-native -v: v0.72.10
npm ls react-native-macos: v0.72.16
node -v: v18.17.1
npm -v: v9.6.7
yarn --version: not using yarn
xcodebuild -version: Xcode 15.2 Build version 15C500b

Steps to reproduce the bug

  1. Create a <TextInput> component
  2. Focus the input and type something
  3. Try to select the text with cmd + a. It does not work.
  4. Select the text and try to copy it with cmd + c. It does not work.
  5. Save a different text from somewhere else to your clipboard and try to paste it inside the input. It does not work.

Expected Behavior

The regular keyboard shortcuts of macOS should work in the input field.

Actual Behavior

I only hear an error sound, besides that nothing happens. See the video below:

https://github.com/microsoft/react-native-macos/assets/45072099/ecbe33fa-3e83-46f9-a912-b95984b6186c

Reproducible Demo

No response

Additional context

I found a few posts about issues with this in React Native in general and unsuccessfully tried the workarounds there. After seeing this PR with a video of the copy/paste working, I tried the same within the default App.tsx of a newly generated project (same versions as mine) and it is working there. That same App.tsx in my project had the issue again though. So this has to be related to my project setup.

The only thing that I can think of right now is that there is something wrong with my AppDelegate.swift (linked below) since I'm not using the default Objective-C setup and my Objective-C and Swift knowledge is quite limited.

So I'm not sure if this is even related to react-native-macos and you can just close this issue if you think that the root cause definitely lies somewhere else. I'm happy for any hints or feedback though. I can also add you to the private repo of the app if you are willing to go that deep (maybe in exchange for a coffee or something like that πŸ˜…).

AppDelegate.swift:

import Foundation
import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
  var window : NSWindow!

  func applicationDidFinishLaunching(_ aNotification: Notification) {
    let jsCodeLocation: URL
    #if DEBUG
      jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
    #else
      jsCodeLocation = Bundle.main.url(forResource: "main", withExtension: "jsbundle")!
    #endif

    let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "JiraTimeTracker", initialProperties: nil, launchOptions: nil)
    let rootViewController = NSViewController()
    rootViewController.view = rootView

    // Create the application window
    window = NSWindow()
    window.contentViewController = rootViewController
    let screen: NSScreen = NSScreen.main!
    let midScreenX = screen.frame.midX
    let posScreenY = 200
    let origin = CGPoint(x: Int(midScreenX), y: posScreenY)
    let size = CGSize(width: 460, height: 548)
    let frame = NSRect(origin: origin, size: size)
    window.setFrame(frame, display: true)
    window.center()
    window.makeKeyAndOrderFront(self)
  }
}
Saadnajmi commented 5 months ago

I highly doubt your AppDelegate has anything to do with it. I wonder if there's an Info.plist value you need to allow copy/paste? (I also doubt that...). Without a way to repro it, I'm not sure I can help further though :(

Can you put breakpoints inside classes like RCTUITextView for pasting and see if they're hit? Or perhaps see if onPaste is hit in JS?

AdrianFahrbach commented 5 months ago

I highly doubt your AppDelegate has anything to do with it. I wonder if there's an Info.plist value you need to allow copy/paste? (I also doubt that...). Without a way to repro it, I'm not sure I can help further though :(

Can you put breakpoints inside classes like RCTUITextView for pasting and see if they're hit? Or perhaps see if onPaste is hit in JS?

I sadly don't really know where to put the breakpoints inside the Objective-C files πŸ˜… The TextInput component doesn't have a onPaste prop, as far as I know that is "replaced" by onChangeText and that one doesn't trigger.

The repo in question is this one. It has a branch called text-input-issues where the App.tsx is basically only a TextInput. Maybe this helps you with debugging although I totally understand if you don't have time to take a look at some random repo online!

Saadnajmi commented 5 months ago

There is a macOS specific onPaste callback, you can see it in RNTester in packages/rn-tester of this repo. https://github.com/microsoft/react-native-macos/blob/3d54a1ac5aa1afe93ceeb0b1ed14bbacfe6c8703/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js#L178

Maybe to start, this method? I can't keep track of all the TextInput native classes, that's one of the most complex controls. I'm more curious the code is even getting hit. https://github.com/microsoft/react-native-macos/blob/3d54a1ac5aa1afe93ceeb0b1ed14bbacfe6c8703/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm#L769

AdrianFahrbach commented 5 months ago

There is a macOS specific onPaste callback, you can see it in RNTester in packages/rn-tester of this repo.

https://github.com/microsoft/react-native-macos/blob/3d54a1ac5aa1afe93ceeb0b1ed14bbacfe6c8703/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js#L178

This still does not work for me. I see the TextInputMacOSProps interface in the node_modules, but searching through the node_modules doesn't show this being used anywhere. I tried importing the TextInput from react-native-macos and even renaming my file to .macos.tsx, but Typescript still wouldn't let me use those props. I don't know, but maybe this has something to do with it.

Maybe to start, this method? I can't keep track of all the TextInput native classes, that's one of the most complex controls. I'm more curious the code is even getting hit.

https://github.com/microsoft/react-native-macos/blob/3d54a1ac5aa1afe93ceeb0b1ed14bbacfe6c8703/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm#L769

This on the other hand did "successfully not work". I tested this using NSLog as seen it the screenshots below. "Backspace" as well as "handle key event" was logged (on those actions), but "Paste" and "handle paste" wasn't. I'm still able to paste code using the right click context menu, that also didn't trigger the logs though.

screenshot 2024-02-14 at 00 38 31@2x screenshot 2024-02-14 at 00 36 40@2x

AdrianFahrbach commented 5 months ago

I found the issue! It is my fault and it is a stupid error as well πŸ˜…

I removed unnecessary items from the main menu, including the edit menu, not knowing that this actually defines the shortcuts and does not just offer another way to use them. It was working in a new project, because the menu wasn't edited there and the error sound that I heard wasn't "This is not possible here" but instead "This shortcut is not defined".

After copying the menu back in from the other default project everything was working as expected. So sorry for the confusion!

screenshot 2024-02-14 at 20 28 22@2x

Saadnajmi commented 5 months ago

That is... quite the find. I had no idea it worked that way πŸ˜