Posts: 1,006
Threads: 330
Joined: Mar 2007
Hi Gintaras,
Hope all is well!
I am trying to monitor continuously in text for the occurrence of certain string and then highlight it (as the user types). Simplified example below. Problem is that RichEditHighlight moves cursor back to starting position each time because of EM_SETSEL 0 0 message. Therefore can not have continuous typing because cursor position changes, etc.
Any thoughts on how to get around this?
Thanks for any thoughts,
Stuart
rep
,1
,int w=win("WordPad" "WordPadClass")
,int w1=win("Document - WordPad" "WordPadClass")
,int cid=id(59648 w) ;;editable text 'Rich Text Window'
,str text.getwintext(cid)
,out text
,;if findrx(text "\bred\b") > -1
,RichEditHighlight(cid "\bred\b" 4 ColorFromRGB(255 255 255) ColorFromRGB(255 0 0))
,RichEditHighlight(cid "\bgreen\b" 4 ColorFromRGB(255 255 255) ColorFromRGB(0 255 0))
Posts: 12,073
Threads: 140
Joined: Dec 2002
In RichEditHighlight replace several last lines to
Function RichEditHighlight
int selStart selEnd
SendMessage hwndre EM_GETSEL &selStart &selEnd
for i 0 a.len
,SendMessage hwndre EM_SETSEL a[0 i].cpMin a[0 i].cpMax
,SendMessage hwndre EM_SETCHARFORMAT SCF_SELECTION m.address
SendMessage hwndre EM_SETSEL selStart selEnd
ret a.len
Posts: 1,006
Threads: 330
Joined: Mar 2007
Thanks Gintaras for this successful answer.
With this version of RichEditHighlight, I can almost make a continuously format-updating tool without changing the cursor position i.e. if i type the phrase "the ball is red" then as soon as findrx finds red, it will change the text to red, even as I go on to type additional text.
But the problem is that it gets glitchy because it keeps on trying to re-apply the formatting to previous instances which have already been turned red. Is it possible to determine whether some formatting, whether it be bold, underline, italicize or text/background color is already true before applying? I tried below using getsel with the CF_RTF limited to the offsets of interest. It works in theory, but it is so jumpy it makes interaction and typing practically impossible. Is there any way to make this more of a background process for the user?
I know from http://www.quickmacros.com/forum/showthr...p?tid=1406 that I could use GetRTF with SendMessage(hre EM_STREAMOUT SF_RTF &es) but the application with the RichEdit control is external so I would need to do the dll injection via hook that you described in the other thread. If there is not a way to salvage the code below, could you suggest how I could do the dll injection. The external app is 32-bit. I work with some folks who could do the C programming if I could just give them some of the details.
Any advice?
Thanks so much, S
Trigger Aj
int w=win("Document - WordPad" "WordPadClass")
int hwndre = id(59648 w) ;;editable text 'Rich Text Window'
rep 60
,if child(mouse) != hwndre; 0.1; continue
,str ReportText.getwintext(hwndre)
,ReportText.findreplace("[]" "[10]")
,;out ReportText
,int i; ARRAY(CHARRANGE) a ;ARRAY(str) s
,findrx(ReportText "(red)|(blue)|(green)" 0 4 a)
,findrx(ReportText "(red)|(blue)|(green)" 0 4 s)
,out F"Total: {a.len}"
,if !a.len; 1;continue
,for i 0 a.len
,,out F"[]{i}: '{s[0 i]}'"
,,int offset(a[0 i].cpMin) length(a[0 i].cpMax-a[0 i].cpMin)
,,str t.get(ReportText offset length)
,,;out "offset=%i length=%i %s" offset length t
,,int selStart selEnd
,,SendMessage hwndre EM_GETSEL &selStart &selEnd
,,SendMessage hwndre EM_SETSEL a[0 i].cpMin a[0 i].cpMax
,,str ColorCaptured = s[0 i]
,,str SelRtf.getsel(0 CF_RTF hwndre)
,,out F"[9][9]{SelRtf}"
,,int r g b
,,str ColorRtf
,,sel s[0 i]
,,,case "red" ColorRtf = "\colortbl ;\red255\green0\blue0"; r = 255; g = 0; b = 0
,,,case "green" ColorRtf = "\colortbl ;\red0\green255\blue0"; r = 0; g = 255; b = 0
,,,case "blue" ColorRtf = "\colortbl ;\red0\green0\blue255"; r = 0; g = 0; b = 255
,,int textcolor = ColorFromRGB(r g b)
,,if find(SelRtf ColorRtf) > -1
,,,out F"[9]already '{ColorCaptured}'"
,,else
,,,__ProcessMemory m.Alloc(hwndre 1000)
,,,if(IsWindowUnicode(hwndre))
,,,,CHARFORMAT2W cfw.cbSize=sizeof(cfw)
,,,,if(textcolor) cfw.dwMask|CFM_COLOR; cfw.crTextColor=textcolor
,,,,m.Write(&cfw sizeof(cfw))
,,,else
,,,,CHARFORMAT2A cfa.cbSize=sizeof(cfa)
,,,,if(textcolor) cfa.dwMask|CFM_COLOR; cfa.crTextColor=textcolor
,,,,m.Write(&cfa sizeof(cfa))
,,,SendMessage hwndre EM_SETCHARFORMAT SCF_SELECTION m.address
,,,0.5
,,SendMessage hwndre EM_SETSEL &selStart &selEnd
,,0.5
Posts: 1,006
Threads: 330
Joined: Mar 2007
I found this in QM Scripting folder: __Tcc --> C example - global hook in dll (pasted below).
I just don't know how to modify this to allow me to use the GetRTF function from http://www.quickmacros.com/forum/showthr...p?tid=1406
The child richedit text element is pretty straightforwawrd - i.e. with text extractable by .getwintext via child definition of
child("" "*.RICHEDIT50W.*" hWnd 0x0 "wfName=rtbReport") ;;editable text
Any advice?
Thanks,
S
Macro C example - global hook in dll
UnloadDll("$desktop$\tcchook.dll")
__Tcc x.Compile("" "$desktop$\tcchook.dll" 2)
dll- "$desktop$\tcchook.dll" #Hook on
if Hook(1) ;;hook
,mes "Press a key and see what comes to DebugView. Don't close this message box now.[][]At first download and run DebugView."
,Hook(0) ;;unhook
else mes "failed to hook"
UnloadDll("$desktop$\tcchook.dll")
#ret
#include <windows.h>
#define EXPORT __declspec(dllexport)
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);
HMODULE g_hmod;
//printf for dll. You can see the text in DebugView: http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
void printf_dll(LPCSTR fmt, ...)
{
,char b[1000];
,if(!fmt || !*fmt) fmt="\n";
,_vsnprintf(b, 999, fmt, (va_list)(&fmt+1));
,OutputDebugString(b);
}
#define printf printf_dll
BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
,switch(fdwReason)
,{
,case DLL_PROCESS_ATTACH:
,,g_hmod=hinstDLL;
,,DisableThreadLibraryCalls(hinstDLL);
,,break;
,case DLL_PROCESS_DETACH:
,,break;
,}
,return 1;
}
EXPORT BOOL Hook(BOOL on)
{
static HHOOK hhook;
if(hhook)
,{
,UnhookWindowsHookEx(hhook);
,hhook=0;
,}
if(on)
,{
,hhook=SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hmod, 0);
,if(!hhook) return 0;
,}
return 1;
}
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if(code!=HC_ACTION) goto g1;
printf("%s: key %i %s.", __func__, wParam, lParam&0x80000000 ? "released" : "pressed");
g1:
return CallNextHookEx(0, code, wParam, lParam);
}
Posts: 12,073
Threads: 140
Joined: Dec 2002
I don't know other ways to get RTF and how to improve this code.
Dll injection - not QM-specific. Need to create a dll in Visual Studio, using C++ language. Inject it with SetWindowsHookEx(WH_CALLWNDPROC, HookFunctionInThisDll, ModuleHandleOfThisDll, ThreadIdOfTheWindow) and SendMessage(hwnd, MyMessage, 0, 0). Then to send data back use eg shared memory or ReadProcessMemory.
Posts: 1,006
Threads: 330
Joined: Mar 2007
Thanks so much! I will see what I can do with your suggestions.
S
Posts: 12,073
Threads: 140
Joined: Dec 2002
Quote:I found this in QM Scripting folder: __Tcc --> C example - global hook in dll (pasted below).
...
With __Tcc possible but much much more difficult than with Visual Studio. No intellisense, no C++, no 64-bit, no exception handling. It is reasonable only for simple small code. Injecting dll, getting RTF and passing it back is not so easy. I cannot help.
Visual Studio Community 2017 is free. It's the best IDE. But it takes maybe 10 GB. If it's too much, you can find a smaller IDE that supports C++.
Quote:how to modify this to allow me to use the GetRTF function from
The function is very simple, easy to convert to C++. Or maybe better look for an EM_STREAMOUT example eg in stackoverflow.
Posts: 1,006
Threads: 330
Joined: Mar 2007
|