autohotkeywindows-subsystem-for-linux

Copy-paste with AutoHotKey using middle mouse button pastes "^C" into WSL terminal


In order to make my WSL experience more Linux-y, I've tried using AutoHotKey to allow the middle mouse button to paste highlighted text. To do this I have used the answer here (taken from here), i.e., create and run an AutoHotKey .ahk script file containing:

cos_mousedrag_treshold := 20 ; pixels
cos_copied_text := ""

#IfWinNotActive ahk_class ConsoleWindowClass

~lButton::
  MouseGetPos, cos_mousedrag_x, cos_mousedrag_y
  keywait lbutton
  mousegetpos, cos_mousedrag_x2, cos_mousedrag_y2
  if (abs(cos_mousedrag_x2 - cos_mousedrag_x) > cos_mousedrag_treshold
    or abs(cos_mousedrag_y2 - cos_mousedrag_y) > cos_mousedrag_treshold)
  {
    wingetclass cos_class, A
    if (cos_class == "Emacs")
      sendinput !w
    else {
      previous_clipboard := clipboard
      sendinput ^c
      sleep 50 ; wait for copied text to be stored in clipboard
      cos_copied_text := clipboard
      clipboard := previous_clipboard
    }
  }
  return

~mbutton::
  WinGetClass cos_class, A
  if (cos_class == "Emacs")
    SendInput ^y
  else {
    previous_clipboard := clipboard
    clipboard := cos_copied_text ; copy stored text to clipboard
    SendInput ^v
    sleep 50 ; I'm not sure if this is necessary
    clipboard := previous_clipboard
  }
  return

#IfWinNotActive

;; clipx
^mbutton::
  sendinput ^+{insert}
  return

This generally works well, but every time I first left mouse click on a Windows Terminal running Ubuntu (or, for that matter, a Windows Powershell terminal) it outputs "^C" on the command prompt. Subsequent left clicks in the same terminal do not produce this, but it happens again if you have switched the active window in between.

Does anyone have an idea how to stop this happening with an amendment to the above script?

Note: the above script will only run with AutoHotKey v1.1 or less, and not v2. If anyone has suggestions of what to change to get it running in v2, that would also be useful.


Solution

  • Before copying or sending any data to clipboard per script, is recommended to empty the clipboard and use ClipWait, to make sure that the specified data appears on the clipboard:

    ~mbutton::
      WinGetClass cos_class, A
      if (cos_class == "Emacs")
        SendInput ^y
      else 
      {
        ClipSaved := ClipboardAll    ; save the entire clipboard to the variable ClipSaved
        clipboard := ""              ; empty the clipboard (start off empty to allow ClipWait to detect when the text has arrived)
        clipboard := cos_copied_text ; copy stored text to clipboard
        ClipWait, 1                  ; wait max. 1 sec for the clipboard to contain data. 
        If (!ErrorLevel)             ; If NOT ErrorLevel ClipWait found data on the clipboard
            SendInput ^v             ; paste the stored text
        else
            MsgBox, 48, Error!, The stored text could not be copied!
        Sleep, 300                   ; Don't change the clipboard while pasting!
        clipboard := ClipSaved       ; restore original clipboard
        VarSetCapacity(ClipSaved, 0) ; Free  the memory of the variable ClipSaved   
      }
      return
    

    Do use the same procedure in the other hotkey definition (~lButton::).

    EDIT:

    Try it this way:

    #NoEnv
    #SingleInstance Force
    
    cos_mousedrag_treshold := 20 ; pixels
    cos_copied_text := ""
    
    Toggle := 0
    
    F1::                  ; Press F1 to enable copy on select and paste on middle click
        Toggle := !Toggle ; Press F1 once again to disable that feature
        CoordMode, ToolTip, Screen
        if (Toggle)
            ToolTip, copy on select`npaste on middle click, 0, 0
        else
            ToolTip
    return
    
    #If (Toggle and !WinActive("ahk_class ConsoleWindowClass"))  
    
        ~lButton::
        MouseGetPos, cos_mousedrag_x, cos_mousedrag_y
        Keywait, LButton, T0.3 ; waits 0.3 seconds maximally for LButton to be released
        If (!ErrorLevel)       ; If not pressed for above that time
            return             ; do nothing
        Keywait, LButton       ; waits for LButton to be released
        MouseGetPos, cos_mousedrag_x2, cos_mousedrag_y2
        if (abs(cos_mousedrag_x2 - cos_mousedrag_x) > cos_mousedrag_treshold or abs(cos_mousedrag_y2 - cos_mousedrag_y) > cos_mousedrag_treshold)
        {
            WinGetClass cos_class, A
            if (cos_class == "Emacs")
                SendInput !w
            else
            {
                ClipSaved := ClipboardAll    ; save the entire clipboard to the variable ClipSaved
                clipboard := ""              ; empty the clipboard (start off empty to allow ClipWait to detect when the text has arrived)
                SendInput ^c                 ; copy the selected text
                ClipWait, 1                  ; wait max. 1 sec for the clipboard to contain data. 
                If (!ErrorLevel)             ; If NOT ErrorLevel ClipWait found data on the clipboard
                    cos_copied_text := clipboard      ; store the copied text text to the variable cos_copied_text
                else
                    MsgBox, 48, Error!, The selected text could not be copied!
                clipboard := ClipSaved       ; restore original clipboard
                VarSetCapacity(ClipSaved, 0) ; Free  the memory of the variable ClipSaved 
            }
        }
        return
    
        ~mbutton::
        WinGetClass cos_class, A
        if (cos_class == "Emacs")
            SendInput ^y
        else 
        {
            ClipSaved := ClipboardAll    ; save the entire clipboard to the variable ClipSaved
            clipboard := ""              ; empty the clipboard (start off empty to allow ClipWait to detect when the text has arrived)
            clipboard := cos_copied_text ; copy stored text to clipboard
            ClipWait, 1                  ; wait max. 1 sec for the clipboard to contain data. 
            If (!ErrorLevel)             ; If NOT ErrorLevel ClipWait found data on the clipboard
                SendInput ^v             ; paste the stored text
            else
                MsgBox, 48, Error!, The stored text could not be copied!
            Sleep, 300                   ; Don't change the clipboard while pasting!
            clipboard := ClipSaved       ; restore original clipboard
            VarSetCapacity(ClipSaved, 0) ; Free  the memory of the variable ClipSaved   
         }
          return
    
    #If
    
    
      ;; clipx
    ^mbutton::
      sendinput ^+{insert}
      return