Reputation: 87
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
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
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
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