blob: 64637bb85608388d4684d980eee03f61baeb81a3 [file] [log] [blame]
/****************************************************************************
* apps/graphics/input/generator/input_gen_event.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <debug.h>
#include <stdint.h>
#include <unistd.h>
#include "input_gen_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define INPUT_GEN_DEFAULT_PRESSURE 42
#define INPUT_GEN_DEFAULT_PRESS_DURATION 50 /* ms */
#define INPUT_GEN_DEFAULT_HOLD_DURATION 5 /* ms */
#define INPUT_GEN_DEFAULT_CLICK_DURATION 100 /* ms */
#define INPUT_GEN_MAX_FINGERS 2
/****************************************************************************
* Private Types
****************************************************************************/
/* Structure to hold parameters for single finger operations, we can support
* multiple fingers by using multiple instances of this structure.
*/
struct input_gen_single_finger_s
{
int16_t x1;
int16_t y1;
int16_t x2;
int16_t y2;
uint32_t press_duration;
uint32_t move_duration;
uint32_t hold_duration;
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: input_gen_tick_get
*
* Description:
* Get the current tick count in milliseconds.
*
* Returned Value:
* The current tick count in milliseconds.
*
****************************************************************************/
static uint32_t input_gen_tick_get(void)
{
struct timespec ts;
uint32_t ms;
clock_gettime(CLOCK_MONOTONIC, &ts);
ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
return ms;
}
/****************************************************************************
* Name: input_gen_tick_elapsed
*
* Description:
* Calculate the elapsed time in milliseconds since the last tick.
*
* Input Parameters:
* act_time - The current tick count.
* prev_tick - The previous tick count.
*
* Returned Value:
* The elapsed time in milliseconds.
*
****************************************************************************/
static uint32_t input_gen_tick_elapsed(uint32_t act_time, uint32_t prev_tick)
{
/* If there is no overflow in sys_time simple subtract */
if (act_time >= prev_tick)
{
prev_tick = act_time - prev_tick;
}
else
{
prev_tick = UINT32_MAX - prev_tick + 1;
prev_tick += act_time;
}
return prev_tick;
}
/****************************************************************************
* Name: input_gen_single_finger
*
* Description:
* Calculate the position of a single finger based on the elapsed time and
* the parameters.
*
* Input Parameters:
* point - The touch point structure to fill in.
* finger - The parameters for the single finger operation.
* elapsed - The elapsed time since the start of the operation.
*
* Returned Value:
* True if the operation is finished, false otherwise.
*
****************************************************************************/
static bool
input_gen_single_finger(FAR struct touch_point_s *point,
FAR const struct input_gen_single_finger_s *finger,
uint32_t elapsed)
{
if (elapsed < finger->press_duration)
{
/* Press */
input_gen_fill_point(point, finger->x1, finger->y1, TOUCH_DOWN);
return false;
}
elapsed -= finger->press_duration;
if (elapsed < finger->move_duration)
{
int16_t x = ((int64_t)(finger->x2 - finger->x1) * elapsed) /
finger->move_duration + finger->x1;
int16_t y = ((int64_t)(finger->y2 - finger->y1) * elapsed) /
finger->move_duration + finger->y1;
input_gen_fill_point(point, x, y, TOUCH_MOVE);
return false;
}
elapsed -= finger->move_duration;
if (elapsed < finger->hold_duration)
{
/* Hold */
input_gen_fill_point(point, finger->x2, finger->y2, TOUCH_DOWN);
return false;
}
/* Release */
input_gen_fill_point(point, finger->x2, finger->y2, TOUCH_UP);
return true;
}
/****************************************************************************
* Name: input_gen_write_motion
*
* Description:
* Write a motion event to the device.
*
* Input Parameters:
* fd - The file descriptor of the device.
* fingers - The parameters for the motion operation.
* nfingers - The number of fingers.
* elapsed - The elapsed time since the start of the operation.
*
* Returned Value:
* Zero (OK) is returned on success. On failure, a negated errno value is
* returned.
*
****************************************************************************/
static int input_gen_write_motion(int fd,
FAR const struct input_gen_single_finger_s *fingers,
size_t nfingers, uint32_t elapsed)
{
size_t finished = 0;
size_t i;
int ret;
union /* A union with enough space to make compiler / checker happy. */
{
struct touch_sample_s sample;
struct
{
uint8_t placeholder[offsetof(struct touch_sample_s, point)];
struct touch_point_s point[INPUT_GEN_MAX_FINGERS];
} points;
} buffer;
/* Check the number of fingers */
if (nfingers < 1 || nfingers > INPUT_GEN_MAX_FINGERS)
{
return -EINVAL;
}
/* Fill the touch sample structure */
buffer.sample.npoints = nfingers;
for (i = 0; i < nfingers; i++)
{
FAR struct touch_point_s *point = &buffer.points.point[i];
point->id = i;
if (input_gen_single_finger(point, &fingers[i], elapsed))
{
finished++;
}
ginfo("Finger %zu: x = %d, y = %d, flags = %02X\n",
i, point->x, point->y, point->flags);
}
/* Write the sample to the device */
ret = input_gen_utouch_write(fd, &buffer.sample);
if (ret < 0)
{
return ret;
}
return finished == nfingers ? OK : -EAGAIN;
}
/****************************************************************************
* Name: input_gen_motion
*
* Description:
* Perform a motion operation.
*
* Input Parameters:
* ctx - The input generator context.
* fingers - The parameters for the motion operation.
* nfingers - The number of fingers.
*
* Returned Value:
* Zero (OK) is returned on success. On failure, a negated errno value is
* returned.
*
****************************************************************************/
static int input_gen_motion(input_gen_ctx_t ctx,
FAR const struct input_gen_single_finger_s *fingers,
size_t nfingers)
{
FAR struct input_gen_dev_s *dev;
uint32_t start;
int ret;
dev = input_gen_search_dev(ctx, INPUT_GEN_DEV_UTOUCH);
if (dev == NULL)
{
return -ENODEV;
}
ret = input_gen_grab(dev);
if (ret < 0)
{
return ret;
}
start = input_gen_tick_get();
do
{
uint32_t elapsed = input_gen_tick_elapsed(input_gen_tick_get(), start);
ret = input_gen_write_motion(dev->fd, fingers, nfingers, elapsed);
if (ret == -EAGAIN && usleep(8 * 1000) < 0)
{
nwarn("WARNING: Maybe interrupted by signal\n");
input_gen_ungrab(dev);
return -errno;
}
}
while (ret == -EAGAIN);
input_gen_ungrab(dev);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: input_gen_tap
*
* Description:
* Perform a tap operation.
*
* Input Parameters:
* ctx - The input generator context.
* x - The x coordinate.
* y - The y coordinate.
*
* Returned Value:
* Zero (OK) is returned on success. On failure, a negated errno value is
* returned.
*
****************************************************************************/
int input_gen_tap(input_gen_ctx_t ctx, int16_t x, int16_t y)
{
struct input_gen_single_finger_s finger =
{
.x1 = x,
.y1 = y,
.x2 = x,
.y2 = y,
.press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION,
.move_duration = 0,
.hold_duration = 0,
};
return input_gen_motion(ctx, &finger, 1);
}
/****************************************************************************
* Name: input_gen_drag / input_gen_swipe
*
* Description:
* Perform a drag or swipe operation.
*
* Input Parameters:
* ctx - The input generator context.
* x1 - The start x coordinate.
* y1 - The start y coordinate.
* x2 - The end x coordinate.
* y2 - The end y coordinate.
* duration - The duration of the operation.
*
* Returned Value:
* Zero (OK) is returned on success. On failure, a negated errno value is
* returned.
*
****************************************************************************/
int input_gen_drag(input_gen_ctx_t ctx, int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint32_t duration)
{
struct input_gen_single_finger_s finger =
{
.x1 = x1,
.y1 = y1,
.x2 = x2,
.y2 = y2,
.press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION,
.move_duration = duration,
.hold_duration = INPUT_GEN_DEFAULT_HOLD_DURATION,
};
return input_gen_motion(ctx, &finger, 1);
}
int input_gen_swipe(input_gen_ctx_t ctx, int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint32_t duration)
{
struct input_gen_single_finger_s finger =
{
.x1 = x1,
.y1 = y1,
.x2 = x2,
.y2 = y2,
.press_duration = 0,
.move_duration = duration,
.hold_duration = 0,
};
return input_gen_motion(ctx, &finger, 1);
}
/****************************************************************************
* Name: input_gen_pinch
*
* Description:
* Perform a pinch operation.
*
* Input Parameters:
* ctx - The input generator context.
* x1_start - The start x coordinate of the first finger.
* y1_start - The start y coordinate of the first finger.
* x2_start - The start x coordinate of the second finger.
* y2_start - The start y coordinate of the second finger.
* x1_end - The end x coordinate of the first finger.
* y1_end - The end y coordinate of the first finger.
* x2_end - The end x coordinate of the second finger.
* y2_end - The end y coordinate of the second finger.
* duration - The duration of the operation.
*
* Returned Value:
* Zero (OK) is returned on success. On failure, a negated errno value is
* returned.
*
****************************************************************************/
int input_gen_pinch(input_gen_ctx_t ctx, int16_t x1_start, int16_t y1_start,
int16_t x2_start, int16_t y2_start, int16_t x1_end,
int16_t y1_end, int16_t x2_end, int16_t y2_end,
uint32_t duration)
{
struct input_gen_single_finger_s fingers[2] =
{
{
.x1 = x1_start,
.y1 = y1_start,
.x2 = x1_end,
.y2 = y1_end,
.press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION,
.move_duration = duration,
.hold_duration = INPUT_GEN_DEFAULT_HOLD_DURATION,
},
{
.x1 = x2_start,
.y1 = y2_start,
.x2 = x2_end,
.y2 = y2_end,
.press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION,
.move_duration = duration,
.hold_duration = INPUT_GEN_DEFAULT_HOLD_DURATION,
},
};
return input_gen_motion(ctx, fingers, 2);
}
/****************************************************************************
* Name: input_gen_button_click / input_gen_button_longpress
*
* Description:
* Perform a button click or long press operation.
*
* Input Parameters:
* ctx - The input generator context.
* mask - The button mask.
* duration - The duration of the operation.
*
* Returned Value:
* Zero (OK) is returned on success. On failure, a negated errno value is
* returned.
*
****************************************************************************/
int input_gen_button_click(input_gen_ctx_t ctx, btn_buttonset_t mask)
{
return input_gen_button_longpress(ctx, mask,
INPUT_GEN_DEFAULT_CLICK_DURATION);
}
int input_gen_button_longpress(input_gen_ctx_t ctx, btn_buttonset_t mask,
uint32_t duration)
{
FAR struct input_gen_dev_s *dev;
int ret;
dev = input_gen_search_dev(ctx, INPUT_GEN_DEV_UBUTTON);
if (dev == NULL)
{
return -ENODEV;
}
ret = input_gen_grab(dev);
if (ret < 0)
{
return ret;
}
ret = input_gen_ubutton_write(dev->fd, mask);
if (ret < 0)
{
goto out;
}
usleep(duration * 1000);
ret = input_gen_ubutton_write(dev->fd, 0);
if (ret < 0)
{
goto out;
}
out:
input_gen_ungrab(dev);
return ret;
}
/****************************************************************************
* Name: input_gen_mouse_wheel
*
* Description:
* Perform a mouse wheel operation.
*
* Input Parameters:
* ctx - The input generator context.
* wheel - The wheel value.
*
* Returned Value:
* Zero (OK) is returned on success. On failure, a negated errno value is
* returned.
*
****************************************************************************/
#ifdef CONFIG_INPUT_MOUSE_WHEEL
int input_gen_mouse_wheel(input_gen_ctx_t ctx, int16_t wheel)
{
FAR struct input_gen_dev_s *dev;
dev = input_gen_search_dev(ctx, INPUT_GEN_DEV_UMOUSE);
if (dev == NULL)
{
return -ENODEV;
}
return input_gen_umouse_write(dev->fd, wheel);
}
#endif
/****************************************************************************
* Name: input_gen_fill_point
*
* Description:
* Fill the touch point structure.
*
* Input Parameters:
* point - The touch point structure.
* x - The x coordinate.
* y - The y coordinate.
* flags - The TOUCH_DOWN, TOUCH_MOVE, TOUCH_UP flag.
*
****************************************************************************/
void input_gen_fill_point(FAR struct touch_point_s *point,
int16_t x, int16_t y, uint8_t flags)
{
point->x = x;
point->y = y;
point->h = 1;
point->w = 1;
if (flags & TOUCH_UP)
{
point->pressure = 0;
point->flags = flags | TOUCH_ID_VALID;
}
else
{
point->pressure = INPUT_GEN_DEFAULT_PRESSURE;
point->flags = flags | TOUCH_ID_VALID | TOUCH_POS_VALID |
TOUCH_PRESSURE_VALID;
}
}