| /* | |
| * Copyright (C) 2026 Igalia S.L. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
| * THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include "BrowserLoggingInputMethodContext.h" | |
| struct _BrowserLoggingInputMethodContext { | |
| WebKitInputMethodContext parent; | |
| gboolean focused; | |
| }; | |
| G_DEFINE_TYPE(BrowserLoggingInputMethodContext, browser_logging_input_method_context, WEBKIT_TYPE_INPUT_METHOD_CONTEXT) | |
| #define logInputMethod(...) \ | |
| g_log("MiniBrowser-IM", G_LOG_LEVEL_MESSAGE, __VA_ARGS__) | |
| static const char *purposeName(WebKitInputPurpose purpose) | |
| { | |
| switch (purpose) { | |
| case WEBKIT_INPUT_PURPOSE_FREE_FORM: | |
| return "FreeForm"; | |
| case WEBKIT_INPUT_PURPOSE_DIGITS: | |
| return "Digits"; | |
| case WEBKIT_INPUT_PURPOSE_NUMBER: | |
| return "Number"; | |
| case WEBKIT_INPUT_PURPOSE_PHONE: | |
| return "Phone"; | |
| case WEBKIT_INPUT_PURPOSE_URL: | |
| return "Url"; | |
| case WEBKIT_INPUT_PURPOSE_EMAIL: | |
| return "Email"; | |
| case WEBKIT_INPUT_PURPOSE_PASSWORD: | |
| return "Password"; | |
| case WEBKIT_INPUT_PURPOSE_SEARCH: | |
| return "Search"; | |
| } | |
| return "Unknown"; | |
| } | |
| static const char *enterKeyHintName(WebKitInputEnterKeyHint hint) | |
| { | |
| switch (hint) { | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_UNSPECIFIED: | |
| return "Unspecified"; | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_ENTER: | |
| return "Enter"; | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_DONE: | |
| return "Done"; | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_GO: | |
| return "Go"; | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_NEXT: | |
| return "Next"; | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_PREVIOUS: | |
| return "Previous"; | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_SEARCH: | |
| return "Search"; | |
| case WEBKIT_INPUT_ENTER_KEY_HINT_SEND: | |
| return "Send"; | |
| } | |
| return "Unknown"; | |
| } | |
| static char *hintsDescription(WebKitInputHints hints) | |
| { | |
| GString *description; | |
| if (!hints) | |
| return g_strdup("None"); | |
| description = g_string_new(NULL); | |
| #define APPEND_HINT(hint, name) \ | |
| if (hints & hint) \ | |
| g_string_append(description, description->len ? "|" name : name); | |
| APPEND_HINT(WEBKIT_INPUT_HINT_SPELLCHECK, "Spellcheck"); | |
| APPEND_HINT(WEBKIT_INPUT_HINT_LOWERCASE, "Lowercase"); | |
| APPEND_HINT(WEBKIT_INPUT_HINT_UPPERCASE_CHARS, "UppercaseChars"); | |
| APPEND_HINT(WEBKIT_INPUT_HINT_UPPERCASE_WORDS, "UppercaseWords"); | |
| APPEND_HINT(WEBKIT_INPUT_HINT_UPPERCASE_SENTENCES, "UppercaseSentences"); | |
| APPEND_HINT(WEBKIT_INPUT_HINT_INHIBIT_OSK, "InhibitOSK"); | |
| APPEND_HINT(WEBKIT_INPUT_HINT_PRIVATE, "Private"); | |
| #undef APPEND_HINT | |
| return g_string_free(description, FALSE); | |
| } | |
| static void logContentType(WebKitInputMethodContext *context, const char *event) | |
| { | |
| g_autofree char *hints = hintsDescription(webkit_input_method_context_get_input_hints(context)); | |
| logInputMethod("%s: purpose=%s hints=%s enter-key-hint=%s", event, purposeName(webkit_input_method_context_get_input_purpose(context)), hints, | |
| enterKeyHintName(webkit_input_method_context_get_enter_key_hint(context))); | |
| } | |
| static void browserLoggingInputMethodContextDispatchPropertiesChanged(GObject *object, guint propertyCount, GParamSpec **properties) | |
| { | |
| guint i; | |
| G_OBJECT_CLASS(browser_logging_input_method_context_parent_class)->dispatch_properties_changed(object, propertyCount, properties); | |
| if (!BROWSER_LOGGING_INPUT_METHOD_CONTEXT(object)->focused) | |
| return; | |
| for (i = 0; i < propertyCount; i++) { | |
| if (g_str_equal(properties[i]->name, "input-purpose") || g_str_equal(properties[i]->name, "input-hints") || g_str_equal(properties[i]->name, "enter-key-hint")) { | |
| logContentType(WEBKIT_INPUT_METHOD_CONTEXT(object), "content type"); | |
| return; | |
| } | |
| } | |
| } | |
| static void browserLoggingInputMethodContextSetEnablePreedit(WebKitInputMethodContext *context G_GNUC_UNUSED, gboolean enabled) | |
| { | |
| logInputMethod("set enable preedit: %s", enabled ? "yes" : "no"); | |
| } | |
| static void browserLoggingInputMethodContextNotifyFocusIn(WebKitInputMethodContext *context) | |
| { | |
| BROWSER_LOGGING_INPUT_METHOD_CONTEXT(context)->focused = TRUE; | |
| logContentType(context, "focus in"); | |
| } | |
| static void browserLoggingInputMethodContextNotifyFocusOut(WebKitInputMethodContext *context) | |
| { | |
| BROWSER_LOGGING_INPUT_METHOD_CONTEXT(context)->focused = FALSE; | |
| logInputMethod("focus out"); | |
| } | |
| static void browserLoggingInputMethodContextNotifyCursorArea(WebKitInputMethodContext *context G_GNUC_UNUSED, int x, int y, int width, int height) | |
| { | |
| logInputMethod("cursor area: %d,%d %dx%d", x, y, width, height); | |
| } | |
| static void browserLoggingInputMethodContextNotifySurrounding(WebKitInputMethodContext *context G_GNUC_UNUSED, const char *text G_GNUC_UNUSED, guint length, guint cursorIndex, guint selectionIndex) | |
| { | |
| logInputMethod("surrounding: %u bytes, cursor=%u, selection=%u", length, cursorIndex, selectionIndex); | |
| } | |
| static void browserLoggingInputMethodContextReset(WebKitInputMethodContext *context G_GNUC_UNUSED) | |
| { | |
| logInputMethod("reset"); | |
| } | |
| static void browser_logging_input_method_context_class_init(BrowserLoggingInputMethodContextClass *klass) | |
| { | |
| GObjectClass *objectClass = G_OBJECT_CLASS(klass); | |
| objectClass->dispatch_properties_changed = browserLoggingInputMethodContextDispatchPropertiesChanged; | |
| WebKitInputMethodContextClass *contextClass = WEBKIT_INPUT_METHOD_CONTEXT_CLASS(klass); | |
| contextClass->set_enable_preedit = browserLoggingInputMethodContextSetEnablePreedit; | |
| contextClass->notify_focus_in = browserLoggingInputMethodContextNotifyFocusIn; | |
| contextClass->notify_focus_out = browserLoggingInputMethodContextNotifyFocusOut; | |
| contextClass->notify_cursor_area = browserLoggingInputMethodContextNotifyCursorArea; | |
| contextClass->notify_surrounding = browserLoggingInputMethodContextNotifySurrounding; | |
| contextClass->reset = browserLoggingInputMethodContextReset; | |
| } | |
| static void browser_logging_input_method_context_init(BrowserLoggingInputMethodContext *context G_GNUC_UNUSED) | |
| { | |
| } | |
| WebKitInputMethodContext *browser_logging_input_method_context_new(void) | |
| { | |
| return WEBKIT_INPUT_METHOD_CONTEXT(g_object_new(BROWSER_TYPE_LOGGING_INPUT_METHOD_CONTEXT, NULL)); | |
| } |