Joseph Gabello
Joseph Gabello

Reputation: 87

Reading from mouse inputs in Ada

I have a procedure in Ada which reads from a touch screen input. The code is very old and I do not have the touch screen anymore. I would like to replace the touch screen code with reading from a mouse input. Would it be simpler to write the function in C and Import it into the Ada code? The code below is the touch screen code.


   HIL_NAME : STRING (1.. 10) := "/dev/touch";

   procedure READ (X, Y : out INTEGER) is

      type BYTE is new INTEGER range 0 .. 255;
      for BYTE'SIZE use 8;
      package IN_IO is new SEQUENTIAL_IO (BYTE);
      use IN_IO;

      type DATA_TYPE is array (2 .. 9) of BYTE;

      HIL_FILE : IN_IO.FILE_TYPE;
      COUNT    : BYTE;
      DATA     : DATA_TYPE;

   begin
      IN_IO.OPEN (HIL_FILE, IN_FILE, HIL_NAME); -- open the touchscreen

      loop
         IN_IO.READ (HIL_FILE, COUNT); -- read the incoming record size
         -- read the incoming record
         for I in INTEGER range 2 .. BYTE'POS (COUNT) loop
            IN_IO.READ (HIL_FILE, DATA (I));
         end loop;
         -- is this a fingerdown?  overkill test.
         if ((COUNT = 9) and (DATA (6) = 2#01000010#) and (DATA (9) = 142)) then
            X := BYTE'POS (DATA (7)); -- pick out coordinates
            Y := BYTE'POS (DATA (8));
            IN_IO.CLOSE (HIL_FILE); -- close touchscreen to flush buffer
            return; -- return to caller
         end if;
      end loop;
   end READ;

Upvotes: 1

Views: 237

Answers (3)

Joseph Gabello
Joseph Gabello

Reputation: 87

I have solved the problem using Ncurses. I downloaded the terminal-interface-curses and used the files to create the following procedure.

with Terminal_Interface.Curses;
use Terminal_Interface.Curses;

tmp2 : Event_Mask;
c    : Key_Code;
firsttime : Bollean;

procedure READ (X1 : out Column_Position;
                Y1 : Line_Position) is

begin
   tmp2 := Start_Mouse (All_Events);
   c:= Character'Pos ('?');
   Set_Raw_Mode (SwitchOn => True);
   Set_KeyPad_Mode (SwitchOn => True);
   firsttime := true;

   loop
      if not firsttime then
         if c = KeyMouse then
            declare
               event  : Mouse_Event;
               Y      : Line_Position;
               X      : Column_Position;
               Button : Mouse_Button;
               State  : Mouse_State;
            begin
               event := Get_Mouse;
               Get_Event (event, Y, X, Button, State);
               X1 := X;
               Y1 := Y;
               exit;
            end;
         end if;
      end if;

      firsttime := False;
      loop
         c := Get_Keystroke;
         exit when c /= Key_None;
      end loop;
   end loop;
   End_Mouse (tmp2);
end READ;

Upvotes: 2

DeeDee
DeeDee

Reputation: 5941

You can read the mouse by using the Linux input subsystem (as was suggested by @Zerte). See also this question on SO and some kernel documentation here and here. Reading the mouse' input doesn't seem hard (at least not on a Raspberry Pi 3 running Raspbian GNU/Linux 10). Of course, you still need to apply proper scaling and you need to figure out the device that exposes the mouse events (in my case: /dev/input/event0)

NOTE: You can find the number by inspecting the output of sudo dmesg | grep "input:". If a mouse (or other pointing device) is connected to inputX, then the events of this device will be exposed on eventX.

main.adb

with Ada.Text_IO;
with Ada.Sequential_IO;
with Interfaces.C;

procedure Main is

   package C renames Interfaces.C;
   use type C.unsigned_short;
   use type C.int;

   --  Input event codes (linux/input-event-codes.h)

   EV_SYN      : constant := 16#00#;
   EV_KEY      : constant := 16#01#;
   EV_REL      : constant := 16#02#;
   EV_ABS      : constant := 16#03#;
   EV_MSC      : constant := 16#04#;
   
   BTN_MOUSE   : constant := 16#110#;
   BTN_LEFT    : constant := 16#110#;
   BTN_RIGHT   : constant := 16#111#;
   BTN_MIDDLE  : constant := 16#112#;

   REL_X       : constant := 16#00#;
   REL_Y       : constant := 16#01#;
   REL_WHEEL   : constant := 16#08#;
   
   -- Time value (sys/time.h)

   subtype suseconds_t is C.long;
   subtype time_t      is C.long;

   type timeval is record
      tv_sec  : time_t;
      tv_usec : suseconds_t;
   end record;
   pragma Convention (C, timeval);

   -- Input event struct (linux/input.h)

   type input_event is record
      time  : timeval;
      typ   : C.unsigned_short;
      code  : C.unsigned_short;
      value : C.int;
   end record;
   pragma Convention (C, input_event);

   --  ... and a package instantiation for sequential IO.

   package Input_Event_IO is new Ada.Sequential_IO (input_event);
   use Input_Event_IO;


   File  : File_Type;
   Event : input_event;

   --  Position of the mouse and wheel.
   X, Y, W : C.int := 0;

begin

   Open (File, In_File, "/dev/input/event0");

   --  Infinite loop, use Ctrl-C to exit.
   loop

      --  Wait for a new event.
      Read (File, Event);

      --  Process the event.
      case Event.typ is
         
         when EV_SYN =>
            Ada.Text_IO.Put_Line 
              (X'Image & "," & Y'Image & " [" & W'Image & "]");

         when EV_KEY =>            
            case Event.code is
               when BTN_LEFT => 
                  Ada.Text_IO.Put_Line ("Left button.");
               when BTN_MIDDLE => 
                  Ada.Text_IO.Put_Line ("Middle button.");
               when BTN_RIGHT => 
                  Ada.Text_IO.Put_Line ("Right button.");
               when others =>
                  null;
            end case;

         when EV_REL =>
            case Event.code is
               when REL_X =>
                  X := X + Event.value;
               when REL_Y =>
                  Y := Y + Event.value;
               when REL_WHEEL =>
                  W := W + Event.value;
               when others =>
                  null;
            end case;

         when EV_ABS =>
            case Event.code is
               when REL_X =>
                  X := Event.value;
               when REL_Y =>
                  Y := Event.value;
               when REL_WHEEL =>
                  W := Event.value;
               when others =>
                  null;
            end case;
         
         when others =>
            null;
         
      end case;

   end loop;

end Main;

output (running on a headless RPi 3)

pi@raspberrypi:~/mouse $ sudo obj/main
[...]
-85, 9 [-5]
-84, 9 [-5]
-83, 9 [-5]
Left button.
-83, 9 [-5]
Left button.
-83, 9 [-5]
Left button.
-83, 9 [-5]
Left button.
-83, 9 [-5]
Right button.
-83, 9 [-5]
Right button.
-83, 9 [-5]
Middle button.
-83, 9 [-5]
Middle button.
-83, 9 [-5]
-84, 9 [-5]
^C
pi@raspberrypi:~/mouse $ 

Upvotes: 0

user1818839
user1818839

Reputation:

It would be useful to know OS, version, compiler, window manager toolkit and version. For example I'm running Debian 10, and with Gnome 3 as my WM I can most easily access the mouse using the GTKAda toolkit. Last time I wrote code directly accessing a mouse was on DOS, in Modula-2.

However, GTKAda is not particularly easy to learn...

If you're willing to use a web browser as the GUI to your app (which also helps portability across systems ... you might even run the app on a PC but access it via a tablet or phone, giving you a touchscreen!) I recommend looking at Gnoga available from www.gnoga.com. Take a look at some of its tutorials, they should be easy to build and get you started accessing mouse and simple drawing.

EDIT

Having found the magic words (Centos, ncurses) in various comments (which you could usefully add to the question, in case there are better answers) what you are looking for is an Ada binding to ncurses such as this one. This binding is part of the official ncurses source since version 5.8 so should already be available on Centos.

It should then be a simple matter of writing a Read procedure which calls the ncurses mouse handling package, returning mouse position (scaled to an 8-bit Integer or Natural, and probably offset from the console window origin) whenever the LH button is pressed, otherwise presumably returning ... whatever an OUT parameter is initialised to, (presumably BYTE'FIRST)

Job done.

Now we can see the touch screen filename si part of the /dev/ hierarchy it may be even simpler to see if there is any mileage in finding documentation on /dev/mouse as @zerte suggests (or /dev/input/mouse[0|1] on my laptop) ... but I think ncurses will be less machine-dependent.

Upvotes: 4

Related Questions