1 /*
2 * keyrecord.c - this file is part of Geany, a fast and lightweight IDE
3 *
4 * Copyright 2007-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2007-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22
23
24 /**
25 * Keystrokes recorder plugin - plugin for recording sequences of keystrokes and replaying it
26 */
27
28
29 #include <geanyplugin.h> /* plugin API, always comes first */
30 #include "keybindings.h"
31 #include <geany.h>
32 #include "Scintilla.h" /* for the SCNotification struct */
33 #include "stdio.h"
34 #include <gdk/gdkkeysyms.h>
35 #include <gtk/gtk.h>
36 #include <assert.h>
37 //#undef geany
38 /* text to be shown in the plugin dialog */
39 static GeanyPlugin* g_plugin = NULL;
40 static gboolean recording;
41 static GdkEventKey** recorded_pattern;
42 static guint recorded_size;
43 int CAPACITY = 2;
44 GeanyKeyBinding *record, *play;
45 GtkWidget *cur_widget;
is_record_key(GdkEventKey * event)46 static gboolean is_record_key(GdkEventKey *event)
47 {
48 //return (event->state & GDK_CONTROL_MASK) && (event->keyval == GDK_KEY_F1);
49 return record->key == event->keyval && (event->state & record->mods);
50 }
51
is_play_key(GdkEventKey * event)52 static gboolean is_play_key(GdkEventKey *event)
53 {
54 // return (event->state & GDK_CONTROL_MASK) && (event->keyval == GDK_KEY_F2);
55 return play->key == event->keyval && (event->state & play->mods);
56 }
57
58
59
60 static gboolean
on_key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)61 on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
62 {
63 cur_widget = widget;
64 //GeanyDocument* doc = (GeanyDocument*)data;
65 guint i;
66 GdkEventKey** tmp = NULL;
67
68 if ((recording) && !(is_record_key(event)||is_play_key(event)))
69 {
70 GdkEventKey* new_event = g_new0(GdkEventKey, 1);
71 *new_event = *event;
72 if (recorded_size == CAPACITY)
73 {
74 tmp = g_new0(GdkEventKey*, CAPACITY * 2);
75 for (i = 0; i < recorded_size; i++)
76 tmp[i] = recorded_pattern[i];
77 g_free(recorded_pattern);
78 recorded_pattern = tmp;
79 CAPACITY *= 2;
80 }
81 assert(recorded_size < CAPACITY);
82 if (recorded_pattern[(recorded_size)] != NULL)
83 g_free(recorded_pattern[recorded_size]);
84 recorded_pattern[recorded_size++] = new_event;
85 }
86
87 return FALSE;
88 }
89
90 static void
on_document_open(GObject * obj,GeanyDocument * doc,gpointer user_data)91 on_document_open(GObject *obj, GeanyDocument *doc, gpointer user_data)
92 {
93 GeanyDocument *data;
94 ScintillaObject *sci;
95 g_return_if_fail(DOC_VALID(doc));
96 sci = doc->editor->sci;
97 data = g_new0(GeanyDocument, 1);
98 *data = *doc;
99 plugin_signal_connect(g_plugin, G_OBJECT(sci), "key-press-event",
100 FALSE, G_CALLBACK(on_key_press), data);
101 /* This will free the data when the sci is destroyed */
102 g_object_set_data_full(G_OBJECT(sci), "keyrecord-userdata", data, g_free);
103 }
104
105 static PluginCallback keyrecord_callbacks[] =
106 {
107 /* Set 'after' (third field) to TRUE to run the callback @a after the default handler.
108 * If 'after' is FALSE, the callback is run @a before the default handler, so the plugin
109 * can prevent Geany from processing the notification. Use this with care. */
110 { "document-open", (GCallback) &on_document_open, FALSE, NULL },
111 { "document-new", (GCallback) &on_document_open, FALSE, NULL },
112 //{ "editor-notify", (GCallback) &on_editor_notify, FALSE, NULL },
113 { NULL, NULL, FALSE, NULL }
114 };
115
116 static void
on_record(guint key_id)117 on_record (guint key_id)
118 {
119 if (!recording)
120 {
121 recording = TRUE;
122 recorded_size = 0;
123 }
124 else
125 {
126 recording = FALSE;
127 }
128 }
129
130
131 static void
on_play(guint key_id)132 on_play (guint key_id)
133 {
134 //fprintf(stderr, "play: %d\n", key_id);
135 guint i;
136 //// sci_start_undo_action(doc->editor->sci);
137 if (cur_widget != NULL)
138 {
139 for (i = 0; i < (recorded_size); i++)
140 gdk_display_put_event(gtk_widget_get_display(cur_widget),
141 (GdkEvent*)(recorded_pattern[i]));
142
143 //return TRUE;
144 }
145 // sci_end_undo_action(doc->editor->sci);
146 }
147 /* Called by Geany to initialize the plugin */
keyrecord_init(GeanyPlugin * plugin,gpointer data)148 static gboolean keyrecord_init(GeanyPlugin *plugin, gpointer data)
149 {
150 GeanyKeyGroup *group;
151
152 group = plugin_set_key_group (plugin, "keyrecord", 2, NULL);
153 record = keybindings_set_item (group, 0, on_record,
154 0, 0, "record", _("Start/Stop record"), NULL);
155 play = keybindings_set_item (group, 1, on_play,
156 0, 0, "play", _("Play"), NULL);
157
158 GeanyData* geany_data = plugin->geany_data;
159 recorded_pattern = g_new0(GdkEventKey*, CAPACITY);
160
161 guint i = 0;
162 foreach_document(i) {
163 on_document_open(NULL, documents[i], NULL);
164 }
165 recording = FALSE;
166 recorded_size = 0;
167
168 geany_plugin_set_data(plugin, plugin, NULL);
169
170 g_plugin = plugin;
171
172 return TRUE;
173 }
174
175
176
177
178
179
180 /* Called by Geany before unloading the plugin.
181 * Here any UI changes should be removed, memory freed and any other finalization done.
182 * Be sure to leave Geany as it was before demo_init(). */
keyrecord_cleanup(GeanyPlugin * plugin,gpointer _data)183 static void keyrecord_cleanup(GeanyPlugin *plugin, gpointer _data)
184 {
185 GeanyData* geany_data = plugin->geany_data;
186 guint i;
187 for (i = 0; i < CAPACITY; i++)
188 if (recorded_pattern[i] != NULL) g_free(recorded_pattern[i]);
189 g_free(recorded_pattern);
190
191 foreach_document(i)
192 {
193 gpointer data;
194 ScintillaObject *sci;
195
196 sci = documents[i]->editor->sci;
197 data = g_object_steal_data(G_OBJECT(sci), "keyrecord-userdata");
198 g_free(data);
199 }
200
201 }
202
geany_load_module(GeanyPlugin * plugin)203 void geany_load_module(GeanyPlugin *plugin)
204 {
205 /* main_locale_init() must be called for your package before any localization can be done */
206 main_locale_init(LOCALEDIR, GETTEXT_PACKAGE);
207 plugin->info->name = _("Keystrokes recorder");
208 plugin->info->description = _("Allows to record some sequence of keystrokes and replay it");
209 plugin->info->version = "0.11";
210 plugin->info->author = _("tunyash");
211
212 plugin->funcs->init = keyrecord_init;
213 plugin->funcs->configure = NULL;
214 plugin->funcs->help = NULL; /* This demo has no help but it is an option */
215 plugin->funcs->cleanup = keyrecord_cleanup;
216 plugin->funcs->callbacks = keyrecord_callbacks;
217
218 GEANY_PLUGIN_REGISTER(plugin, 225);
219
220 }
221