Пример #1
0
int
main(void)
{
    struct xkb_context *context = test_get_context(0);
    struct xkb_keymap *keymap;

    assert(context);

    /* Make sure these are allowed. */
    xkb_context_unref(NULL);
    xkb_keymap_unref(NULL);
    xkb_state_unref(NULL);

    keymap = test_compile_rules(context, "evdev", "pc104", "us,ru", NULL, "grp:menu_toggle");
    assert(keymap);

    test_update_key(keymap);
    test_serialisation(keymap);
    test_repeat(keymap);
    test_consume(keymap);
    test_range(keymap);
    test_get_utf8_utf32(keymap);
    test_ctrl_string_transformation(keymap);

    xkb_keymap_unref(keymap);
    keymap = test_compile_rules(context, "evdev", NULL, "ch", "fr", NULL);
    assert(keymap);

    test_caps_keysym_transformation(keymap);

    xkb_keymap_unref(keymap);
    xkb_context_unref(context);
}
Пример #2
0
static void keyboardHandleKeymap(void* data,
                                 struct wl_keyboard* keyboard,
                                 uint32_t format,
                                 int fd,
                                 uint32_t size)
{
    struct xkb_keymap* keymap;
    struct xkb_state* state;
    char* mapStr;

    if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
    {
        close(fd);
        return;
    }

    mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
    if (mapStr == MAP_FAILED) {
        close(fd);
        return;
    }

    keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
                                        mapStr,
                                        XKB_KEYMAP_FORMAT_TEXT_V1,
                                        0);
    munmap(mapStr, size);
    close(fd);

    if (!keymap)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to compile keymap");
        return;
    }

    state = xkb_state_new(keymap);
    if (!state)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to create XKB state");
        xkb_keymap_unref(keymap);
        return;
    }

    xkb_keymap_unref(_glfw.wl.xkb.keymap);
    xkb_state_unref(_glfw.wl.xkb.state);
    _glfw.wl.xkb.keymap = keymap;
    _glfw.wl.xkb.state = state;

    _glfw.wl.xkb.controlMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
    _glfw.wl.xkb.altMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
    _glfw.wl.xkb.shiftMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
    _glfw.wl.xkb.superMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
}
Пример #3
0
static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
		       uint32_t format, int fd, uint32_t size)
{
	UwacSeat *input = data;
	struct xkb_keymap *keymap;
	struct xkb_state *state;
	char *map_str;

	if (!data) {
		close(fd);
		return;
	}

	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
		close(fd);
		return;
	}

	map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
	if (map_str == MAP_FAILED) {
		close(fd);
		return;
	}

	keymap = xkb_keymap_new_from_string(input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
	munmap(map_str, size);
	close(fd);

	if (!keymap) {
		assert(uwacErrorHandler(input->display, UWAC_ERROR_INTERNAL, "failed to compile keymap\n"));
		return;
	}

	state = xkb_state_new(keymap);
	if (!state) {
		assert(uwacErrorHandler(input->display, UWAC_ERROR_NOMEMORY, "failed to create XKB state\n"));
		xkb_keymap_unref(keymap);
		return;
	}

	xkb_keymap_unref(input->xkb.keymap);
	xkb_state_unref(input->xkb.state);
	input->xkb.keymap = keymap;
	input->xkb.state = state;

	input->xkb.control_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Control");
	input->xkb.alt_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Mod1");
	input->xkb.shift_mask =	1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Shift");
}
Пример #4
0
int
main(int argc, char *argv[])
{
    struct xkb_context *ctx;
    struct xkb_keymap *keymap;
    struct bench_timer timer;
    char *elapsed;
    int i;

    ctx = test_get_context(0);
    assert(ctx);

    xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
    xkb_context_set_log_verbosity(ctx, 0);

    bench_timer_reset(&timer);

    bench_timer_start(&timer);
    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
        keymap = test_compile_rules(ctx, "evdev", "evdev", "us", "", "");
        assert(keymap);
        xkb_keymap_unref(keymap);
    }
    bench_timer_stop(&timer);

    elapsed = bench_timer_get_elapsed_time_str(&timer);
    fprintf(stderr, "compiled %d keymaps in %ss\n",
            BENCHMARK_ITERATIONS, elapsed);
    free(elapsed);

    xkb_context_unref(ctx);
    return 0;
}
Пример #5
0
/*
 * Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
 * Necessary so that we can properly let xkbcommon track the keyboard state and
 * translate keypresses to utf-8.
 *
 */
static bool load_keymap(void) {
    if (xkb_context == NULL) {
        if ((xkb_context = xkb_context_new(0)) == NULL) {
            fprintf(stderr, "[i3lock] could not create xkbcommon context\n");
            return false;
        }
    }

    xkb_keymap_unref(xkb_keymap);

    int32_t device_id = xkb_x11_get_core_keyboard_device_id(conn);
    DEBUG("device = %d\n", device_id);
    if ((xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0)) == NULL) {
        fprintf(stderr, "[i3lock] xkb_x11_keymap_new_from_device failed\n");
        return false;
    }

    struct xkb_state *new_state =
        xkb_x11_state_new_from_device(xkb_keymap, conn, device_id);
    if (new_state == NULL) {
        fprintf(stderr, "[i3lock] xkb_x11_state_new_from_device failed\n");
        return false;
    }

    xkb_state_unref(xkb_state);
    xkb_state = new_state;

    return true;
}
Пример #6
0
static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
		uint32_t format, int fd, uint32_t size) {
	// Keyboard errors are abort-worthy because you wouldn't be able to unlock your screen otherwise.

	struct registry *registry = data;
	if (!data) {
		close(fd);
		return;
	}

	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
		close(fd);
		sway_abort("Unknown keymap format %d, aborting", format);
	}

	char *map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
	if (map_str == MAP_FAILED) {
		close(fd);
		sway_abort("Unable to initialized shared keyboard memory, aborting");
	}

	struct xkb_keymap *keymap = xkb_keymap_new_from_string(registry->input->xkb.context,
			map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
	munmap(map_str, size);
	close(fd);

	if (!keymap) {
		sway_abort("Failed to compile keymap, aborting");
	}

	struct xkb_state *state = xkb_state_new(keymap);
	if (!state) {
		xkb_keymap_unref(keymap);
		sway_abort("Failed to create xkb state, aborting");
	}

	xkb_keymap_unref(registry->input->xkb.keymap);
	xkb_state_unref(registry->input->xkb.state);
	registry->input->xkb.keymap = keymap;
	registry->input->xkb.state = state;

	int i;
	for (i = 0; i < MASK_LAST; ++i) {
		registry->input->xkb.masks[i] = 1 << xkb_keymap_mod_get_index(registry->input->xkb.keymap, XKB_MASK_NAMES[i]);
	}
}
Пример #7
0
int
xrtb_keyboard_reload(struct xcb_rutabaga *xrtb)
{
	struct xkb_keymap *new_keymap;
	int32_t device_id;

	assert(xrtb->xkb_ctx);

	device_id = xkb_x11_get_core_keyboard_device_id(xrtb->xcb_conn);
	if (device_id == -1)
		goto err_get_kbd_device;

	if (!(new_keymap = xkb_x11_keymap_new_from_device(xrtb->xkb_ctx,
					xrtb->xcb_conn, device_id, XKB_KEYMAP_COMPILE_NO_FLAGS)))
		goto err_new_keymap;

	if (xrtb->xkb_keymap)
		xkb_keymap_unref(xrtb->xkb_keymap);
	xrtb->xkb_keymap = new_keymap;

	if (xrtb->xkb_state)
		xkb_state_unref(xrtb->xkb_state);

	if (!(xrtb->xkb_state = xkb_x11_state_new_from_device(new_keymap,
					xrtb->xcb_conn, device_id)))
		goto err_new_state;

#define CACHE_MOD_INDEX(name, constant) \
	xrtb->mod_indices.name = xkb_keymap_mod_get_index(new_keymap, constant)

	CACHE_MOD_INDEX(shift, XKB_MOD_NAME_SHIFT);
	CACHE_MOD_INDEX(ctrl,  XKB_MOD_NAME_CTRL);
	CACHE_MOD_INDEX(alt,   XKB_MOD_NAME_ALT);
	CACHE_MOD_INDEX(super, XKB_MOD_NAME_LOGO);

#undef CACHE_MOD_INDEX
	return 0;

err_new_state:
	xkb_keymap_unref(xrtb->xkb_keymap);
	xrtb->xkb_keymap = NULL;
err_new_keymap:
err_get_kbd_device:
	return -1;
}
Пример #8
0
void KeyboardState::Setup(const Keymap &keymap) {
  Destroy();

  xkb_state_ = xkb_state_new(keymap.xkb_keymap_);
  if (nullptr == xkb_state_) {
    xkb_keymap_unref(keymap.xkb_keymap_);
    throw std::runtime_error("FATAL! Cannot create keyboard state!");
  }
}
Пример #9
0
int uxkb_desc_init(struct uterm_input *input,
		   const char *model,
		   const char *layout,
		   const char *variant,
		   const char *options)
{
	int ret;
	struct xkb_rule_names rmlvo = {
		.rules = "evdev",
		.model = model,
		.layout = layout,
		.variant = variant,
		.options = options,
	};

	input->ctx = xkb_context_new(0);
	if (!input->ctx) {
		log_error("cannot create XKB context");
		return -ENOMEM;
	}

	input->keymap = xkb_keymap_new_from_names(input->ctx, &rmlvo, 0);
	if (!input->keymap) {
		log_warn("failed to create keymap (%s, %s, %s, %s), "
			 "reverting to default system keymap",
			 model, layout, variant, options);

		rmlvo.model = "";
		rmlvo.layout = "";
		rmlvo.variant = "";
		rmlvo.options = "";

		input->keymap = xkb_keymap_new_from_names(input->ctx,
							  &rmlvo, 0);
		if (!input->keymap) {
			log_warn("failed to create XKB keymap");
			ret = -EFAULT;
			goto err_ctx;
		}
	}

	log_debug("new keyboard description (%s, %s, %s, %s)",
		  model, layout, variant, options);
	return 0;

err_ctx:
	xkb_context_unref(input->ctx);
	return ret;
}

void uxkb_desc_destroy(struct uterm_input *input)
{
	xkb_keymap_unref(input->keymap);
	xkb_context_unref(input->ctx);
}
Пример #10
0
/*
 * Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
 * Necessary so that we can properly let xkbcommon track the keyboard state and
 * translate keypresses to utf-8.
 *
 * Ideally, xkbcommon would ship something like this itself, but as of now
 * (version 0.2.0), it doesn’t.
 *
 */
static bool load_keymap(void) {
    bool ret = false;
    XkbFileInfo result;
    memset(&result, '\0', sizeof(result));
    result.xkb = XkbGetKeyboard(display, XkbAllMapComponentsMask, XkbUseCoreKbd);
    if (result.xkb == NULL) {
        fprintf(stderr, "[i3lock] XKB: XkbGetKeyboard failed\n");
        return false;
    }

    FILE *temp = tmpfile();
    if (temp == NULL) {
        fprintf(stderr, "[i3lock] could not create tempfile\n");
        return false;
    }

    bool ok = XkbWriteXKBKeymap(temp, &result, false, false, NULL, NULL);
    if (!ok) {
        fprintf(stderr, "[i3lock] XkbWriteXKBKeymap failed\n");
        goto out;
    }

    rewind(temp);

    if (xkb_context == NULL) {
        if ((xkb_context = xkb_context_new(0)) == NULL) {
            fprintf(stderr, "[i3lock] could not create xkbcommon context\n");
            goto out;
        }
    }

    if (xkb_keymap != NULL)
        xkb_keymap_unref(xkb_keymap);

    if ((xkb_keymap = xkb_keymap_new_from_file(xkb_context, temp, XKB_KEYMAP_FORMAT_TEXT_V1, 0)) == NULL) {
        fprintf(stderr, "[i3lock] xkb_keymap_new_from_file failed\n");
        goto out;
    }

    struct xkb_state *new_state = xkb_state_new(xkb_keymap);
    if (new_state == NULL) {
        fprintf(stderr, "[i3lock] xkb_state_new failed\n");
        goto out;
    }

    if (xkb_state != NULL)
        xkb_state_unref(xkb_state);
    xkb_state = new_state;

    ret = true;
out:
    XkbFreeKeyboard(result.xkb, XkbAllComponentsMask, true);
    fclose(temp);
    return ret;
}
Пример #11
0
static int
test_file(struct xkb_context *ctx, const char *path_rel)
{
    struct xkb_keymap *keymap = test_compile_file(ctx, path_rel);

    if (!keymap)
        return 0;

    xkb_keymap_unref(keymap);
    return 1;
}
Пример #12
0
QLibInputKeyboard::~QLibInputKeyboard()
{
#ifndef QT_NO_XKBCOMMON_EVDEV
    if (m_state)
        xkb_state_unref(m_state);
    if (m_keymap)
        xkb_keymap_unref(m_keymap);
    if (m_ctx)
        xkb_context_unref(m_ctx);
#endif
}
Пример #13
0
static void
ss_seat_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
		      uint32_t format, int fd, uint32_t size)
{
	struct ss_seat *seat = data;
	struct xkb_keymap *keymap;
	char *map_str;

	if (!data)
		goto error;

	if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
		map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
		if (map_str == MAP_FAILED) {
			weston_log("mmap failed: %m\n");
			goto error;
		}

		keymap = xkb_keymap_new_from_string(seat->base.compositor->xkb_context,
						    map_str,
						    XKB_KEYMAP_FORMAT_TEXT_V1,
						    0);
		munmap(map_str, size);

		if (!keymap) {
			weston_log("failed to compile keymap\n");
			goto error;
		}

		seat->keyboard_state_update = STATE_UPDATE_NONE;
	} else if (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
		weston_log("No keymap provided; falling back to default\n");
		keymap = NULL;
		seat->keyboard_state_update = STATE_UPDATE_AUTOMATIC;
	} else {
		weston_log("Invalid keymap\n");
		goto error;
	}

	close(fd);

	if (seat->base.keyboard_device_count)
		weston_seat_update_keymap(&seat->base, keymap);
	else
		weston_seat_init_keyboard(&seat->base, keymap);

	xkb_keymap_unref(keymap);

	return;

error:
	wl_keyboard_release(seat->parent.keyboard);
	close(fd);
}
Пример #14
0
void
xrtb_keyboard_fini(struct xcb_rutabaga *xrtb)
{
	assert(xrtb->xkb_ctx);

	xkb_context_unref(xrtb->xkb_ctx);

	if (xrtb->xkb_keymap)
		xkb_keymap_unref(xrtb->xkb_keymap);

	if (xrtb->xkb_state)
		xkb_state_unref(xrtb->xkb_state);
}
Пример #15
0
/**
 * Process X11 events in the main-loop (gui-thread) of the application.
 */
static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer data )
{
    if ( ev == NULL ) {
        int status = xcb_connection_has_error ( xcb->connection );
        fprintf ( stderr, "The XCB connection to X server had a fatal error: %d\n", status );
        g_main_loop_quit ( main_loop );
        return G_SOURCE_REMOVE;
    }
    uint8_t type = ev->response_type & ~0x80;
    if ( type == xkb.first_event ) {
        switch ( ev->pad0 )
        {
        case XCB_XKB_MAP_NOTIFY:
            xkb_state_unref ( xkb.state );
            xkb_keymap_unref ( xkb.keymap );
            xkb.keymap = xkb_x11_keymap_new_from_device ( xkb.context, xcb->connection, xkb.device_id, 0 );
            xkb.state  = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id );
            break;
        case XCB_XKB_STATE_NOTIFY:
        {
            xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev;
            xkb_state_update_mask ( xkb.state,
                                    ksne->baseMods,
                                    ksne->latchedMods,
                                    ksne->lockedMods,
                                    ksne->baseGroup,
                                    ksne->latchedGroup,
                                    ksne->lockedGroup );
            break;
        }
        }
        return G_SOURCE_CONTINUE;
    }
    RofiViewState *state = rofi_view_get_active ();
    if ( xcb->sndisplay != NULL ) {
        sn_xcb_display_process_event ( xcb->sndisplay, ev );
    }
    if ( state != NULL ) {
        rofi_view_itterrate ( state, ev, &xkb );
        if ( rofi_view_get_completed ( state ) ) {
            // This menu is done.
            rofi_view_finalize ( state );
            // cleanup
            if ( rofi_view_get_active () == NULL ) {
                teardown ( pfd );
                g_main_loop_quit ( main_loop );
            }
        }
    }
    return G_SOURCE_CONTINUE;
}
Пример #16
0
static void
keymap_changed (MetaBackend *backend)
{
  MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
  MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);

  if (priv->keymap)
    {
      xkb_keymap_unref (priv->keymap);
      priv->keymap = NULL;
    }

  g_signal_emit_by_name (backend, "keymap-changed", 0);
}
Пример #17
0
static kbdmap *kbdmap_unref(kbdmap *km) {
        if (!km)
                return NULL;

        assert_return(km->ref > 0, NULL);

        if (--km->ref > 0)
                return NULL;

        xkb_keymap_unref(km->xkb_keymap);
        free(km);

        return 0;
}
Пример #18
0
static void
input_method_keyboard_keymap(void *data,
			     struct wl_keyboard *wl_keyboard,
			     uint32_t format,
			     int32_t fd,
			     uint32_t size)
{
	struct simple_im *keyboard = data;
	char *map_str;

	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
		close(fd);
		return;
	}

	map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
	if (map_str == MAP_FAILED) {
		close(fd);
		return;
	}

	keyboard->keymap =
		xkb_keymap_new_from_string(keyboard->xkb_context,
					   map_str,
					   XKB_KEYMAP_FORMAT_TEXT_V1,
					   0);

	munmap(map_str, size);
	close(fd);

	if (!keyboard->keymap) {
		fprintf(stderr, "failed to compile keymap\n");
		return;
	}

	keyboard->state = xkb_state_new(keyboard->keymap);
	if (!keyboard->state) {
		fprintf(stderr, "failed to create XKB state\n");
		xkb_keymap_unref(keyboard->keymap);
		return;
	}

	keyboard->control_mask =
		1 << xkb_keymap_mod_get_index(keyboard->keymap, "Control");
	keyboard->alt_mask =
		1 << xkb_keymap_mod_get_index(keyboard->keymap, "Mod1");
	keyboard->shift_mask =
		1 << xkb_keymap_mod_get_index(keyboard->keymap, "Shift");
}
Пример #19
0
WaylandDisplay::~WaylandDisplay()
{
    if (m_eventSource)
        g_source_unref(m_eventSource);
    m_eventSource = nullptr;

    if (m_interfaces.compositor)
        wl_compositor_destroy(m_interfaces.compositor);
    if (m_interfaces.data_device_manager)
        wl_data_device_manager_destroy(m_interfaces.data_device_manager);
    if (m_interfaces.drm)
        wl_drm_destroy(m_interfaces.drm);
    if (m_interfaces.seat)
        wl_seat_destroy(m_interfaces.seat);
    if (m_interfaces.xdg)
        xdg_shell_destroy(m_interfaces.xdg);
    if (m_interfaces.ivi_application)
        ivi_application_destroy(m_interfaces.ivi_application);
    m_interfaces = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };

    if (m_registry)
        wl_registry_destroy(m_registry);
    m_registry = nullptr;
    if (m_display)
        wl_display_disconnect(m_display);
    m_display = nullptr;

    if (m_seatData.pointer.object)
        wl_pointer_destroy(m_seatData.pointer.object);
    if (m_seatData.keyboard.object)
        wl_keyboard_destroy(m_seatData.keyboard.object);
    if (m_seatData.touch.object)
        wl_touch_destroy(m_seatData.touch.object);
    if (m_seatData.xkb.context)
        xkb_context_unref(m_seatData.xkb.context);
    if (m_seatData.xkb.keymap)
        xkb_keymap_unref(m_seatData.xkb.keymap);
    if (m_seatData.xkb.state)
        xkb_state_unref(m_seatData.xkb.state);
    if (m_seatData.xkb.composeTable)
        xkb_compose_table_unref(m_seatData.xkb.composeTable);
    if (m_seatData.xkb.composeState)
        xkb_compose_state_unref(m_seatData.xkb.composeState);
    if (m_seatData.repeatData.eventSource)
        g_source_remove(m_seatData.repeatData.eventSource);
    m_seatData = SeatData{ };
}
Пример #20
0
void free_xkb(void)
{
   if (mod_map_idx)
      free(mod_map_idx);
   if (mod_map_bit)
      free(mod_map_bit);
   if (xkb_map)
      xkb_keymap_unref(xkb_map);
   if (xkb_ctx)
      xkb_context_unref(xkb_ctx);
   if (xkb_state)
      xkb_state_unref(xkb_state);

   mod_map_idx = NULL;
   mod_map_bit = NULL;
   xkb_map     = NULL;
   xkb_ctx     = NULL;
   xkb_state   = NULL;
}
Пример #21
0
static void udev_input_free(void *data)
{
   unsigned i;
   udev_input_t *udev = (udev_input_t*)data;

   if (!data || !udev)
      return;

   if (udev->joypad)
      udev->joypad->destroy();

   if (udev->epfd >= 0)
      close(udev->epfd);

   for (i = 0; i < udev->num_devices; i++)
   {
      close(udev->devices[i]->fd);
      free(udev->devices[i]);
   }
   free(udev->devices);

   if (udev->monitor)
      udev_monitor_unref(udev->monitor);
   if (udev->udev)
      udev_unref(udev->udev);

#ifdef HAVE_XKBCOMMON
   if (udev->mod_map_idx)
      free(udev->mod_map_idx);
   if (udev->mod_map_bit)
      free(udev->mod_map_bit);
   if (udev->xkb_map)
      xkb_keymap_unref(udev->xkb_map);
   if (udev->xkb_ctx)
      xkb_context_unref(udev->xkb_ctx);
   if (udev->xkb_state)
      xkb_state_unref(udev->xkb_state);
#endif

   free(udev);
}
Пример #22
0
int
main(void)
{
    struct xkb_context *ctx;
    struct xkb_keymap *keymap;
    struct xkb_state *state;
    struct bench bench;
    char *elapsed;

    ctx = test_get_context(0);
    assert(ctx);

    keymap = test_compile_rules(ctx, "evdev", "pc104", "us,ru,il,de",
                                ",,,neo", "grp:menu_toggle");
    assert(keymap);

    state = xkb_state_new(keymap);
    assert(state);

    xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
    xkb_context_set_log_verbosity(ctx, 0);

    srand(time(NULL));

    bench_start(&bench);
    bench_key_proc(state);
    bench_stop(&bench);

    elapsed = bench_elapsed_str(&bench);
    fprintf(stderr, "ran %d iterations in %ss\n",
            BENCHMARK_ITERATIONS, elapsed);
    free(elapsed);

    xkb_state_unref(state);
    xkb_keymap_unref(keymap);
    xkb_context_unref(ctx);

    return 0;
}
Пример #23
0
void _glfwPlatformTerminate(void)
{
    _glfwTerminateEGL();
    _glfwTerminateJoysticksLinux();
    _glfwTerminateThreadLocalStoragePOSIX();

    xkb_keymap_unref(_glfw.wl.xkb.keymap);
    xkb_state_unref(_glfw.wl.xkb.state);
    xkb_context_unref(_glfw.wl.xkb.context);

    if (_glfw.wl.cursorTheme)
        wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
    if (_glfw.wl.cursorSurface)
        wl_surface_destroy(_glfw.wl.cursorSurface);
    if (_glfw.wl.compositor)
        wl_compositor_destroy(_glfw.wl.compositor);
    if (_glfw.wl.shm)
        wl_shm_destroy(_glfw.wl.shm);
    if (_glfw.wl.shell)
        wl_shell_destroy(_glfw.wl.shell);
    if (_glfw.wl.pointer)
        wl_pointer_destroy(_glfw.wl.pointer);
    if (_glfw.wl.keyboard)
        wl_keyboard_destroy(_glfw.wl.keyboard);
    if (_glfw.wl.seat)
        wl_seat_destroy(_glfw.wl.seat);
    if (_glfw.wl.relativePointerManager)
        zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);
    if (_glfw.wl.pointerConstraints)
        zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);
    if (_glfw.wl.registry)
        wl_registry_destroy(_glfw.wl.registry);
    if (_glfw.wl.display)
    {
        wl_display_flush(_glfw.wl.display);
        wl_display_disconnect(_glfw.wl.display);
    }
}
Пример #24
0
int
main(int argc, char **argv)
{
    struct xkb_context *ctx;
    struct xkb_keymap *keymap;
    struct xkb_rule_names names = {
        .rules = NULL,
        .model = NULL,
        .layout = NULL,
        .variant = NULL,
        .options = NULL,
    };
    int rc;

    if (argc <= 1) {
        usage();
        return 1;
    }

    if (!parse_options(argc, argv, &names))
        return 1;

    ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
    assert(ctx);

    keymap = xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
    rc = (keymap == NULL);

    if (rc == 0 && print)
        printf("%s\n", xkb_keymap_get_as_string(keymap,
                                                XKB_KEYMAP_FORMAT_TEXT_V1));

    xkb_keymap_unref(keymap);
    xkb_context_unref(ctx);

    return rc;
}
int
main(int argc, char *argv[])
{
    struct xkb_context *ctx = test_get_context(0);
    struct xkb_keymap *keymap;
    char *original, *dump;

    assert(ctx);

    /* Load in a prebuilt keymap, make sure we can compile it from a string,
     * then compare it to make sure we get the same result when dumping it
     * to a string. */
    original = test_read_file(DATA_PATH);
    assert(original);

    keymap = test_compile_string(ctx, original);
    assert(keymap);

    dump = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT);
    assert(dump);

    if (!streq(original, dump)) {
        fprintf(stderr,
                "round-trip test failed: dumped map differs from original\n");
        fprintf(stderr, "path to original file: %s\n",
                test_get_path(DATA_PATH));
        fprintf(stderr, "length: dumped %lu, original %lu\n",
                (unsigned long) strlen(dump),
                (unsigned long) strlen(original));
        fprintf(stderr, "dumped map:\n");
        fprintf(stderr, "%s\n", dump);
        fflush(stderr);
        assert(0);
    }

    free(original);
    free(dump);
    xkb_keymap_unref(keymap);

    /* Make sure we can't (falsely claim to) compile an empty string. */
    keymap = test_compile_string(ctx, "");
    assert(!keymap);

    /* Make sure we can recompile our output for a normal keymap from rules. */
    keymap = test_compile_rules(ctx, NULL, NULL,
                                "ru,ca,de,us", ",multix,neo,intl", NULL);
    assert(keymap);
    dump = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT);
    assert(dump);
    xkb_keymap_unref(keymap);
    keymap = test_compile_string(ctx, dump);
    assert(keymap);

    /* Test response to invalid formats and flags. */
    assert(!xkb_keymap_new_from_string(ctx, dump, 0, 0));
    assert(!xkb_keymap_new_from_string(ctx, dump, -1, 0));
    assert(!xkb_keymap_new_from_string(ctx, dump, XKB_KEYMAP_FORMAT_TEXT_V1+1, 0));
    assert(!xkb_keymap_new_from_string(ctx, dump, XKB_KEYMAP_FORMAT_TEXT_V1, -1));
    assert(!xkb_keymap_new_from_string(ctx, dump, XKB_KEYMAP_FORMAT_TEXT_V1, 1414));
    assert(!xkb_keymap_get_as_string(keymap, 0));
    assert(!xkb_keymap_get_as_string(keymap, 4893));

    xkb_keymap_unref(keymap);
    free(dump);

    xkb_context_unref(ctx);

    return 0;
}
Пример #26
0
static void keyboardHandleKeymap(void* data,
                                 struct wl_keyboard* keyboard,
                                 uint32_t format,
                                 int fd,
                                 uint32_t size)
{
    struct xkb_keymap* keymap;
    struct xkb_state* state;

#ifdef HAVE_XKBCOMMON_COMPOSE_H
    struct xkb_compose_table* composeTable;
    struct xkb_compose_state* composeState;
#endif

    char* mapStr;
    const char* locale;

    if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
    {
        close(fd);
        return;
    }

    mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
    if (mapStr == MAP_FAILED) {
        close(fd);
        return;
    }

    keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
                                        mapStr,
                                        XKB_KEYMAP_FORMAT_TEXT_V1,
                                        0);
    munmap(mapStr, size);
    close(fd);

    if (!keymap)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to compile keymap");
        return;
    }

    state = xkb_state_new(keymap);
    if (!state)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to create XKB state");
        xkb_keymap_unref(keymap);
        return;
    }

    // Look up the preferred locale, falling back to "C" as default.
    locale = getenv("LC_ALL");
    if (!locale)
        locale = getenv("LC_CTYPE");
    if (!locale)
        locale = getenv("LANG");
    if (!locale)
        locale = "C";

#ifdef HAVE_XKBCOMMON_COMPOSE_H
    composeTable =
        xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
                                          XKB_COMPOSE_COMPILE_NO_FLAGS);
    if (composeTable)
    {
        composeState =
            xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
        xkb_compose_table_unref(composeTable);
        if (composeState)
            _glfw.wl.xkb.composeState = composeState;
        else
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "Wayland: Failed to create XKB compose state");
    }
    else
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Failed to create XKB compose table");
    }
#endif

    xkb_keymap_unref(_glfw.wl.xkb.keymap);
    xkb_state_unref(_glfw.wl.xkb.state);
    _glfw.wl.xkb.keymap = keymap;
    _glfw.wl.xkb.state = state;

    _glfw.wl.xkb.controlMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
    _glfw.wl.xkb.altMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
    _glfw.wl.xkb.shiftMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
    _glfw.wl.xkb.superMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
    _glfw.wl.xkb.capsLockMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
    _glfw.wl.xkb.numLockMask =
        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
}
Пример #27
0
static void free_keyboard(Keyboard *keyboard) {
    xkb_state_unref(keyboard->state);
    xkb_keymap_unref(keyboard->keymap);
    xkb_context_unref(keyboard->ctx);
}
Пример #28
0
void fill_keycodes() {

	struct xkb_keymap *keymap;
	struct xkb_context *context;
	const struct xkb_rule_names rules={
		.rules=xkb_names[0],
		.model=xkb_names[1],
		.layout=xkb_names[2],
		.variant=xkb_names[3],
		.options=xkb_names[4]
	};
	struct xkb_state *state;
	enum xkb_state_component current_state;
	int counter;
	int i,j,k;
	char mods[256];
	char keysym_asc[256];
	char file_path[256];
	char command[15];
	uint32_t max_keys;
	int w,h,retval;
	int jumpto;

	context=xkb_context_new(0);
	keymap=xkb_keymap_new_from_names(context,&rules,0);

	state=NULL;

	// Get all the modifier keys
	for(i=8;i<256;i++) {
		state=xkb_state_new(keymap);
		current_state=xkb_state_update_key(state, i,XKB_KEY_DOWN);
		if (current_state!=0) {
			mods[i]=1;
		} else {
			mods[i]=0;
		}
		xkb_state_unref(state);
	}
	mods[7]=1; // fake mod, used for "no mod"

	// Read the keyboard definition files

	sprintf(file_path,"%s/%s.keymap",BASE_CONFIG_DIR,lang_onscreen);

	FILE *keyboard_file=fopen(file_path,"r");
	if (keyboard_file==NULL) {
		printf("Can't open keyboard definition file %s. Trying with US file\n",file_path);
		sprintf(file_path,"%s/us.keymap",BASE_CONFIG_DIR);
		keyboard_file=fopen(file_path,"r");
		if (keyboard_file==NULL) {
			printf("Also failed to open the US keymap file. Aborting.\n");
			exit(-1);
		}
	}
	retval=fscanf(keyboard_file,"%s %d",command,&keyboard_blocks);
	if (retval!=2) {
		printf("Can't read the number of blocks\n");
	} else {
		max_keys=keyboard_blocks*4*KEYS_PER_ROW;
		keyboard_lowercase=(struct key_element *)malloc(max_keys*sizeof(struct key_element));
		memset(keyboard_lowercase,0,max_keys*sizeof(struct key_element));
		for(counter=0;(!feof(keyboard_file))&&(counter<max_keys);counter++) {
			retval=fscanf(keyboard_file,"%s %d %d",command,&w,&h);
			if(retval!=3) {
				break;
			}
			keyboard_lowercase[counter].size=KEYS_FONT_SIZE;
			keyboard_lowercase[counter].g_element[0]=0;
			keyboard_lowercase[counter].w=w;
			keyboard_lowercase[counter].h=h;
			keyboard_lowercase[counter].keycode=0;
			keyboard_lowercase[counter].modifier=0;
			if (!strcmp(command,"BLANK")) {
				keyboard_lowercase[counter].type=KEY_BLANK;
				keyboard_lowercase[counter].keysym=0;
			} else if (!strcmp(command,"KEY")) {
				keyboard_lowercase[counter].type=KEY_PH;
				retval=fscanf(keyboard_file,"%s",keyboard_lowercase[counter].g_element);
				keyboard_lowercase[counter].keysym=init_utf8_to_keysym(keyboard_lowercase[counter].g_element);
				if (keyboard_lowercase[counter].keysym==0) {
					keyboard_lowercase[counter].type=KEY_BLANK;
				}
			} else if ((!strcmp(command,"KEYSYM"))||(!strcmp(command,"KEYSYMTEXT"))) {
				keyboard_lowercase[counter].type=KEY_PH;
				retval=fscanf(keyboard_file,"%s",keysym_asc);
				keyboard_lowercase[counter].keysym=xkb_keysym_from_name(keysym_asc,0);
				if (keyboard_lowercase[counter].keysym==0) {
					printf("Unknown keysym %s\n",keysym_asc);
					keyboard_lowercase[counter].type=KEY_BLANK;
				} else {
					if (!strcmp(command,"KEYSYMTEXT")) {
						retval=fscanf(keyboard_file,"%s",keyboard_lowercase[counter].g_element);
						keyboard_lowercase[counter].size=KEYS_TEXT_FONT_SIZE;
					} else {
						retval=xkb_keysym_to_utf8(keyboard_lowercase[counter].keysym,keyboard_lowercase[counter].g_element,7);
						if (retval==-1) {
							retval++;
						}
						keyboard_lowercase[counter].g_element[retval]=0;// terminate string
					}
				}
			} else if (!strcmp(command,"TAB")) {
				keyboard_lowercase[counter].type=KEY_TAB;
				keyboard_lowercase[counter].keysym=XK_Tab;
			} else if (!strcmp(command,"SPACE")) {
				keyboard_lowercase[counter].type=KEY_SPACE;
				keyboard_lowercase[counter].keysym=XK_space;
			} else if (!strcmp(command,"RETURN")) {
				keyboard_lowercase[counter].type=KEY_RETURN;
				keyboard_lowercase[counter].keysym=XK_Return;
			} else if (!strcmp(command,"DELETE")) {
				keyboard_lowercase[counter].type=KEY_DELETE;
				keyboard_lowercase[counter].keysym=XK_BackSpace;
			} else if (!strcmp(command,"JUMPTO")) {
				retval=fscanf(keyboard_file,"%d %s",&jumpto,command);
				keyboard_lowercase[counter].type=KEY_JUMPTO;
				keyboard_lowercase[counter].keycode=jumpto;
				keyboard_lowercase[counter].keysym=0;
				if (!strcmp(command,"GEN")) {
					keyboard_lowercase[counter].modifier=0;
				} else if (!strcmp(command,"SHIFT")) {
					keyboard_lowercase[counter].modifier=1;
				} else if (!strcmp(command,"SYMBOLS")) {
					keyboard_lowercase[counter].modifier=2;
				} else if (!strcmp(command,"LETTERS")) {
					keyboard_lowercase[counter].modifier=3;
				}
				if (jumpto>=keyboard_blocks) {
					printf("Ilegal jump to block %d (max. is %d)\n",jumpto,keyboard_blocks);
					keyboard_lowercase[counter].type=KEY_BLANK;
				}
			} else if (!strcmp(command,"UP")) {
				keyboard_lowercase[counter].type=KEY_UP;
				keyboard_lowercase[counter].keysym=XK_Up;
			} else if (!strcmp(command,"DOWN")) {
				keyboard_lowercase[counter].type=KEY_DOWN;
				keyboard_lowercase[counter].keysym=XK_Down;
			} else if (!strcmp(command,"LEFT")) {
				keyboard_lowercase[counter].type=KEY_LEFT;
				keyboard_lowercase[counter].keysym=XK_Left;
			} else if (!strcmp(command,"RIGHT")) {
				keyboard_lowercase[counter].type=KEY_RIGHT;
				keyboard_lowercase[counter].keysym=XK_Right;
			} else {
				printf("Unknown command %s\n",command);
				keyboard_lowercase[counter].type=KEY_BLANK;
				keyboard_lowercase[counter].keysym=0;
			}
		}

		xkb_keysym_t  keysym;
		xkb_keycode_t keycode_mod;
		for(i=7;i<256;i++) { // do a loop on every modifier
			if (!mods[i]) {
				continue; // In this loop we test each modifier with each keycode
			}
			state=xkb_state_new(keymap);
			if (i!=7) {
				xkb_state_update_key(state, i,XKB_KEY_DOWN); // press the modifier key
				keycode_mod=i;
			} else {
				keycode_mod=0;
			}
			for(j=8;j<256;j++) {
				if (mods[j]) {
					continue;  // Don't test modifiers; we want "normal" keys
				}
				keysym=xkb_state_key_get_one_sym(state, j);
				if (keysym==XKB_KEY_NoSymbol) {
					continue;
				}
				for(k=0;k<counter;k++) { // and now we check each desired key with the keysymbol obtained
					if ((keyboard_lowercase[k].keycode==0)&&(keyboard_lowercase[k].type!=KEY_BLANK)&&(keyboard_lowercase[k].keysym==keysym)) {
						keyboard_lowercase[k].keycode=j;
						keyboard_lowercase[k].modifier=keycode_mod;
					}
				}
			}
			xkb_state_unref(state);
		}
		/*for(k=0;k<counter;k++) { // and now we check each desired key with the keysymbol obtained
			printf("Texto: %s, Keysym: %d, mod: %d\n",keyboard_lowercase[k].g_element,keyboard_lowercase[k].keycode,keyboard_lowercase[k].modifier);
		}*/

		// Now assign new keysyms to keycodes not used, to allow other keysyms not available in US keyboards

		xcb_key_symbols_t *symbols;

		symbols=xcb_key_symbols_alloc(conn);
		xcb_flush(conn);

		xcb_keycode_t keycode=8;
		xcb_keycode_t keycode_found;

		xcb_keysym_t keysyms[4];
		xcb_keycode_t keycode_shift;

		struct lower_upper_t {xcb_keysym_t upper_first;
				xcb_keysym_t upper_last;
				xcb_keysym_t lower_first;
				xcb_keysym_t lower_last;
			};

		struct lower_upper_t lower_upper[] = {
				{XKB_KEY_Agrave,XKB_KEY_Odiaeresis,XKB_KEY_agrave,XKB_KEY_odiaeresis},
				{XKB_KEY_Oslash,XKB_KEY_THORN,XKB_KEY_oslash,XKB_KEY_thorn},
				{0,0,0,0}
			};
		struct lower_upper_t *iter_lu;

		keycode_shift=*xcb_key_symbols_get_keycode(symbols,XKB_KEY_Shift_L);
		for(k=0;k<max_keys;k++) { // and now we check each desired key with the keysymbol obtained
			if ((keyboard_lowercase[k].keycode==0)&&(keyboard_lowercase[k].type!=KEY_BLANK)&&(keyboard_lowercase[k].type!=KEY_JUMPTO)) {
				// this key is not available in US keyboards; let's redefine a keycode for it
				keycode_found=0;
				while(keycode<256) {
					if ((0==xcb_key_symbols_get_keysym(symbols,keycode,0))&&
						(0==xcb_key_symbols_get_keysym(symbols,keycode,1))&&
						(0==xcb_key_symbols_get_keysym(symbols,keycode,2))&&
						(0==xcb_key_symbols_get_keysym(symbols,keycode,3))) {
							keycode_found=keycode;
							break;
					}
					keycode++;
				}

				if (keycode_found==0) {
					printf("No more codes available\n");
					break; // there are no more free keycodes available
				}
				keycode=keycode_found;
				keysyms[0]=keyboard_lowercase[k].keysym;
				keysyms[1]=0;
				keysyms[2]=keyboard_lowercase[k].keysym;
				keysyms[3]=0;
				for(iter_lu=lower_upper;iter_lu->upper_first;iter_lu++) {
					if ((keysyms[0]>=iter_lu->upper_first)&&(keysyms[0]<=iter_lu->upper_last)) { // it's an uppercase special character
						keysyms[0]|=0x20; // first character as lowercase
						break;
					}
					if ((keysyms[0]>=iter_lu->lower_first)&&(keysyms[0]<=iter_lu->lower_last)) { // it's a lowercase special character
						keysyms[2]&=0xDF; // second character as uppercase
						break;
					}
				}
				xcb_change_keyboard_mapping(conn,1,keycode,4,keysyms); // insert the new keysym
				for(j=k;j<max_keys;j++) { // set the keycode and the shift modifier, if needed, to all keys with that keysyms
					if (keyboard_lowercase[j].keysym==keysyms[0]) {
						keyboard_lowercase[j].keycode=keycode;
						keyboard_lowercase[j].modifier=0;
						continue;
					}
					if (keyboard_lowercase[j].keysym==keysyms[2]) {
						keyboard_lowercase[j].keycode=keycode;
						keyboard_lowercase[j].modifier=keycode_shift;
						continue;
					}
				}
				keycode++;
			}
		}
		xcb_key_symbols_free(symbols);
	}

	fclose(keyboard_file);
	keyboard_current_block=0;
	xkb_keymap_unref(keymap);
	xkb_context_unref(context);
}
Пример #29
0
int uxkb_desc_init(struct uterm_input *input,
		   const char *model,
		   const char *layout,
		   const char *variant,
		   const char *options,
		   const char *keymap)
{
	int ret;
	struct xkb_rule_names rmlvo = {
		.rules = "evdev",
		.model = model,
		.layout = layout,
		.variant = variant,
		.options = options,
	};

	input->ctx = xkb_context_new(0);
	if (!input->ctx) {
		log_error("cannot create XKB context");
		return -ENOMEM;
	}

	/* If a complete keymap file was given, first try that. */
	if (keymap && *keymap) {
		input->keymap = xkb_keymap_new_from_string(input->ctx,
					keymap, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
		if (input->keymap) {
			log_debug("new keyboard description from memory");
			return 0;
		}

		log_warn("cannot parse keymap, reverting to rmlvo");
	}

	input->keymap = xkb_keymap_new_from_names(input->ctx, &rmlvo, 0);
	if (!input->keymap) {
		log_warn("failed to create keymap (%s, %s, %s, %s), "
			 "reverting to default system keymap",
			 model, layout, variant, options);

		rmlvo.model = "";
		rmlvo.layout = "";
		rmlvo.variant = "";
		rmlvo.options = "";

		input->keymap = xkb_keymap_new_from_names(input->ctx,
							  &rmlvo, 0);
		if (!input->keymap) {
			log_warn("failed to create XKB keymap");
			ret = -EFAULT;
			goto err_ctx;
		}
	}

	log_debug("new keyboard description (%s, %s, %s, %s)",
		  model, layout, variant, options);
	return 0;

err_ctx:
	xkb_context_unref(input->ctx);
	return ret;
}

void uxkb_desc_destroy(struct uterm_input *input)
{
	xkb_keymap_unref(input->keymap);
	xkb_context_unref(input->ctx);
}
Пример #30
0
int
main(int argc, char *argv[])
{
    int ret;
    int opt;
    struct keyboard *kbds;
    struct xkb_context *ctx;
    struct xkb_keymap *keymap;
    const char *rules = NULL;
    const char *model = NULL;
    const char *layout = NULL;
    const char *variant = NULL;
    const char *options = NULL;
    const char *keymap_path = NULL;
    struct sigaction act;

    setlocale(LC_ALL, "");

    while ((opt = getopt(argc, argv, "r:m:l:v:o:k:n:c")) != -1) {
        switch (opt) {
        case 'r':
            rules = optarg;
            break;
        case 'm':
            model = optarg;
            break;
        case 'l':
            layout = optarg;
            break;
        case 'v':
            variant = optarg;
            break;
        case 'o':
            options = optarg;
            break;
        case 'k':
            keymap_path = optarg;
            break;
        case 'n':
            errno = 0;
            evdev_offset = strtol(optarg, NULL, 10);
            if (errno) {
                fprintf(stderr, "error: -n option expects a number\n");
                exit(EXIT_FAILURE);
            }
            break;
        case 'c':
            report_state_changes = true;
            break;
        case '?':
            fprintf(stderr, "   Usage: %s [-r <rules>] [-m <model>] "
                    "[-l <layout>] [-v <variant>] [-o <options>]\n",
                    argv[0]);
            fprintf(stderr, "      or: %s -k <path to keymap file>\n",
                    argv[0]);
            fprintf(stderr, "For both: -n <evdev keycode offset>\n"
                            "          -c (to report changes to the state)\n");
            exit(EX_USAGE);
        }
    }

    ctx = test_get_context(0);
    if (!ctx) {
        ret = -1;
        fprintf(stderr, "Couldn't create xkb context\n");
        goto err_out;
    }

    if (keymap_path) {
        FILE *file = fopen(keymap_path, "r");
        if (!file) {
            ret = EXIT_FAILURE;
            fprintf(stderr, "Couldn't open '%s': %s\n",
                    keymap_path, strerror(errno));
            goto err_ctx;
        }
        keymap = xkb_keymap_new_from_file(ctx, file,
                                          XKB_KEYMAP_FORMAT_TEXT_V1, 0);
        fclose(file);
    }
    else {
        keymap = test_compile_rules(ctx, rules, model, layout, variant,
                                    options);
    }

    if (!keymap) {
        ret = -1;
        fprintf(stderr, "Couldn't create xkb keymap\n");
        goto err_ctx;
    }

    kbds = get_keyboards(keymap);
    if (!kbds) {
        ret = -1;
        goto err_xkb;
    }

    act.sa_handler = sigintr_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGINT, &act, NULL);
    sigaction(SIGTERM, &act, NULL);

    /* Instead of fiddling with termios.. */
    system("stty -echo");

    ret = loop(kbds);
    if (ret)
        goto err_stty;

err_stty:
    system("stty echo");
    free_keyboards(kbds);
err_xkb:
    xkb_keymap_unref(keymap);
err_ctx:
    xkb_context_unref(ctx);
err_out:
    exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}