diff --git a/protocol/input-method.xml b/protocol/input-method.xml index 69b1277a..0f156441 100644 --- a/protocol/input-method.xml +++ b/protocol/input-method.xml @@ -70,6 +70,15 @@ + + + Allows an input method to receive hardware keyboard input and process + key events to generate text events (with pre-edit) over the. This allows + input methods which compose multiple key events for inputting text + like it is done for CJK languages. + + + The plain surrounding text around the input position. Cursor is the diff --git a/src/text-backend.c b/src/text-backend.c index ece89bb9..edcb08ec 100644 --- a/src/text-backend.c +++ b/src/text-backend.c @@ -72,8 +72,12 @@ struct input_method_context { struct wl_resource resource; struct text_model *model; + struct input_method *input_method; struct wl_list link; + + struct wl_resource *keyboard; + struct wl_keyboard_grab grab; }; struct text_backend { @@ -92,6 +96,7 @@ struct text_backend { static void input_method_context_create(struct text_model *model, struct input_method *input_method); +static void input_method_context_end_keyboard_grab(struct input_method_context *context); static void input_method_init_seat(struct weston_seat *seat); @@ -102,8 +107,12 @@ deactivate_text_model(struct text_model *text_model, struct weston_compositor *ec = text_model->ec; if (input_method->model == text_model) { - if (input_method->context && input_method->input_method_binding) - input_method_send_deactivate(input_method->input_method_binding, &input_method->context->resource); + if (input_method->context && input_method->input_method_binding) { + input_method_context_end_keyboard_grab(input_method->context); + input_method_send_deactivate(input_method->input_method_binding, + &input_method->context->resource); + } + wl_list_remove(&input_method->link); input_method->model = NULL; input_method->context = NULL; @@ -374,13 +383,85 @@ input_method_context_keysym(struct wl_client *client, sym, state, modifiers); } +static void +unbind_keyboard(struct wl_resource *resource) +{ + struct input_method_context *context = resource->data; + + input_method_context_end_keyboard_grab(context); + context->keyboard = NULL; + + free(resource); +} + +static void +input_method_context_grab_key(struct wl_keyboard_grab *grab, + uint32_t time, uint32_t key, uint32_t state_w) +{ + struct input_method_context *input_method_context = container_of(grab, struct input_method_context, grab); + uint32_t serial; + + if (input_method_context->keyboard) { + serial = wl_display_next_serial(input_method_context->model->ec->wl_display); + wl_keyboard_send_key(input_method_context->keyboard, + serial, time, key, state_w); + } +} + +static void +input_method_context_grab_modifier(struct wl_keyboard_grab *grab, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + struct input_method_context *input_method_context = container_of(grab, struct input_method_context, grab); + + if (!input_method_context->keyboard) + return; + + wl_keyboard_send_modifiers(input_method_context->keyboard, + serial, mods_depressed, mods_latched, + mods_locked, group); +} + +static const struct wl_keyboard_grab_interface input_method_context_grab = { + input_method_context_grab_key, + input_method_context_grab_modifier, +}; + +static void +input_method_context_grab_keyboard(struct wl_client *client, + struct wl_resource *resource, + uint32_t id) +{ + struct input_method_context *context = resource->data; + struct wl_resource *cr; + struct weston_seat *seat = context->input_method->seat; + struct wl_keyboard *keyboard = seat->seat.keyboard; + + cr = wl_client_add_object(client, &wl_keyboard_interface, + NULL, id, context); + cr->destroy = unbind_keyboard; + + context->keyboard = cr; + + wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + seat->xkb_info.keymap_fd, + seat->xkb_info.keymap_size); + + if (keyboard->grab != &keyboard->default_grab) { + wl_keyboard_end_grab(keyboard); + } + wl_keyboard_start_grab(keyboard, &context->grab); +} + static const struct input_method_context_interface input_method_context_implementation = { input_method_context_destroy, input_method_context_commit_string, input_method_context_preedit_string, input_method_context_delete_surrounding_text, input_method_context_modifiers_map, - input_method_context_keysym + input_method_context_keysym, + input_method_context_grab_keyboard }; static void @@ -388,6 +469,10 @@ destroy_input_method_context(struct wl_resource *resource) { struct input_method_context *context = resource->data; + if (context->keyboard) { + wl_resource_destroy(context->keyboard); + } + free(context); } @@ -400,7 +485,7 @@ input_method_context_create(struct text_model *model, if (!input_method->input_method_binding) return; - context = malloc(sizeof *context); + context = calloc(1, sizeof *context); if (context == NULL) return; @@ -413,13 +498,27 @@ input_method_context_create(struct text_model *model, wl_signal_init(&context->resource.destroy_signal); context->model = model; + context->input_method = input_method; input_method->context = context; + context->grab.interface = &input_method_context_grab; + wl_client_add_resource(input_method->input_method_binding->client, &context->resource); input_method_send_activate(input_method->input_method_binding, &context->resource); } +static void +input_method_context_end_keyboard_grab(struct input_method_context *context) +{ + struct wl_keyboard_grab *grab = &context->grab; + + if (grab->keyboard && (grab->keyboard->grab == grab)) { + wl_keyboard_end_grab(grab->keyboard); + } +} + + static void unbind_input_method(struct wl_resource *resource) {