Implement keybindings, adjust CMDMODE grammar, update DEPENDS

This commit is contained in:
Michael Stapelberg 2009-02-10 20:49:47 +01:00
parent 069a740a94
commit 3e7b12ba43
5 changed files with 193 additions and 83 deletions

View File

@ -13,7 +13,11 @@ cmd := [ <times> ] [ <move> | <snap> ] <where>
oder oder
with := { [ <times> ] <where> }+ <enter> <cmd> with := <w> { [ <times> ] <where> }+ <space> <cmd>
oder
exec := exec <path>
an jeder Stelle kann mit escape abgebrochen werden an jeder Stelle kann mit escape abgebrochen werden
@ -29,4 +33,4 @@ Fenster nach rechts verschieben:
ml ml
Fenster und Fenster untendrunter nach rechts verschieben: Fenster und Fenster untendrunter nach rechts verschieben:
wk<enter>ml wk ml

13
DEPENDS Normal file
View File

@ -0,0 +1,13 @@
You need the following libraries. The version given is to be understand as the minimum
version. However, if any of these libraries changes the API, i3 may not compile anymore.
In that case, please try using the versions mentioned below until a fix is provided.
* xcb-proto-1.3 (2008-12-10)
* libxcb-1.1.93 (2008-12-11)
* xcb-util-0.3.3 (2009-01-31)
* Xlib, the one that comes with your X-Server
Get the libraries from:
http://xcb.freedesktop.org/dist/xcb-proto-1.3.tar.bz2
http://xcb.freedesktop.org/dist/libxcb-1.1.93.tar.bz2
http://xcb.freedesktop.org/dist/xcb-util-0.3.3.tar.bz2

View File

@ -1,3 +0,0 @@
Weve developed with:
* libxcb-1.1.93 (2008-12-11)
* xcb-util-0.3.3 (2009-01-31)

25
data.h
View File

@ -13,9 +13,23 @@ typedef struct Cell Cell;
typedef struct Font i3Font; typedef struct Font i3Font;
typedef struct Container Container; typedef struct Container Container;
typedef struct Client Client; typedef struct Client Client;
typedef struct Binding Binding;
/* Helper types */ /* Helper types */
typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t; typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t;
enum {
BIND_NONE = 0,
BIND_MOD_1 = XCB_MOD_MASK_1,
BIND_MOD_2 = XCB_MOD_MASK_2,
BIND_MOD_3 = XCB_MOD_MASK_3,
BIND_MOD_4 = XCB_MOD_MASK_4,
BIND_MOD_5 = XCB_MOD_MASK_5,
BIND_SHIFT = XCB_MOD_MASK_SHIFT,
BIND_CONTROL = XCB_MOD_MASK_CONTROL,
BIND_MODE_SWITCH = (1 << 8)
};
struct table_dimensions_t { struct table_dimensions_t {
int x; int x;
int y; int y;
@ -30,6 +44,17 @@ struct Cell {
int column; int column;
}; };
struct Binding {
/* Keycode to bind */
uint32_t keycode;
/* Bitmask consisting of BIND_MOD_1, BIND_MODE_SWITCH, … */
uint32_t mods;
/* Command, like in command mode */
char *command;
TAILQ_ENTRY(Binding) bindings;
};
/* /*
* We need to save the height of a font because it is required for each drawing of * We need to save the height of a font because it is required for each drawing of
* text but relatively hard to get. As soon as a new font needs to be loaded, a * text but relatively hard to get. As soon as a new font needs to be loaded, a

227
mainx.c
View File

@ -26,9 +26,10 @@
#define TERMINAL "/usr/pkg/bin/urxvt" #define TERMINAL "/usr/pkg/bin/urxvt"
i3Font *myfont;
Display *xkbdpy; Display *xkbdpy;
TAILQ_HEAD(bindings_head, Binding) bindings;
static const int TOP = 20; static const int TOP = 20;
static const int LEFT = 5; static const int LEFT = 5;
static const int BOTTOM = 5; static const int BOTTOM = 5;
@ -797,84 +798,142 @@ static void start_application(char *path, char *args) {
} }
} }
/*
* Due to bindings like Mode_switch + <a>, we need to bind some keys in XCB_GRAB_MODE_SYNC.
* Therefore, we just replay all key presses.
*
*/
static int handle_key_release(void *ignored, xcb_connection_t *conn, xcb_key_release_event_t *event) {
printf("got key release, just passing\n");
xcb_allow_events(conn, ReplayKeyboard, event->time);
xcb_flush(conn);
return 1;
}
/*
* Parses a command, see file CMDMODE for more information
*
*/
static void parse_command(xcb_connection_t *conn, const char *command) {
printf("--- parsing command \"%s\" ---\n", command);
/* Hmm, just to be sure */
if (command[0] == '\0')
return;
/* Is it an <exec>? */
if (strncmp(command, "exec ", strlen("exec ")) == 0) {
printf("starting \"%s\"\n", command + strlen("exec "));
start_application(command+strlen("exec "), NULL);
return;
}
/* Is it a <with>? */
if (command[0] == 'w') {
/* TODO: implement */
printf("not yet implemented.\n");
return;
}
/* It's a normal <cmd> */
int times;
char *rest = NULL;
enum { ACTION_FOCUS, ACTION_MOVE, ACTION_SNAP } action = ACTION_FOCUS;
direction_t direction;
times = strtol(command, &rest, 10);
if (rest == NULL) {
printf("Invalid command: Consists only of a movement\n");
return;
}
if (*rest == 'm' || *rest == 's') {
action = (*rest == 'm' ? ACTION_MOVE : ACTION_SNAP);
rest++;
}
/* Now perform action to <where> */
while (*rest != '\0') {
/* TODO: tags */
if (*rest == 'h')
direction = D_LEFT;
else if (*rest == 'j')
direction = D_DOWN;
else if (*rest == 'k')
direction = D_UP;
else if (*rest == 'l')
direction = D_RIGHT;
else {
printf("unknown direction: %c\n", *rest);
return;
}
if (action == ACTION_FOCUS)
focus_window(conn, direction);
else if (action == ACTION_MOVE)
move_current_window(conn, direction);
else if (action == ACTION_SNAP)
/* TODO: implement */
printf("snap not yet implemented\n");
rest++;
}
printf("--- done ---\n");
}
/* /*
* There was a key press. We lookup the key symbol and see if there are any bindings * There was a key press. We lookup the key symbol and see if there are any bindings
* on that. This allows to do things like binding special characters (think of ä) to * on that. This allows to do things like binding special characters (think of ä) to
* functions to get one more modifier while not losing AltGr :-) * functions to get one more modifier while not losing AltGr :-)
* TODO: this description needs to be more understandable
* *
*/ */
static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) { static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) {
/* FIXME: We need to translate the keypress + state into a string (like, ä) printf("Keypress %d\n", event->detail);
because they do not generate keysyms (use xev and see for yourself) */
printf("oh yay!\n");
printf("gots press %d\n", event->detail);
/* We need to get the keysym group (There are group 1 to group 4, each holding /* We need to get the keysym group (There are group 1 to group 4, each holding
two keysyms (without shift and with shift) using Xkb because X fails to two keysyms (without shift and with shift) using Xkb because X fails to
provide them reliably (it works in Xephyr, it does not in real X) */ provide them reliably (it works in Xephyr, it does not in real X) */
XkbStateRec state; XkbStateRec state;
if (XkbGetState(xkbdpy, XkbUseCoreKbd, &state) == Success) { if (XkbGetState(xkbdpy, XkbUseCoreKbd, &state) == Success && (state.group+1) == 2)
if (state.group+1 == 2) event->state |= 0x2;
event->state |= 0x2;
printf("state %d\n", event->state);
/* Find the binding */
Binding *bind, *best_match = TAILQ_END(&bindings);
TAILQ_FOREACH(bind, &bindings, bindings) {
if (bind->keycode == event->detail &&
(bind->mods & event->state) == bind->mods) {
if (best_match == TAILQ_END(&bindings) ||
bind->mods > best_match->mods)
best_match = bind;
}
} }
printf("i'm in state %d\n", event->state);
if (best_match == TAILQ_END(&bindings)) {
printf("This key was not bound by us?! (most likely a bug)\n");
return 1; /* TODO: return 0? what do the codes mean? */
}
xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(conn); if (event->state & 0x2) {
printf("that's mode_switch\n");
xcb_keysym_t k0 = xcb_key_symbols_get_keysym(keysyms, event->detail, event->state); parse_command(conn, best_match->command);
if (k0 == XCB_NONE) printf("ok, hiding this event.\n");
printf("couldn't get k0\n"); xcb_allow_events(conn, SyncKeyboard, event->time);
printf("gots keysym %d and \n", k0);
/* 30 = u
* 57 = n
* 27 = r
* 28 = t
* 40 = d
*
* uhm, I should probably say that Ive remapped my keys in hardware :)
*/
direction_t direction;
if (event->detail == 30) {
/* 'u' */
start_application(TERMINAL, NULL);
return 1;
} else if (event->detail == 57) {
direction = D_LEFT;
} else if (event->detail == 27) {
direction = D_DOWN;
} else if (event->detail == 28) {
direction = D_UP;
} else if (event->detail == 40) {
direction = D_RIGHT;
} else if (event->detail == 25) {
Container *con = CUR_CELL;
if (con->colspan == 1)
con->colspan++;
else con->colspan--;
render_layout(conn);
xcb_flush(conn); xcb_flush(conn);
return 1; return 1;
} else { }
printf("don't want this.\n");
/* If this was an actively grabbed key, and we did not handle it, we need to pass it */
if (best_match->mods & BIND_MODE_SWITCH) {
printf("passing...\n");
xcb_allow_events(conn, ReplayKeyboard, event->time);
xcb_flush(conn);
return 1; return 1;
} }
/* TODO: ctrl -> focus_container(conn, direction) */ parse_command(conn, best_match->command);
/* FIXME: actually wrong but i'm too lazy to grab my keys all the time */ return 1;
if (event->state & XCB_MOD_MASK_CONTROL) {
move_current_window(conn, direction);
} else if (event->state & XCB_MOD_MASK_1)
focus_window(conn, direction);
/* TODO: shift -> move_current_window(conn, direction) */
/* TODO: shift + ctrl -> move_current_container(conn, direction) */
return 1;
} }
/* /*
@ -1036,10 +1095,13 @@ int main(int argc, char *argv[], char *env[]) {
byChild = alloc_table(); byChild = alloc_table();
byParent = alloc_table(); byParent = alloc_table();
TAILQ_INIT(&bindings);
c = xcb_connect(NULL, &screens); c = xcb_connect(NULL, &screens);
printf("x screen is %d\n", screens); printf("x screen is %d\n", screens);
/* TODO: this has to be more beautiful somewhen */
int major, minor, error; int major, minor, error;
major = XkbMajorVersion; major = XkbMajorVersion;
@ -1057,9 +1119,7 @@ int main(int argc, char *argv[], char *env[]) {
fprintf(stderr, "XKB not supported by X-server\n"); fprintf(stderr, "XKB not supported by X-server\n");
return 1; return 1;
} }
/* end of ugliness */
/* Font loading */
myfont = load_font(c, pattern);
xcb_event_handlers_init(c, &evenths); xcb_event_handlers_init(c, &evenths);
for(i = 2; i < 128; ++i) for(i = 2; i < 128; ++i)
@ -1072,8 +1132,9 @@ int main(int argc, char *argv[], char *env[]) {
* contents (= top/bottom bar, titlebars for each window) */ * contents (= top/bottom bar, titlebars for each window) */
xcb_event_set_expose_handler(&evenths, handleExposeEvent, 0); xcb_event_set_expose_handler(&evenths, handleExposeEvent, 0);
/* Key presses are pretty obvious, I think */ /* Key presses/releases are pretty obvious, I think */
xcb_event_set_key_press_handler(&evenths, handle_key_press, 0); xcb_event_set_key_press_handler(&evenths, handle_key_press, 0);
xcb_event_set_key_release_handler(&evenths, handle_key_release, 0);
/* Enter window = user moved his mouse over the window */ /* Enter window = user moved his mouse over the window */
xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0); xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0);
@ -1090,27 +1151,37 @@ int main(int argc, char *argv[], char *env[]) {
uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE }; uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE };
xcb_change_window_attributes(c, root, mask, values); xcb_change_window_attributes(c, root, mask, values);
/* Grab 'a' */ #define BIND(key, modifier, cmd) { \
//xcb_grab_key(c, 0, root, 0, 38, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); Binding *new = malloc(sizeof(Binding)); \
new->keycode = key; \
new->mods = modifier; \
new->command = cmd; \
TAILQ_INSERT_TAIL(&bindings, new, bindings); \
}
xcb_grab_key(c, 0, root, 0, 30, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); /* 38 = 'a' */
xcb_grab_key(c, 0, root, 0, 38, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(38, BIND_MODE_SWITCH, "foo");
BIND(30, 0, "exec /usr/pkg/bin/urxvt");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 57, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(44, BIND_MOD_1, "h");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(45, BIND_MOD_1, "j");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 27, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(46, BIND_MOD_1, "k");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_1, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(47, BIND_MOD_1, "l");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 57, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(44, BIND_MOD_1 | BIND_CONTROL, "mh");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(45, BIND_MOD_1 | BIND_CONTROL, "mj");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 27, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(46, BIND_MOD_1 | BIND_CONTROL, "mk");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); BIND(47, BIND_MOD_1 | BIND_CONTROL, "ml");
xcb_grab_key(c, 0, root, XCB_MOD_MASK_CONTROL, 25, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
Binding *bind;
TAILQ_FOREACH(bind, &bindings, bindings) {
printf("Grabbing %d\n", bind->keycode);
if (bind->mods & BIND_MODE_SWITCH)
xcb_grab_key(c, 0, root, 0, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
else xcb_grab_key(c, 0, root, bind->mods, bind->keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
}
//xcb_grab_key(c, 0, root, XCB_BUTTON_MASK_ANY, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
start_application(TERMINAL, NULL); start_application(TERMINAL, NULL);
xcb_flush(c); xcb_flush(c);