I'm trying to replicate the standard Win10 Cut/Copy/Paste.
In the code below all of pString goes into the clipboard.
How do I select part of on screen text using left mouse/drag ?
I've searched Petzold and Google and found nothing useful.
char* pGlobal;
char* hGlobal;
char pString[] = "Testing, Testing 123";
char* pStringptr;
int i;
hGlobal = GlobalAlloc(GHND | GMEM_SHARE, 50);
if(hGlobal == 0)
ErrorMessage("1");
pGlobal = GlobalLock(hGlobal);
if(pGlobal == 0)
ErrorMessage("2");
pStringptr = pString;
for(i=0 ; i < 20 ; i++)
*pGlobal++ = *pStringptr++; // Copy text to global mem.
GlobalUnlock(hGlobal);
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_TEXT, hGlobal);
CloseClipboard();
Hi DonnyDave,
Welcome to the forum.
To try to answer your question a clarification is needed.
Quote from: DonnyDave on March 05, 2024, 11:43:27 AM
How do I select part of on screen text using left mouse/drag ?
Can you clarify this? What text from the 'screen', from some user open program, from the windows display, from your own windows program text display?
for example for a edit box you might use
lHWND = GetDlgItem(gHWND, idCtrl);
long long int tsize = SendMessageW(lHWND, WM_GETTEXTLENGTH, 0, 0);
if (tsize > 0)
{
wchar_t *p_buffer = malloc((tsize * 4 * sizeof(wchar_t)) + 20);
RetVal = SendMessageW(lHWND, WM_GETTEXT, tsize + 1, (LPARAM)p_buffer);
Now text is in p_buffer which can then be sent to the clipboard.
You can also limit selection by asking for or setting selected text by SendMessage..to the control for example
SendMessage(lHWND, EM_GETSEL, (WPARAM)&Cstart, (LPARAM)&Cend);
John
Hi John,
"Text from screen" could be any text on anything ( eg. https://forum.pellesc.de/index.php?action=post;topic=11150.0;last_msg=39148 )
LH Mouse anywhere in any text,
LH Mouse drag to anywhere else in the text, (selected portion goes to inverse video),
Ctrl C to copy selected to clipboard.
Dave
Hi DonnyDave,
Checking for understanding -
You are envisioning that a program you wrote is running on a windows system. This programs purpose is to allow the highlighting of any text displayed on the window screen from anything that is open and displaying some text in its own program? It does this by first allowing the highlighting of the text using the mouse, then Ctrl+C is executed to copy to the clipboard.....
So - Several huge hurdles to overcome, imo.
As an initial thing there is the fact that everything shown on the windows screen is only a picture composed of pixels. There is actually no 'text' available on the screen there are only pictures of text shown. It is the underlying program that retains/creates the text in 'characters' that are then transformed into pixels and drawn in the programs window display space. This is unlike days of old where the screen was actually a character map of say 24 x 80 that was actually filled with the 'character' to be displayed ie an 'A' in row 1 column 1 was a value of 65 which is capital A. The underlying screen map could be accessed by any program.
So for your program to use the mouse to highlight some text in my program window you would need to have access to the underlying programs storage of the text being displayed so that character could be retrieved instead of a picture of the characters.
The next hurdle is the once the mouse is over a programs windows space that program controls what the mouse can do. If hovering over my program and I don't have a routine to do highlighting, or changed the action of the mouse buttons, then there is no way for your program to do that highlighting without developing a hook or other method to intercept the mouse and do your task before sending the mouse to the underlying program. It is the same with the keyboard btw. When over a programs window the keystrokes go to that window, so there would need to be a hook for that too...
There are intricate ways of doing some of the above but they are very involved.
It would be a lot easier to program a screen capture program (there are many already) then send the screen picture through an OCR program to recover the 'text' as characters.
Hopefully I've not misunderstood your intention and just went on and on for nothing ;D
John Z
John,
That's correct, I want to incorporate into a win10 prog. I'm about to write (using Pelles C).
Dave
I don't really understand the request here, but I am assuming a contextmenu or control that acts as a Copy/Paste for the target string (from Edit control or already stored in clipboard). Obtaining text from Edit control is easy, and you can also "watch" events such as focus and update (this is where you can count string length to perform checks, copy string or simply read string from Edit control among other actions).
This is how I pulled off a responsive Edit control (like typing into Facebook search, same idea - visually). And these events are required for this in my journey:
WM_LBUTTONDOWN
EN_SETFOCUS
EN_KILLFOCUS
EN_CHANGE
eg.
case WM_COMMAND:
case MY_TEXT_CTRL: {
switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
case EN_CHANGE: { ... break; }
// Add more cases
default:
break;
}
}
break;
Just stuff to help. Any string copied into the clipboard is replaced with a new one effectively replacing the last string stored. This applies to OS in general, and all data types it supports for clipboard. Windows also watches and sanitizes copied objects and other data to ensure integrity and security. So it knows when a image is copied from the desktop (BLOB data likely) which allows to insert the image data into accepting applications (like Irfanview), etc.
Strings should be the easiest to work with.
This is roughly what I'm trying to do:-
struct // This structure holds every line to be displayed.
{
char Contents[MAX_TEXT];
} DisplayBuffStruct[RTVNUMLINES];
// ------------------------------------------------
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps); // Prepare the window for painting.
// ****************************** Find painting limits ******************************.
for (n = FirstLine; n <= LastLine; n++)
{
TextOut(hdc, 10, y), DisplayBuffStruct[n].Contents, StrLength); // Write a line of text from DisplayBuffStruct[].Contents to the client area.
}
EndPaint (hwnd, &ps); // Indicate that painting is finished.
return 0;
// ------------------------------------------------
void WatchStr(char *TheString, char *TheText) // This counts as a declaration of WatchStr()
{
if(strlen(TheString) > MAX_TEXT-1)
{
MessageBox(NULL, TEXT("Too Big !"), TEXT("WatchStr"), MB_OK);
exit(0);
}
sprintf(DisplayBuffStruct[DispLine++].Contents, "%s = %s", TheText, TheString);
InvalidateRect(hwnd, NULL, TRUE);
}
// ------------------------------------------------
I want to copy a selected portion of the text from the screen to the clipboard.
Hi DonnyDave,
I think we keep circling the issue. AFAIK using TextOut to the HDC draws the text in pixels on the DC using the current Font and colors. The result is a picture of the text, the underlying characters used to draw the picture in terms of ASCII or Unicode character values are not stored anywhere to be retrieved with mouse highlighting and Ctrl+C.
To do that you would need to use a control like an edit box, or RichEdit control. Using these controls the underlying text is preserved (stored), The Cursor position can be set within the text display and text can be selected programmatically, Ctrl+C will then work to copy the selected text.
I could be wrong but doing a screen capture and then OCR is the only way I know of for retrieving text written using TextOut directly onto a DC.....If I am I'm sure we will here about it shortly ;) ;D
John Z
Hey hi, you need to implement text selection functionality within your application. This involves handling mouse events to determine the start and end points of the selection, updating the selection UI accordingly and some more information you can get https://learn.microsoft.com/en-us/windows/win32/api/.
Hi Ushavilash,
Welcome to the forum. Always nice to see new contributors.
I've attached a skeleton program for PellesC that outputs three TextOut lines. See attached image.
If you can add the needed code to grab the text and send to the clipboard that would
be a great help to DonnyDave. (and me too)
John Z
Quote from: DonnyDave on March 09, 2024, 11:49:14 AM
This is roughly what I'm trying to do:- . . . .
What you will see is that programs that use TextOut to write text to the screen also store the text, ASCII or UNICODE characters, in a buffer
internal to the program to enable being able highlighting and edit the on screen text if editing is a feature.
When another program is trying to copy 'text' from a program that used TextOut it does not have access to that internal buffer.
Attached is some sample code from Win32 Programmer's Reference WIN32.chm which shows the fundamentals of using TextOut and being able to highlight text once written to the screen using TextOut. Basically knowing the character starting point, character widths and heights and number of characters per logical line, one can figure out where in the buffer the characters are from the mouse pointer start point and the mouse pointer end point, the characters can be redrawn highlighted (with TextOut), and if CRTL+C is used then the actual characters are retrieved from the
internal character buffer - not directly from the screen.
Hope this helps . . .
John Z
Quote from: John Z on April 01, 2024, 12:17:02 PM
Hi Ushavilash,
Welcome to the forum. Always nice to see new contributors.
I've attached a skeleton program for PellesC that outputs three TextOut lines. See attached image.
If you can add the needed code to grab the text and send to the clipboard that would
be a great help to DonnyDave. (and me too)
John Z
Ohh, thanks for posting with attachment sure I'll try. If this happens then I'll reach you.
I didn't specify the problem correctly !
I'm OK with adding a text buffer to the clipboard and pasting it to another app,
I can't workout how to select some part of the text from the (screen) buffer using the mouse.
Hi DonnyDave,
Have you looked at the posting above on April 03, 2024, 03:57:12 PM? It has most of the information you need in the example code pdf. The only addition would be to add the character position in the line rather than the entire line. To do that you still get the mouse coordinates, starting and ending, and use them to calculate the buffer start and stop positions by knowing the approximate character width(s). Line number is by height and character position within a line is by knowing character width. Of course you need access to the buffer holding the original text to access once you know where in the buffer to grab.
Suggest you get the select by line working first then add in the select from character to character.
John Z
Hi, I've done it !!
I used an "edit" window and it was all taken care of by windows.
Thanks to all for the help.
DonnyDave
Hi DonnyDave,
Great news. Yes using an Edit window is much easier than using a main window and writing with TextOut.
The Edit control is like a normal text editor albeit with some significant restrictions. Yet it does provide a
means to grab the text back out in total or as user selected text.
Good to not have given up...
John Z
With that you can copy text to the clipboard
#include <windows.h>
#include <windowsx.h>
#include <stdalign.h>
BOOL WINAPI CopyToClipboard(HWND __hWnd,LPSTR __lpszText2Copy)
{
alignas(LPSTR) LPTSTR _lptstrCopy ;
alignas(HANDLE) HGLOBAL _hglbCopy ;
register int _cch, _iLen ;
_iLen = lstrlen(__lpszText2Copy) ;
if(_iLen == 0)
return (FALSE) ;
if(!OpenClipboard(__hWnd))
return (FALSE) ;
EmptyClipboard() ;
cch = _iLen + 256 ;
_hglbCopy = GlobalAlloc(GMEM_MOVEABLE,(_cch + 1) * sizeof(TCHAR)) ;
if(_hglbCopy == NULL)
{
CloseClipboard() ;
return (FALSE) ;
}
_lptstrCopy = GlobalLock(_hglbCopy) ;
memcpy(_lptstrCopy,__lpszText2Copy,_cch * sizeof(TCHAR)) ;
_lptstrCopy[_cch] = (TCHAR) 0 ;
GlobalUnlock(_hglbCopy) ;
SetClipboardData(CF_TEXT,_hglbCopy) ;
CloseClipboard() ;
return (TRUE) ;
}
That is better
#include <windows.h>
#include <windowsx.h>
#include <stdalign.h>
// Input: The handle of a window wanting to be the clipboard owner
// The string to copy to the clipboard
// Output : TRUE => SUCCESS
// 0 => NULL input pointer or empty string (*__lpszText2Copy2Clipboard = '\0')
// Negative value => Cannot allocate memory or clipboard operation not possible
// When the function returns the negative value it is the GetLastError() code
// To get the real GetLastError() do -ErrorCode.
BOOL WINAPI CopyToClipboard(HWND __hWnd,LPSTR __lpszText2Copy2Clipboard)
{
register int _iStringLength ;
register LPTSTR _lptStringForClipboard ;
alignas(HANDLE) HGLOBAL _hglbCopy ;
if(!__lpszText2Copy2Clipboard) // Don't allow NULL pointer
return (FALSE) ;
_iStringLength = lstrlen(__lpszText2Copy2Clipboard) ; // How many char to copy to clipboard
if(_iStringLength == 0) // Don't allow empty string
return (FALSE) ;
if(!OpenClipboard(__hWnd)) // If it is not possible to open
return (-GetLastError()) ; // the clipboard Bye, return a negative error code
EmptyClipboard() ; // Empty the clipboard, it already can contains CF_TEXT format
_iStringLength += 256 ; // Think to reserve a little space
_hglbCopy = GlobalAlloc(GHND,_iStringLength) ; // Try to allocate memory filled with '0'
if(_hglbCopy == NULL) // If not possible Bye Bye
{
CloseClipboard() ; // Close the clipboard already open
return (-GetLastError()) ; // Return a value telling the operation failed
}
// As the buffer is greater that the string and is filled of '\0'
// one can use lstrcpy that is the reason that sizeof(TCHAR) has been removed
_lptStringForClipboard = GlobalLock(_hglbCopy) ; // Lock the handle got to have a real pointer
lstrcpy(_lptStringForClipboard,__lpszText2Copy2Clipboard) ; // Copy the input string into the pointer
GlobalUnlock(_hglbCopy) ; // Lock the memory so the pointer got is not valid afer this line
SetClipboardData(CF_TEXT,_hglbCopy) ; // Copy the datas to the clipboard telling it is TEXT
CloseClipboard() ; // Close the clipboard
return (TRUE) ; // Tell the operation was successful
}
https://learn.microsoft.com/fr-fr/windows/win32/api/winbase/nf-winbase-globalalloc (https://learn.microsoft.com/fr-fr/windows/win32/api/winbase/nf-winbase-globalalloc)
https://learn.microsoft.com/fr-fr/windows/win32/api/winbase/nf-winbase-globallock (https://learn.microsoft.com/fr-fr/windows/win32/api/winbase/nf-winbase-globallock)
https://learn.microsoft.com/fr-fr/windows/win32/api/winbase/nf-winbase-globalfree (https://learn.microsoft.com/fr-fr/windows/win32/api/winbase/nf-winbase-globalfree)
https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-openclipboard (https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-openclipboard)
https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-closeclipboard (https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-closeclipboard)
https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-setclipboarddata (https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-setclipboarddata)
https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-emptyclipboard (https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-emptyclipboard)