Skip to content

Instantly share code, notes, and snippets.

@SkyaTura
Created December 7, 2023 12:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SkyaTura/3fd1959c7997206ca2dfce9804af2e2c to your computer and use it in GitHub Desktop.
Save SkyaTura/3fd1959c7997206ca2dfce9804af2e2c to your computer and use it in GitHub Desktop.
Touch driver draft
extern crate enigo;
#[macro_use]
extern crate lazy_static;
use enigo::*;
use std::collections::HashMap;
use std::sync::Mutex;
lazy_static! {
static ref ENUM_MAP_COORDINATE: Mutex<HashMap<i8, Coordinate>> = {
let mut m = HashMap::new();
m.insert(1, Coordinate::Abs);
m.insert(2, Coordinate::Rel);
Mutex::new(m)
};
static ref ENUM_MAP_BUTTON: Mutex<HashMap<i8, Button>> = {
let mut m = HashMap::new();
m.insert(1, Button::Left);
m.insert(2, Button::Middle);
m.insert(3, Button::Right);
Mutex::new(m)
};
static ref ENUM_MAP_DIRECTION: Mutex<HashMap<i8, Direction>> = {
let mut m = HashMap::new();
m.insert(1, Direction::Press);
m.insert(2, Direction::Release);
m.insert(3, Direction::Click);
Mutex::new(m)
};
static ref ENUM_MAP_AXIS: Mutex<HashMap<i8, Axis>> = {
let mut m = HashMap::new();
m.insert(1, Axis::Horizontal);
m.insert(2, Axis::Vertical);
Mutex::new(m)
};
}
fn parse_coordinate(num: i8) -> Result<Coordinate, &'static str> {
let map = ENUM_MAP_COORDINATE.lock().unwrap();
map.get(&num).cloned().ok_or("invalid enum variant")
}
fn parse_button(num: i8) -> Result<Button, &'static str> {
let map = ENUM_MAP_BUTTON.lock().unwrap();
map.get(&num).cloned().ok_or("invalid enum variant")
}
fn parse_direction(num: i8) -> Result<Direction, &'static str> {
let map = ENUM_MAP_DIRECTION.lock().unwrap();
map.get(&num).cloned().ok_or("invalid enum variant")
}
fn parse_axis(num: i8) -> Result<Axis, &'static str> {
let map = ENUM_MAP_AXIS.lock().unwrap();
map.get(&num).cloned().ok_or("invalid enum variant")
}
#[no_mangle]
pub extern "C" fn move_mouse(x: i32, y: i32, coordinate: i8) -> bool {
let coordinate_enum = match parse_coordinate(coordinate) {
Ok(coord) => coord,
Err(_) => return false,
};
let mut enigo = match Enigo::new(&Settings::default()) {
Ok(enigo) => enigo,
Err(_) => return false,
};
enigo.move_mouse(x, y, coordinate_enum).is_ok()
}
#[no_mangle]
pub extern "C" fn button(button: i8, direction: i8) -> bool {
let button_enum = match parse_button(button) {
Ok(button) => button,
Err(_) => return false,
};
let direction_enum = match parse_direction(direction) {
Ok(direction) => direction,
Err(_) => return false,
};
let mut enigo = match Enigo::new(&Settings::default()) {
Ok(enigo) => enigo,
Err(_) => return false,
};
enigo.button(button_enum, direction_enum).is_ok()
}
#[no_mangle]
pub extern "C" fn scroll(amount: i32, axis: i8) -> bool {
let axis_enum = match parse_axis(axis) {
Ok(axis) => axis,
Err(_) => return false,
};
let mut enigo = match Enigo::new(&Settings::default()) {
Ok(enigo) => enigo,
Err(_) => return false,
};
enigo.scroll(amount, axis_enum).is_ok()
}
import { dlopen, FFIType } from "bun:ffi";
import path from "../libenigo_wrapper.dylib";
// console.log('aaaa', path.replace('compiled://root/', './'))
// const path = '../libenigo_wrapper.dylib'
const lib = dlopen(path, {
move_mouse: {
args: [FFIType.i32, FFIType.i32, FFIType.i8],
returns: FFIType.bool,
},
button: {
args: [FFIType.i8, FFIType.i8],
returns: FFIType.bool,
},
scroll: {
args: [FFIType.i32, FFIType.i8],
returns: FFIType.bool,
},
})
// const lib = {
// symbols: {
// move_mouse: (x: number, y: number, coordinate: Coordinate) => true,
// button: (button: Button, direction: Direction) => true,
// scroll: (amount: number, axis: Axis) => true,
// }
// }
export const Coordinate = {
Abs: 1,
Rel: 2,
}
export type Coordinate = typeof Coordinate[keyof typeof Coordinate]
export const Button = {
Left: 1,
Middle: 2,
Right: 3,
}
export type Button = typeof Button[keyof typeof Button]
export const Axis = {
Vertical: 1,
Horizontal: 2,
}
export type Axis = typeof Axis[keyof typeof Axis]
export const Direction = {
Press: 1,
Release: 2,
Click: 3,
}
export type Direction = typeof Direction[keyof typeof Direction]
export const Enigo = {
moveMouse: (x: number, y: number, coordinate: Coordinate) => lib.symbols.move_mouse(x, y, coordinate),
button: (button: Button, direction: Direction) => lib.symbols.button(button, direction),
scroll: (amount: number, axis: Axis) => lib.symbols.scroll(amount, axis),
}
import { HID, devices as Devices } from 'node-hid'
import { Button, Direction, Enigo } from './enigo'
const DEBUG = false
const log = (...args: any[]) => {
if (!DEBUG) return
console.log(...args)
}
const TOUCH_DATA_HEADER = 1
const TOUCH_DATA_LENGTH = 7
const TOUCH_INDEX_STATE = 0
const TOUCH_INDEX_X = 2
const TOUCH_INDEX_Y = 4
const TOUCH_CALIBRATION_X = 2046
const TOUCH_CALIBRATION_Y = 2040
const PRECISION = 1000
const getCalibrated = (value: number, calibration: number) => Math.min(100, Math.max(0, Math.floor(value / calibration * PRECISION) / PRECISION))
const readTouchData = (buffer: Buffer, finger = 0) => {
const offset = TOUCH_DATA_HEADER + finger + TOUCH_DATA_LENGTH * finger
const state = buffer.readInt8(offset + TOUCH_INDEX_STATE) === 1
if (!state) return { state, xRaw: 0, yRaw: 0, xPos: 0, yPos: 0 }
const xRaw = buffer.readInt16LE(offset + TOUCH_INDEX_X)
const yRaw = buffer.readInt16LE(offset + TOUCH_INDEX_Y)
const xPos = getCalibrated(xRaw, TOUCH_CALIBRATION_X)
const yPos = getCalibrated(yRaw, TOUCH_CALIBRATION_Y)
return { state, xRaw, yRaw, xPos, yPos }
}
const devices = Devices()
const deviceMeta = devices.find(item => item.product === 'USB2IIC_CTP_CONTROL')
if (!deviceMeta?.path) {
console.error('device not found')
throw new Error('device not found')
}
const device = new HID(deviceMeta.path)
let state = false
let mouse = false
let canmove = true
let start: null | [number, number] = null
let canclick = true
let thread: null | symbol = null
const reset = () => {
state = false
mouse = false
canmove = true
start = null
canclick = true
thread = null
log('reseting states')
}
device.on('data', (data) => {
try {
const touchData = readTouchData(data, 0)
if (!touchData.state) {
if (state && canmove) {
log('touch finised')
if (canclick) {
if (mouse) {
Enigo.button(Button.Left, Direction.Release)
log('release')
} else {
Enigo.button(Button.Left, Direction.Click)
log('click')
}
} else {
log('no click')
}
}
reset()
return
}
if (!canmove) return
Enigo.moveMouse(
54 + touchData.xPos * 1920,
1333 + touchData.yPos * 1080,
1
)
if (!mouse) {
const biggestDiff = !start ? 0 : Math.max(
Math.abs(touchData.xPos - start[0]),
Math.abs(touchData.yPos - start[1])
)
if (biggestDiff > 0.1) {
// log(biggestDiff, start, touchData.xPos, touchData.yPos)
canclick = false
}
}
if (!canclick) return
if (!mouse) {
const touchData2 = readTouchData(data, 1)
// log(touchData2)
if (touchData2.state) {
log('right click')
canmove = false
Enigo.button(Button.Right, Direction.Click)
return
}
}
if (!state) {
state = true
start = [touchData.xPos, touchData.yPos]
const tid = Symbol()
thread = tid
log('touch started')
setTimeout(() => {
if (tid !== thread || !canclick) return
Enigo.button(Button.Left, Direction.Press)
mouse = true
thread = null
log('hold')
}, 400)
}
} catch (e) {
console.error(e)
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment