FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour problema en Copy/Paste sobre un Get
Posts: 92
Joined: Fri Nov 18, 2005 11:15 PM
problema en Copy/Paste sobre un Get
Posted: Thu Oct 02, 2025 04:05 PM
Tengo un problema con los get y los caracteres como la "Ñ"
Al hacer Copy/Paste desde un campo a otro, o desde el block de notas a un campo, me aparece un caracter extraño.


Alguien puede indicar la solución? Uso FW2407
Ralph del Castillo

Lima PERU

Fwh 24.07, xHb123_10193, MySQL 8.x, BCC 7.3
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: problema en Copy/Paste sobre un Get
Posted: Fri Oct 03, 2025 12:47 PM

Buenos días. Muéstrenos cómo se ve su MENÚ PRINCIPAL y la configuración de inicio del programa.

Gracias, tks.

Regards, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 92
Joined: Fri Nov 18, 2005 11:15 PM
Re: problema en Copy/Paste sobre un Get
Posted: Sat Nov 22, 2025 01:25 AM

Adjunto un pequeño test.
Si copian desde el block de notas la palabra "NAVIDEÑO" sobre el get, sale el caracter extraño.
Si copian sobre el campo memo, sale correcto.

#include "FiveWin.ch"

function Main()

   local oDlg, oGet1, oGet2, v1 := space(50), v2 := space(100)

   DEFINE DIALOG oDlg TITLE "Testing Gets"

   @ 1, 1 GET oGet1 VAR v1 SIZE 90, 11

   @ 2.5, 1 GET oGet2 VAR v2 SIZE 90, 40 MEMO

   @ 3, 20 BUTTON "Ok" ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED

return nil


Hay algun cambio en la clase TGET que da ese problema.

Ralph del Castillo

Lima PERU

Fwh 24.07, xHb123_10193, MySQL 8.x, BCC 7.3
Posts: 1054
Joined: Sun Oct 09, 2005 10:41 PM
Re: problema en Copy/Paste sobre un Get
Posted: Sat Nov 22, 2025 02:19 AM

HOla amigos----
incluye este codigo antes del Main()

HB_LANGSELECT( 'ES' )       //Selecciona lenguaje español
HB_SETCODEPAGE( 'ESWIN' )
HB_CDPSELECT("ESWIN")
HB_LangSelect( "ES" )
HB_CODEPAGE_ESWIN()              //FW_SetUnicode( .t. )
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
Re: problema en Copy/Paste sobre un Get
Posted: Sun Nov 23, 2025 10:41 AM

Ralph, I’m sure that in the end you will have to create a function manually, similar to this one – it’s only a template and for a different purpose. But with the codepages it never works for me.
Best regards,
Otto

function convertUmlaute( cVData )
    local cTest := ""
    local i := 0

// Beispiel zur Analyse einzelner Zeichen
// for i := 1 to Len( cVData )
//     ? ( cVData + CRLF + SubStr( cVData, i, 1 ) + "  #  " + Str( Asc( SubStr( cVData, i, 1 ) ) ) )
// next

// Umlaute klein
cVData := StrTran( cVData, Chr( 228 ), "ä" )
cVData := StrTran( cVData, Chr( 132 ), "ä" )

cVData := StrTran( cVData, Chr( 246 ), "ö" )
cVData := StrTran( cVData, Chr( 148 ), "ö" )

cVData := StrTran( cVData, Chr( 252 ), "ü" )
cVData := StrTran( cVData, Chr( 129 ), "ü" )

// Umlaute groß
cVData := StrTran( cVData, Chr( 196 ), "Ä" )
cVData := StrTran( cVData, Chr( 142 ), "Ä" )

cVData := StrTran( cVData, Chr( 214 ), "Ö" )
cVData := StrTran( cVData, Chr( 153 ), "Ö" )

cVData := StrTran( cVData, Chr( 220 ), "Ü" )
cVData := StrTran( cVData, Chr( 154 ), "Ü" )

// ß
cVData := StrTran( cVData, Chr( 223 ), "ß" )
cVData := StrTran( cVData, Chr( 225 ), "ß" )

// Weitere Akzente
cVData := StrTran( cVData, Chr( 224 ), "à" )
cVData := StrTran( cVData, Chr( 225 ), "á" )

return cVData
//----------------------------------------------------------------------------//
Posts: 92
Joined: Fri Nov 18, 2005 11:15 PM
Re: problema en Copy/Paste sobre un Get
Posted: Sun Nov 23, 2025 04:52 PM

Willy, probé con tu codigo, sin exito. Reitero el problema: Si se puede escribir directamente en el Get los caracteres "Ñ" o con tilde. El problema es con el PASTE en la clase Tget.

Ralph del Castillo

Lima PERU

Fwh 24.07, xHb123_10193, MySQL 8.x, BCC 7.3
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
Re: problema en Copy/Paste sobre un Get
Posted: Sun Nov 23, 2025 06:20 PM

Solo tienes que convertir la cadena del portapapeles con la función que te di. Así de simple. Comenta los caracteres de arriba para que puedas ver qué valores llegan desde el portapapeles

Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
Re: problema en Copy/Paste sobre un Get
Posted: Sun Nov 23, 2025 06:31 PM

Puedes simplemente llamar a tu función de conversión desde ON CHANGE. No importa si el texto se introduce con el teclado o desde el portapapeles: ON CHANGE captura ambos casos.

Posts: 3358
Joined: Fri Oct 07, 2005 08:20 PM
Re: problema en Copy/Paste sobre un Get
Posted: Mon Nov 24, 2025 05:43 PM

Ralph:

Yo lo tengo así:

Antes del MAI() REQUEST HB_LANG_ES REQUEST HB_CODEPAGE_ESWIN

Dentro del MAIN HB_CDPSELECT("ESWIN") HB_LangSelect( "ESWIN" )

SET( _SET_CODEPAGE, "ESWIN" )

Ojalá te sirva

Saludos

SOI, s.a. de c.v.
estbucarm@gmail.com
http://www.soisa.mex.tl/
http://sqlcmd.blogspot.com/
Tel. (722) 174 44 45
Carpe diem quam minimum credula postero
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
Re: problema en Copy/Paste sobre un Get
Posted: Mon Nov 24, 2025 07:42 PM

Why clipboard text in Harbour/FiveWin often produces wrong characters

Many developers believe that clipboard issues can be solved by selecting the correct Harbour codepage (e.g., ESWIN, DEWIN, UTF8, etc.).
In practice, this does not work reliably.

  1. The main problem today: The clipboard usually delivers UTF-8**

Modern applications almost always copy text in UTF-8:

  • Websites
  • PDFs
  • Word / Outlook
  • WhatsApp Desktop
  • Social media
  • Online editors

UTF-8 uses multiple bytes per character (for example, “ä” = C3 A4).
Harbour/FiveWin GETs, however, expect ANSI (Windows-1252) or OEM (CP850).

Result:
UTF-8 is mistakenly interpreted as ANSI → broken characters (“ä” instead of “ä”).

No Harbour codepage setting can prevent this.

  1. Why codepages alone don’t help**

For a Harbour codepage to work correctly, the following would have to be true:

  • The input bytes must belong exactly to a known codepage
  • Clipboard, Windows, and Harbour must all use the same codepage

Today, this is rarely the case.
The internet and modern software deliver UTF-8, not ANSI.

Therefore, these settings do not work reliably:

HB_CDPSELECT("ESWIN")
HB_LANGSELECT("ES")
SET( _SET_CODEPAGE, "ESWIN" )

  1. Why custom STRTRAN functions work**

Many developers solve the problem pragmatically:

cVData := StrTran( cVData, Chr(228), "ä" )

This works because it replaces byte-by-byte, independent of:

  • OEM
  • ANSI
  • UTF-8
  • PDF encoding

This has nothing to do with codepages – it is a manual mini-conversion that works reliably.

  1. The only clean solution**

The “correct” solution would be:

Read clipboard data as UNICODE (CF_UNICODETEXT)
Then convert it manually to ANSI/UTF-8

FiveWin/Harbour GETs do not do this by default.
That’s why the well-known problems occur.

Posts: 92
Joined: Fri Nov 18, 2005 11:15 PM
Re: problema en Copy/Paste sobre un Get
Posted: Wed Mar 11, 2026 11:35 PM

Con ayuda de Claude.ia encontré la solución a este problema en la clase tGet.

revisa la clase tGet de Fivewin/Harbour adjunta. Sucede lo siguiente:

  • al hacer Copy/Paste desde un block de notas, las tildes y "ñ" se copian mal
  • si copio desde una pagina web, hay veces en que se copian caracteres no visibles como saltos de linea
    Puedes corregir esos problemas?

La solución de Claude:

1. Reemplazar el método Paste() de la clase tGet (la que uso es FWH2407)

2. Agregar 2 funciones a la clase tGet

Lo he probado y FUNCIONA!!!!
@AntonioLinares, puedes considerar esta corrección en las próximas versiones de FW

// =============================================================================
//  PATCH para METHOD Paste() en tget.prg
//  Fecha: 2026-03-11
//
//  Problemas corregidos:
//  1. Tildes y "ñ" se corrompían al pegar desde Notepad (Windows 11)
//     CAUSA:  FW_GetClipBoardData( 13, .f. ) pedía CF_TEXT (formato ANSI),
//             pero Notepad copia en CF_UNICODETEXT (Unicode).
//             Al convertir Unicode→ANSI internamente Windows usaba la
//             codepage del sistema (a veces CP1252) y se perdían los
//             caracteres con acento.
//     FIX:    Leer primero el portapapeles en formato Unicode
//             (FW_GetClipBoardData( 13, .T. ) o ClipboardGetText() en Wide),
//             y luego convertir a UTF-8 si el GET es WideChar, o a ANSI si no.
//
//  2. Caracteres invisibles (CR, LF, TAB, etc.) al pegar desde el navegador
//     CAUSA:  Las páginas web copian texto con saltos de línea y otros
//             caracteres de control que un GET de una sola línea no debería
//             aceptar.
//     FIX:    Limpiar la cadena pegada con FW_CleanPaste() antes de usarla.
// =============================================================================

// ----------------------------------------------------------------------------
// Función auxiliar: limpia la cadena que viene del portapapeles
// Elimina caracteres de control invisibles (CR, LF, TAB, etc.)
// y normaliza espacios múltiples opcionales.
// ----------------------------------------------------------------------------
static function FW_CleanPaste( cText )

   local i, c, cOut := ""
   local nLen := Len( cText )

   for i := 1 to nLen
      c := SubStr( cText, i, 1 )
      // Conservar solo caracteres imprimibles (>= Chr(32)) o caracteres UTF-8
      // de alto byte (>= Chr(128)) que son parte de tildes/ñ en UTF-8.
      // Descartar: Chr(0..31) salvo ninguno (incluye CR=13, LF=10, TAB=9, etc.)
      if Asc( c ) >= 32 .or. Asc( c ) >= 128
         cOut += c
      endif
   next

return cOut

// ----------------------------------------------------------------------------
// Función auxiliar: obtiene texto del portapapeles preferiendo Unicode
// para preservar tildes, ñ y otros caracteres especiales.
// Retorna la cadena en UTF-8 si lWideChar=.T., o en ANSI si lWideChar=.F.
// ----------------------------------------------------------------------------
static function FW_GetClipText( lWideChar )

   local cText  := ""
   local oClp

   // Intentar leer en Unicode (CF_UNICODETEXT) primero
   // FW_GetClipBoardData( 13, .T. ) devuelve UTF-8 en FWH con Harbour
   cText := FW_GetClipBoardData( 13, .T. )   // .T. = Unicode/Wide

   if Empty( cText )
      // Fallback: leer en ANSI
      cText := FW_GetClipBoardData( 13, .F. )
      if !Empty( cText ) .and. lWideChar
         // Convertir ANSI → UTF-8 para GETs WideChar
         cText := AnsiToUtf8( cText )
      endif
   else
      if !lWideChar
         // Convertir UTF-8 → ANSI para GETs normales
         cText := Utf8ToAnsi( cText )
      endif
   endif

return cText

// ----------------------------------------------------------------------------
// METHOD Paste() - versión corregida
// Reemplaza el METHOD Paste() CLASS TGet existente en tget.prg
// ----------------------------------------------------------------------------
METHOD Paste( cPaste ) CLASS TGet

   local cText, nLen, nPos, nDel
   local nStart, nEnd   // selection if any
   local uOrgl, lAccept, V
   local lChanged := .f.

   if !( GetFocus() == ::hWnd )
      return nil
   endif

   // *** FIX 1: Leer portapapeles preservando Unicode (tildes, ñ, etc.) ***
   if cPaste == nil
      cPaste := FW_GetClipText( ::IsWideChar )
   endif

   // *** FIX 2: Limpiar caracteres invisibles (CR, LF, TAB, etc.) ***
   if !Empty( cPaste )
      cPaste := FW_CleanPaste( cPaste )
   endif

   if !Empty( cPaste )

  if ::bPaste != nil
     return Eval( ::bPaste, cPaste, Self )
  endif

  uOrgl := ::cText
  nLen  := Len( ::oGet:Buffer )
  nPos  := ::oGet:Pos
  nDel  := If( ::oGet:Type $ "CM", 0, Len( cPaste ) )
  ::GetSelPos( @nStart, @nEnd )
  if nEnd > nStart
     nPos  := nStart + 1
     nDel  := nEnd - nStart
  endif
  cText := HB_UTF8STUFF( ::oGet:Buffer, nPos, nDel, cPaste )

  do case
  case ::oGet:Type $ "CM"
     cText := ::PadText( cText, nLen )
     ::cText  := cText
     ::SetPos( Min( HB_UTF8LEN( cText ), nPos + HB_UTF8LEN( cPaste ) ) )
     lChanged := .t.

  case ::oGet:Type == "N"
     if ( V := nStrToNum( cPaste, If( ::cPicture == nil, nil, "@E" $ ::cPicture ), .t. ) ) != nil
        ::cText  := v
        lChanged := .f.
     endif

  case ::oGet:Type == "D"
     if !Empty( v := CTOD( cText ) )
        ::cText  := v
        lChanged := .t.
     elseif !Empty( v := CTOD( cPaste ) )
        ::cText  := v
        lChanged := .t.
     endif

  case ::oGet:Type == "T"
#ifdef __XHARBOUR__
         if !Empty( v := CTOT( cText ) )
#else
         if !Empty( v := HB_CTOT( cText ) )
#endif
            ::cText  := v
            lChanged := .t.
         endif

  endcase

  if lChanged .and. ::bChange != nil
     lAccept := Eval( ::bChange,,, Self )
     if HB_ISLOGICAL( lAccept ) .AND. !lAccept
        ::cText  := uOrgl
        ::SetPos( nPos )
     endif
  endif

  if ::oBtn != nil
     ::oBtn:Refresh()
  endif
  if ::oBtnLeft != nil
     ::oBtnLeft:Refresh()
  endif

   endif

return nil
Ralph del Castillo

Lima PERU

Fwh 24.07, xHb123_10193, MySQL 8.x, BCC 7.3
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: problema en Copy/Paste sobre un Get
Posted: Thu Mar 12, 2026 01:34 PM

Probaste asi?

// C:\FWH\SAMPLES\RALPH01.PRG

#include "FiveWin.ch"

REQUEST HB_LANG_ES
REQUEST HB_CODEPAGE_ESWIN

#ifNdef __XHARBOUR__     // HARBOUR
   REQUEST HB_CODEPAGE_UTF8
   REQUEST HB_CODEPAGE_UTF8EX
#endif

FUNCTION Main()

   LOCAL oDlg, oGet1, oGet2, v1 := space(50), v2 := space(100)

   HB_CDPSELECT("ESWIN")
   HB_LangSelect( "ESWIN" )

   SET( _SET_CODEPAGE, "ESWIN" )

   HB_SETCODEPAGE( "UTF8" )
   HB_CDPSELECT( "UTF8EX" )
   HB_CDPSELECT( "PTISO" )

   V1 :=  "ARBOL NAVIDEÑO"
   V2 :=  "ARBOL NAVIDEÑO"

   DEFINE DIALOG oDlg TITLE "Testing Gets"

   @ 1, 1 GET oGet1 VAR v1 SIZE 90, 11

   @ 2.5, 1 GET oGet2 VAR v2 SIZE 90, 40 MEMO

   @ 3, 20 BUTTON "Ok" ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED

RETURN NIL

Regards, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 92
Joined: Fri Nov 18, 2005 11:15 PM
Re: problema en Copy/Paste sobre un Get
Posted: Thu Mar 12, 2026 03:38 PM
karinha wrote:

Probaste asi?

si lo probé, pero no funcionó.

Ralph del Castillo

Lima PERU

Fwh 24.07, xHb123_10193, MySQL 8.x, BCC 7.3
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: problema en Copy/Paste sobre un Get
Posted: Thu Mar 12, 2026 03:47 PM
ralph wrote:

Probaste asi?

si lo probé, pero no funcionó.

Cual FWH, BCC y Harbour ó xHarbour?

Gracias.

Regards, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: problema en Copy/Paste sobre un Get
Posted: Thu Mar 12, 2026 05:29 PM

Estimado Ralph,

Por lo visto parece que hay una solución más simple :)

Análisis de la Causa Raíz

El METHOD Paste() actual en la línea 3366 lee el portapapeles así: 1-cite-0

Code (harbour): Select all Collapse
DEFAULT cPaste := FW_GetClipBoardData( 13, .f. )

FW_GetClipBoardData(13, .f.) lee CF_UNICODETEXT (formato 13) del portapapeles y convierte UTF-16 a UTF-8 mediante UTF16TOUTF8(): 1-cite-1

Entonces cPaste es siempre UTF-8. El problema es que para GETs no-WideChar (::IsWideChar == .f.), el buffer es ANSI. Cuando las secuencias multi-byte UTF-8 de caracteres acentuados (ej: á = 0xC3 0xA1) se insertan en un buffer ANSI, se tratan como dos caracteres separados, causando la corrupción.

El método PadText() lo confirma — para GETs no-WideChar usa PadR() basado en bytes: 1-cite-2

Curiosamente, el manejador WM_PASTE con #ifdef UTFREVN (código de WenSheng) sí maneja esto correctamente, verificando ::lUnicode y leyendo CF_TEXT para GETs no-Unicode: 1-cite-3

Pero el METHOD Paste() en la línea 3353 (usado por el menú contextual y llamadas programáticas) no hace esta distinción.

Problemas en el Parche Propuesto

El parche tiene la intención correcta y funciona en la práctica, pero tiene algunos problemas técnicos:

1. Malentendido del parámetro de FW_GetClipBoardData

El segundo parámetro de FW_GetClipBoardData es lClear (limpiar portapapeles después de leer), no un indicador de Unicode: 1-cite-4

Entonces en FW_GetClipText():

Code (harbour): Select all Collapse
cText := FW_GetClipBoardData( 13, .T. )   // .T. = Unicode/Wide  ← comentario INCORRECTO

.T. en realidad significa "vaciar el portapapeles después de leer". La llamada de respaldo FW_GetClipBoardData( 13, .F. ) no obtendría nada porque el portapapeles ya fue vaciado. Funciona en la práctica porque la primera llamada casi siempre tiene éxito (Windows sintetiza CF_UNICODETEXT a partir de CF_TEXT), pero la lógica de respaldo está rota.

2. Condición redundante en FW_CleanPaste

Code (harbour): Select all Collapse
if Asc( c ) >= 32 .or. Asc( c ) >= 128

El .or. Asc(c) >= 128 es redundante — Asc(c) >= 32 ya cubre todos los valores de 32 a 255. La condición es equivalente a simplemente Asc(c) >= 32.

3. La corrección real que lo hace funcionar

La corrección real es la conversión Utf8ToAnsi() para GETs no-WideChar. Esto es lo que resuelve la corrupción de acentos. La función FW_CleanPaste() resuelve correctamente los caracteres invisibles de páginas web.

Corrección Simplificada Recomendada

La corrección puede ser mucho más simple — solo agregar unas líneas al Paste() existente sin necesidad de FW_GetClipText():

Code (harbour): Select all Collapse
METHOD Paste( cPaste ) CLASS TGet
   ...
   if cPaste == nil
      cPaste := FW_GetClipBoardData( 13, .f. )
      // FIX 1: Convertir UTF-8 → ANSI para GETs no-WideChar
      if !Empty( cPaste ) .and. !::IsWideChar
         cPaste := Utf8ToAnsi( cPaste )
      endif
   endif

   // FIX 2: Eliminar caracteres de control (CR, LF, TAB, etc.)
   if !Empty( cPaste )
      cPaste := FW_CleanPaste( cPaste )
   endif
   ...

Esto evita el wrapper FW_GetClipText() por completo y no vacía accidentalmente el portapapeles.

La función estática FW_CleanPaste() es una buena adición y debería mantenerse (con la condición simplificada):

Code (harbour): Select all Collapse
static function FW_CleanPaste( cText )
   local i, c, cOut := ""
   local nLen := Len( cText )

   for i := 1 to nLen
      c := SubStr( cText, i, 1 )
      if Asc( c ) >= 32
         cOut += c
      endif
   next

return cOut

Resumen

ProblemaCausaCorrección
Tildes y ñ corruptasFW_GetClipBoardData devuelve UTF-8, pero el buffer del GET es ANSIAgregar Utf8ToAnsi() cuando !::IsWideChar
Caracteres invisibles de webCR, LF, TAB copiados del navegadorFiltrar con FW_CleanPaste() (descartar Asc(c) < 32)
regards, saludos

Antonio Linares
www.fivetechsoft.com