1 -------------------------------------------------
2 -- exported functions used by the mag logic
3 -------------------------------------------------
5 Mag.user_state = Mag.get_user_state();
7 -- handle an incoming event
8 function handle_event(ev)
9 -- 1: type, 2: code, 3: value, 4: time, 5: device_id, 6: source
12 local ddh = Mag.sources[source];
14 Mag.sources[source] = {};
15 ddh = Mag.sources[source];
18 local dh = ddh[stream];
20 dh = Mag.create_input_device(source, stream);
23 -- print ("EV: ", ev[1], ev[2], ev[3], ev[4], ev[5], ev[6]);
24 -- 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]));
25 return dh:process_event(ev);
28 -- mag requests infos about a specific input event stream
29 function input_source_info(global_id)
30 local device = Mag.streams[global_id];
35 return device.handler.get_stream_info(device);
38 -- mag requests infos about a specific input event stream
39 function input_source_abs_info(global_id, ...)
40 local device = Mag.streams[global_id];
45 return device.handler.get_abs_info(device, ...);
50 -------------------------------------------------
51 -- The internals of our event handling module
52 -------------------------------------------------
53 module("Mag", package.seeall)
55 -- mag will initialize the variable 'user_state' to refer to
56 -- mag's user state object.
172 KATAKANAHIRAGANA = 93,
297 BRIGHTNESSDOWN = 224,
300 SWITCHVIDEOMODE = 227,
301 KBDILLUMTOGGLE = 228,
444 MT_TOUCH_MAJOR = 0x30,
445 MT_TOUCH_MINOR = 0x31,
446 MT_WIDTH_MAJOR = 0x32,
447 MT_WIDTH_MINOR = 0x33,
448 MT_ORIENTATION = 0x34,
449 MT_POSITION_X = 0x35,
450 MT_POSITION_Y = 0x36,
453 MT_TRACKING_ID = 0x39,
515 TOOL_AIRBRUSH = 0x144,
522 TOOL_DOUBLETAP = 0x14d,
523 TOOL_TRIPLETAP = 0x14e,
530 -- stores all kown input devices
541 [0x05] = "bluetooth",
579 function Input_device:drop_event(e)
583 function Input_device:get_stream_info()
584 return self.source:get_stream_info(self.stream);
587 function Input_device:get_abs_info(...)
588 return self.source:get_abs_info(self.stream, ...);
592 function Input_device:init()
593 self.current_report = Hid_report(self.global_id, 0x10, 0x29, 0x8, 0x10, 0x10 );
596 function Input_device:process_event(ev)
597 local r = self.current_report;
608 elseif t > 1 and t <=5 then
610 elseif t == 0 and c == 2 then -- mt sync
612 elseif t == 0 and c == 0 then -- full sync
619 -- ----------------------------------------------------------------------
620 -- Generic pointer device handling.
622 -- Handles absolute and relative motion events and the buttons
623 -- corresponding to a pointer device, suahc as a mouse.
624 -- ----------------------------------------------------------------------
625 Input_device.Devs.pointer = {};
627 Input_device.Devs.pointer.drag_focus = View_proxy(user_state);
629 function Input_device.new_virt_ctrl(_axes, _core)
630 local ctrl = { axes = _axes, core = _core };
631 for _, a in pairs(_axes) do
637 local screen_width, screen_height = user_state:screen_size()
639 Input_device.core_ctrl = Input_device.new_virt_ctrl(
640 { x = { idx = Event.Abs.X, min = 0, max = screen_width,
641 fuzz = 0, flat = 0, mode = 1, v = 0 },
642 y = { idx = Event.Abs.Y, min = 0, max = screen_height,
643 fuzz = 0, flat = 0, mode = 2, v = 0 } }, true);
645 function Input_device.Devs.pointer:init()
646 Input_device.init(self);
647 self.pointed_view = View_proxy(user_state);
649 -- get core pointer control descriptions for x and y axis
650 local core_ctrl = Input_device.core_ctrl;
652 self.xfrm_abs_axes = {};
654 local d_info = self.info;
656 if d_info:get_absbit(0) and d_info:get_absbit(1) then
657 -- we transfrom the absolute x and y axes of this device to core control
659 self.xfrm_abs_axes[#self.xfrm_abs_axes] =
660 { x = Event.Abs.X, y = Event.Abs.Y,
661 -- we have our abs x and abs y axis controling our core pointer
662 core_x = core_ctrl.axes.x, core_y = core_ctrl.axes.y,
663 xfrm = self:get_pointer_transform_func(Event.Abs.X, Event.Abs.Y) };
666 self.virt_ctrls = { core_ctrl };
668 self.vaxes = { [Event.Abs.X] = core_ctrl.axes.x,
669 [Event.Abs.Y] = core_ctrl.axes.y };
671 self.rel_to_abs_axes = { [Event.Rel.X] = { va = core_ctrl.axes.x, ctrl = core_ctrl },
672 [Event.Rel.Y] = { va = core_ctrl.axes.y, ctrl = core_ctrl } };
674 local abs_info = Axis_info_vector(0x40);
675 self.current_report:set_abs_info(abs_info);
676 self.abs_info = abs_info;
678 if d_info:get_absbit(a) then
679 local r, i = self:get_abs_info(a);
687 abs_info[0].mode = 1;
690 abs_info[1].mode = 2;
693 if d_info:get_absbit(0x35) and d_info:get_absbit(0x36) then
694 local mt_ctrl = Input_device.new_virt_ctrl(
695 { x = { idx = 0x35, min = 0, max = screen_width,
696 fuzz = 0, flat = 0, mode = 1, v = 0 },
697 y = { idx = 0x36, min = 0, max = screen_height,
698 fuzz = 0, flat = 0, mode = 2, v = 0 } })
699 self.xfrm_abs_axes[#self.xfrm_abs_axes + 1] =
700 { x = 0x35, y = 0x36, xfrm = self:get_pointer_transform_func(0x35, 0x36) };
701 self.vaxes[0x35] = mt_ctrl.axes.x;
702 self.vaxes[0x36] = mt_ctrl.axes.y;
703 abs_info[0x35].mode = 1;
704 abs_info[0x36].mode = 2;
708 function Input_device.Devs.pointer:get_stream_info()
709 local r, info = self:get_stream_info();
715 -- This device is translated to a core pointer
716 -- this means it sends always absolute X,Y axis pairs
718 info:set_evbit(Event.ABS, true);
719 for a, _ in pairs(self.vaxes) do
720 info:set_absbit(a, true);
724 if self.rel_to_abs_axes then
725 for a, _ in pairs(self.rel_to_abs_axes) do
726 info:set_relbit(a, false);
733 function Input_device.Devs.pointer:get_abs_info(...)
736 local vaxes = self.vaxes;
739 for _, s in ipairs(axes) do
743 r[_] = self.abs_info[s];
749 return (vaxes ~= nil), unpack(r);
752 -- generic transformationof absolute pointer events to screen coordinates
753 function Input_device:get_pointer_transform_func(ax, ay)
754 -- transformation of raw coordinates to screen coordinates
755 local w, h = user_state:screen_size();
756 return function(self, p)
757 if self.abs_info then
758 return p[1] * w / self.abs_info[ax].delta,
759 p[2] * h / self.abs_info[ay].delta;
766 -- ----------------------------------------------------------------
767 -- sync a set of events from a pointer device
769 -- - converts motion events to the core mouse pointer of mag
770 -- - manages dragging and keyboard focus
773 Input_device.Default = {};
775 function Input_device.Default:axis_xfrm(report)
776 local function do_xfrm_axes(xfrm_axes, axes)
777 if not axes then return end
778 for i, cax in pairs(xfrm_axes) do
779 local x = axes[cax.x];
780 local y = axes[cax.y];
782 x, y = cax.xfrm(self, {x, y});
785 local ca = cax.core_x;
788 ca.ctrl.update = true;
790 local ca = cax.core_y;
793 ca.ctrl.update = true;
799 -- scale and rotate absolute axes
800 local abs = report[3];
801 do_xfrm_axes(self.xfrm_abs_axes, abs);
803 do_xfrm_axes(self.xfrm_abs_axes, report:get_mt_vals(id));
806 -- transform relative to absolute axes if needed
807 local rel = report[2];
809 for a, inf in pairs(self.rel_to_abs_axes) do
813 local vctrl = inf.ctrl;
828 -- write back virtual controls if they are dirty
830 for c, vc in pairs(self.virt_ctrls) do
831 for i, va in pairs(vc.axes) do
832 abs:set(va.idx, va.v);
835 vc.update = true; -- if its a core control we need an update
842 function Input_device.Default:foreach_key(report, func)
845 local c, v = report:get_key_event(i);
849 if func(self, c, v) then
856 function Input_device.Default:do_core_ctrl()
857 local cctrl = Input_device.core_ctrl;
859 cctrl.update = false;
860 local x, y = cctrl.axes.x.v, cctrl.axes.y.v;
861 user_state:set_pointer(x, y, self.hide_cursor or false);
862 user_state:find_pointed_view(self.pointed_view); -- should need x and y here
866 function Input_device.Default:core_keys(report)
867 local toggle_mode = 0;
868 local function xray_key(s, c, v)
872 return (c == 70) or (c == Event.Key.NEXTSONG);
875 local function kill_key(s, c, v)
879 return (c == 210) or (c == 99);
882 local fek = Input_device.Default.foreach_key;
884 if fek(self, report, xray_key) then
886 elseif fek(self, report, kill_key) then
889 if toggle_mode ~= 0 then
890 user_state:toggle_mode(toggle_mode);
896 function Input_device.Default:dnd_handling()
897 local ptr = Input_device.Devs.pointer;
899 if ptr.dragging == self and self.stop_drag then
900 ptr.dragging = false;
902 self.stop_drag = false;
903 return ptr.drag_focus;
905 return self.pointed_view;
909 function Input_device.Devs.pointer:hook(report)
912 local function k(s, c, v)
914 n_press = n_press + 1;
916 n_release = n_release + 1;
919 Input_device.Default.foreach_key(self, report, k);
921 local n = self.pressed_keys + n_press - n_release;
926 self.pressed_keys = n;
928 local ptr = Input_device.Devs.pointer;
930 if (not ptr.dragging) and n_press > 0 and n == n_press then
932 ptr.drag_focus:set(self.pointed_view);
933 self.set_focus = true;
934 elseif n_release > 0 and n == 0 then
935 self.stop_drag = true;
939 function Input_device.Devs.pointer:process(report)
940 local update = false;
942 local dfl = Input_device.Default;
944 dfl.axis_xfrm(self, report);
945 dfl.do_core_ctrl(self);
947 if self.handler.hook then
948 self.handler.hook(self, report);
951 sink = dfl.dnd_handling(self);
952 -- for keyboards: update = dfl.core_keys(self, report);
953 if self.set_focus then
954 update = user_state:set_kbd_focus(self.pointed_view) or update;
955 self.set_focus = false;
957 user_state:post_event(sink, report, update, true);
961 Input_device.Devs.touchscreen = {};
962 setmetatable(Input_device.Devs.touchscreen, { __index = Input_device.Devs.pointer});
964 function Input_device.Devs.touchscreen:init()
965 Input_device.Devs.pointer.init(self);
966 self.hide_cursor = true;
969 function Input_device.Devs.touchscreen:get_stream_info()
970 local r, info = Input_device.Devs.pointer.get_stream_info(self);
976 -- additionally we have a left button, but no longer the touch button
977 --info:set_keybit(Event.Btn.TOUCH, false);
978 --info:set_keybit(Event.Btn.LEFT, true);
982 function Input_device.Devs.touchscreen:button(e)
985 if c == Event.Btn.TOUCH then
986 e[2] = Event.Btn.LEFT;
988 Input_device.Devs.pointer.button(self, e);
991 -- ----------------------------------------------------------------------
992 -- Touchpad pointing device handling
993 -- Inherits from pointer device and adds functionality to:
994 -- - transform absolute finger positions to relative movements
995 -- - tapping button emulation (missing)
996 -- - scroll wheel emulation etc (missing)
997 -- ----------------------------------------------------------------------
998 Input_device.Devs.touchpad = {};
999 setmetatable(Input_device.Devs.touchpad, { __index = Input_device.Devs.pointer});
1001 function Input_device.Devs.touchpad:init()
1002 Input_device.Devs.pointer.init(self);
1007 tap_time = 150 * 1000; -- 150 ms
1008 btn_report = Hid_report(self.global_id,0,0,0,0,0);
1010 local tdev = self.touchdev;
1011 tdev.p = { Axis_buf(4), Axis_buf(4) };
1015 function Input_device.Devs.touchpad:get_stream_info()
1016 local r, info = Input_device.Devs.pointer.get_stream_info(self);
1022 -- additionally we have a left button, but no longer the touch button
1023 info:set_keybit(Event.Btn.LEFT, true);
1024 info:set_keybit(Event.Btn.TOOL_FINGER, false);
1025 info:set_keybit(Event.Btn.TOOL_PEN, true);
1027 -- hm, X does not like to have MT values if we do not send them
1028 info:set_absbit(0x2f, false);
1029 info:set_absbit(0x30, false);
1030 info:set_absbit(0x31, false);
1031 info:set_absbit(0x32, false);
1032 info:set_absbit(0x33, false);
1033 info:set_absbit(0x34, false);
1034 info:set_absbit(0x35, false);
1035 info:set_absbit(0x36, false);
1036 info:set_absbit(0x37, false);
1037 info:set_absbit(0x38, false);
1038 info:set_absbit(0x39, false);
1039 info:set_absbit(0x3a, false);
1040 info:set_absbit(0x3b, false);
1045 function Input_device.Devs.touchpad:button(r)
1046 local c, v = r:find_key_event(Event.Btn.TOUCH);
1047 if not v or v == 2 then
1051 local time = r:time();
1052 local p = self.touchdev;
1054 -- drop the touch event, we convert it to left mouse button
1055 --r[1][Event.Btn.TOUCH] = nil;
1056 r:remove_key_event(Event.Btn.TOOL_FINGER);
1059 if p.release and p.release + p.tap_time > time then
1060 p.touch_drag = true;
1061 r:add_key(Event.Btn.LEFT, 1);
1066 if p.touch_drag then
1067 p.touch_drag = false;
1068 r:add_key(Event.Btn.LEFT, 0);
1069 elseif p.touch and p.touch + p.tap_time > time then
1072 local dr = p.btn_report;
1076 dr:add_key(Event.Btn.LEFT, 1);
1079 r:add_key(Event.Btn.LEFT, 0);
1086 function Input_device.Devs.touchpad:motion(r)
1087 local p = self.touchdev;
1089 -- drop event, if not touched
1102 local size = self.abs_info[c-1].delta;
1103 r[2]:set(c-1, (v - p.p[c]:get(cnt - 2)) * 256 / size);
1109 local nc = p.pkts + 1;
1111 p.p[1]:copy(nc, nc - 1);
1112 p.p[2]:copy(nc, nc - 1);
1115 function Input_device.Devs.touchpad:process(r)
1116 Input_device.Devs.touchpad.button(self, r);
1117 Input_device.Devs.touchpad.motion(self, r);
1118 Input_device.Devs.pointer.process(self, r)
1121 -- ----------------------------------------------------------------------
1122 -- Keyboard device handling
1123 -- ----------------------------------------------------------------------
1124 Input_device.Devs.keyboard = {};
1125 setmetatable(Input_device.Devs.keyboard, { __index = Input_device });
1127 function Input_device.Devs.keyboard:get_stream_info()
1128 return self:get_stream_info();
1131 function Input_device.Devs.keyboard:get_abs_info(...)
1132 return self:get_abs_info(...);
1135 function Input_device.Devs.keyboard:process(report)
1136 local dfl = Input_device.Default;
1138 if self.handler.hook then
1139 self.handler.hook(self, report);
1141 local update = dfl.core_keys(self, report);
1142 user_state:post_event(nil, report, update, true);
1145 Input_device.Devs.unknown = Input_device;
1147 function Input_device:find_device_type()
1148 local bus, vend, prod, ver = self.info:get_device_id();
1149 self.dev_id = { bus = bus, vendor = vend, product = prod, version = ver };
1150 local id = bus .. "_" .. vend .. "_" .. prod;
1152 self.dev_type = "unknown";
1154 if self.quirks[id] and self.quirks[id](self, id) then
1158 id = id .. "_" .. ver;
1160 if self.quirks[id] and self.quirks[id](self, id) then
1164 local have_keys = self.info:get_evbit(1);
1165 if (have_keys and self.info:get_evbit(2)) then
1166 -- we have relative axes, can be a mouse
1167 if (self.info:get_relbit(0) and self.info:get_relbit(1)
1168 and self.info:get_keybit(0x110)) then
1169 -- x and y axis and at least the left mouse button found
1170 self.dev_type = "pointer";
1173 if (have_keys and self.info:get_evbit(3)) then
1174 -- we have absolute axes, can be a mouse
1175 if self.info:get_absbit(0) and self.info:get_absbit(1) then
1176 if self.info:get_keybit(0x110) then
1177 -- x and y axis and at least the left mouse button found
1178 self.dev_type = "pointer";
1180 if self.info:get_keybit(Event.Btn.TOUCH)
1181 and not self.info:get_keybit(0x110) then
1182 -- x and y axis and at least touch button found
1183 self.dev_type = "touchscreen";
1188 if self.dev_type == "pointer" then
1189 if self.info:get_keybit(Event.Btn.TOOL_FINGER) then
1190 self.dev_type = "touchpad";
1197 if (self.info:get_keybit(k)) then
1198 self.dev_type = "keyboard";
1206 -- -----------------------------------------------------------------------
1207 -- Create a input device (stream) object.
1208 -- A single input stream is managed by a device specific set of
1209 -- methods and data structures.
1210 -- -----------------------------------------------------------------------
1211 local input_device_mt = { __index = Input_device };
1213 function create_input_device(source, stream)
1215 -- the device handle itself
1218 global_id = #streams + 1;
1220 -- number of keys currently pressed on this device
1223 -- data according to the current bundle of events (one comound event)
1224 -- need to set the focus to the pointed view
1226 -- the current events stop dragging mode
1228 -- the events to pass to the applications
1230 -- event handler for the device
1231 process = Input_device.drop_event
1234 setmetatable(dh, input_device_mt);
1237 r, dh.info = dh:get_stream_info();
1239 sources[source][stream] = dh;
1240 streams[dh.global_id] = dh;
1242 dh:find_device_type();
1243 dh.handler = Input_device.Devs[dh.dev_type] or {};
1244 dh.process = dh.handler.process or Input_device.drop_event;
1245 if dh.handler.init then dh.handler.init(dh); end
1249 local a, b, c, d = dh.info:get_device_id();
1250 if Input_device.Bus[a] then
1251 return Input_device.Bus[a], b, c, d;
1253 return "bus " .. a, b, c, d;
1256 print (string.format([==[Input: new %s device (src='%s' stream='%s')
1257 bus='%s' vendor=0x%x product=0x%x version=%d]==],
1258 dh.dev_type, tostring(dh.source), tostring(dh.stream),