Skip to content

Commit 25457f7

Browse files
Translate word under mouse when user press ctrl modifier in same time.
1 parent fdf959a commit 25457f7

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

core/js/get_cursor_word.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
(function() {
2+
const getWordAtPoint = (x, y) => {
3+
const element = document.elementFromPoint(x, y);
4+
5+
if (element && (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA')) {
6+
// Simulate a click at the current cursor position
7+
const clickEvent = new MouseEvent('click', {
8+
view: window,
9+
bubbles: true,
10+
cancelable: true,
11+
clientX: x,
12+
clientY: y,
13+
});
14+
document.body.dispatchEvent(clickEvent);
15+
16+
// Then focus on the form element
17+
const inputElement = element;
18+
inputElement.focus();
19+
20+
// Get the word at the cursor position
21+
const cursorPosition = inputElement.selectionStart;
22+
const inputValue = inputElement.value;
23+
24+
let start = cursorPosition;
25+
while (start > 0 && !/\s/.test(inputValue[start - 1])) {
26+
start--;
27+
}
28+
29+
let end = cursorPosition;
30+
while (end < inputValue.length && !/\s/.test(inputValue[end])) {
31+
end++;
32+
}
33+
34+
return inputValue.substring(start, end);
35+
} else {
36+
const range = document.caretRangeFromPoint(x, y);
37+
if (range && range.startContainer.nodeType === Node.TEXT_NODE) {
38+
const data = range.startContainer.data;
39+
const offset = range.startOffset;
40+
41+
let start = offset;
42+
while (start > 0 && !/\s/.test(data[start - 1])) {
43+
start--;
44+
}
45+
46+
let end = offset;
47+
while (end < data.length && !/\s/.test(data[end])) {
48+
end++;
49+
}
50+
51+
return data.substring(start, end);
52+
}
53+
}
54+
return null;
55+
};
56+
57+
var mouseX = parseInt("%{mouse_x}");
58+
var mouseY = parseInt("%{mouse_y}");
59+
const word = getWordAtPoint(mouseX, mouseY);
60+
return word;
61+
})();

core/webengine.py

+25
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import os
4040
import platform
4141
import pathlib
42+
import threading
4243

4344
MOUSE_LEFT_BUTTON = 1
4445
MOUSE_WHEEL_BUTTON = 4
@@ -82,6 +83,9 @@ def __init__(self, buffer_id):
8283
self.focus_input_js = None
8384
self.simulated_wheel_event = False
8485

86+
self.last_mouse_word = None
87+
self.last_mouse_word_timer = None
88+
8589
(self.default_zoom, self.zoom_step,
8690
self.show_hover_link, self.marker_letters,
8791
self.marker_fontsize, self.scroll_step) = get_emacs_vars(
@@ -275,6 +279,20 @@ def eventFilter(self, obj, event):
275279
else:
276280
focus_emacs_buffer(self.buffer_id)
277281

282+
if event.type() == QEvent.Type.MouseMove:
283+
modifiers = QApplication.keyboardModifiers()
284+
if modifiers == Qt.KeyboardModifier.ControlModifier:
285+
word = self.get_cursor_word(event.pos().x() / self.zoomFactor(), event.pos().y() / self.zoomFactor())
286+
if self.last_mouse_word != word:
287+
self.last_mouse_word = word
288+
289+
if self.last_mouse_word is not None:
290+
if self.last_mouse_word_timer is not None and self.last_mouse_word_timer.is_alive():
291+
self.last_mouse_word_timer.cancel()
292+
293+
self.last_mouse_word_timer = threading.Timer(1, lambda : self.translate_cursor_word(word))
294+
self.last_mouse_word_timer.start()
295+
278296
if event.type() == QEvent.Type.MouseButtonPress:
279297

280298
if platform.system() == "Darwin":
@@ -322,6 +340,9 @@ def eventFilter(self, obj, event):
322340

323341
return super(QWebEngineView, self).eventFilter(obj, event)
324342

343+
def translate_cursor_word(self, word):
344+
self.translate_selected_text.emit(word)
345+
325346
def link_hovered(self, url):
326347
self.url_hovered = url
327348

@@ -715,6 +736,10 @@ def focus_input(self):
715736
self.eval_js(self.focus_input_js)
716737
eval_in_emacs('eaf-update-focus-state', [self.buffer_id, "'t"])
717738

739+
def get_cursor_word(self, x, y):
740+
get_cursor_word_js = self.read_js_content("get_cursor_word.js").replace("%{mouse_x}", str(x)).replace("%{mouse_y}", str(y))
741+
return self.execute_js(get_cursor_word_js)
742+
718743
@interactive
719744
def clear_focus(self):
720745
''' Clear the focus.'''

0 commit comments

Comments
 (0)