diff --git a/config/flags.go b/config/flags.go index 96d11693..abf3a272 100644 --- a/config/flags.go +++ b/config/flags.go @@ -40,17 +40,17 @@ const ( IBspellCheckWithRules IBspellCheckWithDicts IBautoCommitWithDelay - IBautoCommitWithMouseMovement - _IBemojiDisabled //deprecated + _IBautoCommitWithMouseMovement //deprecated + _IBemojiDisabled //deprecated IBpreeditElimination _IBinputModeLookupTableEnabled //deprecated IBautoCapitalizeMacro _IBimQuickSwitchEnabled //deprecated _IBrestoreKeyStrokesEnabled //deprecated - IBmouseCapturing + _IBmouseCapturing //deprecated IBworkaroundForFBMessenger IBworkaroundForWPS IBstdFlags = IBspellCheckEnabled | IBspellCheckWithRules | IBautoNonVnRestore | IBddFreeStyle | - IBmouseCapturing | IBautoCapitalizeMacro | IBnoUnderline | IBworkaroundForWPS + IBautoCapitalizeMacro | IBnoUnderline | IBworkaroundForWPS IBUsStdFlags = 0 ) diff --git a/engine.go b/engine.go index e5bff2f9..3533919c 100644 --- a/engine.go +++ b/engine.go @@ -124,11 +124,6 @@ func (e *IBusBambooEngine) FocusIn() *dbus.Error { if e.config.IBflags&config.IBspellCheckWithDicts != 0 && len(dictionary) == 0 { dictionary, _ = loadDictionary(DictVietnameseCm) } - if inStringList(disabledMouseCapturingList, e.getWmClass()) { - stopMouseCapturing() - } else if e.config.IBflags&config.IBmouseCapturing != 0 { - startMouseCapturing() - } fmt.Printf("WM_CLASS=(%s)\n", e.getWmClass()) return nil } @@ -141,7 +136,7 @@ func (e *IBusBambooEngine) FocusOut() *dbus.Error { func (e *IBusBambooEngine) Reset() *dbus.Error { fmt.Print("Reset.\n") if e.checkInputMode(config.PreeditIM) { - e.commitPreeditAndReset(e.getPreeditString()) + e.preeditor.Reset() } return nil } @@ -333,17 +328,6 @@ func (e *IBusBambooEngine) PropertyActivate(propName string, propState uint32) * e.config.IBflags &= ^config.IBspellCheckWithDicts } } - if propName == PropKeyMouseCapturing { - if propState == ibus.PROP_STATE_CHECKED { - e.config.IBflags |= config.IBmouseCapturing - startMouseCapturing() - startMouseRecording() - } else { - e.config.IBflags &= ^config.IBmouseCapturing - stopMouseCapturing() - stopMouseRecording() - } - } if propName == PropKeyMacroEnabled { if propState == ibus.PROP_STATE_CHECKED { e.config.IBflags |= config.IBmacroEnabled diff --git a/engine_preedit.go b/engine_preedit.go index 0ec5601f..307a77dc 100644 --- a/engine_preedit.go +++ b/engine_preedit.go @@ -91,11 +91,6 @@ func (e *IBusBambooEngine) expandMacro(str string) string { } func (e *IBusBambooEngine) updatePreedit(processedStr string) { - defer func() { - if e.config.IBflags&config.IBmouseCapturing != 0 { - mouseCaptureUnlock() - } - }() var encodedStr = e.encodeText(processedStr) var preeditLen = uint32(len([]rune(encodedStr))) if preeditLen == 0 { diff --git a/engine_utils.go b/engine_utils.go index f7a583c4..017d85bf 100644 --- a/engine_utils.go +++ b/engine_utils.go @@ -27,7 +27,6 @@ import ( "os" "strconv" "strings" - "sync" "sync/atomic" "time" "unicode" @@ -86,39 +85,6 @@ func (e *IBusBambooEngine) init() { } } keyPressHandler = e.keyPressForwardHandler - - if e.config.IBflags&config.IBmouseCapturing != 0 { - startMouseCapturing() - startMouseRecording() - } - var mouseMutex sync.Mutex - onMouseMove = func() { - mouseMutex.Lock() - defer mouseMutex.Unlock() - if e.checkInputMode(config.PreeditIM) { - if e.getRawKeyLen() == 0 { - return - } - e.commitPreeditAndReset(e.getPreeditString()) - } - } - onMouseClick = func() { - mouseMutex.Lock() - defer mouseMutex.Unlock() - if e.isEmojiLTOpened { - e.refreshEmojiCandidate() - } else { - e.resetFakeBackspace() - e.resetBuffer() - e.keyPressDelay = KeypressDelayMs - if e.capabilities&IBusCapSurroundingText != 0 { - //e.ForwardKeyEvent(IBUS_Shift_R, XK_Shift_R-8, 0) - x11SendShiftR() - e.isSurroundingTextReady = true - e.keyPressDelay = KeypressDelayMs * 10 - } - } - } } func initConfigFiles(engineName string) { @@ -418,6 +384,7 @@ func (e *IBusBambooEngine) updateInputModeLT() { func isValidState(state uint32) bool { if state&IBusControlMask != 0 || state&IBusMod1Mask != 0 || + state&IBusMod4Mask != 0 || state&IBusIgnoredMask != 0 || state&IBusSuperMask != 0 || state&IBusHyperMask != 0 || diff --git a/ibus_const.go b/ibus_const.go index 7b010e71..d12cef4c 100644 --- a/ibus_const.go +++ b/ibus_const.go @@ -24,6 +24,7 @@ const ( IBusLockMask = 1 << 1 IBusControlMask = 1 << 2 IBusMod1Mask = 1 << 3 + IBusMod4Mask = 1 << 6 /* The next few modifiers are used by XKB so we skip to the end. * Bits 15 - 23 are currently unused. Bit 29 is used internally. @@ -41,7 +42,7 @@ const ( IBusReleaseMask = 1 << 30 IBusModifierMask = 0x5f001fff - IBusDefaultModMask = IBusControlMask | IBusShiftMask | IBusMod1Mask | IBusSuperMask | IBusHyperMask | IBusMetaMask + IBusDefaultModMask = IBusControlMask | IBusShiftMask | IBusMod1Mask | IBusMod4Mask | IBusSuperMask | IBusHyperMask | IBusMetaMask | 0xffeb ) const ( diff --git a/prop.go b/prop.go index 87bc0a21..cc0ae1dd 100644 --- a/prop.go +++ b/prop.go @@ -36,7 +36,6 @@ const ( PropKeySpellCheckByDicts = "spell_check_by_dicts" PropKeyPreeditInvisibility = "preedit_invisibility" PropKeyVnCharsetConvert = "charset_convert_page" - PropKeyMouseCapturing = "mouse_capturing" PropKeyMacroEnabled = "macro_enabled" PropKeyMacroTable = "open_macro_table" PropKeyEmojiEnabled = "emoji_enabled" @@ -369,10 +368,6 @@ func GetOptionsPropListByConfig(c *config.Config) *ibus.PropList { toneFreeMarkingChecked := ibus.PROP_STATE_UNCHECKED preeditInvisibilityChecked := ibus.PROP_STATE_UNCHECKED x11FakeBackspaceChecked := ibus.PROP_STATE_UNCHECKED - mouseCapturingChecked := ibus.PROP_STATE_UNCHECKED - if c.IBflags&config.IBmouseCapturing != 0 { - mouseCapturingChecked = ibus.PROP_STATE_CHECKED - } if c.Flags&bamboo.EstdToneStyle != 0 { toneStdChecked = ibus.PROP_STATE_CHECKED @@ -424,18 +419,6 @@ func GetOptionsPropListByConfig(c *config.Config) *ibus.PropList { Symbol: dbus.MakeVariant(ibus.NewText("P")), SubProps: dbus.MakeVariant(*ibus.NewPropList()), }, - &ibus.Property{ - Name: "IBusProperty", - Key: PropKeyMouseCapturing, - Type: ibus.PROP_TYPE_TOGGLE, - Label: dbus.MakeVariant(ibus.NewText("Bắt sự kiện chuột")), - Tooltip: dbus.MakeVariant(ibus.NewText("Mouse capturing")), - Sensitive: true, - Visible: true, - State: mouseCapturingChecked, - Symbol: dbus.MakeVariant(ibus.NewText("F")), - SubProps: dbus.MakeVariant(*ibus.NewPropList()), - }, &ibus.Property{ Name: "IBusProperty", Key: PropKeyPreeditElimination, diff --git a/utils.go b/utils.go index 3de4554a..5e6e0ecd 100644 --- a/utils.go +++ b/utils.go @@ -64,18 +64,12 @@ var enabledAuxiliaryTextList = []string{ "wpsoffice:wpsoffice", } -var disabledMouseCapturingList = []string{ - "DesktopEditors", //onlyoffice - "DesktopEditors:DesktopEditors", //onlyoffice -} - var DefaultBrowserList = []string{ "Navigator:Firefox", "google-chrome:Google-chrome", "chromium-browser:Chromium-browser", } - func getEngineSubFile(fileName string) string { if _, err := os.Stat(fileName); err == nil { // return source code data/macro.tpl.txt path diff --git a/x11.go b/x11.go index e3fa5d92..3a0ae211 100644 --- a/x11.go +++ b/x11.go @@ -29,12 +29,6 @@ extern void x11Paste(int); extern void clipboard_init(); extern void clipboard_exit(); extern void x11ClipboardReset(); -extern void mouse_capture_init(); -extern void mouse_capture_exit(); -extern void mouse_capture_unlock(); -extern void mouse_capture_start_or_unlock(); -extern void mouse_recording_init(); -extern void mouse_recording_exit(); extern void x11SendBackspace(int n, int timeout); extern void x11SendShiftR(); extern void x11SendShiftLeft(int n, int r, int timeout); @@ -58,19 +52,6 @@ func init() { C.setXIgnoreErrorHandler() } -//export mouse_move_handler -func mouse_move_handler() { - onMouseMove() -} - -//export mouse_click_handler -func mouse_click_handler() { - onMouseClick() -} - -var onMouseMove func() -var onMouseClick func() - func x11StartWindowInspector() { C.x11StartWindowInspector() } @@ -79,48 +60,6 @@ func x11StopWindowInspector() { C.x11StopWindowInspector() } -func startMouseRecording() { - C.mouse_recording_init() -} - -func stopMouseRecording() { - C.mouse_recording_exit() -} - -func startMouseCapturing() { - mcapMutex.Lock() - defer mcapMutex.Unlock() - if !mcapRunning { - C.mouse_capture_init() - mcapRunning = true - } -} - -func stopMouseCapturing() { - mcapMutex.RLock() - defer mcapMutex.RUnlock() - if mcapRunning { - C.mouse_capture_exit() - } -} - -func mouseCaptureStartOrUnlock() { - mcapMutex.Lock() - defer mcapMutex.Unlock() - if !mcapRunning { - C.mouse_capture_start_or_unlock() - mcapRunning = true - } -} - -func mouseCaptureUnlock() { - mcapMutex.RLock() - defer mcapMutex.RUnlock() - if mcapRunning { - C.mouse_capture_unlock() - } -} - func x11Copy(str string) { cs := C.CString(str) defer C.free(unsafe.Pointer(cs)) diff --git a/x11_mouse.c b/x11_mouse.c deleted file mode 100644 index 128fba42..00000000 --- a/x11_mouse.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Bamboo - A Vietnamese Input method editor - * Copyright (C) 2012 Le Quoc Tuan - * Copyright (C) 2018-2020 Luong Thanh Lam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "_cgo_export.h" -#define CAPTURE_MOUSE_MOVE_DELTA 50 - -static pthread_t th_mcap; -static pthread_mutex_t mutex_mcap; -static Display* dpy; -static int mcap_running; - -static void signalHandler(int signo) { - mcap_running = signo; -} -/** - * milliseconds over 1000 will be ignored - */ -static void delay(time_t sec, long msec) { - struct timespec sleep; - - sleep.tv_sec = sec; - sleep.tv_nsec = (msec % 1000) * 1000 * 1000; - - if (nanosleep(&sleep, NULL) == -1) { - signalHandler(1); - } -} -/** - * returns 0 for failure, 1 for success - */ -static int grabPointer(Display *dpy, Window w, unsigned int mask) { - int rc; - - /* retry until we actually get the pointer (with a suitable delay) - * or we get an error we can't recover from. */ - while (mcap_running == 1) { - rc = XGrabPointer(dpy, w, 0, ButtonPressMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - - switch (rc) { - case GrabSuccess: - fprintf(stderr, "XGrabPointer: successfully grabbed mouse pointer\n"); - return 1; - - case AlreadyGrabbed: - fprintf(stderr, "XGrabPointer: already grabbed mouse pointer, retrying with delay\n"); - delay(1, 500); - break; - - case GrabFrozen: - fprintf(stderr, "XGrabPointer: grab was frozen, retrying after delay\n"); - delay(1, 500); - break; - - case GrabNotViewable: - fprintf(stderr, "XGrabPointer: grab was not viewable, exiting\n"); - return 0; - - case GrabInvalidTime: - fprintf(stderr, "XGrabPointer: invalid time, exiting\n"); - return 0; - - default: - fprintf(stderr, "XGrabPointer: could not grab mouse pointer (%d), exiting\n", rc); - return 0; - } - } - - return 0; -} - -static void* thread_mouse_capture(void* data) -{ - XEvent event; - int x_old, y_old, x_root_old, y_root_old, rt; - unsigned int mask; - Window w, w_root_return, w_child_return; - - dpy = XOpenDisplay(NULL); - if (!dpy) { - return NULL; - } - w = XDefaultRootWindow(dpy); - - XQueryPointer(dpy, w, &w_root_return, &w_child_return, &x_root_old, &y_root_old, &x_old, &y_old, &mask); - while (mcap_running == 1 && grabPointer(dpy, w, mask)) { - while (mcap_running == 1) { - if (XPending(dpy) > 0) { - XPeekEvent(dpy, &event); - break; - } - delay(0, 50); - } - XUngrabPointer(dpy, CurrentTime); - XSync(dpy, 1); - pthread_mutex_trylock(&mutex_mcap); // set mutex to lock status, so this thread will wait until next unlock (by update preedit string) - - if (mcap_running == 0) - break; - if (event.type == MotionNotify) // mouse move - { - if ((abs(event.xmotion.x_root - x_root_old) >= CAPTURE_MOUSE_MOVE_DELTA) || - (abs(event.xmotion.y_root - y_root_old) >= CAPTURE_MOUSE_MOVE_DELTA)) // mouse move at least CAPTURE_MOUSE_MOVE_DELTA - { - fprintf(stderr, "MotionNotify: delta_x=%d delta_y=%d\n", abs(event.xmotion.x_root - x_root_old), abs(event.xmotion.y_root - y_root_old)); - mouse_move_handler(); - x_root_old = event.xmotion.x_root; - y_root_old = event.xmotion.y_root; - } - else { // if don't reset -> unlock mutex so mouse continue to be grab - pthread_mutex_unlock(&mutex_mcap); - } - } - else { - fprintf(stderr, "MotionNotify: click\n"); - mouse_click_handler(); - } - pthread_mutex_lock(&mutex_mcap); - } - mcap_running = 0; - XCloseDisplay(dpy); - return NULL; -} - -void mouse_capture_init() -{ - setbuf(stdout, NULL); - setbuf(stderr, NULL); - if (mcap_running==1) { - return; - } - XInitThreads(); - mcap_running = 1; - pthread_mutex_init(&mutex_mcap, NULL); - pthread_mutex_trylock(&mutex_mcap); // lock mutex after init so mouse capture not start - pthread_create(&th_mcap, NULL, &thread_mouse_capture, NULL); - pthread_detach(th_mcap); -} - -void mouse_capture_exit() -{ - if (mcap_running==0) { - return; - } - mcap_running = 0; - pthread_mutex_unlock(&mutex_mcap); // unlock mutex, so thread can exit -} - -// every time have preedit text -> unlock mutex -> start capture mouse -void mouse_capture_unlock() -{ - if (mcap_running==0) { - return; - } - // unlock capture thread (start capture) - pthread_mutex_unlock(&mutex_mcap); -} - -void mouse_capture_start_or_unlock() -{ - if (mcap_running==0) { - mouse_capture_init(); - } - // unlock capture thread (start capture) - pthread_mutex_unlock(&mutex_mcap); -} diff --git a/x11_record.c b/x11_record.c deleted file mode 100644 index a87234f8..00000000 --- a/x11_record.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Bamboo - A Vietnamese Input method editor - * Copyright (C) 2018 Luong Thanh Lam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "_cgo_export.h" -#define CAPTURE_MOUSE_MOVE_DELTA 50 - -/* for this struct, refer to libxnee */ -typedef union { - unsigned char type ; - xEvent event ; - xResourceReq req ; - xGenericReply reply ; - xError error ; - xConnSetupPrefix setup; -} XRecordDatum; - -/* - * FIXME: We need define a private struct for callback function, - * to store cur_x, cur_y, data_disp, ctrl_disp etc. - */ -Display *data_disp = NULL; -Display *ctrl_disp = NULL; - -XRecordRange *rr = NULL; -XRecordClientSpec rcs; -XRecordContext rc; - -/* recording flag */ -static int mouse_recording = 0; - -static int cur_x = 0; -static int cur_y = 0; - -void event_callback (XPointer, XRecordInterceptData*); - -static void* thread_mouse_recording (void* data) -{ - ctrl_disp = XOpenDisplay (NULL); - data_disp = XOpenDisplay (NULL); - - if (!ctrl_disp || !data_disp) { - fprintf (stderr, "Error to open local display!\n"); - return NULL; - } - - /* - * we must set the ctrl_disp to sync mode, or, when we the enalbe - * context in data_disp, there will be a fatal X error !!! - */ - XSynchronize(ctrl_disp,True); - - int major, minor; - if (!XRecordQueryVersion (ctrl_disp, &major, &minor)) { - fprintf (stderr, "RECORD extension is not supported on this X server!\n"); - mouse_recording = 0; - return NULL; - } - - printf ("RECORD extension for local server is version %d.%d\n", major, minor); - - rr = XRecordAllocRange (); - if (!rr) { - fprintf (stderr, "Could not alloc record range object!\n"); - return NULL; - } - - rr->device_events.first = KeyPress; - rr->device_events.last = MotionNotify; - rcs = XRecordAllClients; - - rc = XRecordCreateContext (ctrl_disp, 0, &rcs, 1, &rr, 1); - if (!rc) { - fprintf (stderr, "Could not create a record context!\n"); - return NULL; - } - - if (!XRecordEnableContext (data_disp, rc, event_callback, NULL)) { - fprintf (stderr, "Cound not enable the record context!\n"); - return NULL; - } - - Window w_root_return, w_child_return; - int x_old, y_old, x_root_old, y_root_old, rt; - unsigned int mask; - /* Note: you should not use data_disp to do normal X operations !!!*/ - XQueryPointer(ctrl_disp, XDefaultRootWindow(ctrl_disp), &w_root_return, &w_child_return, &x_root_old, &y_root_old, &x_old, &y_old, &mask); - cur_x = x_root_old; - cur_y = y_root_old; - while (mouse_recording) { - XRecordProcessReplies (data_disp); - } - - XRecordDisableContext (ctrl_disp, rc); - XRecordFreeContext (ctrl_disp, rc); - XFree (rr); - - XCloseDisplay (data_disp); - XCloseDisplay (ctrl_disp); - mouse_recording = 0; - return NULL; -} - -void event_callback(XPointer priv, XRecordInterceptData *hook) -{ - - if (hook->category != XRecordFromServer) { - XRecordFreeData (hook); - return; - } - - XRecordDatum *data = (XRecordDatum*) hook->data; - - int event_type = data->type; - - BYTE btncode, keycode; - btncode = keycode = data->event.u.u.detail; - - int root_x = data->event.u.keyButtonPointer.rootX; - int root_y = data->event.u.keyButtonPointer.rootY; - int time = hook->server_time; - - switch (event_type) { - case KeyPress: - /** printf ("KeyPress: \t%s\n", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0))); */ - break; - case KeyRelease: - /** printf ("KeyRelease: \t%s\n", XKeysymToString(XKeycodeToKeysym(ctrl_disp, keycode, 0))); */ - break; - case ButtonPress: - /*printf("ButtonPress: /t%d, rootX=%d, rootY=%d, recording=%d", btncode, cur_x, cur_y, mouse_recording);*/ - mouse_click_handler(); - break; - case ButtonRelease: - /** printf ("ButtonRelease: /t%d, rootX=%d, rootY=%d", btncode, cur_x, cur_y); */ - break; - case MotionNotify: - /* printf ("MouseMove: /trootX=%d, rootY=%d",rootx, rooty); */ - if ((abs(root_x - cur_x) >= CAPTURE_MOUSE_MOVE_DELTA) || - (abs(root_y - cur_y) >= CAPTURE_MOUSE_MOVE_DELTA)) // mouse move at least CAPTURE_MOUSE_MOVE_DELTA - { - mouse_move_handler(); - cur_x = root_x; - cur_y = root_y; - } - break; - default: - break; - } - XRecordFreeData (hook); -} - -void mouse_recording_init() -{ - setbuf(stdout, NULL); - setbuf(stderr, NULL); - if (mouse_recording==1) { - return; - } - XInitThreads(); - mouse_recording = 1; - pthread_t th_mcap; - pthread_create(&th_mcap, NULL, &thread_mouse_recording, NULL); - pthread_detach(th_mcap); -} - -void mouse_recording_exit() -{ - if (mouse_recording==0 || ctrl_disp == NULL) { - return; - } - XRecordDisableContext (ctrl_disp, rc); - mouse_recording = 0; -} -