1 -------------------------------------------------
2 -- exported functions used by the mag logic
3 -------------------------------------------------
6 local string = require "string"
7 local table = require "table"
9 Mag.user_state = Mag.get_user_state();
11 -- handle an incoming event
12 function handle_event(ev)
13 -- print("handle_event", ev[1], ev[2], ev[3], ev[4], ev[5], ev[6]);
14 -- 1: type, 2: code, 3: value, 4: time, 5: device_id, 6: source
15 local l4re_syn_stream_cfg = (ev[1] == 0 and ev[2] == 0x80);
16 local l4re_close_stream = l4re_syn_stream_cfg and ev[3] == 1;
19 local ddh = Mag.sources[source];
21 if (l4re_close_stream) then
24 Mag.sources[source] = {};
25 ddh = Mag.sources[source];
28 local dh = ddh[stream];
30 if l4re_close_stream then
33 dh = Mag.create_input_device(source, stream);
36 -- print ("EV: ", ev[1], ev[2], ev[3], ev[4], ev[5], ev[6]);
37 -- print(string.format("src=[%s:%s]: type=%x code=%x val=%x (time=%d)", tostring(ev[6]), tostring(ev[5]), ev[1], ev[2], ev[3], ev[4]));
39 if l4re_close_stream then
44 -- mag requests infos about a specific input event stream
45 function input_source_info(global_id)
46 -- print "input_source_info";
47 local device = Mag.streams[global_id];
52 return device.handler.get_stream_info(device);
55 -- mag requests infos about a specific input event stream
56 function input_source_abs_info(global_id, ...)
57 -- print "input_source_abs_info";
58 local device = Mag.streams[global_id];
63 return device.handler.get_abs_info(device, ...);
68 -------------------------------------------------
69 -- The internals of our event handling module
70 -------------------------------------------------
74 local Mag_mt = getmetatable(Mag);
75 local orig_Mag_index = Mag_mt.__index;
76 local function Mag_index(table, key)
77 local o = orig_Mag_index(table, key);
83 Mag_mt.__index = Mag_index;
86 -- mag will initialize the variable 'user_state' to refer to
87 -- mag's user state object.
203 KATAKANAHIRAGANA = 93,
328 BRIGHTNESSDOWN = 224,
331 SWITCHVIDEOMODE = 227,
332 KBDILLUMTOGGLE = 228,
475 MT_TOUCH_MAJOR = 0x30,
476 MT_TOUCH_MINOR = 0x31,
477 MT_WIDTH_MAJOR = 0x32,
478 MT_WIDTH_MINOR = 0x33,
479 MT_ORIENTATION = 0x34,
480 MT_POSITION_X = 0x35,
481 MT_POSITION_Y = 0x36,
484 MT_TRACKING_ID = 0x39,
546 TOOL_AIRBRUSH = 0x144,
553 TOOL_DOUBLETAP = 0x14d,
554 TOOL_TRIPLETAP = 0x14e,
561 -- stores all kown input devices
572 [0x05] = "bluetooth",
610 function Input_device:drop_event(e)
614 function Input_device:get_stream_info()
615 return self.source:get_stream_info(self.stream);
618 function Input_device:get_abs_info(...)
619 return self.source:get_abs_info(self.stream, ...);
623 function Input_device:init()
624 self.current_report = Hid_report(self.global_id, 0x10, 0x29, 0x8, 0x10, 0x10 );
627 function Input_device:process_event(ev)
628 local r = self.current_report;
639 elseif t > 1 and t <=5 then
641 elseif t == 0 and c == 2 then -- mt sync
643 elseif t == 0 and c == 0 then -- full sync
647 elseif t == 0 and c == 0x80 then -- l4re syn cfg
649 for s in Mag.core_api:sessions() do
650 s:put_event(self.global_id, t, c, ev[3], ev[4]);
655 -- ----------------------------------------------------------------------
656 -- Generic pointer device handling.
658 -- Handles absolute and relative motion events and the buttons
659 -- corresponding to a pointer device, such as a mouse.
660 -- ----------------------------------------------------------------------
661 Input_device.Devs.pointer = {};
663 Input_device.Devs.pointer.drag_focus = View_proxy(user_state);
665 function Input_device.new_virt_ctrl(_axes, _core)
666 local ctrl = { axes = _axes, core = _core };
667 for _, a in pairs(_axes) do
673 local screen_width, screen_height = user_state:screen_size()
675 Input_device.core_ctrl = Input_device.new_virt_ctrl(
676 { x = { idx = Event.Abs.X, min = 0, max = screen_width,
677 fuzz = 0, flat = 0, mode = 1, v = 0 },
678 y = { idx = Event.Abs.Y, min = 0, max = screen_height,
679 fuzz = 0, flat = 0, mode = 2, v = 0 } }, true);
681 function Input_device.Devs.pointer:init()
682 Input_device.init(self);
683 self.pointed_view = View_proxy(user_state);
685 -- get core pointer control descriptions for x and y axis
686 local core_ctrl = Input_device.core_ctrl;
688 self.xfrm_abs_axes = {};
690 local d_info = self.info;
692 if d_info:get_absbit(0) and d_info:get_absbit(1) then
693 -- we transfrom the absolute x and y axes of this device to core control
695 self.xfrm_abs_axes[#self.xfrm_abs_axes] =
696 { x = Event.Abs.X, y = Event.Abs.Y,
697 -- we have our abs x and abs y axis controling our core pointer
698 core_x = core_ctrl.axes.x, core_y = core_ctrl.axes.y,
699 xfrm = self:get_pointer_transform_func(Event.Abs.X, Event.Abs.Y) };
702 self.virt_ctrls = { core_ctrl };
704 self.vaxes = { [Event.Abs.X] = core_ctrl.axes.x,
705 [Event.Abs.Y] = core_ctrl.axes.y };
707 self.rel_to_abs_axes = { [Event.Rel.X] = { va = core_ctrl.axes.x, ctrl = core_ctrl },
708 [Event.Rel.Y] = { va = core_ctrl.axes.y, ctrl = core_ctrl } };
710 local abs_info = Axis_info_vector(0x40);
711 self.current_report:set_abs_info(abs_info);
712 self.abs_info = abs_info;
714 if d_info:get_absbit(a) then
715 local r, i = self:get_abs_info(a);
723 abs_info[0].mode = 1;
726 abs_info[1].mode = 2;
729 if d_info:get_absbit(0x35) and d_info:get_absbit(0x36) then
730 local mt_ctrl = Input_device.new_virt_ctrl(
731 { x = { idx = 0x35, min = 0, max = screen_width,
732 fuzz = 0, flat = 0, mode = 1, v = 0 },
733 y = { idx = 0x36, min = 0, max = screen_height,
734 fuzz = 0, flat = 0, mode = 2, v = 0 } })
735 self.xfrm_abs_axes[#self.xfrm_abs_axes + 1] =
736 { x = 0x35, y = 0x36, xfrm = self:get_pointer_transform_func(0x35, 0x36) };
737 self.vaxes[0x35] = mt_ctrl.axes.x;
738 self.vaxes[0x36] = mt_ctrl.axes.y;
739 abs_info[0x35].mode = 1;
740 abs_info[0x36].mode = 2;
743 for a, i in pairs(self.vaxes) do
744 if (not abs_info[a]) then
745 local ai = abs_info:create(a);
746 ai.value = i.value or 0;
749 ai.fuzz = i.fuzz or 0;
750 ai.resolution = i.resolution or 0;
751 ai.delta = i.delta or 0;
752 ai.mode = i.mode or 0;
757 function Input_device.Devs.pointer:get_stream_info()
758 local r, info = self:get_stream_info();
764 -- This device is translated to a core pointer
765 -- this means it sends always absolute X,Y axis pairs
767 info:set_evbit(Event.ABS, true);
768 for a, _ in pairs(self.vaxes) do
769 info:set_absbit(a, true);
773 if self.rel_to_abs_axes then
774 for a, _ in pairs(self.rel_to_abs_axes) do
775 info:set_relbit(a, false);
782 function Input_device.Devs.pointer:get_abs_info(...)
785 local vaxes = self.vaxes;
788 for _, s in ipairs(axes) do
792 r[_] = self.abs_info[s];
798 return (vaxes ~= nil), table.unpack(r);
801 -- generic transformationof absolute pointer events to screen coordinates
802 function Input_device:get_pointer_transform_func(ax, ay)
803 -- transformation of raw coordinates to screen coordinates
804 local w, h = user_state:screen_size();
805 return function(self, p)
806 if self.abs_info then
807 return (p[1] * w) // self.abs_info[ax].delta,
808 (p[2] * h) // self.abs_info[ay].delta;
815 -- ----------------------------------------------------------------
816 -- sync a set of events from a pointer device
818 -- - converts motion events to the core mouse pointer of mag
819 -- - manages dragging and keyboard focus
822 Input_device.Default = {};
824 function Input_device.Default:axis_xfrm(report)
825 local function do_xfrm_axes(xfrm_axes, axes)
826 if not axes then return end
827 for i, cax in pairs(xfrm_axes) do
828 local x = axes[cax.x];
829 local y = axes[cax.y];
831 x, y = cax.xfrm(self, {x, y});
834 local ca = cax.core_x;
837 ca.ctrl.update = true;
839 local ca = cax.core_y;
842 ca.ctrl.update = true;
848 -- scale and rotate absolute axes
849 local abs = report[3];
850 do_xfrm_axes(self.xfrm_abs_axes, abs);
852 do_xfrm_axes(self.xfrm_abs_axes, report:get_mt_vals(id));
855 -- transform relative to absolute axes if needed
856 local rel = report[2];
858 for a, inf in pairs(self.rel_to_abs_axes) do
862 local vctrl = inf.ctrl;
877 -- write back virtual controls if they are dirty
879 for c, vc in pairs(self.virt_ctrls) do
880 for i, va in pairs(vc.axes) do
881 abs:set(va.idx, va.v);
884 vc.update = true; -- if its a core control we need an update
891 function Input_device.Default:foreach_key(report, func)
894 local c, v = report:get_key_event(i);
898 if func(self, c, v) then
905 function Input_device.Default:do_core_ctrl()
906 local cctrl = Input_device.core_ctrl;
908 cctrl.update = false;
909 local x, y = cctrl.axes.x.v, cctrl.axes.y.v;
910 user_state:set_pointer(x, y, self.hide_cursor or false);
911 user_state:find_pointed_view(self.pointed_view); -- should need x and y here
915 function Input_device.Default:core_keys(report)
916 local toggle_mode = 0;
917 local function xray_key(s, c, v)
921 return (c == 70) or (c == Event.Key.NEXTSONG);
924 local function kill_key(s, c, v)
928 return (c == 210) or (c == 99);
931 local fek = Input_device.Default.foreach_key;
933 if fek(self, report, xray_key) then
935 elseif fek(self, report, kill_key) then
938 if toggle_mode ~= 0 then
939 user_state:toggle_mode(toggle_mode);
945 function Input_device.Default:dnd_handling()
946 local ptr = Input_device.Devs.pointer;
948 if ptr.dragging == self and self.stop_drag then
949 ptr.dragging = false;
951 self.stop_drag = false;
952 return ptr.drag_focus;
954 return self.pointed_view;
958 function Input_device.Devs.pointer:hook(report)
961 local function k(s, c, v)
963 n_press = n_press + 1;
965 n_release = n_release + 1;
968 Input_device.Default.foreach_key(self, report, k);
970 local n = self.pressed_keys + n_press - n_release;
975 self.pressed_keys = n;
977 local ptr = Input_device.Devs.pointer;
979 if (not ptr.dragging) and n_press > 0 and n == n_press then
981 ptr.drag_focus:set(self.pointed_view);
982 self.set_focus = true;
983 elseif n_release > 0 and n == 0 then
984 self.stop_drag = true;
988 function Input_device.Devs.pointer:process(report)
989 local update = false;
991 local dfl = Input_device.Default;
993 dfl.axis_xfrm(self, report);
994 dfl.do_core_ctrl(self);
996 if self.handler.hook then
997 self.handler.hook(self, report);
1000 sink = dfl.dnd_handling(self);
1001 -- for keyboards: update = dfl.core_keys(self, report);
1002 if self.set_focus then
1003 update = user_state:set_kbd_focus(self.pointed_view) or update;
1004 self.set_focus = false;
1006 user_state:post_event(sink, report, update, true);
1010 Input_device.Devs.touchscreen = {};
1011 setmetatable(Input_device.Devs.touchscreen, { __index = Input_device.Devs.pointer});
1013 function Input_device.Devs.touchscreen:init()
1014 Input_device.Devs.pointer.init(self);
1015 self.hide_cursor = true;
1018 function Input_device.Devs.touchscreen:get_stream_info()
1019 local r, info = Input_device.Devs.pointer.get_stream_info(self);
1025 -- additionally we have a left button, but no longer the touch button
1026 --info:set_keybit(Event.Btn.TOUCH, false);
1027 --info:set_keybit(Event.Btn.LEFT, true);
1031 function Input_device.Devs.touchscreen:button(e)
1034 if c == Event.Btn.TOUCH then
1035 e[2] = Event.Btn.LEFT;
1037 Input_device.Devs.pointer.button(self, e);
1040 -- ----------------------------------------------------------------------
1041 -- Touchpad pointing device handling
1042 -- Inherits from pointer device and adds functionality to:
1043 -- - transform absolute finger positions to relative movements
1044 -- - tapping button emulation (missing)
1045 -- - scroll wheel emulation etc (missing)
1046 -- ----------------------------------------------------------------------
1047 Input_device.Devs.touchpad = {};
1048 setmetatable(Input_device.Devs.touchpad, { __index = Input_device.Devs.pointer});
1050 function Input_device.Devs.touchpad:init()
1051 Input_device.Devs.pointer.init(self);
1056 tap_time = 150 * 1000; -- 150 ms
1057 btn_report = Hid_report(self.global_id,0,0,0,0,0);
1059 local tdev = self.touchdev;
1060 tdev.p = { Axis_buf(4), Axis_buf(4) };
1064 function Input_device.Devs.touchpad:get_stream_info()
1065 local r, info = Input_device.Devs.pointer.get_stream_info(self);
1071 -- additionally we have a left button, but no longer the touch button
1072 info:set_keybit(Event.Btn.LEFT, true);
1073 info:set_keybit(Event.Btn.TOOL_FINGER, false);
1074 info:set_keybit(Event.Btn.TOOL_PEN, true);
1076 -- hm, X does not like to have MT values if we do not send them
1077 info:set_absbit(0x2f, false);
1078 info:set_absbit(0x30, false);
1079 info:set_absbit(0x31, false);
1080 info:set_absbit(0x32, false);
1081 info:set_absbit(0x33, false);
1082 info:set_absbit(0x34, false);
1083 info:set_absbit(0x35, false);
1084 info:set_absbit(0x36, false);
1085 info:set_absbit(0x37, false);
1086 info:set_absbit(0x38, false);
1087 info:set_absbit(0x39, false);
1088 info:set_absbit(0x3a, false);
1089 info:set_absbit(0x3b, false);
1094 function Input_device.Devs.touchpad:button(r)
1095 local c, v = r:find_key_event(Event.Btn.TOUCH);
1096 if not v or v == 2 then
1100 local time = r:time();
1101 local p = self.touchdev;
1103 -- drop the touch event, we convert it to left mouse button
1104 --r[1][Event.Btn.TOUCH] = nil;
1105 r:remove_key_event(Event.Btn.TOOL_FINGER);
1108 if p.release and p.release + p.tap_time > time then
1109 p.touch_drag = true;
1110 r:add_key(Event.Btn.LEFT, 1);
1115 if p.touch_drag then
1116 p.touch_drag = false;
1117 r:add_key(Event.Btn.LEFT, 0);
1118 elseif p.touch and p.touch + p.tap_time > time then
1121 local dr = p.btn_report;
1125 dr:add_key(Event.Btn.LEFT, 1);
1128 r:add_key(Event.Btn.LEFT, 0);
1135 function Input_device.Devs.touchpad:motion(r)
1136 local p = self.touchdev;
1138 -- drop event, if not touched
1151 local size = self.abs_info[c-1].delta;
1152 r[2]:set(c-1, (v - p.p[c]:get(cnt - 2)) * 256 // size);
1158 local nc = p.pkts + 1;
1160 p.p[1]:copy(nc, nc - 1);
1161 p.p[2]:copy(nc, nc - 1);
1164 function Input_device.Devs.touchpad:process(r)
1165 Input_device.Devs.touchpad.button(self, r);
1166 Input_device.Devs.touchpad.motion(self, r);
1167 Input_device.Devs.pointer.process(self, r)
1170 -- ----------------------------------------------------------------------
1171 -- Keyboard device handling
1172 -- ----------------------------------------------------------------------
1173 Input_device.Devs.keyboard = {};
1174 setmetatable(Input_device.Devs.keyboard, { __index = Input_device });
1176 function Input_device.Devs.keyboard:get_stream_info()
1177 return self:get_stream_info();
1180 function Input_device.Devs.keyboard:get_abs_info(...)
1181 return self:get_abs_info(...);
1184 function Input_device.Devs.keyboard:process(report)
1185 local dfl = Input_device.Default;
1187 if self.handler.hook then
1188 self.handler.hook(self, report);
1190 local update = dfl.core_keys(self, report);
1191 user_state:post_event(nil, report, update, true);
1194 Input_device.Devs.unknown = Input_device;
1196 function Input_device:find_device_type()
1197 local bus, vend, prod, ver = self.info:get_device_id();
1198 self.dev_id = { bus = bus, vendor = vend, product = prod, version = ver };
1199 local id = bus .. "_" .. vend .. "_" .. prod;
1201 self.dev_type = "unknown";
1203 if self.quirks[id] and self.quirks[id](self, id) then
1207 id = id .. "_" .. ver;
1209 if self.quirks[id] and self.quirks[id](self, id) then
1213 local have_keys = self.info:get_evbit(1);
1214 if (have_keys and self.info:get_evbit(2)) then
1215 -- we have relative axes, can be a mouse
1216 if (self.info:get_relbit(0) and self.info:get_relbit(1)
1217 and self.info:get_keybit(0x110)) then
1218 -- x and y axis and at least the left mouse button found
1219 self.dev_type = "pointer";
1222 if (have_keys and self.info:get_evbit(3)) then
1223 -- we have absolute axes, can be a mouse
1224 if self.info:get_absbit(0) and self.info:get_absbit(1) then
1225 if self.info:get_keybit(0x110) then
1226 -- x and y axis and at least the left mouse button found
1227 self.dev_type = "pointer";
1229 if self.info:get_keybit(Event.Btn.TOUCH)
1230 and not self.info:get_keybit(0x110) then
1231 -- x and y axis and at least touch button found
1232 self.dev_type = "touchscreen";
1237 if self.dev_type == "pointer" then
1238 if self.info:get_keybit(Event.Btn.TOOL_FINGER) then
1239 self.dev_type = "touchpad";
1246 if (self.info:get_keybit(k)) then
1247 self.dev_type = "keyboard";
1254 function Input_device:delete()
1255 streams[self.global_id] = nil;
1256 sources[self.source][self.stream] = nil;
1257 print (string.format([==[Input: remove device (src='%s' stream='%s')]==],
1258 tostring(self.source), tostring(self.stream)));
1264 -- -----------------------------------------------------------------------
1265 -- Create a input device (stream) object.
1266 -- A single input stream is managed by a device specific set of
1267 -- methods and data structures.
1268 -- -----------------------------------------------------------------------
1269 local input_device_mt = { __index = Input_device };
1271 function create_input_device(source, stream)
1273 -- the device handle itself
1276 global_id = #streams + 1;
1278 -- number of keys currently pressed on this device
1281 -- data according to the current bundle of events (one comound event)
1282 -- need to set the focus to the pointed view
1284 -- the current events stop dragging mode
1286 -- the events to pass to the applications
1288 -- event handler for the device
1289 process = Input_device.drop_event
1292 setmetatable(dh, input_device_mt);
1295 r, dh.info = dh:get_stream_info();
1297 sources[source][stream] = dh;
1298 streams[dh.global_id] = dh;
1300 dh:find_device_type();
1301 dh.handler = Input_device.Devs[dh.dev_type] or {};
1302 dh.process = dh.handler.process or Input_device.drop_event;
1303 if dh.handler.init then dh.handler.init(dh); end
1307 local a, b, c, d = dh.info:get_device_id();
1308 if Input_device.Bus[a] then
1309 return Input_device.Bus[a], b, c, d;
1311 return "bus " .. a, b, c, d;
1314 print (string.format([==[Input: new %s device (src='%s' stream='%s')
1315 bus='%s' vendor=0x%x product=0x%x version=%d]==],
1316 dh.dev_type, tostring(dh.source), tostring(dh.stream),