czechmate
asked on
How to access selected text in other applications
Hello,
Example: I am using a dictionary application "WordWebPro". This app sits in a system tray waiting for me to select a text (typically a word) in any application (except edits on html forms) and to hit a hot key. It then wakes up with the selected text copied into its own edit. If the selected text comes from an application like Word, Notepad or an edit component I can make a correction and the corrected text replaces the original text.
So, how does one go about doing the same thing?
cj
Example: I am using a dictionary application "WordWebPro". This app sits in a system tray waiting for me to select a text (typically a word) in any application (except edits on html forms) and to hit a hot key. It then wakes up with the selected text copied into its own edit. If the selected text comes from an application like Word, Notepad or an edit component I can make a correction and the corrected text replaces the original text.
So, how does one go about doing the same thing?
cj
ASKER
It is an interesting article, but I cannot imagine this would be the solution for accessing text in any editable window. I guess the way to access text in other apps must be via finding focused control in foreground window. As I say it is just a guess:)
cj
cj
Use keyboard events:
This example copies the selected text in edit1 to the richeditbox when enter key is pressed (normally your hotkey)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,Clipbrd, ComCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
RichEdit1: TRichEdit;
procedure Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Edit1KeyDown(Sender : TObject; var Key: Word;
Shift: TShiftState);
begin
if key=vk_return then
begin
keybd_event(VK_CONTROL,0,0 ,0);
keybd_event(ord('C'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('C'),0,KEY EVENTF_KEY UP,0);
richedit1.Clear;
richedit1.PasteFromClipboa rd;
end;
end;
end.
Then depending on what you want to do with the collected data you eventually paste something back (modify contents of richedit):
richedit.copytoclipboard;
keybd_event(VK_CONTROL,0,0 ,0); //paste back into field.
keybd_event(ord('V'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('V'),0,KEY EVENTF_KEY UP,0);
You must not lose the focus of the application.
For a hotkey control the Jedi JVCL free component library is good. If you use it the control is located under the JvWin32 tab : http://sourceforge.net/project/showfiles.php?group_id=45786
Regards,
Hypoviax
This example copies the selected text in edit1 to the richeditbox when enter key is pressed (normally your hotkey)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,Clipbrd, ComCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
RichEdit1: TRichEdit;
procedure Edit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Edit1KeyDown(Sender
Shift: TShiftState);
begin
if key=vk_return then
begin
keybd_event(VK_CONTROL,0,0
keybd_event(ord('C'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('C'),0,KEY
richedit1.Clear;
richedit1.PasteFromClipboa
end;
end;
end.
Then depending on what you want to do with the collected data you eventually paste something back (modify contents of richedit):
richedit.copytoclipboard;
keybd_event(VK_CONTROL,0,0
keybd_event(ord('V'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('V'),0,KEY
You must not lose the focus of the application.
For a hotkey control the Jedi JVCL free component library is good. If you use it the control is located under the JvWin32 tab : http://sourceforge.net/project/showfiles.php?group_id=45786
Regards,
Hypoviax
Here is a complete working one i coded. It uses a different method for the hotkey rather than a component (reads for a key state). You need 2 richedit controls. :
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
Timer1: TTimer;
RichEdit1: TRichEdit;
RichEdit2: TRichEdit;
procedure Timer1Timer(Sender: TObject);
procedure RichEdit1Change(Sender: TObject);
private
{ Private declarations }
public
control:string;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if ((GetAsyncKeyState(VK_F12) and 1) = 1) then //if the user presses F12
begin
keybd_event(VK_CONTROL,0,0 ,0);
keybd_event(ord('C'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('C'),0,KEY EVENTF_KEY UP,0);
richedit1.Clear;
richedit1.PasteFromClipboa rd; //load contents
control:=richedit1.Text;
end;
end;
procedure TForm1.RichEdit1Change(Sen der: TObject);
begin
if richedit2.Text=control then
exit
else
richedit2.Text:='NEW TEXT'; //Process word here
richedit2.SelectAll;
richedit2.CopyToClipboard; //Copy processed data
keybd_event(VK_CONTROL,0,0 ,0); //paste back into field.
keybd_event(ord('V'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('V'),0,KEY EVENTF_KEY UP,0);
end;
end.
One little bug seems to be you need to press F12 twice - probably something to do with the richedit control
Best Regards,
Hypoviax
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
Timer1: TTimer;
RichEdit1: TRichEdit;
RichEdit2: TRichEdit;
procedure Timer1Timer(Sender: TObject);
procedure RichEdit1Change(Sender: TObject);
private
{ Private declarations }
public
control:string;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Timer1Timer(Sender:
begin
if ((GetAsyncKeyState(VK_F12)
begin
keybd_event(VK_CONTROL,0,0
keybd_event(ord('C'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('C'),0,KEY
richedit1.Clear;
richedit1.PasteFromClipboa
control:=richedit1.Text;
end;
end;
procedure TForm1.RichEdit1Change(Sen
begin
if richedit2.Text=control then
exit
else
richedit2.Text:='NEW TEXT'; //Process word here
richedit2.SelectAll;
richedit2.CopyToClipboard;
keybd_event(VK_CONTROL,0,0
keybd_event(ord('V'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('V'),0,KEY
end;
end.
One little bug seems to be you need to press F12 twice - probably something to do with the richedit control
Best Regards,
Hypoviax
Get rid of the control variable you don't need it:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if ((GetAsyncKeyState(VK_F12) and 1) = 1) then
begin
keybd_event(VK_CONTROL,0,0 ,0);
keybd_event(ord('C'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('C'),0,KEY EVENTF_KEY UP,0);
richedit1.Clear;
richedit1.PasteFromClipboa rd;
end;
end;
procedure TForm1.RichEdit1Change(Sen der: TObject);
begin
richedit2.Text:='NEW TEXT';
richedit2.SelectAll;
richedit2.CopyToClipboard;
keybd_event(VK_CONTROL,0,0 ,0); //paste back into field.
keybd_event(ord('V'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('V'),0,KEY EVENTF_KEY UP,0);
end;
Hypoviax
procedure TForm1.Timer1Timer(Sender:
begin
if ((GetAsyncKeyState(VK_F12)
begin
keybd_event(VK_CONTROL,0,0
keybd_event(ord('C'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('C'),0,KEY
richedit1.Clear;
richedit1.PasteFromClipboa
end;
end;
procedure TForm1.RichEdit1Change(Sen
begin
richedit2.Text:='NEW TEXT';
richedit2.SelectAll;
richedit2.CopyToClipboard;
keybd_event(VK_CONTROL,0,0
keybd_event(ord('V'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('V'),0,KEY
end;
Hypoviax
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Sorry guys I have not come back earlier, down with flu and not enjoying it.
Hypoviax, I thought your solution was about accessing text betweeen two controls in a single application. Anyway it is almost the same as the Molando's comment. I based my test on Molando's code. I think it is the right way to go about it, but I get these bugs with HotKeys.
If I have a combination of any keys with an Alt key then copy from foreground app does not work at all. The other combinations copy text OK, that is until I paste the text back to foreground window. It does it once then the copy and paste stops working altogether.
Here's my code, can you have a look at it? My system, D5 on Win98se, is a bit shaky right now and I thought maybe that was the reason but when I ran the Dictionary App it works happily with Alt/Ctrl/W key combination.
I also put the RegisterHotKey function into if/then statement, it always registers without problem.
Here's the code anyway:
~~~~~~~~~~~~~~~~~~~~~~~~~~
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, clipbrd, ComCtrls, Buttons, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
SpeedButton1: TSpeedButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure SpeedButton1Click(Sender: TObject);
private
{ Private declarations }
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
public
{ Public declarations }
end;
var
Form1: TForm1;
FgWND : HWND;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
//works until and including the 1st Paste back thereafter
//the foreground window does not copy.
//-------------
//RegisterHotKey(Handle, 101, 0, ord('E'));
//same as above
//-------------
//RegisterHotKey(Handle, 101, MOD_ALT, ord('E'))
//does not work - foreground window does not copy
//-------------
//RegisterHotKey(Handle, 101, MOD_CONTROL, ord('E'));
//works until 1st Pasteback....as above
//-------------
//RegisterHotKey(Handle, 101, MOD_SHIFT, ord('E'));
//works until 1st Pasteback....as above
//-------------
//RegisterHotKey(Handle, 101, MOD_CONTROL or MOD_ALT, ord('E'))
//does not work - foreground window does not copy
//-------------
//RegisterHotKey(Handle, 101, MOD_CONTROL OR MOD_SHIFT, ord('E'));
//works until 1st Pasteback....as above
//-------------
//RegisterHotKey(Handle, 101, MOD_SHIFT OR MOD_ALT, ord('E'));
//does not work - foreground window does not copy
//-------------
end;
procedure TForm1.WMHotKey (var Msg : TWMHotKey);
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin //probably no reason to do this, but why not
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), 0, 0);
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), 0, 0 );
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), KEYEVENTF_KEYUP, 0);
Sleep(500); //give windows time to catchup
Memo1.Clear;
Memo1.PasteFromClipBoard;
If IsIconic(Application.Handl e) Then
Application.Restore
else
Application.BringToFront;
end;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.SpeedButton1Click(S ender: TObject);
begin
Memo1.SelectAll;
Memo1.CopyToClipboard;
Memo1.Clear;
SetForeGroundWindow(FgWND) ;
sleep(250);
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), 0, 0);
keybd_event(ord('V'), MapvirtualKey( ord('V'), 0 ), 0, 0 );
keybd_event(ord('V'), MapvirtualKey( ord('V'), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), KEYEVENTF_KEYUP, 0);
end;
end.
Hypoviax, I thought your solution was about accessing text betweeen two controls in a single application. Anyway it is almost the same as the Molando's comment. I based my test on Molando's code. I think it is the right way to go about it, but I get these bugs with HotKeys.
If I have a combination of any keys with an Alt key then copy from foreground app does not work at all. The other combinations copy text OK, that is until I paste the text back to foreground window. It does it once then the copy and paste stops working altogether.
Here's my code, can you have a look at it? My system, D5 on Win98se, is a bit shaky right now and I thought maybe that was the reason but when I ran the Dictionary App it works happily with Alt/Ctrl/W key combination.
I also put the RegisterHotKey function into if/then statement, it always registers without problem.
Here's the code anyway:
~~~~~~~~~~~~~~~~~~~~~~~~~~
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, clipbrd, ComCtrls, Buttons, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
SpeedButton1: TSpeedButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure SpeedButton1Click(Sender: TObject);
private
{ Private declarations }
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
public
{ Public declarations }
end;
var
Form1: TForm1;
FgWND : HWND;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
//works until and including the 1st Paste back thereafter
//the foreground window does not copy.
//-------------
//RegisterHotKey(Handle, 101, 0, ord('E'));
//same as above
//-------------
//RegisterHotKey(Handle, 101, MOD_ALT, ord('E'))
//does not work - foreground window does not copy
//-------------
//RegisterHotKey(Handle, 101, MOD_CONTROL, ord('E'));
//works until 1st Pasteback....as above
//-------------
//RegisterHotKey(Handle, 101, MOD_SHIFT, ord('E'));
//works until 1st Pasteback....as above
//-------------
//RegisterHotKey(Handle, 101, MOD_CONTROL or MOD_ALT, ord('E'))
//does not work - foreground window does not copy
//-------------
//RegisterHotKey(Handle, 101, MOD_CONTROL OR MOD_SHIFT, ord('E'));
//works until 1st Pasteback....as above
//-------------
//RegisterHotKey(Handle, 101, MOD_SHIFT OR MOD_ALT, ord('E'));
//does not work - foreground window does not copy
//-------------
end;
procedure TForm1.WMHotKey (var Msg : TWMHotKey);
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin //probably no reason to do this, but why not
keybd_event(VK_Control,Map
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), 0, 0 );
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map
Sleep(500); //give windows time to catchup
Memo1.Clear;
Memo1.PasteFromClipBoard;
If IsIconic(Application.Handl
Application.Restore
else
Application.BringToFront;
end;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.SpeedButton1Click(S
begin
Memo1.SelectAll;
Memo1.CopyToClipboard;
Memo1.Clear;
SetForeGroundWindow(FgWND)
sleep(250);
keybd_event(VK_Control,Map
keybd_event(ord('V'), MapvirtualKey( ord('V'), 0 ), 0, 0 );
keybd_event(ord('V'), MapvirtualKey( ord('V'), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map
end;
end.
No, you misunderstood me. My code:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if ((GetAsyncKeyState(VK_F12) and 1) = 1) then //if the user presses F12
begin
keybd_event(VK_CONTROL,0,0 ,0);
keybd_event(ord('C'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('C'),0,KEY EVENTF_KEY UP,0);
richedit1.Clear;
richedit1.PasteFromClipboa rd; //load contents
control:=richedit1.Text;
end;
end;
effectively is another way of detecting a keypress. My code works globally. I tested it with notepad etc.
procedure TForm1.Timer1Timer(Sender:
begin
if ((GetAsyncKeyState(VK_F12)
begin
keybd_event(VK_CONTROL,0,0
keybd_event(ord('C'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('C'),0,KEY
richedit1.Clear;
richedit1.PasteFromClipboa
control:=richedit1.Text;
end;
end;
effectively is another way of detecting a keypress. My code works globally. I tested it with notepad etc.
I'll explain my logic. The hotkey section (Molando's or mine) detects the key press. The data selected is copied and pasted into the richedit1 control. This is the data. The OnChange event starts and you manipulate the data that is in richedit1 and put it in richedit2. The data in richedit2 is copied back to the clipboard and pasted where the selected text is.
Regards,
Hypoviax
Regards,
Hypoviax
I'll have a look at your code
Hypoviax
Hypoviax
ASKER
Ok, Hypoviax I'll try it your way. One thing though, isn't the GetAsyncKeyState function using lot of resources? How often does your timer time out?
cj
cj
The problem occurs whether you use the hotkey or my detection method. For some reason you need to press it twice for it to work. The following code illustrates using both methods, the hotkey and the detection.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls,clipbrd, Buttons;
type
TForm1 = class(TForm)
Timer1: TTimer;
RichEdit1: TRichEdit;
RichEdit2: TRichEdit;
Button1: TButton;
SpeedButton1: TSpeedButton;
procedure Timer1Timer(Sender: TObject);
procedure RichEdit1Change(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
public
Fgwnd:hwnd;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.WMHotKey (var Msg : TWMHotKey); //insert the key
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin //probably no reason to do this, but why not
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), 0, 0);
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), 0, 0 );
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), KEYEVENTF_KEYUP, 0);
Sleep(500); //give windows time to catchup
richedit1.Clear;
richedit1.PasteFromClipBoa rd;
If IsIconic(Application.Handl e) Then
Application.Restore
else
Application.BringToFront;
end;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject); //f12 the key
begin
if ((GetAsyncKeyState(VK_F12) and 1) = 1) then
begin
fgwnd:=GetForegroundWindow ;
keybd_event(VK_CONTROL,0,0 ,0);
keybd_event(ord('C'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('C'),0,KEY EVENTF_KEY UP,0);
richedit1.Clear;
richedit1.PasteFromClipboa rd;
application.BringToFront;
end;
end;
procedure TForm1.RichEdit1Change(Sen der: TObject);
var manipulatedtext:string;
begin
if richedit1.Text='' then
exit
else
begin
richedit2.text:=richedit1. Text + 'ADDED'; //modify text
clipboard.SetTextBuf(pansi char(riche dit2.text) );
end;
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
SetForeGroundWindow(FgWND) ;
keybd_event(VK_CONTROL,0,0 ,0); //paste back into field.
keybd_event(ord('V'),0,0,0 );
keybd_event(VK_CONTROL,0,K EYEVENTF_K EYUP,0);
keybd_event(ord('V'),0,KEY EVENTF_KEY UP,0);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
end;
end.
This problem would not really be a problem if you did not require the application to setfocus to view the text as you could just press the keys twice. Will look into it.
Regards,
Hypoviax
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls,clipbrd, Buttons;
type
TForm1 = class(TForm)
Timer1: TTimer;
RichEdit1: TRichEdit;
RichEdit2: TRichEdit;
Button1: TButton;
SpeedButton1: TSpeedButton;
procedure Timer1Timer(Sender: TObject);
procedure RichEdit1Change(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
public
Fgwnd:hwnd;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.WMHotKey (var Msg : TWMHotKey); //insert the key
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin //probably no reason to do this, but why not
keybd_event(VK_Control,Map
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), 0, 0 );
keybd_event(ord('C'), MapvirtualKey( ord('C'), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map
Sleep(500); //give windows time to catchup
richedit1.Clear;
richedit1.PasteFromClipBoa
If IsIconic(Application.Handl
Application.Restore
else
Application.BringToFront;
end;
end;
end;
procedure TForm1.Timer1Timer(Sender:
begin
if ((GetAsyncKeyState(VK_F12)
begin
fgwnd:=GetForegroundWindow
keybd_event(VK_CONTROL,0,0
keybd_event(ord('C'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('C'),0,KEY
richedit1.Clear;
richedit1.PasteFromClipboa
application.BringToFront;
end;
end;
procedure TForm1.RichEdit1Change(Sen
var manipulatedtext:string;
begin
if richedit1.Text='' then
exit
else
begin
richedit2.text:=richedit1.
clipboard.SetTextBuf(pansi
end;
end;
procedure TForm1.Button1Click(Sender
begin
SetForeGroundWindow(FgWND)
keybd_event(VK_CONTROL,0,0
keybd_event(ord('V'),0,0,0
keybd_event(VK_CONTROL,0,K
keybd_event(ord('V'),0,KEY
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
end;
end.
This problem would not really be a problem if you did not require the application to setfocus to view the text as you could just press the keys twice. Will look into it.
Regards,
Hypoviax
With the timer i set it to 1ms ;). I'll have a look at the resources.
Doesn't appear to be on my pc , 3364 kb and no movement in the CPU usage. I agree the hotkey is better, but the problem is not in the hotkey it has something to do with either setting the apps window focus or something to do with the keyboard event. In my original i required to press it twice in order for it to work. I found i needed to do this with Molando's too
Regards,
Hypoviax
Regards,
Hypoviax
Hang on i found this:
Function ReadFromNotepad:string;
var h:hwnd;
Text:string;
NumCaracters:integer;
begin
h:=FindWindow('notepad',ni l);
h:=FindWindowex(h,0,'edit' ,nil);
if h<>0 then begin
NumCaracters:=SendMessage( h,wm_getTe xtLength,0 ,0);
setlength(text,NumCaracter s);
SendMessage(h,wm_getText,N umCaracter s+1,Intege r(text));
result:=text;
end
else result:='ERROR!';
end;
No copy and pasting involved. I'll see if i can modify it for any window
Function ReadFromNotepad:string;
var h:hwnd;
Text:string;
NumCaracters:integer;
begin
h:=FindWindow('notepad',ni
h:=FindWindowex(h,0,'edit'
if h<>0 then begin
NumCaracters:=SendMessage(
setlength(text,NumCaracter
SendMessage(h,wm_getText,N
result:=text;
end
else result:='ERROR!';
end;
No copy and pasting involved. I'll see if i can modify it for any window
Try a slight modification of this. I ditched the last post couldn't get it to work.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Timer1: TTimer;
Memo1: TMemo;
procedure Timer1Timer(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
public
fgwnd:hwnd;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function GetActiveChildWindow: HWND;
var
h, h1: HWND;
begin
h := GetForegroundWindow();
if IsWindow(h) then begin
repeat
h1 := GetWindow(h, GW_CHILD);
if IsWindow(h1) then begin
if h1 <> h then h := h1;
end else break;
until h1 <> 0;
end;
result := h;
end;
function GetWindowText(h:HWND) : string;
var
buf : string;
len : integer;
begin
try
len := SendMessage(h, WM_GETTEXTLENGTH,0,0);
SetLength(buf,len);
SendMessage(h, WM_GETTEXT, len+1, Integer(buf));
result := buf;
except
result := '';
end;
end;
procedure TForm1.WMHotKey (var Msg : TWMHotKey); //insert the key
var
s: string;
h: HWND;
StartPos, EndPos: integer;
res: integer;
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin //probably no reason to do this, but why not
begin
h := GetActiveChildWindow; // get active control
if IsWindow(h) then begin
s := GetWindowText(h); // get the whole text
if Length(s) > 0 then begin
res := SendMessage(h, EM_GETSEL, 0, 0); // get selected text coordinates
StartPos := LOWORD(res);
EndPos := HIWORD(res);
s := Copy(s, StartPos, EndPos - StartPos); // get the selected text
memo1.Text:=s;
if Length(s) > 0 then begin // there is selected text
s:= 'Hello'; // modify it
SendMessage(h, EM_REPLACESEL, 0, Integer(PChar(s))); // replace the selection
end;
end;
end;
end;
If IsIconic(Application.Handl e) Then
Application.Restore
else
Application.BringToFront;
end;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
end;
end.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Timer1: TTimer;
Memo1: TMemo;
procedure Timer1Timer(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
public
fgwnd:hwnd;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function GetActiveChildWindow: HWND;
var
h, h1: HWND;
begin
h := GetForegroundWindow();
if IsWindow(h) then begin
repeat
h1 := GetWindow(h, GW_CHILD);
if IsWindow(h1) then begin
if h1 <> h then h := h1;
end else break;
until h1 <> 0;
end;
result := h;
end;
function GetWindowText(h:HWND) : string;
var
buf : string;
len : integer;
begin
try
len := SendMessage(h, WM_GETTEXTLENGTH,0,0);
SetLength(buf,len);
SendMessage(h, WM_GETTEXT, len+1, Integer(buf));
result := buf;
except
result := '';
end;
end;
procedure TForm1.WMHotKey (var Msg : TWMHotKey); //insert the key
var
s: string;
h: HWND;
StartPos, EndPos: integer;
res: integer;
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin //probably no reason to do this, but why not
begin
h := GetActiveChildWindow; // get active control
if IsWindow(h) then begin
s := GetWindowText(h); // get the whole text
if Length(s) > 0 then begin
res := SendMessage(h, EM_GETSEL, 0, 0); // get selected text coordinates
StartPos := LOWORD(res);
EndPos := HIWORD(res);
s := Copy(s, StartPos, EndPos - StartPos); // get the selected text
memo1.Text:=s;
if Length(s) > 0 then begin // there is selected text
s:= 'Hello'; // modify it
SendMessage(h, EM_REPLACESEL, 0, Integer(PChar(s))); // replace the selection
end;
end;
end;
end;
If IsIconic(Application.Handl
Application.Restore
else
Application.BringToFront;
end;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
end;
end.
Better stick with the original as i can only get that to work in notepad
ASKER
I'll look at this tomorrow it's getting kinda late here:)
Thanks
cj
Thanks
cj
ASKER
Ok I am back, sorry about the delay I got sidetracked on something else.
Hypoviax you've put a lot in this and I appreciate it. Unfortunately the latest stuff copies only from Edit based controls, I get nothing from Outlook Express, IE nor from Word. So I am going to go for Molando solution, it is not perfect in the present form but I will pose other questions later.
However I don't want Hypoviax to walk empty from this, his original suggestion was not far off. I propose to split the points at 150 each for Hypoviax and Molando. Let me know guys if your are happy about it?
cj
Hypoviax you've put a lot in this and I appreciate it. Unfortunately the latest stuff copies only from Edit based controls, I get nothing from Outlook Express, IE nor from Word. So I am going to go for Molando solution, it is not perfect in the present form but I will pose other questions later.
However I don't want Hypoviax to walk empty from this, his original suggestion was not far off. I propose to split the points at 150 each for Hypoviax and Molando. Let me know guys if your are happy about it?
cj
That's fine by me :)
Regards,
Hypoviax
Regards,
Hypoviax
I have more time to help now i've finished my exams. If you still need more work on it i can try later and post it here
Regards,
Hypoviax
Regards,
Hypoviax
ASKER
I think I'll shelve it for a moment. There are confusing variations in behaviour with different Hotkey combinations:
-Insert key on its own works ok. Ctrl/C copies from all apps, OE, IE, Word, Excel.
-Any key in any combination (well, almost:) with Alt key copies from edit based apps only, eg Notebook.
-Can't figure out all variations with Shift/Ctrl
Clipboard behaviour:
-keybd_event Ctrl/C:
As long as I hit the hotkey only (doing Ctrl/C) everything's OK. The app pops up with selected text copied every time.
-keybd_event Ctrl/V:
depending on Hotkey definition it may or may not work. But..! Repeating Ctrl/C event after Ctrl/V does the following:
1) Copies selected text to clipboard, checked with Clipboard Wiever.
2) Getting text from Clipboard causes Delphi error message 'Cannot open Clipboard'.
3) My application pops up empty.
4) If I hide the app and hit the hotkey again everything works normally.
I tried to close and open clipboard in strategic places, tried to find who's the owner and close it, lock it unlock it...to no avail. I searched the web, nada. So if you figure out how it works please let me know:) My email is czechmate@fastmail.fm, let me know when you have it, I'll pose a new question for you to answer.
Here's the last code:
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, clipbrd, ComCtrls, Buttons, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
butPasteBack: TSpeedButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure butPasteBackClick(Sender: TObject);
private
{ Private declarations }
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
procedure SendCtrlKey(c:char);
public
FgWND : HWND;
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
end;
procedure TForm1.WMHotKey (var Msg : TWMHotKey);
var b:boolean;
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin
SendCtrlKey('C');
Sleep(250);
//Memo1.SetFocus;
Memo1.clear;
try
Memo1.Text := Clipboard.AsText;
except
// seems to suppress 'Cannot Open Clipboard'
// message with Debugger setting
//'Stop on Delphi Exception' unchecked
end;
If IsIconic(Application.Handl e) Then
Application.Restore;
Application.BringToFront;
end;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.butPasteBackClick(S ender: TObject);
begin
Memo1.SelectAll;
Clipboard.AsText := Memo1.Text;
SetForeGroundWindow(FgWND) ;//bring FgWND to foreground again
SendCtrlKey('V');
sleep(200);
end;
procedure TForm1.SendCtrlKey(c: char);
begin
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), 0, 0);
keybd_event(ord(c), MapvirtualKey( ord(c), 0 ), 0, 0 );
keybd_event(ord(c), MapvirtualKey( ord(c), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map VirtualKey (VK_Contro l, 0), KEYEVENTF_KEYUP, 0);
end;
end.
-Insert key on its own works ok. Ctrl/C copies from all apps, OE, IE, Word, Excel.
-Any key in any combination (well, almost:) with Alt key copies from edit based apps only, eg Notebook.
-Can't figure out all variations with Shift/Ctrl
Clipboard behaviour:
-keybd_event Ctrl/C:
As long as I hit the hotkey only (doing Ctrl/C) everything's OK. The app pops up with selected text copied every time.
-keybd_event Ctrl/V:
depending on Hotkey definition it may or may not work. But..! Repeating Ctrl/C event after Ctrl/V does the following:
1) Copies selected text to clipboard, checked with Clipboard Wiever.
2) Getting text from Clipboard causes Delphi error message 'Cannot open Clipboard'.
3) My application pops up empty.
4) If I hide the app and hit the hotkey again everything works normally.
I tried to close and open clipboard in strategic places, tried to find who's the owner and close it, lock it unlock it...to no avail. I searched the web, nada. So if you figure out how it works please let me know:) My email is czechmate@fastmail.fm, let me know when you have it, I'll pose a new question for you to answer.
Here's the last code:
~~~~~~~~~~~~~~~~~~~~~~~~~~
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, clipbrd, ComCtrls, Buttons, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
butPasteBack: TSpeedButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure butPasteBackClick(Sender: TObject);
private
{ Private declarations }
procedure WMHotKey(var Msg : TWMHotKey); message WM_HOTKEY;
procedure SendCtrlKey(c:char);
public
FgWND : HWND;
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 101, 0, VK_INSERT);
end;
procedure TForm1.WMHotKey (var Msg : TWMHotKey);
var b:boolean;
begin
if Msg.HotKey = 101 then
begin
FgWND := GetForegroundWindow;
if FgWND <> 0 then
begin
SendCtrlKey('C');
Sleep(250);
//Memo1.SetFocus;
Memo1.clear;
try
Memo1.Text := Clipboard.AsText;
except
// seems to suppress 'Cannot Open Clipboard'
// message with Debugger setting
//'Stop on Delphi Exception' unchecked
end;
If IsIconic(Application.Handl
Application.Restore;
Application.BringToFront;
end;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnRegisterHotkey(Handle, 101);
end;
procedure TForm1.butPasteBackClick(S
begin
Memo1.SelectAll;
Clipboard.AsText := Memo1.Text;
SetForeGroundWindow(FgWND)
SendCtrlKey('V');
sleep(200);
end;
procedure TForm1.SendCtrlKey(c: char);
begin
keybd_event(VK_Control,Map
keybd_event(ord(c), MapvirtualKey( ord(c), 0 ), 0, 0 );
keybd_event(ord(c), MapvirtualKey( ord(c), 0 ), KEYEVENTF_KEYUP, 0);
keybd_event(VK_Control,Map
end;
end.
ASKER
Hypoviax, sorry, somehow I missed the "Assisted Answer" facility for a point split, so I am posting question for you "Points for Hypoviax", just grab it.
Regards
cj
Regards
cj
Thanks,
I'll have a look at your final code to see if i can improve it in anyway ;-)
Best Regards,
Hypoviax
I'll have a look at your final code to see if i can improve it in anyway ;-)
Best Regards,
Hypoviax
ASKER
Thanks and regards
cj:)
cj:)
You can find this useful for reading information from other applications.