Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   FireMonkey (https://www.clubdelphi.com/foros/forumdisplay.php?f=50)
-   -   Lectura de un código de barras vía TMessage (https://www.clubdelphi.com/foros/showthread.php?t=94886)

QuiqueSalamanca 22-09-2020 13:46:10

Lectura de un código de barras vía TMessage
 
Buenas a todos!

Espero que la pandemia os esté tratando bien!

Os pongo un poco en antecedentes, para leer un código de barras a través de un lector yo lo hago vía Messages en VCL, el problema es al migrar esta aplicación a FireMonkey (cosas del cliente), soy incapaz de replicar el funcionamiento.

Os pongo un poco de código y os explico, yo en el Main de la aplicación VCL (no dejo abrir la aplicación más de una vez) en el .OnMessage tengo este código, que no hace más que comprobar dos tipos de mensajes, WM_KEYDOWN para apertura de un cajón portamonedas y cambiar el '.' por ',' y comprobar si lo que se pasa es una WM_CHAR entonces ahí procesar el código de barras:


Código:

procedure TfrMain.AppOnMessage( var Msg: TMsg; var Handled: Boolean);
begin 
  if (Msg.message = WM_KEYDOWN) then
  begin
      oMsg.hwnd  := Msg.hwnd;
      oMsg.message:= Msg.message;
      oMsg.wParam := Msg.wParam;
      oMsg.lParam := Msg.lParam;
      oMsg.time  := Msg.time;
      oMsg.pt    := Msg.pt;
     
      if (Msg.wParam = VK_F9) then
      begin
        Handled := True;  // le indicamos a windows que lo procesamos
                          // nosotros y no queremos que llege a la aplicación
        if Assigned(OdaDisplay) then
        begin
            try
              OdaDisplay.ClearDisplay;
              OdaDisplay.OpenBoxNew;
            except
            end; 
        end; 
      end
      else if Msg.wParam = VK_DECIMAL then
      begin
        PostMessage( Msg.Hwnd, wm_Char, Ord(','), 0 );
        Handled := True;
      end
      else
        ProcesarMensajeKeyDown( Msg, Handled );
  end 
  else if (Msg.message = WM_CHAR) then
      ProcesarMensajeChar( Msg,
                          Handled, tTimerCodBar,
                          ParmPerfil.PrefijoLectorCodBar,
                          ParmPerfil.SufijoLectorCodBar,
                          ParmPerfil.ForzarUpperCase );
end;

El procedimiento ProcesarMensajeChar no hace otra cosa que procesa (valga la redundancia) lo que le llega y hace un PostMessage con un mensaje personalizado que controlo para saber que lo que está llegando es un código de barras:

Código:

procedure ProcesarMensajeChar( var Msg: TMsg;
                              var Handled: Boolean;
                              tTimer  : TTimer;
                              iPrefijo : Integer;
                              iSufijo  : Integer;
                              bForzarUC: Boolean );
var
  iBarType  : TBarType;
  sCaracter  : Char;
  hOwner    : Hwnd;
  iCodigo    : Integer;
  sBuffer    : string;
  i          : Integer;
  oEdit      : TEdit;
begin
  if (Msg.message = WM_CHAR) then
  begin
      Handled := False;
     
      sCaracter := Chr(Msg.wParam);

      if (iSufijo > 0) or (iPrefijo > 0) then
      begin
        if DebugCodBarKeyChar and not DebugCodBarKeyDown then
        begin
            if sCaracter <> #0 then
              BufferCodBar := sCaracter+Format( '%d', [Msg.wParam] )+' ';
             
            if Assigned(Screen.ActiveForm) then
              PostMessage( Screen.ActiveForm.Handle, um_CodBar, 0, Longint( BufferCodBar ) );

            Handled := True;
        end; 
        if not Handled and LeyendoCodBar then
        begin
            if sCaracter = Chr(iSufijo) then
            begin
              sBuffer := '';
              for i := 1 to Length(BufferCodBar) do
              begin
                  if BufferCodBar[i] = #13 then
                    Continue;
                  sBuffer := sBuffer + BufferCodBar[i];
              end;
              LeyendoCodBar  := False;
              tTimer.Enabled := False;
             
                  // a veces es nil
              if Assigned(Screen.ActiveForm) then
              begin
                  BufferCodBar := TrimRight(sBuffer);
                  PostMessage( Screen.ActiveForm.Handle, um_CodBar, 0, Longint( BufferCodBar ) );
              end; 
            end 
            else
            begin
              BufferCodBar := BufferCodBar + sCaracter;
              if Length(BufferCodBar) = 50 then
              begin
                  LeyendoCodBar  := False;
                  tTimer.Enabled := False;
             
                  if Assigned(Screen.ActiveForm) then
                    SendKeys( PChar(BufferCodBar), True ); // bWait
                   
                  BufferCodBar := '';
              end;   
            end;
            Handled := True; 
        end 
        else if (sCaracter = Chr(iPrefijo)) then
        begin
            if LeyendoCodBar then
            begin
              if (BufferCodBar > '') and
                  Assigned(Screen.ActiveForm) then
                  SendKeys(PChar(BufferCodBar), True ); // bWait
            end;
            BufferCodBar  := '';
            LeyendoCodBar  := True;
            Handled        := True;
            tTimer.Enabled := True;  // no en desarrollo
           
              // el sufijo es capturado por el control si esta seleccionado
            if (Screen.ActiveControl is TCustomEdit) then
              TCustomEdit(Screen.ActiveControl).SelLength := 0
             
            else if Screen.ActiveControl is TCustomGrid then
              SetSelectNullGrid( TCustomGrid(Screen.ActiveControl) );
        end
        else if bForzarUC then
        begin
            if Assigned(Screen.ActiveControl) then
            begin
              if (Screen.ActiveControl is TEdit) then
              begin
                  oEdit := TEdit(Screen.ActiveControl);
                  if oEdit.CharCase = ecNormal then
                  begin
                    sBuffer    := AnsiUpperCase(sCaracter);
                    Msg.wParam := Ord(sBuffer[1]);
                  end;
              end
              else if not (Screen.ActiveControl is TCustomMemo) and
                      not (Screen.ActiveControl is TCustomDCMemo) and
                      not (Screen.ActiveControl is TCustomEasyEdit) then
              begin
                  sBuffer    := AnsiUpperCase(sCaracter);
                  Msg.wParam := Ord(sBuffer[1]);
              end
            end;           
        end;   
      end;   
    end; 
end;

Con esto consigo que en mis formularios solo tenga que añadir un procedimiento que esté a la espera de un mensaje tipo um_CodBar y ahí proceso la información específica para él.

Ahora ya en FireMonkey me resulta imposible controlar ni siquiera los mensajes que devuelve Windows...

He rebuscado y lo que he encontrado es el TMessageManager, con esto puedo hacer SendMessages y leerlo pero no controlo el dónde lo tengo que hacer cuando leo un código de barras.

La otra posibilidad es ir controlando objeto por objeto en el KeyDown por si lo introducido es un código de barras, porque solo nos interesan que en dos o tres objetos se pueda hacer una lectura.

Con lo fácil que era lo otro :'(

Gracias de antemano!

Saludos,
Quique.

Neftali [Germán.Estévez] 22-09-2020 15:31:09

Deberías leer estos 2 hilos.
Explican el porqué estás teniendo problemas con los mensajes de Windows en tu aplicación.

https://stackoverflow.com/questions/...iremonkey-form
https://stackoverflow.com/questions/...ssage-handling

Recordemos que la Base de FMX es que es una librería para multiplataforma (Windows, iOS, android, Linux,...), por lo tanto no se si tendría mucho sentido implementar el tratamiento de mensajería de Windows.

QuiqueSalamanca 23-09-2020 08:30:11

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 538591)
Deberías leer estos 2 hilos.
Explican el porqué estás teniendo problemas con los mensajes de Windows en tu aplicación.

https://stackoverflow.com/questions/...iremonkey-form
https://stackoverflow.com/questions/...ssage-handling

Recordemos que la Base de FMX es que es una librería para multiplataforma (Windows, iOS, android, Linux,...), por lo tanto no se si tendría mucho sentido implementar el tratamiento de mensajería de Windows.

Buenos días Neftali.

Toda esa documentación ya me la he mirado (no sé cuantos días llevo con esto), sí, sé que FMX es una librería que no está basada en Windows y por tanto no se parece en nada a VCL, y por eso os pedía ayuda porque ya me estoy quedando bloqueado :confused:, para ver cómo podría implementar algo parecido con FMX y así no tener que estar posicionado en un componente de escritura cuando se haga la lectura, sino que se pueda capturar siempre dicha lectura y poder enviarla al formulario activo.
Gracias de nuevo!

Saludos,
Quique.

Neftali [Germán.Estévez] 23-09-2020 08:50:01

La primera respuesta del segundo link que te he puesto es lo que yo intentaría.
Haz una pequeña prueba a ver si consigues recibir mensajes.
¿Lo has probado? ¿Has conseguido algo?

QuiqueSalamanca 23-09-2020 09:40:41

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 538597)
La primera respuesta del segundo link que te he puesto es lo que yo intentaría.
Haz una pequeña prueba a ver si consigues recibir mensajes.
¿Lo has probado? ¿Has conseguido algo?

Hola Neftali, sí, fue lo primero que probé. EDITO: no, no me funcionó muy bien, me capturaba ciertos mensajes (sobre todo de pantalla, 28...) pero no el que necesitaba.

Estoy probando esto: https://francois-piette.blogspot.com...ndows-and.html

A ver sin el hilo, si es capaz de capturarme un mensaje WM_CHAR...

Te voy contando...

Gracias!

QuiqueSalamanca 24-09-2020 09:45:09

Buenas a todos,

Con esto de Overbyte, pues he conseguido registrar casi todos los eventos de Windows, menos el que necesito :confused:

Me coge bien el WM_KEYDOWN y el WM_KEYUP justo cuando leo un código de barras, obtengo uno de cada uno por cada cifra devuelve el lector, en vez de mandarme un WM_CHAR que no lo consigo manejar, no sé por qué será.

Estoy desistiendo de la idea de manejar mensajes (que al final sería lo más lógico usando FMX) y empezar a controlarlo mirando el prefijo en el KeyDown (ya que los tenemos configurados con un CTRL+B de prefijo) y mirando si lo que se recibe es la tecla CTRL y ésta no está pulsada, sé que es un código de barras.

No sé cómo lo habéis controlado en otras aplicaciones vosotros, si es mejor hacerlo por otro lado o qué.

Saludos,
Quique.

Neftali [Germán.Estévez] 25-09-2020 08:43:03

Cita:

Empezado por QuiqueSalamanca (Mensaje 538611)
Con esto de Overbyte, pues he conseguido registrar casi todos los eventos de Windows, menos el que necesito :confused:

Me coge bien el WM_KEYDOWN y el WM_KEYUP justo cuando leo un código de barras, obtengo uno de cada uno por cada cifra devuelve el lector, en vez de mandarme un WM_CHAR que no lo consigo manejar, no sé por qué será.


¿Has revisado la VCL?
Es posible que no todos los mensajes que le llegan a una aplicación de Windows los esté generando necesariamente el sistema.
En concreto WM_CHA, ¿Puedes comprobar con alguna utilidad que se esté generando realmente?

Estoy pensando que se sea un mensaje que genera alguna unit de la propia VCL.
¿No se si me explico?

QuiqueSalamanca 25-09-2020 15:14:41

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 538626)
¿Has revisado la VCL?
Es posible que no todos los mensajes que le llegan a una aplicación de Windows los esté generando necesariamente el sistema.
En concreto WM_CHA, ¿Puedes comprobar con alguna utilidad que se esté generando realmente?

Estoy pensando que se sea un mensaje que genera alguna unit de la propia VCL.
¿No se si me explico?

Sí, lo he revisado y viene declarada la constante en la unit Messages, lo genera Windows con un valor 0x0102, es gracioso la verdad.

He tirado por la calle del medio y buscando he encontrado un par de cosillas que creo que me van a funcionar.

Cuando compruebe que va bien os pongo el código por si a alguien le interesa.

Gracias!


La franja horaria es GMT +2. Ahora son las 18:53:43.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi