aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Cole Mickens <cole.mickens@gmail.com>2016-01-17 02:53:37 -0800
committerLibravatar Cole Mickens <cole.mickens@gmail.com>2016-01-19 06:51:36 -0800
commit28081b76891ddbbb825dee6c202037d78aa8f164 (patch)
tree6b7412f626f5d9f10dba8920a2543dfd3c5a662e
parentAdd ffmpeg/imagemagick to depenency list (diff)
downloadsway-28081b76891ddbbb825dee6c202037d78aa8f164.tar.gz
sway-28081b76891ddbbb825dee6c202037d78aa8f164.tar.zst
sway-28081b76891ddbbb825dee6c202037d78aa8f164.zip
libinput
-rw-r--r--CMake/FindLibInput.cmake66
-rw-r--r--CMakeLists.txt3
-rw-r--r--include/commands.h3
-rw-r--r--include/config.h28
-rw-r--r--include/input.h23
-rw-r--r--include/ipc.h6
-rw-r--r--sway/CMakeLists.txt3
-rw-r--r--sway/commands.c312
-rw-r--r--sway/config.c116
-rw-r--r--sway/handlers.c38
-rw-r--r--sway/input.c54
-rw-r--r--sway/ipc-server.c20
-rw-r--r--sway/main.c7
-rw-r--r--sway/sway-input.5.txt46
-rw-r--r--swaymsg/main.c2
-rw-r--r--swaymsg/swaymsg.1.txt3
16 files changed, 727 insertions, 3 deletions
diff --git a/CMake/FindLibInput.cmake b/CMake/FindLibInput.cmake
new file mode 100644
index 00000000..87721998
--- /dev/null
+++ b/CMake/FindLibInput.cmake
@@ -0,0 +1,66 @@
1#.rst:
2# FindLibInput
3# -------
4#
5# Find LibInput library
6#
7# Try to find LibInpu library. The following values are defined
8#
9# ::
10#
11# LIBINPUT_FOUND - True if libinput is available
12# LIBINPUT_INCLUDE_DIRS - Include directories for libinput
13# LIBINPUT_LIBRARIES - List of libraries for libinput
14# LIBINPUT_DEFINITIONS - List of definitions for libinput
15#
16# and also the following more fine grained variables
17#
18# ::
19#
20# LIBINPUT_VERSION
21# LIBINPUT_VERSION_MAJOR
22# LIBINPUT_VERSION_MINOR
23# LIBINPUT_VERSION_MICRO
24#
25#=============================================================================
26# Copyright (c) 2015 Jari Vetoniemi
27#
28# Distributed under the OSI-approved BSD License (the "License");
29#
30# This software is distributed WITHOUT ANY WARRANTY; without even the
31# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
32# See the License for more information.
33#=============================================================================
34
35include(FeatureSummary)
36set_package_properties(LibInput PROPERTIES
37 URL "http://freedesktop.org/wiki/Software/libinput/"
38 DESCRIPTION "Library to handle input devices")
39
40find_package(PkgConfig)
41pkg_check_modules(PC_INPUT QUIET libinput)
42find_library(LIBINPUT_LIBRARIES NAMES input HINTS ${PC_INPUT_LIBRARY_DIRS})
43find_path(LIBINPUT_INCLUDE_DIRS libinput.h HINTS ${PC_INPUT_INCLUDE_DIRS})
44
45set(LIBINPUT_VERSION ${PC_INPUT_VERSION})
46string(REPLACE "." ";" VERSION_LIST "${PC_INPUT_VERSION}")
47
48LIST(LENGTH VERSION_LIST n)
49if (n EQUAL 3)
50 list(GET VERSION_LIST 0 LIBINPUT_VERSION_MAJOR)
51 list(GET VERSION_LIST 1 LIBINPUT_VERSION_MINOR)
52 list(GET VERSION_LIST 2 LIBINPUT_VERSION_MICRO)
53endif ()
54
55# This is compatible with libinput-version.h that exists in upstream
56# but isn't in distribution (probably forgotten)
57set(LIBINPUT_DEFINITIONS ${PC_INPUT_CFLAGS_OTHER}
58 -DLIBINPUT_VERSION=\"${LIBINPUT_VERSION}\"
59 -DLIBINPUT_VERSION_MAJOR=${LIBINPUT_VERSION_MAJOR}
60 -DLIBINPUT_VERSION_MINOR=${LIBINPUT_VERSION_MINOR}
61 -DLIBINPUT_VERSION_MICRO=${LIBINPUT_VERSION_MICRO})
62
63include(FindPackageHandleStandardArgs)
64find_package_handle_standard_args(LIBINPUT DEFAULT_MSG LIBINPUT_INCLUDE_DIRS LIBINPUT_LIBRARIES)
65mark_as_advanced(LIBINPUT_INCLUDE_DIRS LIBINPUT_LIBRARIES LIBINPUT_DEFINITIONS
66 LIBINPUT_VERSION LIBINPUT_VERSION_MAJOR LIBINPUT_VERSION_MICRO LIBINPUT_VERSION_MINOR)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 587c3dac..4620ff54 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,6 +57,9 @@ find_package(Pango)
57find_package(GdkPixbuf) 57find_package(GdkPixbuf)
58find_package(PAM) 58find_package(PAM)
59 59
60find_package(LibInput REQUIRED)
61include_directories(${LIBINPUT_INClUDE_DIRS})
62
60find_package(Backtrace) 63find_package(Backtrace)
61if(Backtrace_FOUND) 64if(Backtrace_FOUND)
62 include_directories("${Backtrace_INCLUDE_DIRS}") 65 include_directories("${Backtrace_INCLUDE_DIRS}")
diff --git a/include/commands.h b/include/commands.h
index 52d56e4a..5fa66bb6 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -17,7 +17,8 @@ enum cmd_status {
17 CMD_BLOCK_END, 17 CMD_BLOCK_END,
18 CMD_BLOCK_MODE, 18 CMD_BLOCK_MODE,
19 CMD_BLOCK_BAR, 19 CMD_BLOCK_BAR,
20 CMD_BLOCK_BAR_COLORS 20 CMD_BLOCK_BAR_COLORS,
21 CMD_BLOCK_INPUT
21}; 22};
22 23
23/** 24/**
diff --git a/include/config.h b/include/config.h
index e6a85b29..c2b67aa6 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1,7 +1,9 @@
1#ifndef _SWAY_CONFIG_H 1#ifndef _SWAY_CONFIG_H
2#define _SWAY_CONFIG_H 2#define _SWAY_CONFIG_H
3 3
4#include <libinput.h>
4#include <stdint.h> 5#include <stdint.h>
6#include <wlc/geometry.h>
5#include <wlc/wlc.h> 7#include <wlc/wlc.h>
6#include <xkbcommon/xkbcommon.h> 8#include <xkbcommon/xkbcommon.h>
7#include "wayland-desktop-shell-server-protocol.h" 9#include "wayland-desktop-shell-server-protocol.h"
@@ -46,6 +48,25 @@ struct sway_mode {
46}; 48};
47 49
48/** 50/**
51 * libinput options for input devices
52 */
53struct input_config {
54 char *identifier;
55 int click_method;
56 int drag_lock;
57 int dwt;
58 int middle_emulation;
59 int natural_scroll;
60 float pointer_accel;
61 int scroll_method;
62 int send_events;
63 int tap;
64
65 bool capturable;
66 struct wlc_geometry region;
67};
68
69/**
49 * Size and position configuration for a particular output. 70 * Size and position configuration for a particular output.
50 * 71 *
51 * This is set via the `output` command. 72 * This is set via the `output` command.
@@ -136,6 +157,7 @@ struct sway_config {
136 list_t *cmd_queue; 157 list_t *cmd_queue;
137 list_t *workspace_outputs; 158 list_t *workspace_outputs;
138 list_t *output_configs; 159 list_t *output_configs;
160 list_t *input_configs;
139 list_t *criteria; 161 list_t *criteria;
140 list_t *active_bar_modifiers; 162 list_t *active_bar_modifiers;
141 struct sway_mode *current_mode; 163 struct sway_mode *current_mode;
@@ -172,6 +194,12 @@ bool read_config(FILE *file, bool is_active);
172 * Does variable replacement for a string based on the config's currently loaded variables. 194 * Does variable replacement for a string based on the config's currently loaded variables.
173 */ 195 */
174char *do_var_replacement(char *str); 196char *do_var_replacement(char *str);
197
198int input_identifier_cmp(const void *item, const void *data);
199void merge_input_config(struct input_config *dst, struct input_config *src);
200void apply_input_config(struct input_config *ic, struct libinput_device *dev);
201void free_input_config(struct input_config *ic);
202
175int output_name_cmp(const void *item, const void *data); 203int output_name_cmp(const void *item, const void *data);
176void merge_output_config(struct output_config *dst, struct output_config *src); 204void merge_output_config(struct output_config *dst, struct output_config *src);
177/** Sets up a WLC output handle based on a given output_config. 205/** Sets up a WLC output handle based on a given output_config.
diff --git a/include/input.h b/include/input.h
new file mode 100644
index 00000000..4ed9bffe
--- /dev/null
+++ b/include/input.h
@@ -0,0 +1,23 @@
1#ifndef _SWAY_INPUT_H
2#define _SWAY_INPUT_H
3
4#include <libinput.h>
5#include "config.h"
6#include "list.h"
7
8struct input_config *new_input_config(const char* identifier);
9
10char* libinput_dev_unique_id(struct libinput_device *dev);
11
12/**
13 * Global input device list.
14 */
15extern list_t *input_devices;
16
17/**
18 * Pointer used when reading input blocked.
19 * Shared so that it can be cleared from commands.c when closing the block
20 */
21extern struct input_config *current_input_config;
22
23#endif
diff --git a/include/ipc.h b/include/ipc.h
index 56593529..934049c2 100644
--- a/include/ipc.h
+++ b/include/ipc.h
@@ -5,11 +5,12 @@ enum ipc_command_type {
5 IPC_COMMAND = 0, 5 IPC_COMMAND = 0,
6 IPC_GET_WORKSPACES = 1, 6 IPC_GET_WORKSPACES = 1,
7 IPC_SUBSCRIBE = 2, 7 IPC_SUBSCRIBE = 2,
8 IPC_GET_OUTPUTS = 3, 8 IPC_GET_OUTPUTS = 3,
9 IPC_GET_TREE = 4, 9 IPC_GET_TREE = 4,
10 IPC_GET_MARKS = 5, 10 IPC_GET_MARKS = 5,
11 IPC_GET_BAR_CONFIG = 6, 11 IPC_GET_BAR_CONFIG = 6,
12 IPC_GET_VERSION = 7, 12 IPC_GET_VERSION = 7,
13 IPC_GET_INPUTS = 8,
13 // Events send from sway to clients. Events have the higest bit set. 14 // Events send from sway to clients. Events have the higest bit set.
14 IPC_EVENT_WORKSPACE = (1 << 31 | 0), 15 IPC_EVENT_WORKSPACE = (1 << 31 | 0),
15 IPC_EVENT_OUTPUT = (1 << 31 | 1), 16 IPC_EVENT_OUTPUT = (1 << 31 | 1),
@@ -18,6 +19,7 @@ enum ipc_command_type {
18 IPC_EVENT_BARCONFIG_UPDATE = (1 << 31 | 4), 19 IPC_EVENT_BARCONFIG_UPDATE = (1 << 31 | 4),
19 IPC_EVENT_BINDING = (1 << 31 | 5), 20 IPC_EVENT_BINDING = (1 << 31 | 5),
20 IPC_EVENT_MODIFIER = (1 << 31 | 6), 21 IPC_EVENT_MODIFIER = (1 << 31 | 6),
22 IPC_EVENT_INPUT = (1 << 31 | 7),
21 IPC_SWAY_GET_PIXELS = 0x81 23 IPC_SWAY_GET_PIXELS = 0x81
22}; 24};
23 25
diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt
index 23829dc3..f7cc88ab 100644
--- a/sway/CMakeLists.txt
+++ b/sway/CMakeLists.txt
@@ -4,6 +4,7 @@ include_directories(
4 ${PCRE_INCLUDE_DIRS} 4 ${PCRE_INCLUDE_DIRS}
5 ${JSONC_INCLUDE_DIRS} 5 ${JSONC_INCLUDE_DIRS}
6 ${XKBCOMMON_INCLUDE_DIRS} 6 ${XKBCOMMON_INCLUDE_DIRS}
7 ${LIBINPUT_LIBRARIES}
7) 8)
8 9
9add_executable(sway 10add_executable(sway
@@ -15,6 +16,7 @@ add_executable(sway
15 extensions.c 16 extensions.c
16 focus.c 17 focus.c
17 handlers.c 18 handlers.c
19 input.c
18 input_state.c 20 input_state.c
19 ipc-server.c 21 ipc-server.c
20 layout.c 22 layout.c
@@ -32,6 +34,7 @@ target_link_libraries(sway
32 ${PCRE_LIBRARIES} 34 ${PCRE_LIBRARIES}
33 ${JSONC_LIBRARIES} 35 ${JSONC_LIBRARIES}
34 ${WAYLAND_SERVER_LIBRARIES} 36 ${WAYLAND_SERVER_LIBRARIES}
37 ${LIBINPUT_LIBRARIES}
35 m 38 m
36) 39)
37 40
diff --git a/sway/commands.c b/sway/commands.c
index 1c7eb962..5c8653ed 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -11,6 +11,9 @@
11#include <wordexp.h> 11#include <wordexp.h>
12#include <sys/types.h> 12#include <sys/types.h>
13#include <sys/wait.h> 13#include <sys/wait.h>
14#include <limits.h>
15#include <float.h>
16#include <libinput.h>
14#include "stringop.h" 17#include "stringop.h"
15#include "layout.h" 18#include "layout.h"
16#include "focus.h" 19#include "focus.h"
@@ -26,6 +29,8 @@
26#include "input_state.h" 29#include "input_state.h"
27#include "criteria.h" 30#include "criteria.h"
28#include "ipc-server.h" 31#include "ipc-server.h"
32#include "list.h"
33#include "input.h"
29 34
30typedef struct cmd_results *sway_cmd(int argc, char **argv); 35typedef struct cmd_results *sway_cmd(int argc, char **argv);
31 36
@@ -49,6 +54,7 @@ static sway_cmd cmd_focus_follows_mouse;
49static sway_cmd cmd_for_window; 54static sway_cmd cmd_for_window;
50static sway_cmd cmd_fullscreen; 55static sway_cmd cmd_fullscreen;
51static sway_cmd cmd_gaps; 56static sway_cmd cmd_gaps;
57static sway_cmd cmd_input;
52static sway_cmd cmd_kill; 58static sway_cmd cmd_kill;
53static sway_cmd cmd_layout; 59static sway_cmd cmd_layout;
54static sway_cmd cmd_log_colors; 60static sway_cmd cmd_log_colors;
@@ -866,6 +872,293 @@ static struct cmd_results *cmd_orientation(int argc, char **argv) {
866 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 872 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
867} 873}
868 874
875static void input_cmd_apply(struct input_config *input) {
876 int i;
877 i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier);
878 if (i >= 0) {
879 // merge existing config
880 struct input_config *ic = config->input_configs->items[i];
881 merge_input_config(ic, input);
882 free_input_config(input);
883 input = ic;
884 } else {
885 list_add(config->input_configs, input);
886 }
887
888 current_input_config = input;
889
890 if (input->identifier) {
891 // Try to find the input device and apply configuration now. If
892 // this is during startup then there will be no container and config
893 // will be applied during normal "new input" event from wlc.
894 struct libinput_device *device = NULL;
895 for (int i = 0; i < input_devices->length; ++i) {
896 device = input_devices->items[i];
897 char* dev_identifier = libinput_dev_unique_id(device);
898 int match = dev_identifier && strcmp(dev_identifier, input->identifier) == 0;
899 free(dev_identifier);
900 if (match) {
901 apply_input_config(input, device);
902 break;
903 }
904 }
905 }
906}
907
908static struct cmd_results *input_cmd_click_method(int argc, char **argv) {
909 sway_log(L_DEBUG, "click_method for device: %d %s", current_input_config==NULL, current_input_config->identifier);
910 struct cmd_results *error = NULL;
911 if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) {
912 return error;
913 }
914 if (!current_input_config) {
915 return cmd_results_new(CMD_FAILURE, "click_method", "No input device defined.");
916 }
917 struct input_config *new_config = new_input_config(current_input_config->identifier);
918
919 if (strcasecmp(argv[0], "none") == 0) {
920 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
921 } else if (strcasecmp(argv[0], "button_areas") == 0) {
922 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
923 } else if (strcasecmp(argv[0], "clickfinger") == 0) {
924 new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
925 } else {
926 return cmd_results_new(CMD_INVALID, "click_method", "Expected 'click_method <none|button_areas|clickfinger'");
927 }
928
929 input_cmd_apply(new_config);
930 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
931}
932
933static struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
934 struct cmd_results *error = NULL;
935 if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) {
936 return error;
937 }
938 if (!current_input_config) {
939 return cmd_results_new(CMD_FAILURE, "drag_lock", "No input device defined.");
940 }
941 struct input_config *new_config = new_input_config(current_input_config->identifier);
942
943 if (strcasecmp(argv[0], "enabled") == 0) {
944 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
945 } else if (strcasecmp(argv[0], "disabled") == 0) {
946 new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
947 } else {
948 return cmd_results_new(CMD_INVALID, "drag_lock", "Expected 'drag_lock <enabled|disabled>'");
949 }
950
951 input_cmd_apply(new_config);
952 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
953}
954
955static struct cmd_results *input_cmd_dwt(int argc, char **argv) {
956 struct cmd_results *error = NULL;
957 if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) {
958 return error;
959 }
960 if (!current_input_config) {
961 return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined.");
962 }
963 struct input_config *new_config = new_input_config(current_input_config->identifier);
964
965 if (strcasecmp(argv[0], "enabled") == 0) {
966 new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
967 } else if (strcasecmp(argv[0], "disabled") == 0) {
968 new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
969 } else {
970 return cmd_results_new(CMD_INVALID, "dwt", "Expected 'dwt <enabled|disabled>'");
971 }
972
973 input_cmd_apply(new_config);
974 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
975}
976
977static struct cmd_results *input_cmd_events(int argc, char **argv) {
978 sway_log(L_DEBUG, "events for device: %s", current_input_config->identifier);
979 struct cmd_results *error = NULL;
980 if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) {
981 return error;
982 }
983 if (!current_input_config) {
984 return cmd_results_new(CMD_FAILURE, "events", "No input device defined.");
985 }
986 struct input_config *new_config = new_input_config(current_input_config->identifier);
987
988 if (strcasecmp(argv[0], "enabled") == 0) {
989 new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
990 } else if (strcasecmp(argv[0], "disabled") == 0) {
991 new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
992 } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) {
993 new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
994 } else {
995 return cmd_results_new(CMD_INVALID, "events", "Expected 'events <enabled|disabled|disabled_on_external_mouse>'");
996 }
997
998 input_cmd_apply(new_config);
999 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1000}
1001
1002static struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
1003 struct cmd_results *error = NULL;
1004 if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) {
1005 return error;
1006 }
1007 if (!current_input_config) {
1008 return cmd_results_new(CMD_FAILURE, "middle_emulation", "No input device defined.");
1009 }
1010 struct input_config *new_config = new_input_config(current_input_config->identifier);
1011
1012 if (strcasecmp(argv[0], "enabled") == 0) {
1013 new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
1014 } else if (strcasecmp(argv[0], "disabled") == 0) {
1015 new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
1016 } else {
1017 return cmd_results_new(CMD_INVALID, "middle_emulation", "Expected 'middle_emulation <enabled|disabled>'");
1018 }
1019
1020 input_cmd_apply(new_config);
1021 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1022}
1023
1024static struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
1025 struct cmd_results *error = NULL;
1026 if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) {
1027 return error;
1028 }
1029 if (!current_input_config) {
1030 return cmd_results_new(CMD_FAILURE, "natural_scoll", "No input device defined.");
1031 }
1032 struct input_config *new_config = new_input_config(current_input_config->identifier);
1033
1034 if (strcasecmp(argv[0], "enabled") == 0) {
1035 new_config->natural_scroll = 1;
1036 } else if (strcasecmp(argv[0], "disabled") == 0) {
1037 new_config->natural_scroll = 0;
1038 } else {
1039 return cmd_results_new(CMD_INVALID, "natural_scroll", "Expected 'natural_scroll <enabled|disabled>'");
1040 }
1041
1042 input_cmd_apply(new_config);
1043 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1044}
1045
1046static struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) {
1047 struct cmd_results *error = NULL;
1048 if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) {
1049 return error;
1050 }
1051 if (!current_input_config) {
1052 return cmd_results_new(CMD_FAILURE, "pointer_accel", "No input device defined.");
1053 }
1054 struct input_config *new_config = new_input_config(current_input_config->identifier);
1055
1056 float pointer_accel = atof(argv[0]);
1057 if (pointer_accel < -1 || pointer_accel > 1) {
1058 return cmd_results_new(CMD_INVALID, "pointer_accel", "Input out of range [-1, 1]");
1059 }
1060 new_config->pointer_accel = pointer_accel;
1061
1062 input_cmd_apply(new_config);
1063 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1064}
1065
1066static struct cmd_results *input_cmd_scroll_method(int argc, char **argv) {
1067 struct cmd_results *error = NULL;
1068 if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) {
1069 return error;
1070 }
1071 if (!current_input_config) {
1072 return cmd_results_new(CMD_FAILURE, "scroll_method", "No input device defined.");
1073 }
1074 struct input_config *new_config = new_input_config(current_input_config->identifier);
1075
1076 if (strcasecmp(argv[0], "none") == 0) {
1077 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
1078 } else if (strcasecmp(argv[0], "two_finger") == 0) {
1079 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
1080 } else if (strcasecmp(argv[0], "edge") == 0) {
1081 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
1082 } else if (strcasecmp(argv[0], "on_button_down") == 0) {
1083 new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
1084 } else {
1085 return cmd_results_new(CMD_INVALID, "scroll_method", "Expected 'scroll_method <none|two_finger|edge|on_button_down>'");
1086 }
1087
1088 input_cmd_apply(new_config);
1089 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1090}
1091
1092static struct cmd_results *input_cmd_tap(int argc, char **argv) {
1093 sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier);
1094 struct cmd_results *error = NULL;
1095 if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) {
1096 return error;
1097 }
1098 if (!current_input_config) {
1099 return cmd_results_new(CMD_FAILURE, "tap", "No input device defined.");
1100 }
1101 struct input_config *new_config = new_input_config(current_input_config->identifier);
1102
1103 if (strcasecmp(argv[0], "enabled") == 0) {
1104 new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED;
1105 } else if (strcasecmp(argv[0], "disabled") == 0) {
1106 new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
1107 } else {
1108 return cmd_results_new(CMD_INVALID, "tap", "Expected 'tap <enabled|disabled>'");
1109 }
1110
1111 sway_log(L_DEBUG, "apply-tap for device: %s", current_input_config->identifier);
1112 input_cmd_apply(new_config);
1113 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1114}
1115
1116static struct cmd_results *cmd_input(int argc, char **argv) {
1117 struct cmd_results *error = NULL;
1118 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) {
1119 return error;
1120 }
1121
1122 if (config->reading && strcmp("{", argv[1]) == 0) {
1123 current_input_config = new_input_config(argv[0]);
1124 sway_log(L_DEBUG, "entering input block: %s", current_input_config->identifier);
1125 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
1126 }
1127
1128 if (argc > 2) {
1129 int argc_new = argc-2;
1130 char **argv_new = argv+2;
1131
1132 struct cmd_results *res;
1133 current_input_config = new_input_config(argv[0]);
1134 if (strcasecmp("click_method", argv[1]) == 0) {
1135 res = input_cmd_click_method(argc_new, argv_new);
1136 } else if (strcasecmp("drag_lock", argv[1]) == 0) {
1137 res = input_cmd_drag_lock(argc_new, argv_new);
1138 } else if (strcasecmp("dwt", argv[1]) == 0) {
1139 res = input_cmd_dwt(argc_new, argv_new);
1140 } else if (strcasecmp("events", argv[1]) == 0) {
1141 res = input_cmd_events(argc_new, argv_new);
1142 } else if (strcasecmp("middle_emulation", argv[1]) == 0) {
1143 res = input_cmd_middle_emulation(argc_new, argv_new);
1144 } else if (strcasecmp("natural_scroll", argv[1]) == 0) {
1145 res = input_cmd_natural_scroll(argc_new, argv_new);
1146 } else if (strcasecmp("pointer_accel", argv[1]) == 0) {
1147 res = input_cmd_pointer_accel(argc_new, argv_new);
1148 } else if (strcasecmp("scroll_method", argv[1]) == 0) {
1149 res = input_cmd_scroll_method(argc_new, argv_new);
1150 } else if (strcasecmp("tap", argv[1]) == 0) {
1151 res = input_cmd_tap(argc_new, argv_new);
1152 } else {
1153 res = cmd_results_new(CMD_INVALID, "input <device>", "Unknonwn command %s", argv[1]);
1154 }
1155 current_input_config = NULL;
1156 return res;
1157 }
1158
1159 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
1160}
1161
869static struct cmd_results *cmd_output(int argc, char **argv) { 1162static struct cmd_results *cmd_output(int argc, char **argv) {
870 struct cmd_results *error = NULL; 1163 struct cmd_results *error = NULL;
871 if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) { 1164 if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) {
@@ -1683,6 +1976,7 @@ static struct cmd_handler handlers[] = {
1683 { "for_window", cmd_for_window }, 1976 { "for_window", cmd_for_window },
1684 { "fullscreen", cmd_fullscreen }, 1977 { "fullscreen", cmd_fullscreen },
1685 { "gaps", cmd_gaps }, 1978 { "gaps", cmd_gaps },
1979 { "input", cmd_input },
1686 { "kill", cmd_kill }, 1980 { "kill", cmd_kill },
1687 { "layout", cmd_layout }, 1981 { "layout", cmd_layout },
1688 { "log_colors", cmd_log_colors }, 1982 { "log_colors", cmd_log_colors },
@@ -2422,6 +2716,18 @@ static struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv
2422 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 2716 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
2423} 2717}
2424 2718
2719static struct cmd_handler input_handlers[] = {
2720 { "click_method", input_cmd_click_method },
2721 { "drag_lock", input_cmd_drag_lock },
2722 { "dwt", input_cmd_dwt },
2723 { "events", input_cmd_events },
2724 { "middle_emulation", input_cmd_middle_emulation },
2725 { "natural_scroll", input_cmd_natural_scroll },
2726 { "pointer_accel", input_cmd_pointer_accel },
2727 { "scroll_method", input_cmd_scroll_method },
2728 { "tap", input_cmd_tap },
2729};
2730
2425static struct cmd_handler bar_colors_handlers[] = { 2731static struct cmd_handler bar_colors_handlers[] = {
2426 { "active_workspace", bar_colors_cmd_active_workspace }, 2732 { "active_workspace", bar_colors_cmd_active_workspace },
2427 { "background", bar_colors_cmd_background }, 2733 { "background", bar_colors_cmd_background },
@@ -2442,6 +2748,7 @@ static int handler_compare(const void *_a, const void *_b) {
2442static struct cmd_handler *find_handler(char *line, enum cmd_status block) { 2748static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
2443 struct cmd_handler d = { .command=line }; 2749 struct cmd_handler d = { .command=line };
2444 struct cmd_handler *res = NULL; 2750 struct cmd_handler *res = NULL;
2751 sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT);
2445 if (block == CMD_BLOCK_BAR) { 2752 if (block == CMD_BLOCK_BAR) {
2446 res = bsearch(&d, bar_handlers, 2753 res = bsearch(&d, bar_handlers,
2447 sizeof(bar_handlers) / sizeof(struct cmd_handler), 2754 sizeof(bar_handlers) / sizeof(struct cmd_handler),
@@ -2450,6 +2757,11 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
2450 res = bsearch(&d, bar_colors_handlers, 2757 res = bsearch(&d, bar_colors_handlers,
2451 sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), 2758 sizeof(bar_colors_handlers) / sizeof(struct cmd_handler),
2452 sizeof(struct cmd_handler), handler_compare); 2759 sizeof(struct cmd_handler), handler_compare);
2760 } else if (block == CMD_BLOCK_INPUT) {
2761 sway_log(L_DEBUG, "lookng at input handlers");
2762 res = bsearch(&d, input_handlers,
2763 sizeof(input_handlers) / sizeof(struct cmd_handler),
2764 sizeof(struct cmd_handler), handler_compare);
2453 } else { 2765 } else {
2454 res = bsearch(&d, handlers, 2766 res = bsearch(&d, handlers,
2455 sizeof(handlers) / sizeof(struct cmd_handler), 2767 sizeof(handlers) / sizeof(struct cmd_handler),
diff --git a/sway/config.c b/sway/config.c
index ae6a02b1..debd480a 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -6,6 +6,9 @@
6#include <sys/types.h> 6#include <sys/types.h>
7#include <sys/wait.h> 7#include <sys/wait.h>
8#include <signal.h> 8#include <signal.h>
9#include <libinput.h>
10#include <limits.h>
11#include <float.h>
9#include "wayland-desktop-shell-server-protocol.h" 12#include "wayland-desktop-shell-server-protocol.h"
10#include "readline.h" 13#include "readline.h"
11#include "stringop.h" 14#include "stringop.h"
@@ -16,6 +19,7 @@
16#include "layout.h" 19#include "layout.h"
17#include "input_state.h" 20#include "input_state.h"
18#include "criteria.h" 21#include "criteria.h"
22#include "input.h"
19 23
20struct sway_config *config = NULL; 24struct sway_config *config = NULL;
21 25
@@ -59,6 +63,11 @@ static void free_bar(struct bar_config *bar) {
59 free(bar); 63 free(bar);
60} 64}
61 65
66void free_input_config(struct input_config *ic) {
67 free(ic->identifier);
68 free(ic);
69}
70
62void free_output_config(struct output_config *oc) { 71void free_output_config(struct output_config *oc) {
63 free(oc->name); 72 free(oc->name);
64 free(oc); 73 free(oc);
@@ -99,6 +108,11 @@ static void free_config(struct sway_config *config) {
99 } 108 }
100 list_free(config->criteria); 109 list_free(config->criteria);
101 110
111 for (i = 0; i < config->input_configs->length; ++i) {
112 free_input_config(config->input_configs->items[i]);
113 }
114 list_free(config->input_configs);
115
102 for (i = 0; i < config->output_configs->length; ++i) { 116 for (i = 0; i < config->output_configs->length; ++i) {
103 free_output_config(config->output_configs->items[i]); 117 free_output_config(config->output_configs->items[i]);
104 } 118 }
@@ -119,6 +133,7 @@ static void config_defaults(struct sway_config *config) {
119 config->bars = create_list(); 133 config->bars = create_list();
120 config->workspace_outputs = create_list(); 134 config->workspace_outputs = create_list();
121 config->criteria = create_list(); 135 config->criteria = create_list();
136 config->input_configs = create_list();
122 config->output_configs = create_list(); 137 config->output_configs = create_list();
123 138
124 config->cmd_queue = create_list(); 139 config->cmd_queue = create_list();
@@ -294,6 +309,14 @@ bool read_config(FILE *file, bool is_active) {
294 } 309 }
295 break; 310 break;
296 311
312 case CMD_BLOCK_INPUT:
313 if (block == CMD_BLOCK_END) {
314 block = CMD_BLOCK_INPUT;
315 } else {
316 sway_log(L_ERROR, "Invalid block '%s'", line);
317 }
318 break;
319
297 case CMD_BLOCK_BAR: 320 case CMD_BLOCK_BAR:
298 if (block == CMD_BLOCK_END) { 321 if (block == CMD_BLOCK_END) {
299 block = CMD_BLOCK_BAR; 322 block = CMD_BLOCK_BAR;
@@ -318,6 +341,12 @@ bool read_config(FILE *file, bool is_active) {
318 block = CMD_BLOCK_END; 341 block = CMD_BLOCK_END;
319 break; 342 break;
320 343
344 case CMD_BLOCK_INPUT:
345 sway_log(L_DEBUG, "End of input block");
346 current_input_config = NULL;
347 block = CMD_BLOCK_END;
348 break;
349
321 case CMD_BLOCK_BAR: 350 case CMD_BLOCK_BAR:
322 sway_log(L_DEBUG, "End of bar block"); 351 sway_log(L_DEBUG, "End of bar block");
323 config->current_bar = NULL; 352 config->current_bar = NULL;
@@ -353,6 +382,12 @@ bool read_config(FILE *file, bool is_active) {
353 return success; 382 return success;
354} 383}
355 384
385int input_identifier_cmp(const void *item, const void *data) {
386 const struct input_config *ic = item;
387 const char *identifier = data;
388 return strcmp(ic->identifier, identifier);
389}
390
356int output_name_cmp(const void *item, const void *data) { 391int output_name_cmp(const void *item, const void *data) {
357 const struct output_config *output = item; 392 const struct output_config *output = item;
358 const char *name = data; 393 const char *name = data;
@@ -360,6 +395,42 @@ int output_name_cmp(const void *item, const void *data) {
360 return strcmp(output->name, name); 395 return strcmp(output->name, name);
361} 396}
362 397
398void merge_input_config(struct input_config *dst, struct input_config *src) {
399 if (src->identifier) {
400 if (dst->identifier) {
401 free(dst->identifier);
402 }
403 dst->identifier = strdup(src->identifier);
404 }
405 if (src->click_method != INT_MIN) {
406 dst->click_method = src->click_method;
407 }
408 if (src->drag_lock != INT_MIN) {
409 dst->drag_lock = src->drag_lock;
410 }
411 if (src->dwt != INT_MIN) {
412 dst->dwt = src->dwt;
413 }
414 if (src->middle_emulation != INT_MIN) {
415 dst->middle_emulation = src->middle_emulation;
416 }
417 if (src->natural_scroll != INT_MIN) {
418 dst->natural_scroll = src->natural_scroll;
419 }
420 if (src->pointer_accel != FLT_MIN) {
421 dst->pointer_accel = src->pointer_accel;
422 }
423 if (src->scroll_method != INT_MIN) {
424 dst->scroll_method = src->scroll_method;
425 }
426 if (src->send_events != INT_MIN) {
427 dst->send_events = src->send_events;
428 }
429 if (src->tap != INT_MIN) {
430 dst->tap = src->tap;
431 }
432}
433
363void merge_output_config(struct output_config *dst, struct output_config *src) { 434void merge_output_config(struct output_config *dst, struct output_config *src) {
364 if (src->name) { 435 if (src->name) {
365 if (dst->name) { 436 if (dst->name) {
@@ -508,6 +579,51 @@ void load_swaybars(swayc_t *output, int output_idx) {
508 list_free(bars); 579 list_free(bars);
509} 580}
510 581
582void apply_input_config(struct input_config *ic, struct libinput_device *dev) {
583 if (ic) {
584 sway_log(L_DEBUG,
585 "apply_input_config(%s)",
586 ic->identifier);
587 }
588
589 if (ic && ic->click_method != INT_MIN) {
590 sway_log(L_DEBUG, "apply_input_config(%s) click_set_method(%d)", ic->identifier, ic->click_method);
591 libinput_device_config_click_set_method(dev, ic->click_method);
592 }
593 if (ic && ic->drag_lock != INT_MIN) {
594 sway_log(L_DEBUG, "apply_input_config(%s) tap_set_drag_lock_enabled(%d)", ic->identifier, ic->click_method);
595 libinput_device_config_tap_set_drag_lock_enabled(dev, ic->drag_lock);
596 }
597 if (ic && ic->dwt != INT_MIN) {
598 sway_log(L_DEBUG, "apply_input_config(%s) dwt_set_enabled(%d)", ic->identifier, ic->dwt);
599 libinput_device_config_dwt_set_enabled(dev, ic->dwt);
600 }
601 if (ic && ic->middle_emulation != INT_MIN) {
602 sway_log(L_DEBUG, "apply_input_config(%s) middle_emulation_set_enabled(%d)", ic->identifier, ic->middle_emulation);
603 libinput_device_config_middle_emulation_set_enabled(dev, ic->middle_emulation);
604 }
605 if (ic && ic->natural_scroll != INT_MIN) {
606 sway_log(L_DEBUG, "apply_input_config(%s) natural_scroll_set_enabled(%d)", ic->identifier, ic->natural_scroll);
607 libinput_device_config_scroll_set_natural_scroll_enabled(dev, ic->natural_scroll);
608 }
609 if (ic && ic->pointer_accel != FLT_MIN) {
610 sway_log(L_DEBUG, "apply_input_config(%s) accel_set_speed(%f)", ic->identifier, ic->pointer_accel);
611 libinput_device_config_accel_set_speed(dev, ic->pointer_accel);
612 }
613 if (ic && ic->scroll_method != INT_MIN) {
614 sway_log(L_DEBUG, "apply_input_config(%s) scroll_set_method(%d)", ic->identifier, ic->scroll_method);
615 libinput_device_config_scroll_set_method(dev, ic->scroll_method);
616 }
617 if (ic && ic->send_events != INT_MIN) {
618 sway_log(L_DEBUG, "apply_input_config(%s) send_events_set_mode(%d)", ic->identifier, ic->send_events);
619 libinput_device_config_send_events_set_mode(dev, ic->send_events);
620 }
621 if (ic && ic->tap != INT_MIN) {
622 sway_log(L_DEBUG, "apply_input_config(%s) tap_set_enabled(%d)", ic->identifier, ic->tap);
623 libinput_device_config_tap_set_enabled(dev, ic->tap);
624 }
625}
626
511void apply_output_config(struct output_config *oc, swayc_t *output) { 627void apply_output_config(struct output_config *oc, swayc_t *output) {
512 if (oc && oc->width > 0 && oc->height > 0) { 628 if (oc && oc->width > 0 && oc->height > 0) {
513 output->width = oc->width; 629 output->width = oc->width;
diff --git a/sway/handlers.c b/sway/handlers.c
index 60bfac87..b1c0e26a 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -1,6 +1,7 @@
1#include <xkbcommon/xkbcommon.h> 1#include <xkbcommon/xkbcommon.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdbool.h> 3#include <stdbool.h>
4#include <libinput.h>
4#include <math.h> 5#include <math.h>
5#include <wlc/wlc.h> 6#include <wlc/wlc.h>
6#include <wlc/wlc-wayland.h> 7#include <wlc/wlc-wayland.h>
@@ -21,6 +22,8 @@
21#include "extensions.h" 22#include "extensions.h"
22#include "criteria.h" 23#include "criteria.h"
23#include "ipc-server.h" 24#include "ipc-server.h"
25#include "list.h"
26#include "input.h"
24 27
25// Event should be sent to client 28// Event should be sent to client
26#define EVENT_PASSTHROUGH false 29#define EVENT_PASSTHROUGH false
@@ -30,6 +33,37 @@
30 33
31/* Handles */ 34/* Handles */
32 35
36static bool handle_input_created(struct libinput_device *device) {
37 const char *identifier = libinput_dev_unique_id(device);
38 sway_log(L_INFO, "Found input device (%s)", identifier);
39
40 list_add(input_devices, device);
41
42 struct input_config *ic = NULL;
43 int i;
44 for (i = 0; i < config->input_configs->length; ++i) {
45 struct input_config *cur = config->input_configs->items[i];
46 if (strcasecmp(identifier, cur->identifier) == 0) {
47 ic = cur;
48 break;
49 }
50 }
51
52 apply_input_config(ic, device);
53 return true;
54}
55
56static void handle_input_destroyed(struct libinput_device *device) {
57 int i;
58 list_t *list = input_devices;
59 for (i = 0; i < list->length; ++i) {
60 if(((struct libinput_device *)list->items[i]) == device) {
61 list_del(list, i);
62 break;
63 }
64 }
65}
66
33static bool handle_output_created(wlc_handle output) { 67static bool handle_output_created(wlc_handle output) {
34 swayc_t *op = new_output(output); 68 swayc_t *op = new_output(output);
35 69
@@ -660,5 +694,9 @@ struct wlc_interface interface = {
660 }, 694 },
661 .compositor = { 695 .compositor = {
662 .ready = handle_wlc_ready 696 .ready = handle_wlc_ready
697 },
698 .input = {
699 .created = handle_input_created,
700 .destroyed = handle_input_destroyed
663 } 701 }
664}; 702};
diff --git a/sway/input.c b/sway/input.c
new file mode 100644
index 00000000..fe0d1aff
--- /dev/null
+++ b/sway/input.c
@@ -0,0 +1,54 @@
1#include <ctype.h>
2#include <float.h>
3#include <limits.h>
4#include <stdio.h>
5#include <string.h>
6#include <libinput.h>
7#include "config.h"
8#include "input.h"
9#include "list.h"
10#include "log.h"
11
12struct input_config *new_input_config(const char* identifier) {
13 struct input_config *input = calloc(1, sizeof(struct input_config));
14 sway_log(L_DEBUG, "new_input_config(%s)", identifier);
15 input->identifier = strdup(identifier);
16
17 input->tap = INT_MIN;
18 input->drag_lock = INT_MIN;
19 input->dwt = INT_MIN;
20 input->send_events = INT_MIN;
21 input->click_method = INT_MIN;
22 input->middle_emulation = INT_MIN;
23 input->natural_scroll = INT_MIN;
24 input->pointer_accel = FLT_MIN;
25 input->scroll_method = INT_MIN;
26
27 return input;
28}
29
30char *libinput_dev_unique_id(struct libinput_device *device) {
31 int vendor = libinput_device_get_id_vendor(device);
32 int product = libinput_device_get_id_product(device);
33 char *name = strdup(libinput_device_get_name(device));
34
35 char *p = name;
36 for (; *p; ++p) {
37 if (*p == ' ') {
38 *p = '_';
39 }
40 }
41
42 sway_log(L_DEBUG, "rewritten name %s", name);
43
44 int len = strlen(name) + sizeof(char) * 6;
45 char *identifier = malloc(len);
46
47 const char *fmt = "%d:%d:%s";
48 snprintf(identifier, len, fmt, vendor, product, name);
49 free(name);
50 return identifier;
51}
52
53list_t *input_devices = NULL;
54struct input_config *current_input_config = NULL;
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 8d92b919..58a291cd 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -13,6 +13,7 @@
13#include <ctype.h> 13#include <ctype.h>
14#include <json-c/json.h> 14#include <json-c/json.h>
15#include <list.h> 15#include <list.h>
16#include <libinput.h>
16#include "ipc-server.h" 17#include "ipc-server.h"
17#include "log.h" 18#include "log.h"
18#include "config.h" 19#include "config.h"
@@ -20,6 +21,7 @@
20#include "list.h" 21#include "list.h"
21#include "stringop.h" 22#include "stringop.h"
22#include "util.h" 23#include "util.h"
24#include "input.h"
23 25
24static int ipc_socket = -1; 26static int ipc_socket = -1;
25static struct wlc_event_source *ipc_event_source = NULL; 27static struct wlc_event_source *ipc_event_source = NULL;
@@ -325,6 +327,24 @@ void ipc_client_handle_command(struct ipc_client *client) {
325 json_object_put(workspaces); // free 327 json_object_put(workspaces); // free
326 break; 328 break;
327 } 329 }
330 case IPC_GET_INPUTS:
331 {
332 json_object *inputs = json_object_new_array();
333 if (input_devices) {
334 for(int i=0; i<input_devices->length; i++) {
335 struct libinput_device *device = input_devices->items[i];
336 char* identifier = libinput_dev_unique_id(device);
337 json_object *device_object = json_object_new_object();
338 json_object_object_add(device_object, "identifier", json_object_new_string(identifier));
339 json_object_array_add(inputs, device_object);
340 free(identifier);
341 }
342 }
343 const char *json_string = json_object_to_json_string(inputs);
344 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
345 json_object_put(inputs);
346 break;
347 }
328 case IPC_GET_OUTPUTS: 348 case IPC_GET_OUTPUTS:
329 { 349 {
330 json_object *outputs = json_object_new_array(); 350 json_object *outputs = json_object_new_array();
diff --git a/sway/main.c b/sway/main.c
index e85f7269..bec6a725 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -17,6 +17,7 @@
17#include "handlers.h" 17#include "handlers.h"
18#include "ipc-client.h" 18#include "ipc-client.h"
19#include "ipc-server.h" 19#include "ipc-server.h"
20#include "input.h"
20#include "sway.h" 21#include "sway.h"
21 22
22static bool terminate_request = false; 23static bool terminate_request = false;
@@ -173,6 +174,8 @@ int main(int argc, char **argv) {
173 wlc_log_set_handler(wlc_log_handler); 174 wlc_log_set_handler(wlc_log_handler);
174 detect_proprietary(); 175 detect_proprietary();
175 176
177 input_devices = create_list();
178
176 /* Changing code earlier than this point requires detailed review */ 179 /* Changing code earlier than this point requires detailed review */
177 /* (That code runs as root on systems without logind, and wlc_init drops to 180 /* (That code runs as root on systems without logind, and wlc_init drops to
178 * another user.) */ 181 * another user.) */
@@ -208,6 +211,10 @@ int main(int argc, char **argv) {
208 wlc_run(); 211 wlc_run();
209 } 212 }
210 213
214 if (input_devices) {
215 free(input_devices);
216 }
217
211 ipc_terminate(); 218 ipc_terminate();
212 219
213 return 0; 220 return 0;
diff --git a/sway/sway-input.5.txt b/sway/sway-input.5.txt
new file mode 100644
index 00000000..ec5d1314
--- /dev/null
+++ b/sway/sway-input.5.txt
@@ -0,0 +1,46 @@
1/////
2vim:set ts=4 sw=4 tw=82 noet:
3/////
4sway (5)
5========
6
7Name
8----
9sway - input configuration file and commands
10
11Description
12-----------
13
14Sway allows for configuration of libinput dveices.
15
16
17Commands
18--------
19
20**input** <identifier> click_method <none|button_areas|clickfinger>:
21 Changes the click method for the specified device.
22
23**input** <identifier> drag_lock <enabled|disabled>:
24 Enables or disables drag lock for specified input device.
25
26**input** <identifier> dwt <enabled|disabled>:
27 Enables or disables disable-while-typing for the specified input device.
28
29**input** <identifier> events <enable|disabled>:
30 Enables or disables send_events for specified input device.
31 (Disabling send_events disables the input device)
32
33**input** <identifier> middle_emulation <enabled|disabled>:
34 Enables or disables middle click emulation.
35
36**input** <identifier> natural_scroll <enabled|disabled>:
37 Enables or disables natural scrolling for the specified input device.
38
39**input** <identifier> pointer_accel <[-1,1]>:
40 Changes the pointer acceleration for the specified input device.
41
42**input** <identifier> scroll_method <none|two_finger|edge|on_button_down>:
43 Changes the scroll method for the specified input device.
44
45**input** <identifier> tap <enabled|disabled>:
46 Enables or disables tap for specified input device.
diff --git a/swaymsg/main.c b/swaymsg/main.c
index dac84a9b..22572b6f 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -87,6 +87,8 @@ int main(int argc, char **argv) {
87 type = IPC_COMMAND; 87 type = IPC_COMMAND;
88 } else if (strcasecmp(cmdtype, "get_workspaces") == 0) { 88 } else if (strcasecmp(cmdtype, "get_workspaces") == 0) {
89 type = IPC_GET_WORKSPACES; 89 type = IPC_GET_WORKSPACES;
90 } else if (strcasecmp(cmdtype, "get_inputs") == 0) {
91 type = IPC_GET_INPUTS;
90 } else if (strcasecmp(cmdtype, "get_outputs") == 0) { 92 } else if (strcasecmp(cmdtype, "get_outputs") == 0) {
91 type = IPC_GET_OUTPUTS; 93 type = IPC_GET_OUTPUTS;
92 } else if (strcasecmp(cmdtype, "get_tree") == 0) { 94 } else if (strcasecmp(cmdtype, "get_tree") == 0) {
diff --git a/swaymsg/swaymsg.1.txt b/swaymsg/swaymsg.1.txt
index 984780fa..c3af28d5 100644
--- a/swaymsg/swaymsg.1.txt
+++ b/swaymsg/swaymsg.1.txt
@@ -43,6 +43,9 @@ IPC Message Types
43*get_workspaces*:: 43*get_workspaces*::
44 Gets a JSON-encoded list of workspaces and their status. 44 Gets a JSON-encoded list of workspaces and their status.
45 45
46*get_inputs*::
47 Gets a JSON-encoded list of current inputs.
48
46*get_outputs*:: 49*get_outputs*::
47 Gets a JSON-encoded list of current outputs. 50 Gets a JSON-encoded list of current outputs.
48 51