1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiSource Program Utilities
4  * Copyright (C) 1998 AbiSource, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 
22 
23 
24 
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "ut_assert.h"
31 #include "ut_debugmsg.h"
32 #include "ut_types.h"
33 #include "ev_EditMethod.h"
34 #include "ev_EditBinding.h"
35 #include "ev_NamedVirtualKey.h"
36 
37 
38 /*****************************************************************/
39 /*****************************************************************/
40 
EV_EditBinding(EV_EditBindingMap * pebm)41 EV_EditBinding::EV_EditBinding(EV_EditBindingMap * pebm)
42 {
43 	m_ebt = EV_EBT_PREFIX;
44 	u.m_pebm = pebm;
45 }
46 
EV_EditBinding(EV_EditMethod * pem)47 EV_EditBinding::EV_EditBinding(EV_EditMethod * pem)
48 {
49 	m_ebt = EV_EBT_METHOD;
50 	u.m_pem = pem;
51 }
52 
getMap(void) const53 EV_EditBindingMap * EV_EditBinding::getMap(void) const
54 {
55 	UT_ASSERT(m_ebt == EV_EBT_PREFIX);
56 	return u.m_pebm;
57 }
58 
getMethod(void) const59 EV_EditMethod * EV_EditBinding::getMethod(void) const
60 {
61 	UT_ASSERT(m_ebt == EV_EBT_METHOD);
62 	return u.m_pem;
63 }
64 
65 /*****************************************************************/
66 /*****************************************************************/
67 
68 class ABI_EXPORT ev_EB_MouseTable
69 {
70 public:
ev_EB_MouseTable()71 	ev_EB_MouseTable()
72 		{
73 			reset();
74 		};
75 
reset()76 	void reset()
77 		{
78 			memset(m_peb,0,sizeof(m_peb));
79 		}
80 
~ev_EB_MouseTable()81 	~ev_EB_MouseTable()
82 		{
83 			for (UT_uint32 i=0; i < EV_COUNT_EMO; i++)
84 				for (UT_uint32 j=0; j < EV_COUNT_EMS; j++)
85 					for (UT_uint32 k=0; k< EV_COUNT_EMC; k++)
86 						if (m_peb[i][j][k])
87 							delete m_peb[i][j][k];
88 		}
89 
90 	EV_EditBinding *	m_peb[EV_COUNT_EMO][EV_COUNT_EMS][EV_COUNT_EMC];
91 };
92 
93 class ABI_EXPORT ev_EB_NVK_Table
94 {
95 public:
ev_EB_NVK_Table()96 	ev_EB_NVK_Table()
97 		{
98 			reset();
99 		};
reset()100 	void reset()
101 		{
102 			memset(m_peb,0,sizeof(m_peb));
103 		}
~ev_EB_NVK_Table()104 	~ev_EB_NVK_Table()
105 		{
106 			for (UT_sint32 i=0; i < static_cast<UT_sint32>(EV_COUNT_NVK); i++)
107 				for (UT_sint32 j=0; j < EV_COUNT_EMS; j++)
108 					if (m_peb[i][j])
109 						delete m_peb[i][j];
110 		}
111 
112 	EV_EditBinding *	m_peb[EV_COUNT_NVK][EV_COUNT_EMS];
113 };
114 
115 class ABI_EXPORT ev_EB_Char_Table
116 {
117 public:
ev_EB_Char_Table()118 	ev_EB_Char_Table()
119 		{
120 			reset();
121 		};
reset()122 	void reset()
123 		{
124 			memset(m_peb,0,sizeof(m_peb));
125 		}
~ev_EB_Char_Table()126 	~ev_EB_Char_Table()
127 		{
128 			for (UT_sint32 i=0; i < 256; i++)
129 				for (UT_sint32 j=0; j < EV_COUNT_EMS_NoShift; j++)
130 					if (m_peb[i][j])
131 						delete m_peb[i][j];
132 		}
133 
134 
135 	// TODO Note[1]  we currently limit the range on regular (non-nvk)
136 	// TODO Note[1]  keys to 256.  This is probably OK for Latin1, but
137 	// TODO Note[1]  will probably need to be re-addressed later.
138 
139 	EV_EditBinding *	m_peb[256][EV_COUNT_EMS_NoShift];
140 };
141 
142 /*****************************************************************/
143 /*****************************************************************/
144 
EV_EditBindingMap(EV_EditMethodContainer * pemc)145 EV_EditBindingMap::EV_EditBindingMap(EV_EditMethodContainer * pemc):
146 	m_iLastMouseNo(0)
147 {
148 	UT_ASSERT(pemc);
149 	m_pemc = pemc;
150 	UT_sint32 i = 0;
151 	for (i=0; i<EV_COUNT_EMB; i++)
152 	{
153 	  m_pebMT[i] = (ev_EB_MouseTable*) NULL;
154 	}
155 	m_pebNVK = (ev_EB_NVK_Table*) NULL;
156 	m_pebChar = (ev_EB_Char_Table*) NULL;
157 }
158 
~EV_EditBindingMap()159 EV_EditBindingMap::~EV_EditBindingMap()
160 {
161 	UT_sint32 i = 0;
162 	for (i=0; i<EV_COUNT_EMB; i++)
163 	{
164 		if (m_pebMT[i])
165 			delete m_pebMT[i];
166 	}
167 
168 	if (m_pebNVK)
169 		delete m_pebNVK;
170 
171 	if (m_pebChar)
172 		delete m_pebChar;
173 }
174 
MakeMouseEditBits(UT_uint32 button,UT_uint32 op,UT_uint32 mod,UT_uint32 context)175 static EV_EditBits MakeMouseEditBits( UT_uint32 button, UT_uint32 op, UT_uint32 mod, UT_uint32 context )
176 {
177 	EV_EditBits eb = 0;
178 	switch (button) {
179 		case 0: eb |= EV_EMB_BUTTON0; break;
180 		case 1: eb |= EV_EMB_BUTTON1; break;
181 		case 2: eb |= EV_EMB_BUTTON2; break;
182 		case 3: eb |= EV_EMB_BUTTON3; break;
183 		case 4: eb |= EV_EMB_BUTTON4; break;
184 		case 5: eb |= EV_EMB_BUTTON5; break;
185 		default: UT_ASSERT(UT_SHOULD_NOT_HAPPEN); break;
186 	}
187 	eb |= EV_EMO_FromNumber( op+1 );
188 	eb |= EV_EMS_FromNumber( mod );
189 	switch (context) {
190 		case 0: eb |= EV_EMC_UNKNOWN; break;
191 		case 1: eb |= EV_EMC_TEXT; break;
192 		case 2: eb |= EV_EMC_LEFTOFTEXT; break;
193 		case 3: eb |= EV_EMC_MISSPELLEDTEXT; break;
194 		case 4: eb |= EV_EMC_IMAGE; break;
195 		case 5: eb |= EV_EMC_IMAGESIZE; break;
196 		case 6: eb |= EV_EMC_FIELD; break;
197 		case 7: eb |= EV_EMC_HYPERLINK; break;
198 		case 8: eb |= EV_EMC_RIGHTOFTEXT; break;
199 		case 9: eb |= EV_EMC_REVISION; break;
200 		case 10: eb |= EV_EMC_VLINE; break;
201 		case 11: eb |= EV_EMC_HLINE; break;
202 		case 12: eb |= EV_EMC_FRAME; break;
203 		case 13: eb |= EV_EMC_VISUALTEXTDRAG; break;
204 		case 14: eb |= EV_EMC_TOPCELL; break;
205 		case 15: eb |= EV_EMC_TOC; break;
206 		case 16: eb |= EV_EMC_POSOBJECT; break;
207 		case 17: eb |= EV_EMC_MATH; break;
208 		case 18: eb |= EV_EMC_EMBED; break;
209 		default: UT_ASSERT(UT_SHOULD_NOT_HAPPEN); break;
210 	}
211 	return eb;
212 }
213 
MakeNVKEditBits(UT_uint32 mod,UT_uint32 nvk)214 static EV_EditBits MakeNVKEditBits( UT_uint32 mod, UT_uint32 nvk )
215 {
216 	return EV_EMS_FromNumberNoShift(mod) | nvk | EV_EKP_NAMEDKEY;
217 }
218 
MakeKeyPressEditBits(UT_uint32 mod,UT_uint32 key)219 static EV_EditBits MakeKeyPressEditBits( UT_uint32 mod, UT_uint32 key )
220 {
221 	return EV_EMS_FromNumberNoShift(mod) | key | EV_EKP_PRESS;
222 }
223 
getAll(std::map<EV_EditBits,const char * > & map)224 void EV_EditBindingMap::getAll( std::map<EV_EditBits,const char*>& map )
225 {
226 	// loop through mouse contexts
227 	if (m_pebMT) {
228 		for (UT_uint32 button=0; button<sizeof(m_pebMT)/sizeof(m_pebMT[0]); ++button) {
229 			if (m_pebMT[button]) {
230 				for (UT_uint32 op=0; op<sizeof(m_pebMT[0]->m_peb)/sizeof(m_pebMT[0]->m_peb[0]); ++op) {
231 					for (UT_uint32 mod=0; mod<sizeof(m_pebMT[0]->m_peb[0])/sizeof(m_pebMT[0]->m_peb[0][0]); ++mod) {
232 						for (UT_uint32 context=0; context<sizeof(m_pebMT[0]->m_peb[0][0])/sizeof(m_pebMT[0]->m_peb[0][0][0]); ++context) {
233 							EV_EditBinding* binding = m_pebMT[button]->m_peb[op][mod][context];
234 							if (binding && binding->getType()==EV_EBT_METHOD) {
235 								map.insert(
236 									std::map<EV_EditBits,const char*>::value_type(
237 										MakeMouseEditBits( button, op, mod, context ),
238 										binding->getMethod()->getName() )
239 								);
240 							}
241 						}
242 					}
243 				}
244 			}
245 		}
246 	}
247 
248 	// loop through NVK's
249 	if (m_pebNVK) {
250 		for (UT_uint32 nvk=0; nvk<sizeof(m_pebNVK->m_peb)/sizeof(m_pebNVK->m_peb[0]); ++nvk) {
251 			for (UT_uint32 mod=0; mod<sizeof(m_pebNVK->m_peb[0])/sizeof(m_pebNVK->m_peb[0][0]); ++mod) {
252 				EV_EditBinding* binding = m_pebNVK->m_peb[nvk][mod];
253 				if (binding && binding->getType()==EV_EBT_METHOD) {
254 					map.insert(
255 						std::map<EV_EditBits,const char*>::value_type(
256 							MakeNVKEditBits( mod, nvk ),
257 							binding->getMethod()->getName() )
258 					);
259 				}
260 			}
261 		}
262 	}
263 
264 	// loop through keypresses
265 	if (m_pebChar) {
266 		for (UT_uint32 key=0; key<sizeof(m_pebChar->m_peb)/sizeof(m_pebChar->m_peb[0]); ++key) {
267 			for (UT_uint32 mod=0; mod<sizeof(m_pebChar->m_peb[0])/sizeof(m_pebChar->m_peb[0][0]); ++mod) {
268 				EV_EditBinding* binding = m_pebChar->m_peb[key][mod];
269 				if (binding && binding->getType()==EV_EBT_METHOD) {
270 					map.insert(
271 						std::map<EV_EditBits,const char*>::value_type(
272 							MakeKeyPressEditBits( mod, key ),
273 							binding->getMethod()->getName() )
274 					);
275 				}
276 			}
277 		}
278 	}
279 }
280 
findEditBits(const char * szMethodName,std::vector<EV_EditBits> & list)281 void EV_EditBindingMap::findEditBits( const char* szMethodName, std::vector<EV_EditBits>& list )
282 {
283 	// first check if we even know the specified method
284 	EV_EditMethod* method = m_pemc->findEditMethodByName( szMethodName );
285 	if (method) {
286 
287 		// search in mouse contexts
288 		if (m_pebMT) {
289 			for (UT_uint32 button=0; button<sizeof(m_pebMT)/sizeof(m_pebMT[0]); ++button) {
290 				if (m_pebMT[button]) {
291 					for (UT_uint32 op=0; op<sizeof(m_pebMT[0]->m_peb)/sizeof(m_pebMT[0]->m_peb[0]); ++op) {
292 						for (UT_uint32 mod=0; mod<sizeof(m_pebMT[0]->m_peb[0])/sizeof(m_pebMT[0]->m_peb[0][0]); ++mod) {
293 							for (UT_uint32 context=0; context<sizeof(m_pebMT[0]->m_peb[0][0])/sizeof(m_pebMT[0]->m_peb[0][0][0]); ++context) {
294 								if (bindingUsesMethod( m_pebMT[button]->m_peb[op][mod][context], method )) {
295 									list.push_back( MakeMouseEditBits( button, op, mod, context ) );
296 								}
297 							}
298 						}
299 					}
300 				}
301 			}
302 		}
303 
304 		// search in NVK's
305 		if (m_pebNVK) {
306 			for (UT_uint32 nvk=0; nvk<sizeof(m_pebNVK->m_peb)/sizeof(m_pebNVK->m_peb[0]); ++nvk) {
307 				for (UT_uint32 mod=0; mod<sizeof(m_pebNVK->m_peb[0])/sizeof(m_pebNVK->m_peb[0][0]); ++mod) {
308 					if (bindingUsesMethod( m_pebNVK->m_peb[nvk][mod], method )) {
309 						list.push_back( MakeNVKEditBits( mod, nvk ) );
310 					}
311 				}
312 			}
313 		}
314 
315 		// search in keypresses
316 		if (m_pebChar) {
317 			for (UT_uint32 key=0; key<sizeof(m_pebChar->m_peb)/sizeof(m_pebChar->m_peb[0]); ++key) {
318 				for (UT_uint32 mod=0; mod<sizeof(m_pebChar->m_peb[0])/sizeof(m_pebChar->m_peb[0][0]); ++mod) {
319 					if (bindingUsesMethod( m_pebChar->m_peb[key][mod], method )) {
320 						list.push_back( MakeKeyPressEditBits( mod, key ) );
321 					}
322 				}
323 			}
324 		}
325 	}
326 }
327 
bindingUsesMethod(EV_EditBinding * binding,EV_EditMethod * method)328 bool EV_EditBindingMap::bindingUsesMethod( EV_EditBinding* binding, EV_EditMethod* method )
329 {
330 	return binding && binding->getType()==EV_EBT_METHOD && binding->getMethod()==method;
331 }
332 
findEditBinding(EV_EditBits eb)333 EV_EditBinding * EV_EditBindingMap::findEditBinding(EV_EditBits eb)
334 {
335 	// this handles keyboard (nvk and char) and mouse.
336 
337 	if (EV_IsMouse(eb))					// mouse
338 	{
339 		UT_uint32 n_emb = EV_EMB_ToNumber(eb)-1;
340 		xxx_UT_DEBUGMSG(("is mouse %d binding number %d \n",eb,n_emb));
341 		//
342 		// Handle the case of accidently middle clicking during a
343 		// mouse wheel scroll.
344 		//
345 		if((n_emb == 2) && ((m_iLastMouseNo == 4) || (m_iLastMouseNo == 5)))
346 		{
347 				n_emb = m_iLastMouseNo;
348 		}
349 		m_iLastMouseNo = n_emb;
350 		class ev_EB_MouseTable * p = m_pebMT[n_emb];
351 		if (!p)
352 			return 0;					// no bindings of anykind for this mouse button
353 		UT_uint32 n_emo = EV_EMO_ToNumber(eb)-1;
354 		UT_uint32 n_ems = EV_EMS_ToNumber(eb);
355 		UT_uint32 n_emc = EV_EMC_ToNumber(eb);
356 		return p->m_peb[n_emo][n_ems][n_emc];
357 
358 	}
359 	else if (EV_IsKeyboard(eb))			// a keyevent, find out what kind
360 	{
361 		if (eb & EV_EKP_NAMEDKEY)		// a NVK
362 		{
363 			if (!m_pebNVK)
364 				return 0;				// no bindings of anykind for nvk keys
365 
366 			UT_uint32 n_nvk = EV_NVK_ToNumber(eb);
367 			UT_uint32 n_ems = EV_EMS_ToNumber(eb);
368 			return m_pebNVK->m_peb[n_nvk][n_ems];
369 		}
370 		else							// not a NVK -- regular char
371 		{
372 			if (!m_pebChar)
373 				return 0;				// no bindings of anykind for non-nvk keys
374 
375 			UT_uint32 n_evk = EV_EVK_ToNumber(eb);
376 			if (n_evk >= 256)
377 			{
378 				if ( n_evk >= 256 && (n_evk - 65280) < 256)
379 					n_evk -= 65280;  // quick fix
380 				else
381 				{
382 					n_evk = 'a';
383 					/* in hopes that there will be
384 					   'insertData' method assigned to
385 					    plain 'a'
386 					*/
387 				}
388 			};
389 
390 			UT_uint32 n_ems = EV_EMS_ToNumberNoShift(eb);
391 			return m_pebChar->m_peb[n_evk][n_ems];
392 		}
393 	}
394 	UT_ASSERT(0);
395 	return 0;
396 }
397 
setBinding(EV_EditBits eb,const char * szMethodName)398 bool EV_EditBindingMap::setBinding(EV_EditBits eb, const char * szMethodName)
399 {
400 	EV_EditMethod * pem = m_pemc->findEditMethodByName(szMethodName);
401 	if (!pem)
402 	{
403 	        if(strcmp(szMethodName,"NULL") == 0)
404 		{
405 		    EV_EditBinding * ev = NULL;
406 		    return setBinding(eb,ev);
407 		}
408 		UT_DEBUGMSG(("Unknown method name [%s] in binding table.\n",szMethodName));
409 		UT_ASSERT(pem);				// TODO remove this and find a better way of doing a spelling-check...
410 		return false;
411 	}
412 
413 	EV_EditBinding * peb = new EV_EditBinding(pem);
414 	if (!peb)
415 		return false;
416 
417 	return setBinding(eb,peb);
418 }
419 
setBinding(EV_EditBits eb,EV_EditBinding * peb)420 bool EV_EditBindingMap::setBinding(EV_EditBits eb, EV_EditBinding * peb)
421 {
422 	// this handles keyboard (nvk and char) and mouse.
423 	// return false if the given location is already bound.
424 
425 	if (EV_IsMouse(eb))					// mouse
426 	{
427 		UT_uint32 n_emb = EV_EMB_ToNumber(eb)-1;
428 		class ev_EB_MouseTable * p = m_pebMT[n_emb];
429 		if (!p)
430 		{
431 			m_pebMT[n_emb] = new ev_EB_MouseTable();
432 			p = m_pebMT[n_emb];
433 			if (!p) {
434 				delete peb;
435 				return false;
436 			}
437 		}
438 		UT_uint32 n_emo = EV_EMO_ToNumber(eb)-1;
439 		UT_uint32 n_ems = EV_EMS_ToNumber(eb);
440 		UT_uint32 n_emc = EV_EMC_ToNumber(eb);
441 		if (p->m_peb[n_emo][n_ems][n_emc]) {
442 			delete peb;
443 			return false;
444 		}
445 		p->m_peb[n_emo][n_ems][n_emc] = peb;
446 		return true;
447 	}
448 	else if (EV_IsKeyboard(eb))			// a keyevent, find out what kind
449 	{
450 		if (eb & EV_EKP_NAMEDKEY)		// nvk
451 		{
452 			if (!m_pebNVK)
453 			{
454 				m_pebNVK = new ev_EB_NVK_Table();
455 				if (!m_pebNVK) {
456 					delete peb;
457 					return false;
458 				}
459 			}
460 			UT_uint32 n_nvk = EV_NVK_ToNumber(eb);
461 			UT_uint32 n_ems = EV_EMS_ToNumber(eb);
462 			if (m_pebNVK->m_peb[n_nvk][n_ems]) {
463 				delete peb;
464 				return false;
465 			}
466 			m_pebNVK->m_peb[n_nvk][n_ems] = peb;
467 			return true;
468 		}
469 		else							// a non-nvk -- regular char
470 		{
471 			if (!m_pebChar)
472 			{
473 				m_pebChar = new ev_EB_Char_Table();
474 				if (!m_pebChar) {
475 					delete peb;
476 					return false;
477 				}
478 			}
479 			UT_uint32 n_evk = EV_EVK_ToNumber(eb);
480 			UT_ASSERT(n_evk < 256);		// TODO see note [1] above.
481 			UT_uint32 n_ems = EV_EMS_ToNumberNoShift(eb);
482 			if (m_pebChar->m_peb[n_evk][n_ems])
483 			{
484 			        UT_DEBUGMSG(("Removing and Deleting previous keybinding %p \n",m_pebChar->m_peb[n_evk][n_ems]));
485 				delete m_pebChar->m_peb[n_evk][n_ems];
486 			}
487 			m_pebChar->m_peb[n_evk][n_ems] = peb;
488 			return true;
489 		}
490 	}
491 	delete peb;
492 	UT_ASSERT(0);
493 	return 0;
494 }
495 
removeBinding(EV_EditBits eb)496 bool EV_EditBindingMap::removeBinding(EV_EditBits eb)
497 {
498 	// this handles keyboard (nvk and char) and mouse.
499 	// remove the binding from the map.
500 	// return true if binding updated.
501 	// we do not g_free the unreferenced binding.
502 
503 	if (EV_IsMouse(eb))					// mouse
504 	{
505 		UT_uint32 n_emb = EV_EMB_ToNumber(eb)-1;
506 		class ev_EB_MouseTable * p = m_pebMT[n_emb];
507 		if (!p)
508 			return false;
509 		UT_uint32 n_emo = EV_EMO_ToNumber(eb)-1;
510 		UT_uint32 n_ems = EV_EMS_ToNumber(eb);
511 		UT_uint32 n_emc = EV_EMC_ToNumber(eb);
512 		p->m_peb[n_emo][n_ems][n_emc] = 0;
513 		return true;
514 	}
515 	else if (EV_IsKeyboard(eb))			// a keyevent, find out what kind
516 	{
517 		if (eb & EV_EKP_NAMEDKEY)		// nvk
518 		{
519 			if (!m_pebNVK)
520 				return false;
521 			UT_uint32 n_nvk = EV_NVK_ToNumber(eb);
522 			UT_uint32 n_ems = EV_EMS_ToNumber(eb);
523 			m_pebNVK->m_peb[n_nvk][n_ems] = 0;
524 			return true;
525 		}
526 		else							// a non-nvk -- regular char
527 		{
528 			if (!m_pebChar)
529 				return false;
530 			UT_uint32 n_evk = EV_EVK_ToNumber(eb);
531 			UT_ASSERT(n_evk < 256);		// TODO see note [1] above.
532 			UT_uint32 n_ems = EV_EMS_ToNumberNoShift(eb);
533 			m_pebChar->m_peb[n_evk][n_ems] = 0;
534 			return true;
535 		}
536 	}
537 	UT_ASSERT(0);
538 	return 0;
539 }
540 
resetAll()541 void EV_EditBindingMap::resetAll()
542 {
543 	// NOTE: this to me seems like a memory leak,
544 	// but since removeBinding is so seemingly easy with leaking
545 	// memory as well, I just copy it's MO.
546 	for (size_t i=0; i<sizeof(m_pebMT)/sizeof(m_pebMT[0]); ++i) {
547 		m_pebMT[i]->reset();
548 	}
549 	m_pebNVK->reset();
550 	m_pebChar->reset();
551 }
552 
getShortcutFor(const EV_EditMethod * pEM) const553 const char * EV_EditBindingMap::getShortcutFor(const EV_EditMethod * pEM) const
554 {
555 	UT_ASSERT(pEM);
556 	if(!m_pebChar)
557 	  return NULL;
558 	// lookup the keyboard shortcut bound to pEM, if any
559 
560 	EV_EditModifierState ems = 0;
561 	EV_EditBinding * pEB;
562 	UT_sint32 i, j;
563 	char shortcut = 0;
564 
565 	// search characters first
566 	bool bChar = false;
567 
568 	/* we lookup the table in decreasing order to be able to catch lowercase
569 	 BEFORE uppercase. Uppercase = Shift modifier. That is the rule */
570 	if (m_pebChar)
571 	{
572 		for (i=255; (i >= 0) && !bChar; i--)
573 		{
574 			for (j=0; j < EV_COUNT_EMS_NoShift; j++)
575 			{
576 				if (m_pebChar->m_peb[i][j])
577 				{
578 					// only check non-null entries
579 					pEB = m_pebChar->m_peb[i][j];
580 
581 					if ((pEB->getType() == EV_EBT_METHOD) &&
582 						(pEB->getMethod() == pEM))
583 					{
584 						// bingo
585 						bChar = true;
586 						shortcut = i;
587 
588 						ems = EV_EMS_FromNumberNoShift(j);
589 						break;
590 					}
591 				}
592 			}
593 		}
594 	}
595 
596 	bool bNVK = false;
597 
598 	if (!bChar && m_pebNVK)
599 	{
600 		// then search NVKs
601 		for (i=0; (i < static_cast<UT_sint32>(EV_COUNT_NVK)) && !bNVK; i++)
602 		{
603 			for (j=0; j < EV_COUNT_EMS; j++)
604 			{
605 				if (m_pebNVK->m_peb[i][j])
606 				{
607 					// only check non-null entries
608 					pEB = m_pebNVK->m_peb[i][j];
609 
610 					if ((pEB->getType() == EV_EBT_METHOD) &&
611 						(pEB->getMethod() == pEM))
612 					{
613 						// bingo
614 						bNVK = true;
615 						shortcut = i;
616 
617 						ems = EV_EMS_FromNumber(j);
618 						break;
619 					}
620 				}
621 			}
622 		}
623 	}
624 
625 
626 	if (!bChar && !bNVK)
627 	  return (const char *) NULL;
628 
629 	// translate into displayable string
630 	static char buf[128];
631 	memset(buf,0,G_N_ELEMENTS(buf));
632 
633 	if (ems&EV_EMS_CONTROL)
634 		strcat(buf, "Ctrl+");
635 
636 	if (ems&EV_EMS_SHIFT)
637 		strcat(buf, "Shift+");
638 
639 	if (ems&EV_EMS_ALT)
640 		strcat(buf, "Alt+");
641 
642 	if (bChar)
643 	{
644 		if ((shortcut >= 'A') && (shortcut <= 'Z')) {
645 			/* always return an uppercase letter for the shortcut, unlike the mapper do */
646 			if (!(ems&EV_EMS_SHIFT)) {
647 				strcat(buf, "Shift+");
648 			}
649 		}
650 		 else
651 			shortcut = toupper (shortcut);
652 
653 		int len = strlen(buf);
654 		buf[len] = shortcut;
655 	}
656 	else
657 	{
658 		// translate NVK
659 	  const char * szNVK = (const char *) NULL;
660 
661 		// TODO: look these up from table, rather than switch
662 		switch(EV_NamedKey(shortcut))
663 		{
664 		case EV_NVK_DELETE:
665 			szNVK = "Del";
666 			break;
667 
668 		case EV_NVK_F1:
669 			szNVK = "F1";
670 			break;
671 
672 		case EV_NVK_F3:
673 			szNVK = "F3";
674 			break;
675 
676 		case EV_NVK_F4:
677 			szNVK = "F4";
678 			break;
679 
680 		case EV_NVK_F7:
681 			szNVK = "F7";
682 			break;
683 
684 		case EV_NVK_F10:
685 			szNVK = "F10";
686 			break;
687 
688 		case EV_NVK_F11:
689 			szNVK = "F11";
690 			break;
691 
692 		case EV_NVK_F12:
693 			szNVK = "F12";
694 			break;
695 
696 		default:
697 			szNVK = "unmapped NVK";
698 			break;
699 		}
700 
701 		strcat(buf, szNVK);
702 	}
703 
704 	return buf;
705 }
706 
parseEditBinding(void)707 bool EV_EditBindingMap::parseEditBinding(void /*const char * szAscii*/)
708 {
709 	/* TODO here we import a binding from a primitive ascii format
710 	** TODO or XML syntax.
711 	*/
712   /*
713     The Ascii format is close to the definition in wp/ap/xp/ap_LB_Default.cpp
714 Lines beginning with "//" are comments
715 
716 Each CR seperated lines define a set of bindings for a single mouse context or
717 key stroke. Entries are seperated by commas. In creating the context, several
718 modifiers can be used. Control, Alt, Shift, Control-Alt (C, A, S )
719 
720 The first token of each line determines whether the defintion is for mouse context (mse), Named Virtual Key (nvk), or keystroke (key).
721 
722 The definition of each set of bindings are always in the following order for
723 mouse contexts.
724 
725 Up to to 6 buttons are available for the mouse. (B0, B1, B2, B3, B4, B5, B6)
726 The follow contexts are available:
727 
728 Short cut       C++ enum
729 =========       =========
730 CU		EV_EMC_UNKNOWN
731 CT		EV_EMC_TEXT
732 CM		EV_EMC_MISSPELLEDTEXT
733 CL		EV_EMC_LEFTOFTEXT
734 CR		EV_EMC_RIGHTOFTEXT
735 CI		EV_EMC_IMAGE
736 CZ		EV_EMC_IMAGESIZE
737 CF		EV_EMC_FIELD
738 CH		EV_EMC_HYPERLINK
739 CV		EV_EMC_REVISION
740 CTV		EV_EMC_VLINE
741 CTH		EV_EMC_HLINE
742 CTF		EV_EMC_FRAME
743 CVD		EV_EMC_VISUALTEXTDRAG
744 CTC		EV_EMC_TOPCELL
745 CTO		EV_EMC_TOC
746 CPO		EV_EMC_POSOBJECT
747 CMA		EV_EMC_MATH
748 CEM		EV_EMC_EMBED
749 
750 mse, Button, context, click, dblclick, drag, dbldrag, release, double release
751 
752 The first 3 entries describe the combination of buttons and context, the six entries that follow are the names of the EditMethods that called for each invocation of the mouse button and context.
753 
754 So some examples are:
755 
756 mse, B0,      CU   ,        ,       , cursorDefault,  ,  ,
757 mse, B0,     CEM   ,        ,       , btn0InlineImage ,  ,
758 mse, B1,     CVD   , cutVisualText, copyVisualText, dragVisualText, dragVisualText, dragVisualText, pasteVisualText
759 mse, B1, CVD C     ,copyVisualText,cutVisualText,dragVisualText,dragVisualText, pasteVisualText,pasteVisualText
760 
761 //
762 // mse/NVK/Key
763 // NVK, Key Name,    No modifier, S,     C,  S C,A , A S, A C, A C S
764 //
765 NVK, EV_NVK_BACKSPACE, delLeft,delLeft,delBOW,  ,   ,   ,    ,
766 //
767 // key, Key Value,    No modifier,   C,       A,    A C
768 //
769 key,    0x41,         insertData, selectAll,      ,
770   */
771 
772 	return false;
773 }
774