swayfx/sway/input_state.c

315 lines
7.3 KiB
C
Raw Normal View History

#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include "input_state.h"
2015-08-20 21:24:39 +10:00
#define KEY_STATE_MAX_LENGTH 64
static keycode key_state_array[KEY_STATE_MAX_LENGTH];
void input_init(void) {
int i;
for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) {
key_state_array[i] = 0;
}
}
static uint8_t find_key(keycode key) {
int i;
2015-08-20 21:24:39 +10:00
for (i = 0; i < KEY_STATE_MAX_LENGTH; ++i) {
if (key_state_array[i] == key) {
break;
}
}
return i;
}
bool check_key(keycode key) {
2015-08-20 21:24:39 +10:00
return find_key(key) < KEY_STATE_MAX_LENGTH;
}
void press_key(keycode key) {
// Check if key exists
if (!check_key(key)) {
// Check that we dont exceed buffer length
2015-08-20 21:24:39 +10:00
int insert = find_key(0);
if (insert < KEY_STATE_MAX_LENGTH) {
key_state_array[insert] = key;
}
}
}
void release_key(keycode key) {
uint8_t index = find_key(key);
2015-08-20 21:24:39 +10:00
if (index < KEY_STATE_MAX_LENGTH) {
2015-08-20 22:06:22 +10:00
// shift it over and remove key
2015-08-20 21:24:39 +10:00
key_state_array[index] = 0;
}
}
2015-08-23 14:03:45 +10:00
// Pointer state and mode
struct pointer_state pointer_state;
static struct mode_state {
2015-08-23 14:03:45 +10:00
// initial view state
double x, y, w, h;
swayc_t *ptr;
// containers resized with tiling resize
struct {
2015-08-23 14:03:45 +10:00
double x, w;
swayc_t *ptr;
2015-08-23 15:32:41 +10:00
struct {
double x, w;
swayc_t *ptr;
} sib;
2015-08-23 14:03:45 +10:00
} lr;
struct {
2015-08-23 14:03:45 +10:00
double y, h;
swayc_t *ptr;
2015-08-23 15:32:41 +10:00
struct {
double y, h;
swayc_t *ptr;
} sib;
2015-08-23 14:03:45 +10:00
} tb;
} initial;
static struct {
2015-08-23 14:03:45 +10:00
bool left;
bool top;
} lock;
2015-08-23 15:14:59 +10:00
// initial set/unset
2015-08-23 14:03:45 +10:00
static void set_initial_view(swayc_t *view) {
initial.ptr = view;
initial.x = view->x;
initial.y = view->y;
initial.w = view->width;
initial.h = view->height;
}
2015-08-23 15:14:59 +10:00
static void set_initial_sibling(void) {
bool reset = true;
if ((initial.lr.ptr = get_swayc_in_direction(initial.ptr, lock.left ? MOVE_RIGHT: MOVE_LEFT))) {
initial.lr.x = initial.lr.ptr->x;
initial.lr.w = initial.lr.ptr->width;
2015-08-23 15:32:41 +10:00
initial.lr.sib.ptr = get_swayc_in_direction(initial.lr.ptr, lock.left ? MOVE_LEFT : MOVE_RIGHT);
initial.lr.sib.x = initial.lr.sib.ptr->x;
initial.lr.sib.w = initial.lr.sib.ptr->width;
2015-08-23 15:14:59 +10:00
reset = false;
}
if ((initial.tb.ptr = get_swayc_in_direction(initial.ptr, lock.top ? MOVE_DOWN: MOVE_UP))) {
initial.tb.y = initial.tb.ptr->y;
initial.tb.h = initial.tb.ptr->height;
2015-08-23 15:32:41 +10:00
initial.tb.sib.ptr = get_swayc_in_direction(initial.tb.ptr, lock.top ? MOVE_UP : MOVE_DOWN);
initial.tb.sib.y = initial.tb.sib.ptr->y;
initial.tb.sib.h = initial.tb.sib.ptr->height;
2015-08-23 15:14:59 +10:00
reset = false;
}
// If nothing changes just undo the mode
if (reset) {
pointer_state.mode = 0;
}
}
2015-08-23 14:03:45 +10:00
static void reset_initial_view(void) {
initial.ptr->x = initial.x;
initial.ptr->y = initial.y;
initial.ptr->width = initial.w;
initial.ptr->height = initial.h;
arrange_windows(initial.ptr, -1, -1);
pointer_state.mode = 0;
}
// Mode set left/right click
static void pointer_mode_set_left(void) {
2015-08-23 14:03:45 +10:00
set_initial_view(pointer_state.left.view);
if (initial.ptr->is_floating) {
pointer_state.mode = M_DRAGGING | M_FLOATING;
} else {
pointer_state.mode = M_DRAGGING | M_TILING;
}
}
static void pointer_mode_set_right(void) {
2015-08-23 14:03:45 +10:00
set_initial_view(pointer_state.right.view);
// Setup locking information
2015-08-23 14:03:45 +10:00
int midway_x = initial.ptr->x + initial.ptr->width/2;
int midway_y = initial.ptr->y + initial.ptr->height/2;
2015-08-23 14:03:45 +10:00
lock.left = pointer_state.origin.x > midway_x;
lock.top = pointer_state.origin.y > midway_y;
2015-08-23 14:03:45 +10:00
if (initial.ptr->is_floating) {
pointer_state.mode = M_RESIZING | M_FLOATING;
} else {
pointer_state.mode = M_RESIZING | M_TILING;
2015-08-23 15:14:59 +10:00
set_initial_sibling();
}
}
// Mode set/update/reset
void pointer_mode_set(uint32_t button, bool condition) {
// switch on drag/resize mode
switch (pointer_state.mode & (M_DRAGGING | M_RESIZING)) {
case M_DRAGGING:
// end drag mode when left click is unpressed
2015-08-23 14:03:45 +10:00
if (!pointer_state.left.held) {
pointer_state.mode = 0;
}
break;
case M_RESIZING:
// end resize mode when right click is unpressed
2015-08-23 14:03:45 +10:00
if (!pointer_state.right.held) {
pointer_state.mode = 0;
}
break;
// No mode case
default:
// return if failed condition, or no view
if (!condition || !pointer_state.view) {
break;
}
2015-08-23 14:03:45 +10:00
// Set mode depending on current button press
switch (button) {
// Start dragging mode
case M_LEFT_CLICK:
// if button release dont do anything
2015-08-23 14:03:45 +10:00
if (pointer_state.left.held) {
pointer_mode_set_left();
}
break;
// Start resize mode
case M_RIGHT_CLICK:
// if button release dont do anyhting
2015-08-23 14:03:45 +10:00
if (pointer_state.right.held) {
pointer_mode_set_right();
}
break;
}
}
}
void pointer_mode_update(void) {
2015-08-23 14:03:45 +10:00
if (initial.ptr->type != C_VIEW) {
pointer_state.mode = 0;
return;
}
2015-08-23 14:03:45 +10:00
int dx = pointer_state.origin.x;
int dy = pointer_state.origin.y;
switch (pointer_state.mode) {
case M_FLOATING | M_DRAGGING:
// Update position
2015-08-23 14:03:45 +10:00
dx -= pointer_state.left.x;
dy -= pointer_state.left.y;
if (initial.x + dx != initial.ptr->x) {
initial.ptr->x = initial.x + dx;
}
2015-08-23 14:03:45 +10:00
if (initial.y + dy != initial.ptr->y) {
initial.ptr->y = initial.y + dy;
}
2015-08-23 14:03:45 +10:00
update_geometry(initial.ptr);
break;
case M_FLOATING | M_RESIZING:
2015-08-23 14:03:45 +10:00
dx -= pointer_state.right.x;
dy -= pointer_state.right.y;
initial.ptr = pointer_state.right.view;
if (lock.left) {
if (initial.w + dx > min_sane_w) {
initial.ptr->width = initial.w + dx;
}
} else { //lock.right
2015-08-23 14:03:45 +10:00
if (initial.w - dx > min_sane_w) {
initial.ptr->width = initial.w - dx;
initial.ptr->x = initial.x + dx;
}
}
2015-08-23 14:03:45 +10:00
if (lock.top) {
if (initial.h + dy > min_sane_h) {
initial.ptr->height = initial.h + dy;
}
} else { //lock.bottom
2015-08-23 14:03:45 +10:00
if (initial.h - dy > min_sane_h) {
initial.ptr->height = initial.h - dy;
initial.ptr->y = initial.y + dy;
}
}
2015-08-23 14:03:45 +10:00
update_geometry(initial.ptr);
break;
case M_TILING | M_DRAGGING:
// swap current view under pointer with dragged view
2015-08-23 14:54:39 +10:00
if (pointer_state.view && pointer_state.view->type == C_VIEW
&& pointer_state.view != initial.ptr) {
// Swap them around
2015-08-23 14:03:45 +10:00
swap_container(pointer_state.view, initial.ptr);
update_geometry(pointer_state.view);
2015-08-23 14:03:45 +10:00
update_geometry(initial.ptr);
// Set focus back to initial view
2015-08-23 14:03:45 +10:00
set_focused_container(initial.ptr);
}
break;
case M_TILING | M_RESIZING:
2015-08-23 14:03:45 +10:00
dx -= pointer_state.right.x;
dy -= pointer_state.right.y;
// resize if we can
if (initial.lr.ptr) {
if (lock.left) {
// Check whether its fine to resize
if (initial.w + dx > min_sane_w && initial.lr.w - dx > min_sane_w) {
initial.lr.ptr->width = initial.lr.w - dx;
2015-08-23 15:32:41 +10:00
initial.lr.sib.ptr->width = initial.lr.sib.w + dx;
2015-08-23 14:03:45 +10:00
}
} else { //lock.right
if (initial.w - dx > min_sane_w && initial.lr.w + dx > min_sane_w) {
initial.lr.ptr->width = initial.lr.w + dx;
2015-08-23 15:32:41 +10:00
initial.lr.sib.ptr->width = initial.lr.sib.w - dx;
2015-08-23 14:03:45 +10:00
}
}
arrange_windows(initial.lr.ptr->parent, -1, -1);
}
if (initial.tb.ptr) {
if (lock.top) {
if (initial.h + dy > min_sane_h && initial.tb.h - dy > min_sane_h) {
initial.tb.ptr->height = initial.tb.h - dy;
2015-08-23 15:32:41 +10:00
initial.tb.sib.ptr->height = initial.tb.sib.h + dy;
2015-08-23 14:03:45 +10:00
}
} else { //lock.bottom
if (initial.h - dy > min_sane_h && initial.tb.h + dy > min_sane_h) {
initial.tb.ptr->height = initial.tb.h + dy;
2015-08-23 15:32:41 +10:00
initial.tb.sib.ptr->height = initial.tb.sib.h - dy;
2015-08-23 14:03:45 +10:00
}
}
arrange_windows(initial.tb.ptr->parent, -1, -1);
}
default:
return;
}
}
void pointer_mode_reset(void) {
switch (pointer_state.mode) {
case M_FLOATING | M_DRAGGING:
case M_FLOATING | M_RESIZING:
2015-08-23 14:03:45 +10:00
reset_initial_view();
break;
case M_TILING | M_DRAGGING:
case M_TILING | M_RESIZING:
default:
return;
}
}