JavaFX disable highlight and copy mode in WebEngine

2.8k views Asked by At

I'm switching from JEditorPane to WebEngine(JavaFX).
I used to lock the text highlighting(selecting) in JEditorPane as following.

my_editor.setEditable(false);
my_editor.getInputMap().put(KeyStroke.getKeyStroke("control C"), "none");

Now I like to do the same with WebEngine, how may I do this? disabling copy, highlighting and editing mode. Thanks.

2

There are 2 answers

4
José Pereda On BEST ANSWER

If you want to disable copy, highlighting and editing from JavaFX, without the use of Javascript, one way to do it is by trapping the events and deal accordingly with them, leaving the rest of the options intact.

Let's use an event dispatcher to filter a few events:

For key events:

  • Avoid copy with Ctrl+C or Ctrl+Insert
  • Avoid selection with shift+Arrow

For Mouse events:

  • Avoid selection of word, line, paragraph with mouse click
  • Avoid selection with mouse dragging, but allowing dragging the scrollbars

(Others could be added if you need to)

public class WebEventDispatcher implements EventDispatcher {

    private final EventDispatcher oldDispatcher;
    private Point2D limit;

    public WebEventDispatcher(EventDispatcher oldDispatcher) {
        this.oldDispatcher = oldDispatcher;
    }

    public void setLimit(Point2D limit){
        this.limit = limit;
    }

    private boolean allowDrag=false;

    @Override
    public Event dispatchEvent(Event event, EventDispatchChain tail) {
        if (event instanceof MouseEvent){
            MouseEvent m = (MouseEvent)event;
            if (event.getEventType().equals(MouseEvent.MOUSE_CLICKED) || 
                event.getEventType().equals(MouseEvent.MOUSE_PRESSED)) {
                Point2D origin=new Point2D(m.getX(),m.getY());
                allowDrag=!(origin.getX()<limit.getX() && origin.getY()<limit.getY());
            }
            // avoid selection with mouse dragging, allowing dragging the scrollbars
            if (event.getEventType().equals(MouseEvent.MOUSE_DRAGGED)) {
                if(!allowDrag){
                    event.consume();
                }
            }
            // Avoid selection of word, line, paragraph with mouse click
            if(m.getClickCount()>1){
                event.consume();
            }
        }
        if (event instanceof KeyEvent && event.getEventType().equals(KeyEvent.KEY_PRESSED)){
            KeyEvent k= (KeyEvent)event;
            // Avoid copy with Ctrl+C or Ctrl+Insert
            if((k.getCode().equals(KeyCode.C) || k.getCode().equals(KeyCode.INSERT)) && k.isControlDown()){
                event.consume();
            }
            // Avoid selection with shift+Arrow
            if(k.isShiftDown() && (k.getCode().equals(KeyCode.RIGHT) || k.getCode().equals(KeyCode.LEFT) ||
                k.getCode().equals(KeyCode.UP) || k.getCode().equals(KeyCode.DOWN))){
                event.consume();
            }
        }
        return oldDispatcher.dispatchEvent(event, tail);
    }
}

Now on your scene, disable context menu to avoid copy/paste options, find the content area of the webview without the scrollbars, if any, and set the custom event dispatcher.

private Point2D pLimit;
private double width, height;

@Override
public void start(Stage primaryStage) {
    WebView webView = new WebView();
    WebEngine webEngine = webView.getEngine();

    // disable context menu (copy option)
    webView.setContextMenuEnabled(false);

    WebEventDispatcher webEventDispatcher = new WebEventDispatcher(webView.getEventDispatcher());
    webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {

        @Override
        public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
            if(newValue.equals(State.SUCCEEDED)){
                // dispatch all events
                webView.setEventDispatcher(webEventDispatcher);
            }
        }

    });
    webEngine.load("<URL>");

    Scene scene = new Scene(webView);

    primaryStage.setTitle("WebView scrollbar test");
    primaryStage.setScene(scene);
    primaryStage.show();

    webView.getChildrenUnmodifiable().addListener(new ListChangeListener<Node>() {

        @Override
        public void onChanged(Change<? extends Node> c) {
            pLimit=webView.localToScene(webView.getWidth(),webView.getHeight());
            webView.lookupAll(".scroll-bar").stream()
                    .map(s->(ScrollBar)s).forEach(s->{
                        if(s.getOrientation().equals(VERTICAL)){
                            width=s.getBoundsInLocal().getWidth();
                        }
                        if(s.getOrientation().equals(HORIZONTAL)){
                            height=s.getBoundsInLocal().getHeight();
                        }
                    });
            // dispatch all events
            webEventDispatcher.setLimit(pLimit.subtract(width, height));
        }
    });

}
0
Guillaume F. On

You can disable highlight and copy with the following CSS:

body {-webkit-user-select: none;}