Unicode clipboard in Windows VM...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Unicode clipboard in Windows VM...

Chris Petsos
 
Ok guys... this is my solution for unicode clipboard support in Windows VM... It works fine... I can make some improvements in memory management but it's ok for now...
 

/****************************************************************************/
/*                      Clipboard                                           */
/****************************************************************************/
 
int clipboardSize(void)
{ HANDLE h, h2;
  WCHAR *src;
  unsigned char *csrc;
  int len, bytesNeeded;
 
  // Do we have text in the clipboard?
  if(!IsClipboardFormatAvailable(CF_TEXT))
    return 0;
  if(!OpenClipboard(stWindow))
    return 0;
 
  // Get it in unicode format.
  h = GetClipboardData(CF_UNICODETEXT);
 
  src = GlobalLock(h);
 
  // How many bytes do we want to store those unicode chars in UTF8 format?
  bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, src, -1,
        NULL, 0, NULL, NULL );
 
  h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, bytesNeeded);
  csrc = GlobalLock(h2);
 
  // Convert Unicode text to UTF8.
  WideCharToMultiByte( CP_UTF8, 0, src, -1,
        csrc, bytesNeeded, NULL, NULL );
 
  // Consider CrLf as a 1-byte character.
  len = bytesNeeded;
  while(len--)
    if(((*csrc == 13) && (csrc[1] == 10)))
      {
 bytesNeeded--;
 csrc++;
      }
    else
      {
 csrc++;
      } 
 

  // Clipboard size is bytesNeeded excluding the terminating character.
  len = bytesNeeded - 1;
 
  GlobalUnlock(h);
  GlobalUnlock(h2);
 
  return len;
}
 

/* send the given string to the clipboard */
int clipboardWriteFromAt(int count, int byteArrayIndex, int startIndex)
{ HANDLE h, h2;
  unsigned char *src;
  int wcharsNeeded, len;
  WCHAR *out, *tmp;
 
  if(!OpenClipboard(stWindow))
    return 0;
 
  // Get the pointer to the byte array.
  src = (unsigned char *)byteArrayIndex + startIndex;
 
  // How many WCHARs do we need to store the UTF8 represented bytes from Squeak?
  wcharsNeeded = MultiByteToWideChar( CP_UTF8, 0, src,
        count+1, NULL,  
 0 );
 
  // If we have Cr only "returns" then we will need another character for Lf.
  len = wcharsNeeded * sizeof(WCHAR);
  while(len--)
    if ((*src++ == 13) && (*src != 10))
      wcharsNeeded++; 
 
  // Point to start of byte aray.
  src = (unsigned char *)byteArrayIndex + startIndex;
 
  // Allocate needed memory for wcharsNeeded WCHARs.
  h = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wcharsNeeded * sizeof(WCHAR));
  out = GlobalLock(h);
 
  // Convert them to Unicode UTF16.
  MultiByteToWideChar( CP_UTF8, 0, src,
        count+1, out,  
 wcharsNeeded );
 
  // Allocate needed memory for intermediate buffer.
  // OK, i could do some more work here in order to avoid a whole new buffer just for
  // fixing the CrLf thing, but it's ok for now...
  h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wcharsNeeded * sizeof(WCHAR));
  tmp = GlobalLock(h2);
 
  // Add missing Lf characters...
  len = wcharsNeeded;
  while(len--)
    if((*out == 13))
      { /* special case: crlf translation */
 *tmp = 13;
 tmp++;
 *tmp = 10;
 tmp++;
 out++;
      }
    else
      { /* regular case: lookup translation */
 *tmp = *out;
 tmp++;
 out++;
      }
 
  EmptyClipboard();
  GlobalUnlock(h);
  GlobalUnlock(h2);
 
  // Send the Unicode text to the clipboard.
  SetClipboardData(CF_UNICODETEXT, h2);
 
  *src=0;
  *tmp=0;
 
  /* Note: After setting clipboard data,
     the memory block previously allocated belongs to
     the clipboard - not to the app. */
  CloseClipboard();
  return 1;
}
 

/* transfer the clipboard data into the given byte array */
int clipboardReadIntoAt(int count, int byteArrayIndex, int startIndex)
{ HANDLE h, h2;
  unsigned char *dst, *tmp;
  WCHAR *src;
  int tel,len, bytesNeeded;
 

  if(!IsClipboardFormatAvailable(CF_TEXT)) /* check for format CF_TEXT */
    return 0;
 
  if(!OpenClipboard(stWindow))
    return 0;
 
  // Get clipboard data in Unicode format
  h = GetClipboardData(CF_UNICODETEXT);
  src = GlobalLock(h);
 
  // How many bytes do we want to store the Unicode chars to UTF8 representation?
  bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, src, -1,
        tmp, 0, NULL, NULL ) + 1;
 
  h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, bytesNeeded);
  tmp = GlobalLock(h2);
 
  // Convert Unicode text to UTF8.
  WideCharToMultiByte( CP_UTF8, 0, src, -1,
        tmp, bytesNeeded, NULL, NULL);
 
  len = bytesNeeded;
 
  // Get the pointer to the byte array.
  dst= (unsigned char *)byteArrayIndex + startIndex;
 
  while(len--)
    if(((*tmp == 13) && (tmp[1] == 10)))
      { /* RvL 17-04-1998
           drop the line feed after a carriage return
           but leave lone line feeds alone
           may transfer less than 'len' bytes but who cares
           i.e. if they use the clipboardSize there should
           be no problem.*/
 *dst = 13;
 dst++;
        tmp++;
        tmp++;
      }
    else
      { /* regular case: lookup translation */
 *dst = *tmp;
 dst++;
 tmp++;
      } 
 
  GlobalUnlock(h);
  GlobalUnlock(h2);
  CloseClipboard();
  return bytesNeeded;
}
 
The only thing is that in the image side you need a UTF8TextConverter before sending text to the clipboard or getting from it...so, my unicode clipboard interpreter has these methods...
 
fromSystemClipboard: aString
 ^ aString convertFromWithConverter: (UTF8TextConverter new).
 
toSystemClipboard: aString
 | result utfString |
" aString isOctetString ifTrue: [^ aString asOctetString]."
 utfString := aString convertToWithConverter: (UTF8TextConverter new).
 result _ WriteStream on: (String new: utfString size).
 utfString do: [:each | result nextPut: each].
 ^ result contents.
 
I am pretty sure it will need some minor fixes...
I'll post links to ready made builds of this version so others can try it too, soon.
 
Any comments, suggestions, C-related fixes are most welcome...
 
Christos
Reply | Threaded
Open this post in threaded view
|

Re: Unicode clipboard in Windows VM...

Andreas.Raab
 
Hi Chris -

This looks good; one question though: Do you know whether the windows
clipboard automatically provides the CF_UNICODETEXT -> CF_TEXT translation?

Cheers,
   - Andreas

Chris Petsos wrote:

>  
>
>
> ------------------------------------------------------------------------
>
> Ok guys... this is my solution for unicode clipboard support in Windows
> VM... It works fine... I can make some improvements in memory management
> but it's ok for now...
>  
>
> /****************************************************************************/
> /*                      
> Clipboard                                           */
> /****************************************************************************/
>  
> int clipboardSize(void)
> { HANDLE h, h2;
>   WCHAR *src;
>   unsigned char *csrc;
>   int len, bytesNeeded;
>  
>   // Do we have text in the clipboard?
>   if(!IsClipboardFormatAvailable(CF_TEXT))
>     return 0;
>   if(!OpenClipboard(stWindow))
>     return 0;
>  
>   // Get it in unicode format.
>   h = GetClipboardData(CF_UNICODETEXT);
>  
>   src = GlobalLock(h);
>  
>   // How many bytes do we want to store those unicode chars in UTF8 format?
>   bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         NULL, 0, NULL, NULL );
>  
>   h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, bytesNeeded);
>   csrc = GlobalLock(h2);
>  
>   // Convert Unicode text to UTF8.
>   WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         csrc, bytesNeeded, NULL, NULL );
>  
>   // Consider CrLf as a 1-byte character.
>   len = bytesNeeded;
>   while(len--)
>     if(((*csrc == 13) && (csrc[1] == 10)))
>       {
>  bytesNeeded--;
>  csrc++;
>       }
>     else
>       {
>  csrc++;
>       }
>  
>
>   // Clipboard size is bytesNeeded excluding the terminating character.
>   len = bytesNeeded - 1;
>  
>   GlobalUnlock(h);
>   GlobalUnlock(h2);
>  
>   return len;
> }
>  
>
> /* send the given string to the clipboard */
> int clipboardWriteFromAt(int count, int byteArrayIndex, int startIndex)
> { HANDLE h, h2;
>   unsigned char *src;
>   int wcharsNeeded, len;
>   WCHAR *out, *tmp;
>  
>   if(!OpenClipboard(stWindow))
>     return 0;
>  
>   // Get the pointer to the byte array.
>   src = (unsigned char *)byteArrayIndex + startIndex;
>  
>   // How many WCHARs do we need to store the UTF8 represented bytes
>  >from Squeak?
>   wcharsNeeded = MultiByteToWideChar( CP_UTF8, 0, src,
>         count+1, NULL,  
>  0 );
>  
>   // If we have Cr only "returns" then we will need another character
> for Lf.
>   len = wcharsNeeded * sizeof(WCHAR);
>   while(len--)
>     if ((*src++ == 13) && (*src != 10))
>       wcharsNeeded++;
>  
>   // Point to start of byte aray.
>   src = (unsigned char *)byteArrayIndex + startIndex;
>  
>   // Allocate needed memory for wcharsNeeded WCHARs.
>   h = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wcharsNeeded *
> sizeof(WCHAR));
>   out = GlobalLock(h);
>  
>   // Convert them to Unicode UTF16.
>   MultiByteToWideChar( CP_UTF8, 0, src,
>         count+1, out,  
>  wcharsNeeded );
>  
>   // Allocate needed memory for intermediate buffer.
>   // OK, i could do some more work here in order to avoid a whole new
> buffer just for
>   // fixing the CrLf thing, but it's ok for now...
>   h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wcharsNeeded *
> sizeof(WCHAR));
>   tmp = GlobalLock(h2);
>  
>   // Add missing Lf characters...
>   len = wcharsNeeded;
>   while(len--)
>     if((*out == 13))
>       { /* special case: crlf translation */
>  *tmp = 13;
>  tmp++;
>  *tmp = 10;
>  tmp++;
>  out++;
>       }
>     else
>       { /* regular case: lookup translation */
>  *tmp = *out;
>  tmp++;
>  out++;
>       }
>  
>   EmptyClipboard();
>   GlobalUnlock(h);
>   GlobalUnlock(h2);
>  
>   // Send the Unicode text to the clipboard.
>   SetClipboardData(CF_UNICODETEXT, h2);
>  
>   *src=0;
>   *tmp=0;
>  
>   /* Note: After setting clipboard data,
>      the memory block previously allocated belongs to
>      the clipboard - not to the app. */
>   CloseClipboard();
>   return 1;
> }
>  
>
> /* transfer the clipboard data into the given byte array */
> int clipboardReadIntoAt(int count, int byteArrayIndex, int startIndex)
> { HANDLE h, h2;
>   unsigned char *dst, *tmp;
>   WCHAR *src;
>   int tel,len, bytesNeeded;
>  
>
>   if(!IsClipboardFormatAvailable(CF_TEXT)) /* check for format CF_TEXT */
>     return 0;
>  
>   if(!OpenClipboard(stWindow))
>     return 0;
>  
>   // Get clipboard data in Unicode format
>   h = GetClipboardData(CF_UNICODETEXT);
>   src = GlobalLock(h);
>  
>   // How many bytes do we want to store the Unicode chars to UTF8
> representation?
>   bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         tmp, 0, NULL, NULL ) + 1;
>  
>   h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, bytesNeeded);
>   tmp = GlobalLock(h2);
>  
>   // Convert Unicode text to UTF8.
>   WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         tmp, bytesNeeded, NULL, NULL);
>  
>   len = bytesNeeded;
>  
>   // Get the pointer to the byte array.
>   dst= (unsigned char *)byteArrayIndex + startIndex;
>  
>   while(len--)
>     if(((*tmp == 13) && (tmp[1] == 10)))
>       { /* RvL 17-04-1998
>            drop the line feed after a carriage return
>            but leave lone line feeds alone
>            may transfer less than 'len' bytes but who cares
>            i.e. if they use the clipboardSize there should
>            be no problem.*/
>  *dst = 13;
>  dst++;
>         tmp++;
>         tmp++;
>       }
>     else
>       { /* regular case: lookup translation */
>  *dst = *tmp;
>  dst++;
>  tmp++;
>       }
>  
>   GlobalUnlock(h);
>   GlobalUnlock(h2);
>   CloseClipboard();
>   return bytesNeeded;
> }
>  
> The only thing is that in the image side you need a UTF8TextConverter
> before sending text to the clipboard or getting from it...so, my unicode
> clipboard interpreter has these methods...
>  
> fromSystemClipboard: aString
>  ^ aString convertFromWithConverter: (UTF8TextConverter new).
>  
> toSystemClipboard: aString
>  | result utfString |
> " aString isOctetString ifTrue: [^ aString asOctetString]."
>  utfString := aString convertToWithConverter: (UTF8TextConverter new).
>  result _ WriteStream on: (String new: utfString size).
>  utfString do: [:each | result nextPut: each].
>  ^ result contents.
>  
> I am pretty sure it will need some minor fixes...
> I'll post links to ready made builds of this version so others can try
> it too, soon.
>  
> Any comments, suggestions, C-related fixes are most welcome...
>  
> Christos
Reply | Threaded
Open this post in threaded view
|

Re: Unicode clipboard in Windows VM...

Chris Petsos
 
> This looks good; one question though: Do you know whether the windows
> clipboard automatically provides the CF_UNICODETEXT -> CF_TEXT
> translation?

I suppose you are asking if
    IsClipboardFormatAvailable(CF_TEXT)
returns TRUE when we have CF_UNICODETEXT on the clipboard...
Well... from what i saw it does...even the vice versa is again evaluated to
TRUE.
Actually i couldn' see any difference in asking
    IsClipboardFormatAvailable(CF_TEXT)
from
    IsClipboardFormatAvailable(CF_UNICODETEXT)
when transporting UTF-8 chars to/from the clipboard.

Christos.