Branch: refs/heads/master Author: xiota github@mentalfossa.com Committer: xiota github@mentalfossa.com Date: Mon, 06 Mar 2023 01:53:10 UTC Commit: b061ff8aa1ef04402905339ad655043564d07207 https://github.com/geany/geany-plugins/commit/b061ff8aa1ef04402905339ad65504...
Log Message: ----------- GeanyLua: Fix geany.keygrab * Make platform agnostic * Fix infinite loop * Update documentation
Modified Paths: -------------- geanylua/docs/geanylua-ref.html geanylua/glspi_app.c
Modified: geanylua/docs/geanylua-ref.html 57 lines changed, 28 insertions(+), 29 deletions(-) =================================================================== @@ -638,39 +638,38 @@
-<a name="keygrab"></a><hr><h3><tt>geany.keygrab ( [prompt] )</tt></h3><p> +<a name="keygrab"></a><hr><h3><tt>geany.keygrab ( [prompt] )</tt></h3>
-Intercepts the next keyboard key pressed, preventing the editor from receiving -that keyboard event.</p> -<p> -The function returns the value of the pressed key as a string, -alphanumeric keys will return their keyboard value, such as - <tt>"a"</tt> or <tt>"1"</tt> while other keys may -return a string describing the key, such -as <tt>"Return"</tt> or <tt>"Escape"</tt>. -( Consult the file <tt>gdk/gdkkeysyms.h</tt> in the GTK sources for some idea of the key names. ) -</p><p> -It should be possible to use this function on keyboards other than US, -although this hasn't been tested, and scripts written for one keyboard -might not be portable to another system. </p> -<p>Key combinations with the modifier keys <b>[Ctrl]</b> or <b>[Alt]</b> -are not supported. Detection of the <b>[Shift]</b> key state is somewhat supported, -although currently it may not be completely reliable. - Repeatedly calling this function in rapid succession (as in a loop) may also result in some "dropped" keys, -so for best results its use should be confined to detecting a single "lowercase" key press.</p><p> - -If the optional <tt>prompt</tt> string argument is present, its text will be shown -as a "calltip" near the upper left-hand area of the current document. -(but only if there is a document open.)</p> -<p> -This function was primarily intended for assigning "chained" sets of hot key -options, in conjunction with user-defined <a href="geanylua-keys.html">keybindings</a>. +<p>Intercepts the next keyboard key pressed, preventing the editor from +receiving that keyboard event.</p>
+<p>This function returns the value of the pressed key as a string. +Alphanumeric keys will return their keyboard value, +such as <tt>"a"</tt> or <tt>"1"</tt>, +while other keys may return a string describing the key, +such as <tt>"Return"</tt> or <tt>"Escape"</tt>.</p>
-</p> -<p> +<p>Only one instance of this function may be active at a time. +This function will return <tt><b>nil</b></tt> if another instance is already waiting for a keypress.</p>
-</p><br><br> +<p>If the optional <tt>prompt</tt> string argument is present, its text will be shown +in a "calltip" near the upper left-hand area of the current document. +The prompt will not be shown if no document is open.</p> + +<p>Notes: +<ul> +<li>This function should work on non-US keyboards, although this has not been tested. +Scripts written for one keyboard may not be portable to other systems.</li> +<li>Key combinations with the modifier keys <b>[Ctrl]</b> or <b>[Alt]</b> +are not supported.</li> +<li>Detection of the <b>[Shift]</b> key state is unreliable.</li> +<li>Keys may be dropped when this function is called in rapid succession (as in a loop). For best results, use of this function should be confined to detecting single "lowercase" key presses.</li> +<li>Consult <tt>gdk/gdkkeysyms.h</tt> in the GTK sources for an idea of key names.</li> +<li>This function was primarily intended for assigning "chained" sets of hot key +options, in conjunction with user-defined <a href="geanylua-keys.html">keybindings</a>.</li> +</ul> +</p> +<br><br>
Modified: geanylua/glspi_app.c 188 lines changed, 50 insertions(+), 138 deletions(-) =================================================================== @@ -439,170 +439,82 @@ static gint glspi_launch(lua_State* L) }
-static guint My_Shift_L=0; -static guint My_Shift_R=0; -static guint My_Control_L=0; -static guint My_Control_R=0; -static guint My_Alt_L=0; -static guint My_Alt_R=0; - - -#ifndef G_OS_WIN32 - -#include <X11/Xlib.h> -#include <X11/keysym.h> - - -#define IsShift ( (My_Shift_L == ev->xkey.keycode) || (My_Shift_R == ev->xkey.keycode) ) - -#define IsCtrl ( (My_Control_L == ev->xkey.keycode) || (My_Control_R == ev->xkey.keycode) ) -#define IsAlt ( (My_Alt_L == ev->xkey.keycode) || (My_Alt_R == ev->xkey.keycode) ) - -#define IsCtrlAlt ( IsCtrl || IsAlt ) - typedef struct _KeyGrabData { -gchar *prompt; -GdkKeymapKey km; + gboolean keypress; + guint keyval; } _KeyGrabData;
-static GdkFilterReturn keygrab_cb(GdkXEvent *xevent, GdkEvent *event, gpointer data) +static gboolean keygrab_cb(GtkWidget *widget, GdkEventKey *ev, gpointer data) { - XEvent*ev = (XEvent*) xevent; - GdkKeymapKey *km = (GdkKeymapKey*) data; - switch (ev->type) { - case KeyPress:{ - if (IsShift) { - km->level=1; - } else { - if (!IsCtrlAlt) km->group=1; /* Flag to know we have keydown before keyup */ - } - return GDK_FILTER_REMOVE; - } - case KeyRelease:{ - if (IsShift) { - km->level=0; - } else { - if ((km->group==1)&&(!IsCtrlAlt)) { /* OK, we already got our keydown */ - km->group=2; - km->level=(ev->xkey.state & ShiftMask)?1:0; - km->keycode=ev->xkey.keycode; - } - } - return GDK_FILTER_REMOVE; - } - default:{} - } - return GDK_FILTER_CONTINUE; -} + _KeyGrabData *km = (_KeyGrabData*) data;
-#define dosleep() g_usleep(1) + if (ev->keyval == 0) { + return FALSE; + }
-#else -#include <windows.h> -#define dosleep() Sleep(1) + km->keyval = ev->keyval; + km->keypress = TRUE; + return TRUE; +}
-#define IsShift ( (My_Shift_L == msg->wParam) || (My_Shift_R == msg->wParam) )
-#define IsCtrl ( (My_Control_L == msg->wParam) || (My_Control_R == msg->wParam) ) -#define IsAlt ( (My_Alt_L == msg->wParam) || (My_Alt_R == msg->wParam) ) +static gint glspi_keygrab(lua_State* L) +{ + GeanyDocument *doc = NULL; + const gchar *prompt = NULL; + static gulong keygrab_cb_handle = 0;
-#define IsCtrlAlt ( IsCtrl || IsAlt )
+ _KeyGrabData km; + km.keypress = FALSE; + km.keyval = 0;
-static GdkFilterReturn keygrab_cb(GdkXEvent *xevent, GdkEvent *event, gpointer data) -{ - MSG*msg = (MSG*) xevent; - GdkKeymapKey *km = (GdkKeymapKey*) data; - switch (msg->message) { - case WM_KEYDOWN:{ - if (IsShift) { - km->level=1; - } else { - if (!IsCtrlAlt) km->group=1; /* Flag to know we have keydown before keyup */ - } - return GDK_FILTER_REMOVE; - } - case WM_KEYUP:{ - if (IsShift) { - km->level=0; - } else { - if ((km->group==1)&&(!IsCtrlAlt)) { /* OK, we already got our keydown */ - km->group=2; - km->level=HIBYTE(GetKeyState(VK_SHIFT))?1:0; - km->keycode=msg->wParam; - } - } - return GDK_FILTER_REMOVE; + /* get prompt, if exists */ + if (lua_gettop(L) > 0) { + if (!lua_isstring(L, 1)) { + return FAIL_STRING_ARG(1); } - default:{} + prompt = lua_tostring(L,1); + doc = document_get_current(); } - return GDK_FILTER_CONTINUE; -} -
-#endif - - -#include <gdk/gdkkeysyms.h> -static gint init_key(guint keyval){ - GdkKeymapKey *kmk=NULL; - GdkKeymap *gdk_key_map=gdk_keymap_get_default(); - gint n_keys=0; - gint rv=0; - if (gdk_keymap_get_entries_for_keyval(gdk_key_map,keyval,&kmk,&n_keys)) { - rv=kmk[0].keycode; - g_free(kmk); + /* show prompt in tooltip */ + if (prompt && doc && doc->is_valid ) { + gint fvl = scintilla_send_message(doc->editor->sci, SCI_GETFIRSTVISIBLELINE, 0, 0); + gint pos = sci_get_position_from_line(doc->editor->sci, fvl+1); + scintilla_send_message(doc->editor->sci, SCI_CALLTIPSHOW, pos+3, (sptr_t) prompt); } - return rv; -} - -#define InitKey(code,value) if (!code) { code=init_key(value); }
-static gint glspi_keygrab(lua_State* L) -{ - GeanyDocument*doc=NULL; - const gchar*prompt=NULL; - GdkKeymapKey km={0,0,0}; - GdkKeymap *gdk_key_map; - km.keycode=0; - km.group=0; /* Note: we hijack this field to use as a flag for first keydown. */ - km.level=0; - InitKey(My_Shift_L, GDK_Shift_L); - InitKey(My_Shift_R, GDK_Shift_R); - InitKey(My_Control_L, GDK_Control_L); - InitKey(My_Control_R, GDK_Control_R); - InitKey(My_Alt_L, GDK_Alt_L); - InitKey(My_Alt_R, GDK_Alt_R); - if (lua_gettop(L)>0) { - if (!lua_isstring(L,1)) {return FAIL_STRING_ARG(1); } - prompt=lua_tostring(L,1); - doc=document_get_current(); + /* callback to handle keypress + only one keygrab callback can be running at a time, otherwise geanylua will hang + */ + if (!keygrab_cb_handle) { + keygrab_cb_handle = g_signal_connect(main_widgets->window, "key-press-event", G_CALLBACK(keygrab_cb), &km); + } else { + lua_pushnil(L); + return 1; }
- if (prompt && doc && doc->is_valid ) { - gint fvl=scintilla_send_message(doc->editor->sci,SCI_GETFIRSTVISIBLELINE, 0,0); - gint pos=sci_get_position_from_line(doc->editor->sci, fvl+1); - scintilla_send_message(doc->editor->sci,SCI_CALLTIPSHOW,pos+3, (sptr_t)prompt); - } - gdk_window_add_filter(gtk_widget_get_window(main_widgets->window), keygrab_cb, &km); - do { + /* wait for keypress */ + while (!km.keypress) { while (gtk_events_pending()) { - if (km.group==2) { break; } + if (km.keypress) { + break; + } gtk_main_iteration(); } - if (km.group==2) { break; } - dosleep(); - } while (km.group!=2); + } + + /* clear callback */ + g_clear_signal_handler(&keygrab_cb_handle, main_widgets->window);
- gdk_window_remove_filter(gtk_widget_get_window(main_widgets->window), keygrab_cb, &km); + /* clear tooltip */ if (prompt && doc && doc->is_valid) { - sci_send_command(doc->editor->sci, SCI_CALLTIPCANCEL); + sci_send_command(doc->editor->sci, SCI_CALLTIPCANCEL); } - km.group=0; /* reset the hijacked flag before passing to GDK */ - gdk_key_map = gdk_keymap_get_default(); - lua_pushstring(L, gdk_keyval_name(gdk_keymap_lookup_key(gdk_key_map, &km)));
+ lua_pushstring(L, gdk_keyval_name(km.keyval)); return 1; }
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
plugins-commits@lists.geany.org