1 /* Copyright (C) 2012 by Ben Martin */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef FONTFORGE_HOTKEYS_H
29 #define FONTFORGE_HOTKEYS_H
30 
31 #include "basics.h"
32 #include "dlist.h"
33 #include "gdraw.h"
34 
35 #define HOTKEY_ACTION_MAX_SIZE 200
36 #define HOTKEY_TEXT_MAX_SIZE   100
37 
38 
39 /**
40  * A hotkey binds some keyboard combination to an abstract "action"
41  *
42  * A major use of the action is to be able to pick off menu items from
43  * various windows as an action path. For example,
44  * CharView.Menu.File.Open is an action for the file/open menu item in
45  * the charview/glyph editing window.
46  *
47  * This namespace convension uses dot separated strings. The window
48  * type as the first string, followed by "Menu", followed by each menu
49  * item on the path down to the menu that should be invoked when the
50  * hotkey is pressed.
51  *
52  * The same system can be extended to allow python code to be
53  * executed. The current plan is to use Python instead of Menu. There
54  * is no reason that the syntax can not be varied slightly for Python,
55  * for example to allow something like
56  *
57  * CharView.Python.MyFooFunction( 7, "fdsfsd" ): Alt+t
58  *
59  * Where everything after the "Python." is to be the name of a valid
60  * python function to execute, in this case a call to MyFooFunction.
61  * While we could allow raw python code inthere too, it's probably
62  * simpler for the fontforge code to rely on calling a function
63  * instead. There is no reason that arguments can not be supplied as
64  * above.
65  *
66  * The hotkeys are actually made effective (ie execute something), in
67  * the GMenuBarCheckKey() function in gmenu.c. That code would need
68  * some extending to allow the execution of a python function instead
69  * of the current code which only executes a menu item which is named
70  * in the action.
71  *
72  * I am tempted there to move the execution of an action hack into
73  * hotkeys.c with GMenuBarCheckKey() passing the window and menubar to
74  * the new hotkeyExecuteAction() function which itself could handle
75  * working out if it is a CharView.Python prefix action and
76  * dispatching accordingly. The gain to that is that other code might
77  * also like to execute a hotkey independant of the existing code. For
78  * example, python code might execute an "action" through that
79  * function.
80  *
81  * The part I haven't personally investigated is the code to dispatch
82  * a python function from C. I've done similar with other codebases
83  * but haven't seen how it's done in ff. Others might like to put some
84  * hints here for whoever (maybe me!) writes the code to allow python
85  * dispatch from hotkeys.
86  *
87  * In a similar way, I was thinking of just having a top level
88  * directory of Action.Foo to allow generic, but maybe too low level
89  * for a menuitem things to be made available to the hotkey system.
90  * Perhaps an Action.ActionsList which just enumerates these actions
91  * to the console would be handy to allow folks to see what the code
92  * current version of ff offers in terms of actions.
93  *
94  */
95 typedef struct hotkey {
96     /**
97      * Hotkeys are stored in a doubly linked list. Having this entry
98      * first makes a pointer to a hotkey able to e treated as a list
99      * node.
100      */
101     struct dlistnode listnode;
102 
103     /**
104      * The name of the action this hotkey is to perform. For example,
105      * CharView.Menu.File.Open
106      */
107     char   action[HOTKEY_ACTION_MAX_SIZE+1];
108 
109     /**
110      * A directly machine usable represetation of the modifiers that
111      * must be in use for this hotkey to be fired. For example, shift,
112      * control etc.
113      */
114     uint16 state;
115 
116     /**
117      * A directly machine usable represetation of the key that is to
118      * be pressed fo r this hotkey. This would be a number for a key
119      * so that 'k' might be 642
120      */
121     uint16 keysym;
122 
123     /**
124      * If this hotkey is user defined this is true. If this is true
125      * then the hotkey should be saved back to the user
126      * ~/.FontForge/hotkeys file instead of any system file.
127      */
128     int    isUserDefined;
129 
130     /**
131      * The plain text representation for the key combination that is
132      * to be pressed for this hotkey. For example, "Ctrl+k". Note that
133      * the modifiers are not localized in this string, it is as it
134      * would appear in the hotkeys file and system hotkeys
135      * definitations.
136      */
137     char   text[HOTKEY_TEXT_MAX_SIZE+1];
138 } Hotkey;
139 
140 /**
141  * Load the list of hotkey from both system and user catalogs. These
142  * include the locale versions like en_GB which provide the shipped
143  * defaults and the user overrides in ~/.FontForge/hotkeys.
144  */
145 extern void    hotkeysLoad(void);
146 
147 /**
148  * Save all user defined hotkeys back to ~/.FontForge/hotkeys.
149  */
150 extern void    hotkeysSave(void);
151 
152 /**
153  * Return the non localized string definition of the keys that must
154  * be pressed for this action. The return value might be Shift+Ctl+8
155  */
156 extern char*   hotkeysGetKeyDescriptionFromAction( char* action );
157 
158 /**
159  * Find the hotkey that matches the given event for the given window.
160  * The window is needed because hotkeys can bind to specific windows
161  * like the fontview, metricsview or charview.
162  *
163  * Do not free the return value, it's not yours!
164  */
165 extern Hotkey* hotkeyFindByEvent( GWindow w, GEvent *event );
166 
167 /**
168  * Like hotkeyFindByEvent but this gives you access to all the hotkeys
169  * that are to be triggered for the given event on the given window.
170  *
171  * You should call dlist_free_external() on the return value. The
172  * hotkeys returned are not yours to free, but the list nodes that
173  * point to the hotkeys *ARE* yours to free.
174  */
175 extern struct dlistnodeExternal* hotkeyFindAllByEvent( GWindow w, GEvent *event );
176 
177 /**
178  * Strip off any modifier definitation from the given fill hotkey string
179  * definition. Given a string like Shift+Ctl+8 returns 8.
180  * No memory allocations are performed, the return value is null or a pointer
181  * into the hktext string.
182  */
183 extern char*   hotkeyTextWithoutModifiers( char* hktext );
184 
185 /**
186  * Convert text like Control to the command key unicode value.
187  * Caller must free the returned value
188  */
189 extern char* hotkeyTextToMacModifiers( char* keydesc );
190 
191 /**
192  * Given a menu path like File/Open find the hotkey which will trigger
193  * that menu item. The window is needed because there might be a
194  * menuitem with the same text path in fontview and charview which the
195  * user has decided should have different hotkeys
196  *
197  * Do not free the return value, it's not yours!
198  */
199 extern Hotkey* hotkeyFindByMenuPath( GWindow w, char* path );
200 extern Hotkey* hotkeyFindByMenuPathInSubMenu( GWindow w, char* subMenuName, char* path );
201 
202 /**
203  * Immediate keys are hotkeys like the ` key to turn on preview mode in charview.
204  * They are perhaps toggle keys, or just keys which code wants to respond to a keypress
205  * but also allow the user to configure what that key is using their hotkeys file.
206  * Instead of doing event->u.chr.keysym == '`' code can pass the event and a text name
207  * like "TogglePreview" and a window (to determine the prefix like CharView) and this
208  * function will tell you if that event matches the key that the user has defined to
209  * trigger your event.
210  */
211 extern Hotkey* isImmediateKey( GWindow w, char* path, GEvent *event );
212 
213 
214 
215 /**
216  * Set a hotkey to trigger the given action. If append is not true
217  * then any other hotkey bindings using keydefinition for the window
218  * type specified in the action you passed are first removed.
219  *
220  * The new hotkey is returned.
221  */
222 extern Hotkey* hotkeySet( char* action, char* keydefinition, int append );
223 
224 extern void HotkeyParse( Hotkey* hk, const char *shortcut );
225 
226 /**
227  * Set to true if the hotkey system can use the Command key for its
228  * own actions.
229  */
230 extern void hotkeySystemSetCanUseMacCommand( int v );
231 extern int hotkeySystemGetCanUseMacCommand(void);
232 
233 #endif /* FONTFORGE_HOTKEYS_H */
234