mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-16 17:24:23 +00:00
Add events for key press and key release on gui systems.
And detection of double/triple taps on modifier keys. * lisp/low-level-key.el (llk-tap-timeout): (llk-tap-count): (llk-tap-keys): (llk-bindings): (llk-modifier-bindings): (llk-init): (llk-bind): (llk-modifier-bind): (llk-events): (llk-modifier-events): (llm-handle): * src/gtkutil.c (xg_create_frame_widgets): (xg_maybe_send_low_level_key_event): (xg_widget_key_press_event_cb): (xg_widget_key_release_event_cb): * src/xterm.c (x_maybe_send_physical_key_event): (x_filter_event): (handle_one_xevent): (syms_of_xterm):
This commit is contained in:
parent
3efdb553e4
commit
bcdd9ffac7
9 changed files with 577 additions and 1 deletions
141
lisp/low-level-key.el
Normal file
141
lisp/low-level-key.el
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
;;; -*- lexical-binding: t -*-
|
||||
(require 'cl-lib)
|
||||
|
||||
;; User options
|
||||
(defvar llk-tap-timeout 1000)
|
||||
(defvar llk-tap-count 2)
|
||||
(defvar llk-tap-keys
|
||||
'(lshift rshift lctrl rctrl lalt ralt shift ctrl alt))
|
||||
(defvar llk-bindings nil)
|
||||
(defvar llm-bindings nil)
|
||||
|
||||
(defun llk-init ()
|
||||
(interactive)
|
||||
(define-key special-event-map [low-level-key] 'llk-handle)
|
||||
(define-key special-event-map [low-level-modifier] 'llm-handle)
|
||||
|
||||
(setq llk-bindings nil)
|
||||
(setq llm-bindings nil)
|
||||
|
||||
;; (llm-bind 'tap 'shift 'delete-other-windows)
|
||||
;; (llk-bind 'tap 'lctrl 'hyper)
|
||||
(setq enable-low-level-key-events t))
|
||||
|
||||
;; For example:
|
||||
;; (llk-add-binding 'tap 'lshift 'delete-other-windows)
|
||||
;; Can bind to a command, a function or the symbol 'hyper.
|
||||
(defun llk-bind (action key function)
|
||||
(push (list action key function) llk-bindings))
|
||||
|
||||
(defun llm-bind (action key function)
|
||||
(push (list action key function) llm-bindings))
|
||||
|
||||
;; We store the last events here to test for multitap.
|
||||
(defvar llk-events nil)
|
||||
(defvar llm-events nil)
|
||||
|
||||
;; If positive, return key ('lshift, etc) else return nil.
|
||||
(defun llk-detect-n-tap (n timeout)
|
||||
;; The physical-key event is like this:
|
||||
;; (physical-key t lshift 90196265 #<frame>)
|
||||
;; The second element is t for a key press, nil for a key release
|
||||
;; The fourth element is the time in milliseconds
|
||||
;; The fifth is the frame, we don't use it yet.
|
||||
|
||||
(let ((key (cl-third last-input-event)))
|
||||
(if (not (member key llk-tap-keys))
|
||||
;; Key not in tap list, clear history
|
||||
(setq llk-events nil)
|
||||
;; Clear it also if the first element is from a different key
|
||||
(and llk-events
|
||||
(not (equal (cl-third (car llk-events)) key))
|
||||
(setq llk-events nil))
|
||||
(push last-input-event llk-events)
|
||||
;; Only care about last 2xN events
|
||||
(ntake (* 2 n) llk-events)
|
||||
;; If we have:
|
||||
;; - Exactly 2 * n events.
|
||||
;; - down, up, down, up, ...
|
||||
;; - not two much time between first and last
|
||||
(and (eq (* 2 n) (length llk-events))
|
||||
(cl-every 'eq
|
||||
(ntake (* 2 n)
|
||||
(list nil t nil t nil t nil t
|
||||
nil t nil t nil t nil t))
|
||||
(mapcar 'cl-second llk-events))
|
||||
(< (- (cl-fourth (cl-first llk-events))
|
||||
(cl-fourth (car (last llk-events))))
|
||||
timeout)
|
||||
(progn
|
||||
(setq llk-events nil)
|
||||
key)))))
|
||||
|
||||
|
||||
;; this function is a copy of llk-detect-n-tap, but for llm-events
|
||||
(defun llm-detect-n-tap (n timeout)
|
||||
(let ((key (cl-third last-input-event)))
|
||||
(if (not (member key llk-tap-keys))
|
||||
(setq llm-events nil)
|
||||
(and llm-events
|
||||
(not (equal (cl-third (car llm-events)) key))
|
||||
(setq llm-events nil))
|
||||
(push last-input-event llm-events)
|
||||
(ntake (* 2 n) llm-events)
|
||||
(and (eq (* 2 n) (length llm-events))
|
||||
(cl-every 'eq
|
||||
(ntake (* 2 n)
|
||||
(list nil t nil t nil t nil t
|
||||
nil t nil t nil t nil t))
|
||||
(mapcar 'cl-second llm-events))
|
||||
(< (- (cl-fourth (cl-first llm-events))
|
||||
(cl-fourth (car (last llm-events))))
|
||||
timeout)
|
||||
(progn
|
||||
(setq llm-events nil)
|
||||
key)))))
|
||||
|
||||
(defun llk-handle ()
|
||||
(interactive)
|
||||
|
||||
(let ((tap-key (llk-detect-n-tap
|
||||
llk-tap-count
|
||||
llk-tap-timeout)))
|
||||
(when tap-key
|
||||
(let ((func (cl-third
|
||||
(seq-find
|
||||
(lambda (b)
|
||||
(and (eq (cl-first b) 'tap)
|
||||
(eq (cl-second b) tap-key)))
|
||||
llk-bindings))))
|
||||
(cond
|
||||
((commandp func) (call-interactively func))
|
||||
((functionp func) (funcall func))
|
||||
((eq 'hyper func)
|
||||
(message "H-...")
|
||||
(let ((r (read-event)))
|
||||
(setq unread-command-events
|
||||
(list (event-apply-modifier
|
||||
r 'hyper 24 "H-"))))))))))
|
||||
|
||||
(defun llm-handle()
|
||||
(interactive)
|
||||
|
||||
(let ((tap-key (llm-detect-n-tap
|
||||
llk-tap-count
|
||||
llk-tap-timeout)))
|
||||
(when tap-key
|
||||
(let ((func (cl-third
|
||||
(seq-find
|
||||
(lambda (b)
|
||||
(and (eq (cl-first b) 'tap)
|
||||
(eq (cl-second b) tap-key)))
|
||||
llm-bindings))))
|
||||
(cond
|
||||
((commandp func) (call-interactively func))
|
||||
((functionp func) (funcall func))
|
||||
((eq 'hyper func)
|
||||
(message "H-...")
|
||||
(let ((r (read-event)))
|
||||
(setq unread-command-events
|
||||
(list (event-apply-modifier
|
||||
r 'hyper 24 "H-"))))))))))
|
||||
133
src/gtkutil.c
133
src/gtkutil.c
|
|
@ -98,6 +98,7 @@ static void xg_im_context_commit (GtkIMContext *, gchar *, gpointer);
|
|||
static void xg_im_context_preedit_changed (GtkIMContext *, gpointer);
|
||||
static void xg_im_context_preedit_end (GtkIMContext *, gpointer);
|
||||
static bool xg_widget_key_press_event_cb (GtkWidget *, GdkEvent *, gpointer);
|
||||
static bool xg_widget_key_release_event_cb (GtkWidget *, GdkEvent *, gpointer);
|
||||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 10, 0)
|
||||
|
|
@ -1752,6 +1753,12 @@ xg_create_frame_widgets (struct frame *f)
|
|||
g_signal_connect (G_OBJECT (wfixed), "key-press-event",
|
||||
G_CALLBACK (xg_widget_key_press_event_cb),
|
||||
NULL);
|
||||
|
||||
g_signal_connect (G_OBJECT (wfixed), "key-release-event",
|
||||
G_CALLBACK (xg_widget_key_release_event_cb),
|
||||
NULL);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
|
|
@ -6384,6 +6391,105 @@ xg_im_context_preedit_end (GtkIMContext *imc, gpointer user_data)
|
|||
kbd_buffer_store_event (&inev);
|
||||
}
|
||||
|
||||
static void
|
||||
xg_maybe_send_low_level_key_event (struct frame *f,
|
||||
GdkEvent *xev)
|
||||
{
|
||||
GdkEventKey xkey = xev->key;
|
||||
bool is_press;
|
||||
int keysym;
|
||||
Lisp_Object key, modifier;
|
||||
union buffered_input_event inev;
|
||||
|
||||
if (!Venable_low_level_key_events)
|
||||
return;
|
||||
switch (xev->type)
|
||||
{
|
||||
case GDK_KEY_PRESS:
|
||||
is_press = true;
|
||||
break;
|
||||
case GDK_KEY_RELEASE:
|
||||
is_press = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
keysym = xkey.keyval;
|
||||
|
||||
switch (keysym)
|
||||
{
|
||||
case GDK_KEY_Shift_L: key = Qlshift; break;
|
||||
case GDK_KEY_Shift_R: key = Qrshift; break;
|
||||
case GDK_KEY_Control_L: key = Qlctrl; break;
|
||||
case GDK_KEY_Control_R: key = Qrctrl; break;
|
||||
case GDK_KEY_Alt_L: key = Qlalt; break;
|
||||
case GDK_KEY_Alt_R: key = Qralt; break;
|
||||
default:
|
||||
key = Qnil;
|
||||
}
|
||||
|
||||
switch (keysym)
|
||||
{
|
||||
case GDK_KEY_Shift_L:
|
||||
case GDK_KEY_Shift_R:
|
||||
modifier = Qshift;
|
||||
break;
|
||||
case GDK_KEY_Control_L:
|
||||
case GDK_KEY_Control_R:
|
||||
modifier = Vx_ctrl_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qctrl;
|
||||
break;
|
||||
case GDK_KEY_Alt_L:
|
||||
case GDK_KEY_Alt_R:
|
||||
modifier = Vx_meta_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qalt;
|
||||
break;
|
||||
case GDK_KEY_Meta_L:
|
||||
case GDK_KEY_Meta_R:
|
||||
modifier = Vx_meta_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qmeta;
|
||||
break;
|
||||
case GDK_KEY_Hyper_L:
|
||||
case GDK_KEY_Hyper_R:
|
||||
modifier = Vx_hyper_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qhyper;
|
||||
break;
|
||||
case GDK_KEY_Super_L:
|
||||
case GDK_KEY_Super_R:
|
||||
modifier = Vx_super_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qsuper;
|
||||
break;
|
||||
default:
|
||||
modifier = Qnil;
|
||||
}
|
||||
|
||||
if (!NILP (key))
|
||||
{
|
||||
EVENT_INIT (inev.ie);
|
||||
XSETFRAME (inev.ie.frame_or_window, f);
|
||||
inev.ie.kind = LOW_LEVEL_KEY_EVENT;
|
||||
inev.ie.timestamp = xkey.time;
|
||||
inev.ie.arg = list2 (is_press ? Qt : Qnil, key);
|
||||
kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event);
|
||||
}
|
||||
|
||||
if (!NILP (modifier))
|
||||
{
|
||||
EVENT_INIT (inev.ie);
|
||||
XSETFRAME (inev.ie.frame_or_window, f);
|
||||
inev.ie.kind = LOW_LEVEL_MODIFIER_KEY_EVENT;
|
||||
inev.ie.timestamp = xkey.time;
|
||||
inev.ie.arg = list2 (is_press ? Qt : Qnil, modifier);
|
||||
kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
|
||||
gpointer user_data)
|
||||
|
|
@ -6412,6 +6518,10 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
|
|||
if (!f)
|
||||
return true;
|
||||
|
||||
#ifndef HAVE_XINPUT2
|
||||
xg_maybe_send_low_level_key_event (f, event);
|
||||
#endif
|
||||
|
||||
if (popup_activated ())
|
||||
return true;
|
||||
|
||||
|
|
@ -6565,6 +6675,29 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
xg_widget_key_release_event_cb (GtkWidget *widget, GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
#ifndef HAVE_XINPUT2
|
||||
Lisp_Object tail, tem;
|
||||
struct frame *f = NULL;
|
||||
|
||||
FOR_EACH_FRAME (tail, tem)
|
||||
{
|
||||
if (FRAME_X_P (XFRAME (tem))
|
||||
&& (FRAME_GTK_WIDGET (XFRAME (tem)) == widget))
|
||||
{
|
||||
f = XFRAME (tem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f)
|
||||
xg_maybe_send_low_level_key_event (f, event);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
xg_filter_key (struct frame *frame, XEvent *xkey)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4274,6 +4274,8 @@ kbd_buffer_get_event (KBOARD **kbp,
|
|||
case FOCUS_OUT_EVENT:
|
||||
case SELECT_WINDOW_EVENT:
|
||||
case SLEEP_EVENT:
|
||||
case LOW_LEVEL_KEY_EVENT:
|
||||
case LOW_LEVEL_MODIFIER_KEY_EVENT:
|
||||
{
|
||||
obj = make_lispy_event (&event->ie);
|
||||
kbd_fetch_ptr = next_kbd_event (event);
|
||||
|
|
@ -7231,6 +7233,22 @@ make_lispy_event (struct input_event *event)
|
|||
case PREEDIT_TEXT_EVENT:
|
||||
return list2 (Qpreedit_text, event->arg);
|
||||
|
||||
case LOW_LEVEL_KEY_EVENT:
|
||||
return listn (5,
|
||||
Qlow_level_key,
|
||||
XCAR (event->arg), /* Press or release. */
|
||||
XCAR (XCDR (event->arg)), /* The key symbol. */
|
||||
make_fixnum (event->timestamp),
|
||||
event->frame_or_window);
|
||||
|
||||
case LOW_LEVEL_MODIFIER_KEY_EVENT:
|
||||
return listn (5,
|
||||
Qlow_level_modifier,
|
||||
XCAR (event->arg), /* Press or release. */
|
||||
XCAR (XCDR (event->arg)), /* The key symbol. */
|
||||
make_fixnum (event->timestamp),
|
||||
event->frame_or_window);
|
||||
|
||||
/* The 'kind' field of the event is something we don't recognize. */
|
||||
default:
|
||||
emacs_abort ();
|
||||
|
|
@ -13112,6 +13130,20 @@ syms_of_keyboard (void)
|
|||
DEFSYM (Qfile_notify, "file-notify");
|
||||
#endif /* USE_FILE_NOTIFY */
|
||||
|
||||
DEFVAR_LISP ("enable-low-level-key-events", Venable_low_level_key_events,
|
||||
doc: /* Enabled the recepcion of low level key events.
|
||||
This includes 'low-level-key' and 'low-level-modifier' events. */);
|
||||
Venable_low_level_key_events = false;
|
||||
|
||||
DEFSYM (Qlow_level_key, "low-level-key");
|
||||
DEFSYM (Qlow_level_modifier, "low-level-modifier");
|
||||
DEFSYM (Qlshift, "lshift");
|
||||
DEFSYM (Qrshift, "rshift");
|
||||
DEFSYM (Qlctrl, "lctrl");
|
||||
DEFSYM (Qrctrl, "rctrl");
|
||||
DEFSYM (Qlalt, "lalt");
|
||||
DEFSYM (Qralt, "ralt");
|
||||
|
||||
DEFSYM (Qtouch_end, "touch-end");
|
||||
DEFSYM (Qsleep_event, "sleep-event");
|
||||
|
||||
|
|
@ -14208,6 +14240,12 @@ keys_of_keyboard (void)
|
|||
"handle-move-frame");
|
||||
initial_define_lispy_key (Vspecial_event_map, "sleep-event",
|
||||
"ignore");
|
||||
initial_define_lispy_key (Vspecial_event_map, "low-level-key",
|
||||
"ignore");
|
||||
initial_define_lispy_key (Vspecial_event_map, "low-level-modifier",
|
||||
"ignore");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Mark the pointers in the kboard objects.
|
||||
|
|
|
|||
|
|
@ -5222,6 +5222,39 @@ pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit)
|
|||
evq_enqueue (&inev);
|
||||
}
|
||||
|
||||
static void
|
||||
pgtk_maybe_send_low_level_key_event (GdkEvent *event)
|
||||
{
|
||||
if (!Venable_low_level_key_events)
|
||||
return;
|
||||
|
||||
Lisp_Object key;
|
||||
switch (event->key.keyval)
|
||||
{
|
||||
case GDK_KEY_Shift_L: key = Qlshift; break;
|
||||
case GDK_KEY_Shift_R: key = Qrshift; break;
|
||||
case GDK_KEY_Control_L: key = Qlctrl; break;
|
||||
case GDK_KEY_Control_R: key = Qrctrl; break;
|
||||
case GDK_KEY_Alt_L: key = Qlalt; break;
|
||||
case GDK_KEY_Alt_R: key = Qralt; break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
bool keypress = event->key.type == GDK_KEY_PRESS;
|
||||
struct frame *f = pgtk_any_window_to_frame (event->key.window);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
union buffered_input_event inev;
|
||||
|
||||
EVENT_INIT (inev.ie);
|
||||
XSETFRAME (inev.ie.frame_or_window, f);
|
||||
inev.ie.kind = LOW_LEVEL_KEY_EVENT;
|
||||
inev.ie.timestamp = event->key.time;
|
||||
inev.ie.arg = list2 (keypress ? Qt : Qnil, key);
|
||||
evq_enqueue (&inev);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
|
||||
{
|
||||
|
|
@ -5231,6 +5264,8 @@ key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
|
|||
struct frame *f;
|
||||
struct pgtk_display_info *dpyinfo;
|
||||
|
||||
pgtk_maybe_send_low_level_key_event(event);
|
||||
|
||||
f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
|
||||
EVENT_INIT (inev.ie);
|
||||
hlinfo = MOUSE_HL_INFO (f);
|
||||
|
|
@ -5475,6 +5510,8 @@ key_release_event (GtkWidget *widget,
|
|||
GdkDisplay *display;
|
||||
struct pgtk_display_info *dpyinfo;
|
||||
|
||||
pgtk_maybe_send_low_level_key_event(event);
|
||||
|
||||
display = gtk_widget_get_display (widget);
|
||||
dpyinfo = pgtk_display_info_for_display (display);
|
||||
|
||||
|
|
|
|||
|
|
@ -350,6 +350,8 @@ enum event_kind
|
|||
/* In a NOTIFICATION_EVENT, .arg is a lambda to evaluate. */
|
||||
, NOTIFICATION_EVENT
|
||||
#endif /* HAVE_ANDROID */
|
||||
, LOW_LEVEL_KEY_EVENT
|
||||
, LOW_LEVEL_MODIFIER_KEY_EVENT
|
||||
};
|
||||
|
||||
/* Bit width of an enum event_kind tag at the start of structs and unions. */
|
||||
|
|
|
|||
11
src/w32fns.c
11
src/w32fns.c
|
|
@ -4679,6 +4679,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
record_keyup (wParam, lParam);
|
||||
if (Venable_low_level_key_events)
|
||||
{
|
||||
signal_user_input ();
|
||||
my_post_msg( &wmsg, hwnd, WM_EMACS_LOW_LEVEL_KEY, wParam, lParam );
|
||||
}
|
||||
goto dflt;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
|
|
@ -4705,6 +4710,12 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
if (w32_use_fallback_wm_chars_method)
|
||||
wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
|
||||
|
||||
if (Venable_low_level_key_events)
|
||||
{
|
||||
signal_user_input ();
|
||||
my_post_msg( &wmsg, hwnd, WM_EMACS_LOW_LEVEL_KEY, wParam, lParam );
|
||||
}
|
||||
|
||||
windows_translate = 0;
|
||||
|
||||
switch (wParam)
|
||||
|
|
|
|||
|
|
@ -5270,6 +5270,75 @@ w32_read_socket (struct terminal *terminal,
|
|||
}
|
||||
break;
|
||||
|
||||
case WM_EMACS_LOW_LEVEL_KEY:
|
||||
WORD key_flags = HIWORD (msg.msg.lParam);
|
||||
BOOL is_wm_keyup = key_flags & KF_UP;
|
||||
|
||||
if (is_wm_keyup || (key_flags & KF_REPEAT) == 0) /* WM_KEYDOWN, not repeating. */
|
||||
{
|
||||
WORD scan_code = LOBYTE (key_flags);
|
||||
if (key_flags & KF_EXTENDED)
|
||||
scan_code = MAKEWORD (scan_code, 0xE0);
|
||||
|
||||
UINT translated = MapVirtualKey (scan_code, MAPVK_VSC_TO_VK_EX);
|
||||
WORD vk = LOWORD (msg.msg.wParam);
|
||||
if (translated)
|
||||
vk = LOWORD (translated);
|
||||
|
||||
Lisp_Object key = Qnil;
|
||||
Lisp_Object modifier = Qnil;
|
||||
|
||||
switch (vk)
|
||||
{
|
||||
case VK_LSHIFT: key = Qlshift; break;
|
||||
case VK_RSHIFT: key = Qrshift; break;
|
||||
case VK_LCONTROL: key = Qlctrl; break;
|
||||
case VK_RCONTROL: key = Qrctrl; break;
|
||||
case VK_LMENU: key = Qlalt; break;
|
||||
case VK_RMENU: key = Qralt; break;
|
||||
}
|
||||
|
||||
switch (vk)
|
||||
{
|
||||
case VK_LSHIFT:
|
||||
case VK_RSHIFT:
|
||||
modifier = Qshift;
|
||||
break;
|
||||
case VK_LCONTROL:
|
||||
case VK_RCONTROL:
|
||||
modifier = Qctrl;
|
||||
break;
|
||||
case VK_LMENU:
|
||||
case VK_RMENU:
|
||||
modifier = Qmeta;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NILP (key))
|
||||
{
|
||||
f = w32_window_to_frame (dpyinfo, msg.msg.hwnd);
|
||||
inev.kind = LOW_LEVEL_KEY_EVENT;
|
||||
XSETFRAME (inev.frame_or_window, f);
|
||||
inev.timestamp = msg.msg.time;
|
||||
inev.arg = list2 (is_wm_keyup ? Qnil : Qt, key);
|
||||
kbd_buffer_store_event_hold (&inev, hold_quit);
|
||||
|
||||
}
|
||||
|
||||
if (!NILP (modifier))
|
||||
{
|
||||
f = w32_window_to_frame (dpyinfo, msg.msg.hwnd);
|
||||
inev.kind = LOW_LEVEL_MODIFIER_KEY_EVENT;
|
||||
XSETFRAME (inev.frame_or_window, f);
|
||||
inev.timestamp = msg.msg.time;
|
||||
inev.arg = list2 (is_wm_keyup ? Qnil : Qt, modifier);
|
||||
kbd_buffer_store_event_hold (&inev, hold_quit);
|
||||
}
|
||||
inev.kind = NO_EVENT;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_UNICHAR:
|
||||
case WM_SYSCHAR:
|
||||
case WM_CHAR:
|
||||
|
|
|
|||
|
|
@ -714,7 +714,8 @@ do { \
|
|||
#define WM_EMACS_IME_STATUS (WM_EMACS_START + 26)
|
||||
#define WM_EMACS_DRAGOVER (WM_EMACS_START + 27)
|
||||
#define WM_EMACS_DROP (WM_EMACS_START + 28)
|
||||
#define WM_EMACS_END (WM_EMACS_START + 29)
|
||||
#define WM_EMACS_LOW_LEVEL_KEY (WM_EMACS_START + 29)
|
||||
#define WM_EMACS_END (WM_EMACS_START + 30)
|
||||
|
||||
#define WND_FONTWIDTH_INDEX (0)
|
||||
#define WND_LINEHEIGHT_INDEX (4)
|
||||
|
|
|
|||
144
src/xterm.c
144
src/xterm.c
|
|
@ -17819,6 +17819,143 @@ static struct x_display_info *XTread_socket_fake_io_error;
|
|||
|
||||
static struct x_display_info *next_noop_dpyinfo;
|
||||
|
||||
static void
|
||||
x_maybe_send_low_level_key_event (struct x_display_info *dpyinfo,
|
||||
const XEvent *xev)
|
||||
{
|
||||
XKeyEvent xkey;
|
||||
bool is_press;
|
||||
KeySym keysym;
|
||||
Lisp_Object key, modifier;
|
||||
struct input_event ie;
|
||||
|
||||
if (!Venable_low_level_key_events)
|
||||
return;
|
||||
|
||||
switch (xev->type)
|
||||
{
|
||||
case KeyPress:
|
||||
is_press = true;
|
||||
xkey = xev->xkey;
|
||||
break;
|
||||
case KeyRelease:
|
||||
is_press = false;
|
||||
xkey = xev->xkey;
|
||||
break;
|
||||
#ifdef HAVE_XINPUT2
|
||||
case GenericEvent:
|
||||
XIDeviceEvent *xiev = xev->xcookie.data;
|
||||
switch (xev->xgeneric.evtype)
|
||||
{
|
||||
case XI_KeyPress:
|
||||
is_press = true;
|
||||
break;
|
||||
case XI_KeyRelease:
|
||||
is_press = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
xkey.serial = xiev->serial;
|
||||
xkey.send_event = xiev->send_event;
|
||||
xkey.display = xiev->display;
|
||||
xkey.window = xiev->event;
|
||||
xkey.root = xiev->root;
|
||||
xkey.subwindow = xiev->child;
|
||||
xkey.time = xiev->time;
|
||||
xkey.x = xiev->event_x;
|
||||
xkey.y = xiev->event_y;
|
||||
xkey.x_root = xiev->root_x;
|
||||
xkey.y_root = xiev->root_y;
|
||||
xkey.state = xiev->mods.effective;
|
||||
xkey.keycode = xiev->detail;
|
||||
xkey.same_screen = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
struct frame *f = x_any_window_to_frame (dpyinfo, xkey.window);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
XLookupString (&xkey, NULL, 0, &keysym, NULL);
|
||||
|
||||
switch (keysym)
|
||||
{
|
||||
case XK_Shift_L: key = Qlshift; break;
|
||||
case XK_Shift_R: key = Qrshift; break;
|
||||
case XK_Control_L: key = Qlctrl; break;
|
||||
case XK_Control_R: key = Qrctrl; break;
|
||||
case XK_Alt_L: key = Qlalt; break;
|
||||
case XK_Alt_R: key = Qralt; break;
|
||||
default:
|
||||
key = Qnil;
|
||||
}
|
||||
|
||||
switch (keysym)
|
||||
{
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R:
|
||||
modifier = Qshift;
|
||||
break;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R:
|
||||
modifier = Vx_ctrl_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qctrl;
|
||||
break;
|
||||
case XK_Alt_L:
|
||||
case XK_Alt_R:
|
||||
modifier = Vx_meta_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qalt;
|
||||
break;
|
||||
case XK_Meta_L:
|
||||
case XK_Meta_R:
|
||||
modifier = Vx_meta_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qmeta;
|
||||
break;
|
||||
case XK_Hyper_L:
|
||||
case XK_Hyper_R:
|
||||
modifier = Vx_hyper_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qhyper;
|
||||
break;
|
||||
case XK_Super_L:
|
||||
case XK_Super_R:
|
||||
modifier = Vx_super_keysym;
|
||||
if (NILP (modifier))
|
||||
modifier = Qsuper;
|
||||
break;
|
||||
default:
|
||||
modifier = Qnil;
|
||||
}
|
||||
|
||||
if (!NILP (key))
|
||||
{
|
||||
EVENT_INIT (ie);
|
||||
XSETFRAME (ie.frame_or_window, f);
|
||||
ie.kind = LOW_LEVEL_KEY_EVENT;
|
||||
ie.timestamp = xkey.time;
|
||||
ie.arg = list2 (is_press ? Qt : Qnil, key);
|
||||
kbd_buffer_store_event (&ie);
|
||||
}
|
||||
|
||||
if (!NILP (modifier))
|
||||
{
|
||||
EVENT_INIT (ie);
|
||||
XSETFRAME (ie.frame_or_window, f);
|
||||
ie.kind = LOW_LEVEL_MODIFIER_KEY_EVENT;
|
||||
ie.timestamp = xkey.time;
|
||||
ie.arg = list2 (is_press ? Qt : Qnil, key);
|
||||
kbd_buffer_store_event (&ie);
|
||||
}
|
||||
}
|
||||
|
||||
/* Filter events for the current X input method.
|
||||
DPYINFO is the display this event is for.
|
||||
EVENT is the X event to filter.
|
||||
|
|
@ -20179,6 +20316,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
goto OTHER;
|
||||
|
||||
case KeyPress:
|
||||
x_maybe_send_low_level_key_event (dpyinfo, event);
|
||||
x_display_set_last_user_time (dpyinfo, event->xkey.time,
|
||||
event->xkey.send_event,
|
||||
true);
|
||||
|
|
@ -20688,6 +20826,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
#endif
|
||||
|
||||
case KeyRelease:
|
||||
x_maybe_send_low_level_key_event (dpyinfo, event);
|
||||
#ifdef HAVE_X_I18N
|
||||
/* Don't dispatch this event since XtDispatchEvent calls
|
||||
XFilterEvent, and two calls in a row may freeze the
|
||||
|
|
@ -23952,6 +24091,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
struct xi_device_t *device, *source;
|
||||
XKeyPressedEvent xkey;
|
||||
|
||||
x_maybe_send_low_level_key_event (dpyinfo, event);
|
||||
|
||||
coding = Qlatin_1;
|
||||
|
||||
/* The code under this label is quite desultory. There
|
||||
|
|
@ -24568,6 +24709,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
#endif
|
||||
|
||||
case XI_KeyRelease:
|
||||
x_maybe_send_low_level_key_event (dpyinfo, event);
|
||||
|
||||
#if defined HAVE_X_I18N || defined USE_GTK || defined USE_LUCID
|
||||
{
|
||||
XKeyPressedEvent xkey;
|
||||
|
|
@ -32635,6 +32778,7 @@ Android does not support scroll bars at all. */);
|
|||
Vx_toolkit_scroll_bars = Qnil;
|
||||
#endif
|
||||
|
||||
DEFSYM (Qshift, "shift");
|
||||
DEFSYM (Qmodifier_value, "modifier-value");
|
||||
DEFSYM (Qctrl, "ctrl");
|
||||
Fput (Qctrl, Qmodifier_value, make_fixnum (ctrl_modifier));
|
||||
|
|
|
|||
Loading…
Reference in a new issue