Welcome, Guest

Author Topic: Perform copy/cut/paste in BrowserViewControl  (Read 461 times)

jpharis

  • Posts: 7
    • View Profile
Perform copy/cut/paste in BrowserViewControl
« on: January 31, 2017, 10:34:21 AM »
I have an application where we have a proprietary on-screen keyboard. I am looking for a way to perform copy/cut/paste without emulating physical keyboard strokes. I tried using a sequence similar to below, however the key combination does not seem to have any affect. Is there a way to get the selected text within the BrowserView so that I could then set it on the Clipboard, and conversely inject text into the view where the cursor is?

Code: [Select]
private void DoKeyboardComboFunction(KeyFunction function)
        {
            var ctrlKey = new VirtualKeyPressedEventArgs
            {
                TargetObject = viewControl,
                Key = Key.LeftCtrl
            };
            var key = new VirtualKeyPressedEventArgs
            {
                TargetObject = viewControl
            };
            switch (function)
            {
                case KeyFunction.Copy:
                    key.Key = Key.C;
                    break;
                case KeyFunction.Cut:
                    key.Key = Key.X;
                    break;
                case KeyFunction.Paste:
                    key.Key = Key.V;
                    break;

            }

            ProcessKeyDown(ctrlKey);
            Task.Delay(10);
            ProcessKeyDown(key);
            Task.Delay(10);
            ProcessKeyUp(key);
            Task.Delay(10);
            ProcessKeyUp(ctrlKey);
        }

John

  • Coherent Labs support
  • Administrator
  • *****
  • Posts: 205
    • View Profile
Re: Perform copy/cut/paste in BrowserViewControl
« Reply #1 on: February 02, 2017, 07:26:35 AM »
Hi Josh,

To access the system clipboard through WPF, you will need to make use of System.Windows.Clipboard. If you intend to handle only text operations, SetText() and GetText() will be sufficient since they use unformatted Unicode text.

To send the data from the web page to the C#, you will have to use our binding system. This can be done by injecting coherent.js with ExecuteScript on FinishLoad. The following JavaScript code will take care of cut, copy, and paste for text areas and input fields with a physical keyboard.

Code: [Select]
var clipboard;

function getFocusedInputElement() {
  var activeEl = document.activeElement;
  var tagName = activeEl && activeEl.tagName;
  return (tagName == 'TEXTAREA' || tagName == 'INPUT') ? activeEl : null;
}

function getSelectionText() {
  var focusedEl = getFocusedInputElement();
  if (focusedEl == null) {
    return window.getSelection().toString();
  }
  return focusedEl.value.slice(focusedEl.selectionStart, focusedEl.selectionEnd);
}

function removeSelectionText(){
  var focusedEl = getFocusedInputElement();
  if (focusedEl == null) {
    return;
  }
  var beforeSelection = focusedEl.value.substr(0, focusedEl.selectionStart);
  var afterSelection = focusedEl.value.substr(focusedEl.selectionEnd);
  focusedEl.value = beforeSelection + afterSelection;
}

function pasteClipboard(data) {
  var focusedEl = getFocusedInputElement();
  if (!focusedEl) {
      return;
  }
  var beforeCursor = focusedEl.value.slice(0, focusedEl.selectionStart);
  var afterCursor = focusedEl.value.slice(focusedEl.selectionEnd);
  focusedEl.value = beforeCursor + data + afterCursor;
}

function keyDownFunction(evt) {
  evt = evt || window.event;
  if ((evt.ctrlKey || evt.metaKey)) {
    if (evt.keyCode == 67) {
      clipboard = getSelectionText();
      engine.call('SaveClipboard', clipboard);
    } else if (evt.keyCode == 88) {
      clipboard = getSelectionText();
      engine.call('SaveClipboard', clipboard);
      removeSelectionText();
    } else if (evt.keyCode == 86) {
      if (engine && engine.IsAttached) {
        engine.call('GetClipboard').then(pasteClipboard);
      } else {
        pasteClipboard(clipboard);
      }
    }
  }
}

document.body.addEventListener('keydown', keyDownFunction, false);

If you wish to enable the cut/copy/paste operations for the entire page in getFocusedInputElement() return only activeEl. Then, add a check for the types of elements you want to allow cutting and pasting in removeSelectionText and pasteClipboard.

Here is an example binding that works with the JavaScript above:

Code: [Select]
        private void BindingCopy(string textToCopy)
        {
            System.Windows.Clipboard.SetText(textToCopy);
        }

        private string BindingPaste()
        {

            return System.Windows.Clipboard.GetText();
        }

        private void viewControl_ReadyForBindings(int frameId, string path, bool isMainFrame)
        {
            viewControl.BrowserView.BindCall("SaveClipboard", (System.Action<string>)BindingCopy);
            viewControl.BrowserView.BindCall("GetClipboard", (System.Func<string>)BindingPaste);
        }

Of course, you can modify the EventListener and the keyDownFunction to handle your custom keyboard by using binding for the Ctrl + X/C/V combinations and triggering events on the JS side for each operation. Another approach that may improve the user experience is to change the label of the touch-screen letters to the permitted actions when a modifier key like Ctrl is pressed and held (replace C with Copy, V with Paste, R with Refresh for example).

Regards,
John

jpharis

  • Posts: 7
    • View Profile
Re: Perform copy/cut/paste in BrowserViewControl
« Reply #2 on: February 07, 2017, 03:44:58 PM »
Hi John,

I was able to get this working, however, using the below code did not set evt.CtrlKey in the JS KeyDown event handler:

Code: [Select]
private void DoKeyboardComboFunction(KeyFunction function)
        {
            var ctrlArgs = new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(viewControl as Visual), 0, Key.RightCtrl)
            {
                RoutedEvent = Keyboard.KeyDownEvent
            };

            Key key;
            switch (function)
            {
                case KeyFunction.Copy:
                    key = Key.C;
                    break;
                case KeyFunction.Cut:
                    key = Key.X;
                    break;
                case KeyFunction.Paste:
                    key = Key.V;
                    break;

            }
            var keyArgs = new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(viewControl as Visual), 0, key)
            {
                RoutedEvent = Keyboard.KeyDownEvent
            };

            viewControl.ProcessKeyDown(ctrlArgs);
            Task.Delay(50);

            viewControl.ProcessKeyDown(keyArgs);
            Task.Delay(50);

            keyArgs.RoutedEvent = Keyboard.KeyUpEvent;
            viewControl.ProcessKeyUp(keyArgs);
            Task.Delay(50);

            ctrlArgs.RoutedEvent = Keyboard.KeyUpEvent;
            viewControl.ProcessKeyUp(ctrlArgs);
        }

I was able to modify the JS as follows:
Code: [Select]
var clipboard;
var ctrlKeyDown;
function keyDownFunction(evt) {
    evt = evt || window.event;
    console.log('keydown');
    console.log(evt);
    if (evt.keyCode == 17) {
        console.log('Setting ctrlKeyDown = true');
        ctrlKeyDown = true;
    }
    if (ctrlKeyDown && !evt.ctrlKey) {
        console.log('Control key is down');
        if (evt.keyCode == 67) {
            clipboard = getSelectionText();
            engine.call('SaveClipboard', clipboard);
        } else if (evt.keyCode == 88) {
            clipboard = getSelectionText();
            engine.call('SaveClipboard', clipboard);
            removeSelectionText();
        } else if (evt.keyCode == 86) {
            if (engine && engine.IsAttached) {
                engine.call('GetClipboard').then(pasteClipboard);
            } else {
                pasteClipboard(clipboard);
            }
        }
    }
}

function keyUpFunction(evt) {
    evt = evt || window.event;
    console.log('keyup');
    console.log(evt);
    if (evt.keyCode == 17) {
        ctrlKeyDown = false;
    }
}

Tags: