#!/opt/lnxall_app/bin/lua

-- Created by jiaqiang.ye@lnxall.com
-- Simple Touchscreen press emulator
-- 2025/11/25

local struct = require 'struct'
local invoker = require 'invoker'

local gfmt = string.format
local g_fd = nil
local g_dev = nil

local EV_ABS               = 3
local ABS_MT_TRACKING_ID   = 57
local ABS_MT_POSITION_X    = 53
local ABS_MT_POSITION_Y    = 54
local EV_KEY               = 1
local BTN_TOUCH            = 330
local ABS_X                = 0
local ABS_Y                = 1
local EV_MSC               = 4
local MSC_TIMESTAMP        = 5
local UP                   = 0
local DOWN                 = 1
local EV_SYN               = 0
local SYN_REPORT           = 0
local MSC_SCAN             = 4
local KEY_LEFTALT          = 0x38
local KEY_F9               = 0x43
local KEY_LEFTMETA         = 0x7d

local g_key0 = KEY_LEFTMETA
-- /dev/input/event3: 0004 0004 000700e3
-- /dev/input/event3: 0001 007d 00000001
-- /dev/input/event3: 0000 0000 00000000
-- /dev/input/event3: 0004 0004 000700e3
-- /dev/input/event3: 0001 007d 00000000
-- /dev/input/event3: 0000 0000 00000000
-- 
-- /dev/input/event3: EV_MSC       MSC_SCAN             000700e3
-- /dev/input/event3: EV_KEY       KEY_LEFTMETA         DOWN
-- /dev/input/event3: EV_SYN       SYN_REPORT           00000000
-- /dev/input/event3: EV_MSC       MSC_SCAN             000700e3
-- /dev/input/event3: EV_KEY       KEY_LEFTMETA         UP
-- /dev/input/event3: EV_SYN       SYN_REPORT           00000000

local function press_init()
	local dev = arg[1]
	if invoker.statfile(dev) ~= "character" then
		local _, output = invoker.invoke(invoker.OUTPUT,
			"/bin/bash", "-c", "libinput list-devices 2>/dev/null | grep -A 1 -e 'Keyboard emulator'")
		if type(output) ~= "string" then output = "" end
		dev = string.match(output, "Kernel:%s+([^%s]+)")
		if invoker.statfile(dev) ~= "character" then
			io.stderr:write("Error, input device not specified.\n")
			io.stderr:write("Execute command:\n\tinput-emulator start kbd\n")
			io.stderr:flush()
			return false
		end
	end
	g_dev = dev

	local keyv = arg[2]
	if keyv and #keyv > 0 then keyv = tonumber(keyv) end
	if type(keyv) == "number" and keyv >= 0 then g_key0 = keyv end

	io.stdout:write(gfmt("Press key: 0x%x -> %s\n",
		g_key0, dev))
	io.stdout:flush()
	return true
end

local function open_device()
	local fd = invoker.open(g_dev, 524290)
	if not fd then
		io.stderr:write(gfmt("Eror, failed to open device: %s\n", g_dev))
		io.stderr:flush()
		return false
	end
	g_fd = fd
	return true
end

local function write_event(evkey, evcode, value)
	local ups, upm = invoker.uptime()
	local wbuf = struct.pack("<I8I8HHi4", ups, upm * 1000, evkey, evcode, value)
	if invoker.writefd(g_fd, wbuf) ~= #wbuf then
		io.stderr:write("Error, write Event has failed.\n")
		io.stderr:flush()
		return false
	end
	return true
end

local function touchscreen(key0)
	write_event(EV_MSC, MSC_SCAN,             0x700e3)
	write_event(EV_KEY, key0,                 DOWN)
	write_event(EV_SYN, SYN_REPORT,           0x0)
	invoker.msleep(60)
	write_event(EV_MSC, MSC_SCAN,             0x700e3)
	write_event(EV_KEY, KEY_LEFTMETA,         UP)
	write_event(EV_SYN, SYN_REPORT,           0x0)
	return true
end

if not press_init() then os.exit(1) end
if not open_device() then os.exit(2) end
touchscreen(g_key0)
os.exit(0)
