-
Mar 16th, 2015, 06:45 AM
#1
Thread Starter
Member
[RESOLVED] How can I Run "Copy" Command/Function Outside of Program/Form?
Looking for a way, to run, the equivalent of "Ctrl+C" using my own VB program. Essentially the reason I am doing this is because the program I am trying to write is a converter, and the plan is to have it use "Ctrl+F" instead of "Ctrl+C". It would copy whatever is highlighted, check if it is a number if it is convert it to another number and paste it back to where it was copied from.
I will figure the rest out later, for now I am just looking for a way to copy selected text using a pre-specified shortcut key combination such as "Ctrl+F" from any window in any program. Heck it can even store the copied text in the regular clipboard, I just don't want to use Ctrl+C to do the copying.
If I need to explain better please say so, and as always any help, suggestions ideas, links etc is very much appreciated.
Thanks in advance.
-
Mar 16th, 2015, 08:52 AM
#2
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
What type of application is the 3rd party program: website, word, other(exe, pdf, etc.)?
-
Mar 16th, 2015, 08:59 AM
#3
Thread Starter
Member
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
It can be anything, word, excel, chrome, notepad, pdf etc. I'm thinking the way to do it might be to call the Ctrl+C keyboard combination or emulate it?
-
Mar 16th, 2015, 09:03 AM
#4
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
That would certainly be your easiest bet:
- Set focus to the 3rd party program
- Use sendkeys to send control + f
- Use sendkeys to send control + c
- Check to make sure that text was found by checking if the clipboard's text is not empty
- If the clipboard's text is not empty then get it by calling the clipboard's GetText
-
Mar 16th, 2015, 09:18 AM
#5
Thread Starter
Member
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
Perhaps I should not have chosen "Ctrl+F" as my keyboard combo. Let us use"ctrl+Q" instead. (That way there is no confusion to the 'Find" feature Ctrl+F usually does)
So I need to select some text somewhere on a random window in a random program, and hit Ctrl+Q, once hit it will copy the selected text into the clipboard, convert it (using a math equation I'll input later, and re-paste the new converted value exactly where it was originally converted from.
You thik setting focus on the third party window still applys in the same way?
-
Mar 16th, 2015, 09:31 AM
#6
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
To be honest, what you're asking for is a global keyboard hook. I'm not sure VB is the best language for this. I'm not saying VB can't do it, but it's likely to be outside the bounds of what the .NET framework can do. It's going to be deeper at a lower level. I'd think that C/C++ would be a much better candidate.
-tg
-
Mar 16th, 2015, 09:40 AM
#7
Thread Starter
Member
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
Shoot, I was hoping this wasn't the case. I can post what I have:
Code:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Debug.WriteLine(m.Msg.ToString & ":" & m.WParam.ToString & ":" & m.LParam.ToString)
keybd_event(Keys.LControlKey, 0, 0, 0) 'key down
keybd_event(Keys.A, 0, 0, 67) 'key down
keybd_event(Keys.A, 0, &H2, 67) 'key up
keybd_event(Keys.LControlKey, 0, &H2, 0) 'keyup
'CONVERSION CODE FOLLOWED BY PASTING CODE WOULD GO HERE
End If
MyBase.WndProc(m)
End Sub
I got the majority of this off of somewhere I forget where, but it isn't my original code just for disclaimer purposes. It will recognize that I have hit a keyboard combo even outside the program, but it wont run the copy function.
-
Mar 16th, 2015, 10:50 AM
#8
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
Try breaking my steps down into code:
1.Set focus to the 3rd party program
You do this by first starting the process using System.Diagnostics.Process.Start and then using the BringWindowToTop API:
Code:
Dim notepad As Process = Process.Start("notepad.exe")
BringWindowToTop(notepad.Handle)
2.Use sendkeys to send control + f
You will have to use the SendKeys.Send method to send the keys, only because control is a special key(^) it'll look a little strange:
Code:
SendKeys.Send("^(f)")
3.Use sendkeys to send control + c
Do the same thing for control + c that you did for control + f:
Code:
SendKeys.Send("^(c)")
4.Check to make sure that text was found by checking if the clipboard's text is not empty
For this step, use a conditional statement to make sure it's not empty by using the Clipboard.ContainsText method:
Code:
If Clipboard.ContainsText Then
5.If the clipboard's text is not empty then get it by calling the clipboard's GetText
Very simple, in the conditional statement's true condition display the text using the Clipboard.GetText method:
Code:
If Clipboard.ContainsText Then
MessageBox.Show(Cliboard.GetText)
End If
Or you could simplify it by using the If short-circuit:
Code:
MessageBox.Show(If(Clipboard.ContainsText, Clipboard.GetText, "Nothing Copied."))
-
Mar 16th, 2015, 11:00 AM
#9
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
dday - I think you're missing the point... he's not trying SEND Ctrl+F ... he wants to use Ctrl+F (or Q, or Z, or T, or what ever) FROM ANY application... as a global hotkey. So let's say he has Word open, selects some text, presses Ctrl+Q ... it should find the selected text, copy it to the clipboard, process it, then paste the new value right back into the same spot.
-tg
-
Mar 16th, 2015, 11:07 AM
#10
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
Ohhh.... Yeah I did misunderstand that. I was under the assumption that he wanted to find text on a 3rd party application and copy the text if anything was found. I don't know how that could even be done... I'll have to bow out of this one.
-
Mar 16th, 2015, 11:33 AM
#11
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
IT can be done with a global keyboard hotkey handler... for which I question the use of VB for since it seems like it would be a lower level kind of issue.
Back to the OP, so what DOES that code do? You mention what it doesn't do, which is fine, but what does it do?
-tg
-
Mar 16th, 2015, 12:09 PM
#12
Thread Starter
Member
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
Alrighty, I figured this out:
Code:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Debug.WriteLine(m.Msg.ToString & ":" & m.WParam.ToString & ":" & m.LParam.ToString)
SendKeys.Send("^(c)")
If IsNumeric(Clipboard.GetText) Then
valHolder3 = Clipboard.GetText
valHolder3 = valHolder3 / 25.4
Clipboard.SetText(valHolder3)
SendKeys.Send("^(v)")
End If
End If
MyBase.WndProc(m)
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Call UnregisterHotKey(Me.Handle, 9)
End Sub
Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call RegisterHotKey(Me.Handle.ToInt32, 0, &H2, 70)
End Sub
That's all of the code, including the copy and paste functionality and the hot-key functionality. Just in case anyone else ever comes across this. Now there may be a better way to accomplish this but this is what I came up with.
-
Mar 16th, 2015, 12:17 PM
#13
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
I wouldn't involve the clipboard or use sendkeys if I didn't have to. This is my idea, Register the hotkey, when hotkey is detected get handle of the foreground app, with that we get the handle of the control that has focus on the app. I'm not sure how you check if a control is an edit control so I just check to see if its classname has the word "edit" in it. , I then take the external text & convert to a decimal, add 1.1 to it and send it back to the control as a string...
Code:
Imports System.Runtime.InteropServices
Imports System.Text
Public Class Form1
Private Const hotKey1 As Integer = 100 ' Our hot key ID
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
' Register our hot key, (Control + Q)
If Not RegisterHotKey(Me.Handle, hotKey1, fsModifier.CONTROL Or fsModifier.NOREPEAT, CUInt(Keys.Q)) Then
MessageBox.Show("RegisterHotKey 'Control+Q' failed!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
End If
End Sub
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
' UnRegister our hot key
UnregisterHotKey(Me.Handle, hotKey1)
End Sub
' watch for messages ( i.e. our hot-key)
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Dim id As Int32 = m.WParam.ToInt32
If id = hotKey1 Then ' Control + Q detected
' Get handle of the Foreground app.
Dim hWndParent As IntPtr = GetForegroundWindow()
' check handle is not me, or zero
If hWndParent <> IntPtr.Zero AndAlso hWndParent <> Me.Handle Then
' get handle of child control that has focus
Dim hWndFocusChild = hWndWithFocus(hWndParent)
' only read/write text if the control has "edit" in the classname.
If Get_ClassName(hWndFocusChild).ToLower.Contains("edit") Then
' convert the text to decimal value
Dim value As Decimal
Decimal.TryParse(GetText(hWndFocusChild), value)
' add 1.1 to the value.
value += 1.1D
' set external control Text to the value as a string.
SendMessage(hWndFocusChild, WM_SETTEXT, 0, value.ToString)
End If
End If
End If
End If
' proc all msgs.
MyBase.WndProc(m)
End Sub
#Region "API"
Private Const WM_HOTKEY As Int32 = &H312
Private Enum fsModifier As UInt32
NONE = &H0
ALT = &H1
CONTROL = &H2
SHIFT = &H4
WIN = &H8
NOREPEAT = &H4000
End Enum
<DllImport("User32.dll")> _
Private Shared Function RegisterHotKey(ByVal hwnd As IntPtr, ByVal id As Int32, ByVal fsModifiers As UInt32, ByVal vk As UInt32) As Boolean
End Function
<DllImport("User32.dll")> _
Private Shared Function UnregisterHotKey(ByVal hwnd As IntPtr, ByVal id As Int32) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub GetClassName(ByVal hWnd As System.IntPtr, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer)
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Private Shared Function GetForegroundWindow() As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessId As IntPtr) As UInt32
End Function
<DllImport("user32.dll")> _
Private Shared Function AttachThreadInput(ByVal idAttach As UInt32, ByVal idAttachTo As UInt32, ByVal fAttach As Boolean) As Boolean
End Function
<DllImport("kernel32.dll")> _
Private Shared Function GetCurrentThreadId() As UInt32
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetFocus() As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function GetWindowTextLength(ByVal hwnd As IntPtr) As Integer
End Function
Private Function Get_ClassName(ByVal hWnd As IntPtr) As String
Dim sb As New StringBuilder(256)
GetClassName(hWnd, sb, 256)
Return sb.ToString
End Function
Private Function hWndWithFocus(hWnd As IntPtr) As IntPtr
Dim hFocus As IntPtr
Dim foreThread As UInt32 = GetWindowThreadProcessId(hWnd, IntPtr.Zero)
Dim appThread As UInt32 = GetCurrentThreadId()
If foreThread <> appThread Then
AttachThreadInput(foreThread, appThread, True)
hFocus = GetFocus()
AttachThreadInput(foreThread, appThread, False)
End If
Return hFocus
End Function
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Const WM_SETTEXT As Integer = &HC
Private Const WM_GETTEXT As Integer = &HD
Private Const WM_GETTEXTLENGTH As Integer = &HE
Private Function GetText(ByVal WindowHandle As IntPtr) As String
Dim TextLen As Integer = SendMessage(WindowHandle, WM_GETTEXTLENGTH, 0, 0) + 1
Dim Buffer As String = New String(" "c, TextLen)
SendMessage(WindowHandle, WM_GETTEXT, TextLen, Buffer)
Buffer = Buffer.Substring(0, Buffer.IndexOf(Chr(0)))
Return Buffer
End Function
#End Region
End Class
Last edited by Edgemeal; Apr 17th, 2015 at 01:15 PM.
Reason: minor code & comment changes
-
Mar 16th, 2015, 01:18 PM
#14
Thread Starter
Member
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
I'm looking at what you have supplied and it makes sense code wise, but I am unsure of why I would do that? Any chance you can clear up why it'd be better to do it that way?
-
Mar 16th, 2015, 01:38 PM
#15
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
Originally Posted by TomToms
I'm looking at what you have supplied and it makes sense code wise, but I am unsure of why I would do that? Any chance you can clear up why it'd be better to do it that way?
Just that I've seen problems with the clipboard when attempting to read and write to it too often or too fast, so I'm wary to use it like that, plus I don't like the idea of apps overwriting whatever I currently have stored on the clipboard.
-
Mar 19th, 2015, 08:53 AM
#16
Thread Starter
Member
Re: How can I Run "Copy" Command/Function Outside of Program/Form?
@Edgemeal, my originally posted solution works sometimes but not always, the solution you gave seems to work flawlessly, and quicker. Thank-you.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|