2019-06-19 10:04:47 +02:00
|
|
|
#include "input.h"
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <threads.h>
|
2019-07-09 10:00:54 +02:00
|
|
|
#include <locale.h>
|
2019-06-19 10:04:47 +02:00
|
|
|
#include <sys/mman.h>
|
2019-07-17 21:30:57 +02:00
|
|
|
#include <sys/time.h>
|
2019-06-19 10:04:47 +02:00
|
|
|
|
2019-07-10 14:17:44 +02:00
|
|
|
#include <linux/input-event-codes.h>
|
|
|
|
|
|
2019-06-19 10:04:47 +02:00
|
|
|
#include <xkbcommon/xkbcommon.h>
|
|
|
|
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
2019-07-09 10:00:54 +02:00
|
|
|
#include <xkbcommon/xkbcommon-compose.h>
|
2019-06-19 10:04:47 +02:00
|
|
|
|
|
|
|
|
#define LOG_MODULE "input"
|
2019-07-03 20:21:03 +02:00
|
|
|
#define LOG_ENABLE_DBG 0
|
2019-06-19 10:04:47 +02:00
|
|
|
#include "log.h"
|
|
|
|
|
#include "terminal.h"
|
2019-07-05 10:44:57 +02:00
|
|
|
#include "render.h"
|
2019-07-09 14:27:26 +02:00
|
|
|
#include "keymap.h"
|
2019-07-09 16:26:36 +02:00
|
|
|
#include "commands.h"
|
2019-07-11 09:51:51 +02:00
|
|
|
#include "selection.h"
|
2019-07-15 15:42:21 +02:00
|
|
|
#include "vt.h"
|
2019-06-19 10:04:47 +02:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
|
uint32_t format, int32_t fd, uint32_t size)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
|
|
|
|
|
|
|
|
|
char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
|
|
|
|
|
|
|
|
/* TODO: free old context + keymap */
|
|
|
|
|
|
|
|
|
|
term->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
|
|
|
|
term->kbd.xkb_keymap = xkb_keymap_new_from_string(
|
|
|
|
|
term->kbd.xkb, map_str, XKB_KEYMAP_FORMAT_TEXT_V1,
|
|
|
|
|
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
|
|
|
|
|
|
|
|
|
/* TODO: initialize in enter? */
|
|
|
|
|
term->kbd.xkb_state = xkb_state_new(term->kbd.xkb_keymap);
|
|
|
|
|
|
2019-07-05 15:13:06 +02:00
|
|
|
term->kbd.mod_shift = xkb_keymap_mod_get_index(term->kbd.xkb_keymap, "Shift");
|
|
|
|
|
term->kbd.mod_alt = xkb_keymap_mod_get_index(term->kbd.xkb_keymap, "Mod1") ;
|
|
|
|
|
term->kbd.mod_ctrl = xkb_keymap_mod_get_index(term->kbd.xkb_keymap, "Control");
|
|
|
|
|
|
2019-07-09 10:00:54 +02:00
|
|
|
/* Compose (dead keys) */
|
|
|
|
|
term->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
|
|
|
|
|
term->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
|
|
|
|
|
term->kbd.xkb_compose_state = xkb_compose_state_new(
|
|
|
|
|
term->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
|
|
|
|
|
|
2019-06-19 10:04:47 +02:00
|
|
|
munmap(map_str, size);
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|
|
|
|
struct wl_surface *surface, struct wl_array *keys)
|
|
|
|
|
{
|
|
|
|
|
LOG_DBG("enter");
|
|
|
|
|
#if 0
|
|
|
|
|
uint32_t *key;
|
|
|
|
|
wl_array_for_each(key, keys)
|
|
|
|
|
xkb_state_update_key(xkb_state, *key, 1);
|
|
|
|
|
#endif
|
2019-07-19 11:11:48 +02:00
|
|
|
struct terminal *term = data;
|
|
|
|
|
term->input_serial = serial;
|
|
|
|
|
term_focus_in(term);
|
2019-06-19 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|
|
|
|
struct wl_surface *surface)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
2019-07-19 11:11:48 +02:00
|
|
|
term->input_serial = serial;
|
2019-07-16 10:34:08 +02:00
|
|
|
term_focus_out(term);
|
2019-06-21 18:40:53 +02:00
|
|
|
|
|
|
|
|
mtx_lock(&term->kbd.repeat.mutex);
|
|
|
|
|
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
|
|
|
|
term->kbd.repeat.cmd = REPEAT_STOP;
|
|
|
|
|
cnd_signal(&term->kbd.repeat.cond);
|
|
|
|
|
}
|
|
|
|
|
mtx_unlock(&term->kbd.repeat.mutex);
|
2019-06-19 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|
|
|
|
uint32_t time, uint32_t key, uint32_t state)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
2019-07-19 11:11:48 +02:00
|
|
|
term->input_serial = serial;
|
2019-06-19 10:04:47 +02:00
|
|
|
|
2019-07-05 15:13:06 +02:00
|
|
|
const xkb_mod_mask_t ctrl = 1 << term->kbd.mod_ctrl;
|
|
|
|
|
const xkb_mod_mask_t alt = 1 << term->kbd.mod_alt;
|
|
|
|
|
const xkb_mod_mask_t shift = 1 << term->kbd.mod_shift;
|
2019-06-19 10:04:47 +02:00
|
|
|
|
|
|
|
|
if (state == XKB_KEY_UP) {
|
|
|
|
|
mtx_lock(&term->kbd.repeat.mutex);
|
|
|
|
|
if (term->kbd.repeat.key == key) {
|
|
|
|
|
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
|
|
|
|
term->kbd.repeat.cmd = REPEAT_STOP;
|
|
|
|
|
cnd_signal(&term->kbd.repeat.cond);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mtx_unlock(&term->kbd.repeat.mutex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key += 8;
|
|
|
|
|
xkb_keysym_t sym = xkb_state_key_get_one_sym(term->kbd.xkb_state, key);
|
|
|
|
|
|
2019-07-09 14:27:26 +02:00
|
|
|
#if 0
|
|
|
|
|
char foo[100];
|
|
|
|
|
xkb_keysym_get_name(sym, foo, sizeof(foo));
|
|
|
|
|
LOG_ERR("%s", foo);
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-07-09 10:00:54 +02:00
|
|
|
xkb_compose_state_feed(term->kbd.xkb_compose_state, sym);
|
|
|
|
|
enum xkb_compose_status compose_status = xkb_compose_state_get_status(
|
|
|
|
|
term->kbd.xkb_compose_state);
|
|
|
|
|
|
|
|
|
|
if (compose_status == XKB_COMPOSE_COMPOSING)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-06-19 10:04:47 +02:00
|
|
|
xkb_mod_mask_t mods = xkb_state_serialize_mods(
|
2019-06-22 20:31:53 +02:00
|
|
|
term->kbd.xkb_state, XKB_STATE_MODS_DEPRESSED);
|
|
|
|
|
//xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods(term->kbd.xkb_state, key);
|
|
|
|
|
xkb_mod_mask_t consumed = 0x0;
|
|
|
|
|
xkb_mod_mask_t significant = ctrl | alt | shift;
|
2019-06-19 10:04:47 +02:00
|
|
|
xkb_mod_mask_t effective_mods = mods & ~consumed & significant;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
for (size_t i = 0; i < 32; i++) {
|
|
|
|
|
if (mods & (1 << i)) {
|
|
|
|
|
LOG_DBG("%s", xkb_keymap_mod_get_name(term->kbd.xkb_keymap, i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
LOG_DBG("sym=%u, mod=0x%08x, consumed=0x%08x, significant=0x%08x, "
|
|
|
|
|
"effective=0x%08x",
|
|
|
|
|
sym, mods, consumed, significant, effective_mods);
|
|
|
|
|
|
2019-07-09 14:27:26 +02:00
|
|
|
bool found_map = false;
|
|
|
|
|
|
|
|
|
|
enum modifier keymap_mods = MOD_NONE;
|
|
|
|
|
keymap_mods |= term->kbd.shift ? MOD_SHIFT : MOD_NONE;
|
|
|
|
|
keymap_mods |= term->kbd.alt ? MOD_ALT : MOD_NONE;
|
|
|
|
|
keymap_mods |= term->kbd.ctrl ? MOD_CTRL : MOD_NONE;
|
|
|
|
|
|
2019-07-09 16:26:36 +02:00
|
|
|
if (effective_mods == shift) {
|
|
|
|
|
if (sym == XKB_KEY_Page_Up) {
|
2019-07-10 09:15:37 +02:00
|
|
|
cmd_scrollback_up(term, term->rows);
|
2019-07-09 16:26:36 +02:00
|
|
|
found_map = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (sym == XKB_KEY_Page_Down) {
|
2019-07-10 09:15:37 +02:00
|
|
|
cmd_scrollback_down(term, term->rows);
|
2019-07-09 16:26:36 +02:00
|
|
|
found_map = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-11 12:16:50 +02:00
|
|
|
else if (effective_mods == (shift | ctrl)) {
|
|
|
|
|
if (sym == XKB_KEY_C) {
|
|
|
|
|
selection_to_clipboard(term, serial);
|
|
|
|
|
found_map = true;
|
|
|
|
|
}
|
2019-07-11 12:33:31 +02:00
|
|
|
|
|
|
|
|
else if (sym == XKB_KEY_V) {
|
|
|
|
|
selection_from_clipboard(term, serial);
|
|
|
|
|
found_map = true;
|
|
|
|
|
}
|
2019-07-11 12:16:50 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-09 15:05:07 +02:00
|
|
|
for (size_t i = 0; i < sizeof(key_map) / sizeof(key_map[0]) && !found_map; i++) {
|
2019-07-09 14:27:26 +02:00
|
|
|
const struct key_map *k = &key_map[i];
|
|
|
|
|
if (k->sym != sym)
|
|
|
|
|
continue;
|
|
|
|
|
|
2019-07-09 15:05:07 +02:00
|
|
|
for (size_t j = 0; j < k->count; j++) {
|
|
|
|
|
const struct key_data *info = &k->data[j];
|
|
|
|
|
if (info->modifiers != MOD_ANY && info->modifiers != keymap_mods)
|
|
|
|
|
continue;
|
2019-07-09 14:27:26 +02:00
|
|
|
|
2019-07-09 15:05:07 +02:00
|
|
|
if (info->cursor_keys_mode != CURSOR_KEYS_DONTCARE &&
|
|
|
|
|
info->cursor_keys_mode != term->cursor_keys_mode)
|
|
|
|
|
continue;
|
2019-07-09 14:27:26 +02:00
|
|
|
|
2019-07-09 15:05:07 +02:00
|
|
|
if (info->keypad_keys_mode != KEYPAD_DONTCARE &&
|
|
|
|
|
info->keypad_keys_mode != term->keypad_keys_mode)
|
|
|
|
|
continue;
|
2019-07-09 14:27:26 +02:00
|
|
|
|
2019-07-15 15:42:21 +02:00
|
|
|
vt_to_slave(term, info->seq, strlen(info->seq));
|
2019-07-09 15:05:07 +02:00
|
|
|
found_map = true;
|
2019-07-09 16:26:36 +02:00
|
|
|
|
|
|
|
|
if (term->grid->view != term->grid->offset) {
|
|
|
|
|
term->grid->view = term->grid->offset;
|
|
|
|
|
term_damage_all(term);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-11 09:51:51 +02:00
|
|
|
selection_cancel(term);
|
2019-07-09 15:05:07 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2019-07-09 14:27:26 +02:00
|
|
|
}
|
2019-06-22 20:40:28 +02:00
|
|
|
|
2019-07-09 14:27:26 +02:00
|
|
|
if (!found_map) {
|
2019-06-22 20:40:28 +02:00
|
|
|
char buf[64] = {0};
|
2019-07-09 10:00:54 +02:00
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
if (compose_status == XKB_COMPOSE_COMPOSED) {
|
|
|
|
|
count = xkb_compose_state_get_utf8(
|
|
|
|
|
term->kbd.xkb_compose_state, buf, sizeof(buf));
|
|
|
|
|
xkb_compose_state_reset(term->kbd.xkb_compose_state);
|
|
|
|
|
} else {
|
|
|
|
|
count = xkb_state_key_get_utf8(
|
|
|
|
|
term->kbd.xkb_state, key, buf, sizeof(buf));
|
|
|
|
|
}
|
2019-06-19 10:04:47 +02:00
|
|
|
|
2019-06-22 20:31:53 +02:00
|
|
|
if (count > 0) {
|
2019-06-19 10:04:47 +02:00
|
|
|
|
2019-07-26 18:49:09 +02:00
|
|
|
#define is_control_key(x) ((x) >= 0x40 && (x) <= 0x7f)
|
|
|
|
|
#define IS_CTRL(x) ((x) < 0x20 || ((x) >= 0x7f && (x) <= 0x9f))
|
|
|
|
|
|
|
|
|
|
if ((keymap_mods & MOD_CTRL) &&
|
|
|
|
|
!is_control_key(sym) &&
|
|
|
|
|
(count == 1 && !IS_CTRL(buf[0])) &&
|
|
|
|
|
sym < 256)
|
|
|
|
|
{
|
|
|
|
|
static const int mod_param_map[16] = {
|
|
|
|
|
[MOD_SHIFT] = 2,
|
|
|
|
|
[MOD_ALT] = 3,
|
|
|
|
|
[MOD_SHIFT | MOD_ALT] = 4,
|
|
|
|
|
[MOD_CTRL] = 5,
|
|
|
|
|
[MOD_SHIFT | MOD_CTRL] = 6,
|
|
|
|
|
[MOD_ALT | MOD_CTRL] = 7,
|
|
|
|
|
[MOD_SHIFT | MOD_ALT | MOD_CTRL] = 8,
|
|
|
|
|
};
|
|
|
|
|
int modify_param = mod_param_map[keymap_mods];
|
|
|
|
|
assert(modify_param != 0);
|
|
|
|
|
|
|
|
|
|
char reply[1024];
|
|
|
|
|
snprintf(reply, sizeof(reply), "\x1b[27;%d;%d~", modify_param, sym);
|
|
|
|
|
vt_to_slave(term, reply, strlen(reply));
|
|
|
|
|
}
|
2019-07-09 16:26:36 +02:00
|
|
|
|
2019-07-26 18:49:09 +02:00
|
|
|
else {
|
|
|
|
|
if (effective_mods & alt)
|
|
|
|
|
vt_to_slave(term, "\x1b", 1);
|
|
|
|
|
|
|
|
|
|
vt_to_slave(term, buf, count);
|
|
|
|
|
|
|
|
|
|
if (term->grid->view != term->grid->offset) {
|
|
|
|
|
term->grid->view = term->grid->offset;
|
|
|
|
|
term_damage_all(term);
|
|
|
|
|
}
|
2019-07-09 16:26:36 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-11 09:51:51 +02:00
|
|
|
selection_cancel(term);
|
2019-06-22 20:31:53 +02:00
|
|
|
}
|
2019-06-19 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mtx_lock(&term->kbd.repeat.mutex);
|
|
|
|
|
if (!term->kbd.repeat.dont_re_repeat) {
|
|
|
|
|
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
|
|
|
|
term->kbd.repeat.cmd = REPEAT_START;
|
|
|
|
|
term->kbd.repeat.key = key - 8;
|
|
|
|
|
cnd_signal(&term->kbd.repeat.cond);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mtx_unlock(&term->kbd.repeat.mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|
|
|
|
uint32_t mods_depressed, uint32_t mods_latched,
|
|
|
|
|
uint32_t mods_locked, uint32_t group)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
2019-07-19 11:11:48 +02:00
|
|
|
term->input_serial = serial;
|
2019-06-19 10:04:47 +02:00
|
|
|
|
|
|
|
|
LOG_DBG("modifiers: depressed=0x%x, latched=0x%x, locked=0x%x, group=%u",
|
|
|
|
|
mods_depressed, mods_latched, mods_locked, group);
|
|
|
|
|
|
|
|
|
|
xkb_state_update_mask(
|
|
|
|
|
term->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
2019-07-05 15:13:06 +02:00
|
|
|
|
|
|
|
|
/* Update state of modifiers we're interrested in for e.g mouse events */
|
|
|
|
|
term->kbd.shift = xkb_state_mod_index_is_active(
|
|
|
|
|
term->kbd.xkb_state, term->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED);
|
|
|
|
|
term->kbd.alt = xkb_state_mod_index_is_active(
|
|
|
|
|
term->kbd.xkb_state, term->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED);
|
|
|
|
|
term->kbd.ctrl = xkb_state_mod_index_is_active(
|
|
|
|
|
term->kbd.xkb_state, term->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED);
|
2019-06-19 10:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
|
int32_t rate, int32_t delay)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
|
|
|
|
LOG_DBG("keyboard repeat: rate=%d, delay=%d", rate, delay);
|
|
|
|
|
term->kbd.repeat.rate = rate;
|
|
|
|
|
term->kbd.repeat.delay = delay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct wl_keyboard_listener keyboard_listener = {
|
|
|
|
|
.keymap = &keyboard_keymap,
|
|
|
|
|
.enter = &keyboard_enter,
|
|
|
|
|
.leave = &keyboard_leave,
|
|
|
|
|
.key = &keyboard_key,
|
|
|
|
|
.modifiers = &keyboard_modifiers,
|
|
|
|
|
.repeat_info = &keyboard_repeat_info,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
input_repeat(struct terminal *term, uint32_t key)
|
|
|
|
|
{
|
|
|
|
|
keyboard_key(term, NULL, 0, 0, key, XKB_KEY_DOWN);
|
|
|
|
|
}
|
2019-07-05 10:44:57 +02:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t serial, struct wl_surface *surface,
|
|
|
|
|
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
2019-07-19 11:11:48 +02:00
|
|
|
term->input_serial = serial;
|
2019-07-05 15:13:06 +02:00
|
|
|
|
|
|
|
|
int x = wl_fixed_to_int(surface_x) * 1; //scale
|
|
|
|
|
int y = wl_fixed_to_int(surface_y) * 1; //scale
|
|
|
|
|
|
|
|
|
|
term->mouse.col = x / term->cell_width;
|
|
|
|
|
term->mouse.row = y / term->cell_height;
|
2019-07-05 10:44:57 +02:00
|
|
|
|
|
|
|
|
render_update_cursor_surface(term);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t serial, struct wl_surface *surface)
|
|
|
|
|
{
|
2019-07-19 11:11:48 +02:00
|
|
|
struct terminal *term = data;
|
|
|
|
|
term->input_serial = serial;
|
2019-07-05 10:44:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
|
|
|
|
{
|
|
|
|
|
struct terminal *term = data;
|
2019-07-05 15:13:06 +02:00
|
|
|
|
|
|
|
|
int x = wl_fixed_to_int(surface_x) * 1;//backend->monitor->scale;
|
|
|
|
|
int y = wl_fixed_to_int(surface_y) * 1;//backend->monitor->scale;
|
|
|
|
|
|
|
|
|
|
int col = x / term->cell_width;
|
2019-07-05 15:28:39 +02:00
|
|
|
int row = y / term->cell_height;
|
2019-07-05 15:13:06 +02:00
|
|
|
|
2019-07-11 11:09:34 +02:00
|
|
|
if (col < 0 || row < 0 || col >= term->cols || row >= term->rows)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-07-11 09:51:51 +02:00
|
|
|
bool update_selection = term->mouse.button == BTN_LEFT;
|
|
|
|
|
bool update_selection_early = term->selection.end.row == -1;
|
|
|
|
|
|
|
|
|
|
if (update_selection && update_selection_early)
|
|
|
|
|
selection_update(term, col, row);
|
|
|
|
|
|
2019-07-05 15:13:06 +02:00
|
|
|
if (col == term->mouse.col && row == term->mouse.row)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-07-05 15:28:39 +02:00
|
|
|
term->mouse.col = col;
|
|
|
|
|
term->mouse.row = row;
|
2019-07-05 15:13:06 +02:00
|
|
|
|
2019-07-11 09:51:51 +02:00
|
|
|
if (update_selection && !update_selection_early)
|
|
|
|
|
selection_update(term, col, row);
|
2019-07-10 20:57:09 +02:00
|
|
|
|
2019-07-05 15:13:06 +02:00
|
|
|
term_mouse_motion(
|
|
|
|
|
term, term->mouse.button, term->mouse.row, term->mouse.col,
|
|
|
|
|
term->kbd.shift, term->kbd.alt, term->kbd.ctrl);
|
2019-07-05 10:44:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
|
|
|
|
|
{
|
2019-07-05 14:24:51 +02:00
|
|
|
LOG_DBG("BUTTON: button=%x, state=%u", button, state);
|
|
|
|
|
|
|
|
|
|
struct terminal *term = data;
|
2019-07-19 11:11:48 +02:00
|
|
|
term->input_serial = serial;
|
2019-07-05 14:24:51 +02:00
|
|
|
|
|
|
|
|
switch (state) {
|
2019-07-17 21:30:57 +02:00
|
|
|
case WL_POINTER_BUTTON_STATE_PRESSED: {
|
|
|
|
|
bool double_click = false;
|
|
|
|
|
|
|
|
|
|
struct timeval now;
|
|
|
|
|
gettimeofday(&now, NULL);
|
|
|
|
|
|
|
|
|
|
struct timeval since_last;
|
|
|
|
|
timersub(&now, &term->mouse.last_time, &since_last);
|
|
|
|
|
if (button == term->mouse.last_button &&
|
|
|
|
|
since_last.tv_sec == 0 && since_last.tv_usec <= 300 * 1000)
|
|
|
|
|
{
|
|
|
|
|
double_click = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (button == BTN_LEFT) {
|
|
|
|
|
if (double_click)
|
|
|
|
|
selection_mark_word(term, term->mouse.col, term->mouse.row, serial);
|
|
|
|
|
else
|
|
|
|
|
selection_start(term, term->mouse.col, term->mouse.row);
|
|
|
|
|
} else {
|
2019-07-11 16:42:59 +02:00
|
|
|
if (button == BTN_MIDDLE)
|
|
|
|
|
selection_from_primary(term);
|
2019-07-11 09:51:51 +02:00
|
|
|
selection_cancel(term);
|
2019-07-11 16:42:59 +02:00
|
|
|
}
|
2019-07-10 20:57:09 +02:00
|
|
|
|
2019-07-05 15:13:06 +02:00
|
|
|
term->mouse.button = button; /* For motion events */
|
2019-07-17 21:30:57 +02:00
|
|
|
term->mouse.last_button = button;
|
|
|
|
|
term->mouse.last_time = now;
|
2019-07-05 15:13:06 +02:00
|
|
|
term_mouse_down(term, button, term->mouse.row, term->mouse.col,
|
|
|
|
|
term->kbd.shift, term->kbd.alt, term->kbd.ctrl);
|
2019-07-05 14:24:51 +02:00
|
|
|
break;
|
2019-07-17 21:30:57 +02:00
|
|
|
}
|
2019-07-05 14:24:51 +02:00
|
|
|
|
|
|
|
|
case WL_POINTER_BUTTON_STATE_RELEASED:
|
2019-07-11 18:17:40 +02:00
|
|
|
if (button != BTN_LEFT || term->selection.end.col == -1)
|
2019-07-11 09:51:51 +02:00
|
|
|
selection_cancel(term);
|
2019-07-11 11:10:53 +02:00
|
|
|
else
|
2019-07-11 17:34:52 +02:00
|
|
|
selection_finalize(term, serial);
|
2019-07-10 20:57:09 +02:00
|
|
|
|
2019-07-05 15:13:06 +02:00
|
|
|
term->mouse.button = 0; /* For motion events */
|
|
|
|
|
term_mouse_up(term, button, term->mouse.row, term->mouse.col,
|
|
|
|
|
term->kbd.shift, term->kbd.alt, term->kbd.ctrl);
|
2019-07-05 14:24:51 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2019-07-05 10:44:57 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-26 18:47:56 +02:00
|
|
|
static void
|
|
|
|
|
mouse_scroll(struct terminal *term, int amount)
|
|
|
|
|
{
|
|
|
|
|
int button = amount < 0 ? BTN_BACK : BTN_FORWARD;
|
|
|
|
|
|
|
|
|
|
void (*scrollback)(struct terminal *term, int rows)
|
|
|
|
|
= amount < 0 ? &cmd_scrollback_up : &cmd_scrollback_down;
|
|
|
|
|
|
|
|
|
|
amount = abs(amount);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < amount; i++)
|
|
|
|
|
term_mouse_down(term, button, term->mouse.row, term->mouse.col,
|
|
|
|
|
term->kbd.shift, term->kbd.alt, term->kbd.ctrl);
|
|
|
|
|
|
|
|
|
|
scrollback(term, amount);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-05 10:44:57 +02:00
|
|
|
static void
|
|
|
|
|
wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t time, uint32_t axis, wl_fixed_t value)
|
|
|
|
|
{
|
2019-07-26 18:47:56 +02:00
|
|
|
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-07-10 09:15:37 +02:00
|
|
|
struct terminal *term = data;
|
2019-07-26 18:47:56 +02:00
|
|
|
if (term->mouse.have_discrete)
|
|
|
|
|
return;
|
2019-07-10 09:15:37 +02:00
|
|
|
|
2019-07-26 18:47:56 +02:00
|
|
|
mouse_scroll(term, wl_fixed_to_int(value));
|
|
|
|
|
}
|
2019-07-10 09:15:37 +02:00
|
|
|
|
2019-07-26 18:47:56 +02:00
|
|
|
static void
|
|
|
|
|
wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t axis, int32_t discrete)
|
|
|
|
|
{
|
2019-07-10 09:15:37 +02:00
|
|
|
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-07-26 18:47:56 +02:00
|
|
|
struct terminal *term = data;
|
|
|
|
|
term->mouse.have_discrete = true;
|
|
|
|
|
mouse_scroll(term, discrete);
|
2019-07-05 10:44:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
|
|
|
|
|
{
|
2019-07-26 18:47:56 +02:00
|
|
|
struct terminal *term = data;
|
|
|
|
|
term->mouse.have_discrete = false;
|
2019-07-05 10:44:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t axis_source)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
|
uint32_t time, uint32_t axis)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct wl_pointer_listener pointer_listener = {
|
|
|
|
|
.enter = wl_pointer_enter,
|
|
|
|
|
.leave = wl_pointer_leave,
|
|
|
|
|
.motion = wl_pointer_motion,
|
|
|
|
|
.button = wl_pointer_button,
|
|
|
|
|
.axis = wl_pointer_axis,
|
|
|
|
|
.frame = wl_pointer_frame,
|
|
|
|
|
.axis_source = wl_pointer_axis_source,
|
|
|
|
|
.axis_stop = wl_pointer_axis_stop,
|
|
|
|
|
.axis_discrete = wl_pointer_axis_discrete,
|
|
|
|
|
};
|