1 | /*
|
---|
2 | * synergy -- mouse and keyboard sharing utility
|
---|
3 | * Copyright (C) 2002 Chris Schoeneman
|
---|
4 | *
|
---|
5 | * This package is free software; you can redistribute it and/or
|
---|
6 | * modify it under the terms of the GNU General Public License
|
---|
7 | * found in the file COPYING that should have accompanied this file.
|
---|
8 | *
|
---|
9 | * This package is distributed in the hope that it will be useful,
|
---|
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
12 | * GNU General Public License for more details.
|
---|
13 | */
|
---|
14 |
|
---|
15 | #include "CConfig.h"
|
---|
16 | #include "CServer.h"
|
---|
17 | #include "CKeyMap.h"
|
---|
18 | #include "KeyTypes.h"
|
---|
19 | #include "XSocket.h"
|
---|
20 | #include "stdistream.h"
|
---|
21 | #include "stdostream.h"
|
---|
22 | #include <stdlib.h>
|
---|
23 |
|
---|
24 | //
|
---|
25 | // CConfig
|
---|
26 | //
|
---|
27 |
|
---|
28 | CConfig::CConfig() : m_hasLockToScreenAction(false)
|
---|
29 | {
|
---|
30 | // do nothing
|
---|
31 | }
|
---|
32 |
|
---|
33 | CConfig::~CConfig()
|
---|
34 | {
|
---|
35 | // do nothing
|
---|
36 | }
|
---|
37 |
|
---|
38 | bool
|
---|
39 | CConfig::addScreen(const CString& name)
|
---|
40 | {
|
---|
41 | // alias name must not exist
|
---|
42 | if (m_nameToCanonicalName.find(name) != m_nameToCanonicalName.end()) {
|
---|
43 | return false;
|
---|
44 | }
|
---|
45 |
|
---|
46 | // add cell
|
---|
47 | m_map.insert(std::make_pair(name, CCell()));
|
---|
48 |
|
---|
49 | // add name
|
---|
50 | m_nameToCanonicalName.insert(std::make_pair(name, name));
|
---|
51 |
|
---|
52 | return true;
|
---|
53 | }
|
---|
54 |
|
---|
55 | bool
|
---|
56 | CConfig::renameScreen(const CString& oldName,
|
---|
57 | const CString& newName)
|
---|
58 | {
|
---|
59 | // get canonical name and find cell
|
---|
60 | CString oldCanonical = getCanonicalName(oldName);
|
---|
61 | CCellMap::iterator index = m_map.find(oldCanonical);
|
---|
62 | if (index == m_map.end()) {
|
---|
63 | return false;
|
---|
64 | }
|
---|
65 |
|
---|
66 | // accept if names are equal but replace with new name to maintain
|
---|
67 | // case. otherwise, the new name must not exist.
|
---|
68 | if (!CStringUtil::CaselessCmp::equal(oldName, newName) &&
|
---|
69 | m_nameToCanonicalName.find(newName) != m_nameToCanonicalName.end()) {
|
---|
70 | return false;
|
---|
71 | }
|
---|
72 |
|
---|
73 | // update cell
|
---|
74 | CCell tmpCell = index->second;
|
---|
75 | m_map.erase(index);
|
---|
76 | m_map.insert(std::make_pair(newName, tmpCell));
|
---|
77 |
|
---|
78 | // update name
|
---|
79 | m_nameToCanonicalName.erase(oldCanonical);
|
---|
80 | m_nameToCanonicalName.insert(std::make_pair(newName, newName));
|
---|
81 |
|
---|
82 | // update connections
|
---|
83 | CName oldNameObj(this, oldName);
|
---|
84 | for (index = m_map.begin(); index != m_map.end(); ++index) {
|
---|
85 | index->second.rename(oldNameObj, newName);
|
---|
86 | }
|
---|
87 |
|
---|
88 | // update alias targets
|
---|
89 | if (CStringUtil::CaselessCmp::equal(oldName, oldCanonical)) {
|
---|
90 | for (CNameMap::iterator index = m_nameToCanonicalName.begin();
|
---|
91 | index != m_nameToCanonicalName.end(); ++index) {
|
---|
92 | if (CStringUtil::CaselessCmp::equal(
|
---|
93 | index->second, oldCanonical)) {
|
---|
94 | index->second = newName;
|
---|
95 | }
|
---|
96 | }
|
---|
97 | }
|
---|
98 |
|
---|
99 | return true;
|
---|
100 | }
|
---|
101 |
|
---|
102 | void
|
---|
103 | CConfig::removeScreen(const CString& name)
|
---|
104 | {
|
---|
105 | // get canonical name and find cell
|
---|
106 | CString canonical = getCanonicalName(name);
|
---|
107 | CCellMap::iterator index = m_map.find(canonical);
|
---|
108 | if (index == m_map.end()) {
|
---|
109 | return;
|
---|
110 | }
|
---|
111 |
|
---|
112 | // remove from map
|
---|
113 | m_map.erase(index);
|
---|
114 |
|
---|
115 | // disconnect
|
---|
116 | CName nameObj(this, name);
|
---|
117 | for (index = m_map.begin(); index != m_map.end(); ++index) {
|
---|
118 | index->second.remove(nameObj);
|
---|
119 | }
|
---|
120 |
|
---|
121 | // remove aliases (and canonical name)
|
---|
122 | for (CNameMap::iterator index = m_nameToCanonicalName.begin();
|
---|
123 | index != m_nameToCanonicalName.end(); ) {
|
---|
124 | if (index->second == canonical) {
|
---|
125 | m_nameToCanonicalName.erase(index++);
|
---|
126 | }
|
---|
127 | else {
|
---|
128 | ++index;
|
---|
129 | }
|
---|
130 | }
|
---|
131 | }
|
---|
132 |
|
---|
133 | void
|
---|
134 | CConfig::removeAllScreens()
|
---|
135 | {
|
---|
136 | m_map.clear();
|
---|
137 | m_nameToCanonicalName.clear();
|
---|
138 | }
|
---|
139 |
|
---|
140 | bool
|
---|
141 | CConfig::addAlias(const CString& canonical, const CString& alias)
|
---|
142 | {
|
---|
143 | // alias name must not exist
|
---|
144 | if (m_nameToCanonicalName.find(alias) != m_nameToCanonicalName.end()) {
|
---|
145 | return false;
|
---|
146 | }
|
---|
147 |
|
---|
148 | // canonical name must be known
|
---|
149 | if (m_map.find(canonical) == m_map.end()) {
|
---|
150 | return false;
|
---|
151 | }
|
---|
152 |
|
---|
153 | // insert alias
|
---|
154 | m_nameToCanonicalName.insert(std::make_pair(alias, canonical));
|
---|
155 |
|
---|
156 | return true;
|
---|
157 | }
|
---|
158 |
|
---|
159 | bool
|
---|
160 | CConfig::removeAlias(const CString& alias)
|
---|
161 | {
|
---|
162 | // must not be a canonical name
|
---|
163 | if (m_map.find(alias) != m_map.end()) {
|
---|
164 | return false;
|
---|
165 | }
|
---|
166 |
|
---|
167 | // find alias
|
---|
168 | CNameMap::iterator index = m_nameToCanonicalName.find(alias);
|
---|
169 | if (index == m_nameToCanonicalName.end()) {
|
---|
170 | return false;
|
---|
171 | }
|
---|
172 |
|
---|
173 | // remove alias
|
---|
174 | m_nameToCanonicalName.erase(index);
|
---|
175 |
|
---|
176 | return true;
|
---|
177 | }
|
---|
178 |
|
---|
179 | bool
|
---|
180 | CConfig::removeAliases(const CString& canonical)
|
---|
181 | {
|
---|
182 | // must be a canonical name
|
---|
183 | if (m_map.find(canonical) == m_map.end()) {
|
---|
184 | return false;
|
---|
185 | }
|
---|
186 |
|
---|
187 | // find and removing matching aliases
|
---|
188 | for (CNameMap::iterator index = m_nameToCanonicalName.begin();
|
---|
189 | index != m_nameToCanonicalName.end(); ) {
|
---|
190 | if (index->second == canonical && index->first != canonical) {
|
---|
191 | m_nameToCanonicalName.erase(index++);
|
---|
192 | }
|
---|
193 | else {
|
---|
194 | ++index;
|
---|
195 | }
|
---|
196 | }
|
---|
197 |
|
---|
198 | return true;
|
---|
199 | }
|
---|
200 |
|
---|
201 | void
|
---|
202 | CConfig::removeAllAliases()
|
---|
203 | {
|
---|
204 | // remove all names
|
---|
205 | m_nameToCanonicalName.clear();
|
---|
206 |
|
---|
207 | // put the canonical names back in
|
---|
208 | for (CCellMap::iterator index = m_map.begin();
|
---|
209 | index != m_map.end(); ++index) {
|
---|
210 | m_nameToCanonicalName.insert(
|
---|
211 | std::make_pair(index->first, index->first));
|
---|
212 | }
|
---|
213 | }
|
---|
214 |
|
---|
215 | bool
|
---|
216 | CConfig::connect(const CString& srcName,
|
---|
217 | EDirection srcSide,
|
---|
218 | float srcStart, float srcEnd,
|
---|
219 | const CString& dstName,
|
---|
220 | float dstStart, float dstEnd)
|
---|
221 | {
|
---|
222 | assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
|
---|
223 |
|
---|
224 | // find source cell
|
---|
225 | CCellMap::iterator index = m_map.find(getCanonicalName(srcName));
|
---|
226 | if (index == m_map.end()) {
|
---|
227 | return false;
|
---|
228 | }
|
---|
229 |
|
---|
230 | // add link
|
---|
231 | CCellEdge srcEdge(srcSide, CInterval(srcStart, srcEnd));
|
---|
232 | CCellEdge dstEdge(dstName, srcSide, CInterval(dstStart, dstEnd));
|
---|
233 | return index->second.add(srcEdge, dstEdge);
|
---|
234 | }
|
---|
235 |
|
---|
236 | bool
|
---|
237 | CConfig::disconnect(const CString& srcName, EDirection srcSide)
|
---|
238 | {
|
---|
239 | assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
|
---|
240 |
|
---|
241 | // find source cell
|
---|
242 | CCellMap::iterator index = m_map.find(srcName);
|
---|
243 | if (index == m_map.end()) {
|
---|
244 | return false;
|
---|
245 | }
|
---|
246 |
|
---|
247 | // disconnect side
|
---|
248 | index->second.remove(srcSide);
|
---|
249 |
|
---|
250 | return true;
|
---|
251 | }
|
---|
252 |
|
---|
253 | bool
|
---|
254 | CConfig::disconnect(const CString& srcName, EDirection srcSide, float position)
|
---|
255 | {
|
---|
256 | assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
|
---|
257 |
|
---|
258 | // find source cell
|
---|
259 | CCellMap::iterator index = m_map.find(srcName);
|
---|
260 | if (index == m_map.end()) {
|
---|
261 | return false;
|
---|
262 | }
|
---|
263 |
|
---|
264 | // disconnect side
|
---|
265 | index->second.remove(srcSide, position);
|
---|
266 |
|
---|
267 | return true;
|
---|
268 | }
|
---|
269 |
|
---|
270 | void
|
---|
271 | CConfig::setSynergyAddress(const CNetworkAddress& addr)
|
---|
272 | {
|
---|
273 | m_synergyAddress = addr;
|
---|
274 | }
|
---|
275 |
|
---|
276 | bool
|
---|
277 | CConfig::addOption(const CString& name, OptionID option, OptionValue value)
|
---|
278 | {
|
---|
279 | // find options
|
---|
280 | CScreenOptions* options = NULL;
|
---|
281 | if (name.empty()) {
|
---|
282 | options = &m_globalOptions;
|
---|
283 | }
|
---|
284 | else {
|
---|
285 | CCellMap::iterator index = m_map.find(name);
|
---|
286 | if (index != m_map.end()) {
|
---|
287 | options = &index->second.m_options;
|
---|
288 | }
|
---|
289 | }
|
---|
290 | if (options == NULL) {
|
---|
291 | return false;
|
---|
292 | }
|
---|
293 |
|
---|
294 | // add option
|
---|
295 | options->insert(std::make_pair(option, value));
|
---|
296 | return true;
|
---|
297 | }
|
---|
298 |
|
---|
299 | bool
|
---|
300 | CConfig::removeOption(const CString& name, OptionID option)
|
---|
301 | {
|
---|
302 | // find options
|
---|
303 | CScreenOptions* options = NULL;
|
---|
304 | if (name.empty()) {
|
---|
305 | options = &m_globalOptions;
|
---|
306 | }
|
---|
307 | else {
|
---|
308 | CCellMap::iterator index = m_map.find(name);
|
---|
309 | if (index != m_map.end()) {
|
---|
310 | options = &index->second.m_options;
|
---|
311 | }
|
---|
312 | }
|
---|
313 | if (options == NULL) {
|
---|
314 | return false;
|
---|
315 | }
|
---|
316 |
|
---|
317 | // remove option
|
---|
318 | options->erase(option);
|
---|
319 | return true;
|
---|
320 | }
|
---|
321 |
|
---|
322 | bool
|
---|
323 | CConfig::removeOptions(const CString& name)
|
---|
324 | {
|
---|
325 | // find options
|
---|
326 | CScreenOptions* options = NULL;
|
---|
327 | if (name.empty()) {
|
---|
328 | options = &m_globalOptions;
|
---|
329 | }
|
---|
330 | else {
|
---|
331 | CCellMap::iterator index = m_map.find(name);
|
---|
332 | if (index != m_map.end()) {
|
---|
333 | options = &index->second.m_options;
|
---|
334 | }
|
---|
335 | }
|
---|
336 | if (options == NULL) {
|
---|
337 | return false;
|
---|
338 | }
|
---|
339 |
|
---|
340 | // remove options
|
---|
341 | options->clear();
|
---|
342 | return true;
|
---|
343 | }
|
---|
344 |
|
---|
345 | bool
|
---|
346 | CConfig::isValidScreenName(const CString& name) const
|
---|
347 | {
|
---|
348 | // name is valid if matches validname
|
---|
349 | // name ::= [_A-Za-z0-9] | [_A-Za-z0-9][-_A-Za-z0-9]*[_A-Za-z0-9]
|
---|
350 | // domain ::= . name
|
---|
351 | // validname ::= name domain*
|
---|
352 | // we also accept names ending in . because many OS X users have
|
---|
353 | // so misconfigured their systems.
|
---|
354 |
|
---|
355 | // empty name is invalid
|
---|
356 | if (name.empty()) {
|
---|
357 | return false;
|
---|
358 | }
|
---|
359 |
|
---|
360 | // check each dot separated part
|
---|
361 | CString::size_type b = 0;
|
---|
362 | for (;;) {
|
---|
363 | // accept trailing .
|
---|
364 | if (b == name.size()) {
|
---|
365 | break;
|
---|
366 | }
|
---|
367 |
|
---|
368 | // find end of part
|
---|
369 | CString::size_type e = name.find('.', b);
|
---|
370 | if (e == CString::npos) {
|
---|
371 | e = name.size();
|
---|
372 | }
|
---|
373 |
|
---|
374 | // part may not be empty
|
---|
375 | if (e - b < 1) {
|
---|
376 | return false;
|
---|
377 | }
|
---|
378 |
|
---|
379 | // check first and last characters
|
---|
380 | if (!(isalnum(name[b]) || name[b] == '_') ||
|
---|
381 | !(isalnum(name[e - 1]) || name[e - 1] == '_')) {
|
---|
382 | return false;
|
---|
383 | }
|
---|
384 |
|
---|
385 | // check interior characters
|
---|
386 | for (CString::size_type i = b; i < e; ++i) {
|
---|
387 | if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') {
|
---|
388 | return false;
|
---|
389 | }
|
---|
390 | }
|
---|
391 |
|
---|
392 | // next part
|
---|
393 | if (e == name.size()) {
|
---|
394 | // no more parts
|
---|
395 | break;
|
---|
396 | }
|
---|
397 | b = e + 1;
|
---|
398 | }
|
---|
399 |
|
---|
400 | return true;
|
---|
401 | }
|
---|
402 |
|
---|
403 | CConfig::const_iterator
|
---|
404 | CConfig::begin() const
|
---|
405 | {
|
---|
406 | return const_iterator(m_map.begin());
|
---|
407 | }
|
---|
408 |
|
---|
409 | CConfig::const_iterator
|
---|
410 | CConfig::end() const
|
---|
411 | {
|
---|
412 | return const_iterator(m_map.end());
|
---|
413 | }
|
---|
414 |
|
---|
415 | CConfig::all_const_iterator
|
---|
416 | CConfig::beginAll() const
|
---|
417 | {
|
---|
418 | return m_nameToCanonicalName.begin();
|
---|
419 | }
|
---|
420 |
|
---|
421 | CConfig::all_const_iterator
|
---|
422 | CConfig::endAll() const
|
---|
423 | {
|
---|
424 | return m_nameToCanonicalName.end();
|
---|
425 | }
|
---|
426 |
|
---|
427 | bool
|
---|
428 | CConfig::isScreen(const CString& name) const
|
---|
429 | {
|
---|
430 | return (m_nameToCanonicalName.count(name) > 0);
|
---|
431 | }
|
---|
432 |
|
---|
433 | bool
|
---|
434 | CConfig::isCanonicalName(const CString& name) const
|
---|
435 | {
|
---|
436 | return (!name.empty() &&
|
---|
437 | CStringUtil::CaselessCmp::equal(getCanonicalName(name), name));
|
---|
438 | }
|
---|
439 |
|
---|
440 | CString
|
---|
441 | CConfig::getCanonicalName(const CString& name) const
|
---|
442 | {
|
---|
443 | CNameMap::const_iterator index = m_nameToCanonicalName.find(name);
|
---|
444 | if (index == m_nameToCanonicalName.end()) {
|
---|
445 | return CString();
|
---|
446 | }
|
---|
447 | else {
|
---|
448 | return index->second;
|
---|
449 | }
|
---|
450 | }
|
---|
451 |
|
---|
452 | CString
|
---|
453 | CConfig::getNeighbor(const CString& srcName, EDirection srcSide,
|
---|
454 | float position, float* positionOut) const
|
---|
455 | {
|
---|
456 | assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
|
---|
457 |
|
---|
458 | // find source cell
|
---|
459 | CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
|
---|
460 | if (index == m_map.end()) {
|
---|
461 | return CString();
|
---|
462 | }
|
---|
463 |
|
---|
464 | // find edge
|
---|
465 | const CCellEdge* srcEdge, *dstEdge;
|
---|
466 | if (!index->second.getLink(srcSide, position, srcEdge, dstEdge)) {
|
---|
467 | // no neighbor
|
---|
468 | return "";
|
---|
469 | }
|
---|
470 | else {
|
---|
471 | // compute position on neighbor
|
---|
472 | if (positionOut != NULL) {
|
---|
473 | *positionOut =
|
---|
474 | dstEdge->inverseTransform(srcEdge->transform(position));
|
---|
475 | }
|
---|
476 |
|
---|
477 | // return neighbor's name
|
---|
478 | return getCanonicalName(dstEdge->getName());
|
---|
479 | }
|
---|
480 | }
|
---|
481 |
|
---|
482 | bool
|
---|
483 | CConfig::hasNeighbor(const CString& srcName, EDirection srcSide) const
|
---|
484 | {
|
---|
485 | return hasNeighbor(srcName, srcSide, 0.0f, 1.0f);
|
---|
486 | }
|
---|
487 |
|
---|
488 | bool
|
---|
489 | CConfig::hasNeighbor(const CString& srcName, EDirection srcSide,
|
---|
490 | float start, float end) const
|
---|
491 | {
|
---|
492 | assert(srcSide >= kFirstDirection && srcSide <= kLastDirection);
|
---|
493 |
|
---|
494 | // find source cell
|
---|
495 | CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
|
---|
496 | if (index == m_map.end()) {
|
---|
497 | return false;
|
---|
498 | }
|
---|
499 |
|
---|
500 | return index->second.overlaps(CCellEdge(srcSide, CInterval(start, end)));
|
---|
501 | }
|
---|
502 |
|
---|
503 | CConfig::link_const_iterator
|
---|
504 | CConfig::beginNeighbor(const CString& srcName) const
|
---|
505 | {
|
---|
506 | CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
|
---|
507 | assert(index != m_map.end());
|
---|
508 | return index->second.begin();
|
---|
509 | }
|
---|
510 |
|
---|
511 | CConfig::link_const_iterator
|
---|
512 | CConfig::endNeighbor(const CString& srcName) const
|
---|
513 | {
|
---|
514 | CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
|
---|
515 | assert(index != m_map.end());
|
---|
516 | return index->second.end();
|
---|
517 | }
|
---|
518 |
|
---|
519 | const CNetworkAddress&
|
---|
520 | CConfig::getSynergyAddress() const
|
---|
521 | {
|
---|
522 | return m_synergyAddress;
|
---|
523 | }
|
---|
524 |
|
---|
525 | const CConfig::CScreenOptions*
|
---|
526 | CConfig::getOptions(const CString& name) const
|
---|
527 | {
|
---|
528 | // find options
|
---|
529 | const CScreenOptions* options = NULL;
|
---|
530 | if (name.empty()) {
|
---|
531 | options = &m_globalOptions;
|
---|
532 | }
|
---|
533 | else {
|
---|
534 | CCellMap::const_iterator index = m_map.find(name);
|
---|
535 | if (index != m_map.end()) {
|
---|
536 | options = &index->second.m_options;
|
---|
537 | }
|
---|
538 | }
|
---|
539 |
|
---|
540 | // return options
|
---|
541 | return options;
|
---|
542 | }
|
---|
543 |
|
---|
544 | bool
|
---|
545 | CConfig::hasLockToScreenAction() const
|
---|
546 | {
|
---|
547 | return m_hasLockToScreenAction;
|
---|
548 | }
|
---|
549 |
|
---|
550 | bool
|
---|
551 | CConfig::operator==(const CConfig& x) const
|
---|
552 | {
|
---|
553 | if (m_synergyAddress != x.m_synergyAddress) {
|
---|
554 | return false;
|
---|
555 | }
|
---|
556 | if (m_map.size() != x.m_map.size()) {
|
---|
557 | return false;
|
---|
558 | }
|
---|
559 | if (m_nameToCanonicalName.size() != x.m_nameToCanonicalName.size()) {
|
---|
560 | return false;
|
---|
561 | }
|
---|
562 |
|
---|
563 | // compare global options
|
---|
564 | if (m_globalOptions != x.m_globalOptions) {
|
---|
565 | return false;
|
---|
566 | }
|
---|
567 |
|
---|
568 | for (CCellMap::const_iterator index1 = m_map.begin(),
|
---|
569 | index2 = x.m_map.begin();
|
---|
570 | index1 != m_map.end(); ++index1, ++index2) {
|
---|
571 | // compare names
|
---|
572 | if (!CStringUtil::CaselessCmp::equal(index1->first, index2->first)) {
|
---|
573 | return false;
|
---|
574 | }
|
---|
575 |
|
---|
576 | // compare cells
|
---|
577 | if (index1->second != index2->second) {
|
---|
578 | return false;
|
---|
579 | }
|
---|
580 | }
|
---|
581 |
|
---|
582 | for (CNameMap::const_iterator index1 = m_nameToCanonicalName.begin(),
|
---|
583 | index2 = x.m_nameToCanonicalName.begin();
|
---|
584 | index1 != m_nameToCanonicalName.end();
|
---|
585 | ++index1, ++index2) {
|
---|
586 | if (!CStringUtil::CaselessCmp::equal(index1->first, index2->first) ||
|
---|
587 | !CStringUtil::CaselessCmp::equal(index1->second, index2->second)) {
|
---|
588 | return false;
|
---|
589 | }
|
---|
590 | }
|
---|
591 |
|
---|
592 | // compare input filters
|
---|
593 | if (m_inputFilter != x.m_inputFilter) {
|
---|
594 | return false;
|
---|
595 | }
|
---|
596 |
|
---|
597 | return true;
|
---|
598 | }
|
---|
599 |
|
---|
600 | bool
|
---|
601 | CConfig::operator!=(const CConfig& x) const
|
---|
602 | {
|
---|
603 | return !operator==(x);
|
---|
604 | }
|
---|
605 |
|
---|
606 | void
|
---|
607 | CConfig::read(CConfigReadContext& context)
|
---|
608 | {
|
---|
609 | CConfig tmp;
|
---|
610 | while (context) {
|
---|
611 | tmp.readSection(context);
|
---|
612 | }
|
---|
613 | *this = tmp;
|
---|
614 | }
|
---|
615 |
|
---|
616 | const char*
|
---|
617 | CConfig::dirName(EDirection dir)
|
---|
618 | {
|
---|
619 | static const char* s_name[] = { "left", "right", "up", "down" };
|
---|
620 |
|
---|
621 | assert(dir >= kFirstDirection && dir <= kLastDirection);
|
---|
622 |
|
---|
623 | return s_name[dir - kFirstDirection];
|
---|
624 | }
|
---|
625 |
|
---|
626 | CInputFilter*
|
---|
627 | CConfig::getInputFilter()
|
---|
628 | {
|
---|
629 | return &m_inputFilter;
|
---|
630 | }
|
---|
631 |
|
---|
632 | CString
|
---|
633 | CConfig::formatInterval(const CInterval& x)
|
---|
634 | {
|
---|
635 | if (x.first == 0.0f && x.second == 1.0f) {
|
---|
636 | return "";
|
---|
637 | }
|
---|
638 | return CStringUtil::print("(%d,%d)", (int)(x.first * 100.0f + 0.5f),
|
---|
639 | (int)(x.second * 100.0f + 0.5f));
|
---|
640 | }
|
---|
641 |
|
---|
642 | void
|
---|
643 | CConfig::readSection(CConfigReadContext& s)
|
---|
644 | {
|
---|
645 | static const char s_section[] = "section:";
|
---|
646 | static const char s_options[] = "options";
|
---|
647 | static const char s_screens[] = "screens";
|
---|
648 | static const char s_links[] = "links";
|
---|
649 | static const char s_aliases[] = "aliases";
|
---|
650 |
|
---|
651 | CString line;
|
---|
652 | if (!s.readLine(line)) {
|
---|
653 | // no more sections
|
---|
654 | return;
|
---|
655 | }
|
---|
656 |
|
---|
657 | // should be a section header
|
---|
658 | if (line.find(s_section) != 0) {
|
---|
659 | throw XConfigRead(s, "found data outside section");
|
---|
660 | }
|
---|
661 |
|
---|
662 | // get section name
|
---|
663 | CString::size_type i = line.find_first_not_of(" \t", sizeof(s_section) - 1);
|
---|
664 | if (i == CString::npos) {
|
---|
665 | throw XConfigRead(s, "section name is missing");
|
---|
666 | }
|
---|
667 | CString name = line.substr(i);
|
---|
668 | i = name.find_first_of(" \t");
|
---|
669 | if (i != CString::npos) {
|
---|
670 | throw XConfigRead(s, "unexpected data after section name");
|
---|
671 | }
|
---|
672 |
|
---|
673 | // read section
|
---|
674 | if (name == s_options) {
|
---|
675 | readSectionOptions(s);
|
---|
676 | }
|
---|
677 | else if (name == s_screens) {
|
---|
678 | readSectionScreens(s);
|
---|
679 | }
|
---|
680 | else if (name == s_links) {
|
---|
681 | readSectionLinks(s);
|
---|
682 | }
|
---|
683 | else if (name == s_aliases) {
|
---|
684 | readSectionAliases(s);
|
---|
685 | }
|
---|
686 | else {
|
---|
687 | throw XConfigRead(s, "unknown section name \"%{1}\"", name);
|
---|
688 | }
|
---|
689 | }
|
---|
690 |
|
---|
691 | void
|
---|
692 | CConfig::readSectionOptions(CConfigReadContext& s)
|
---|
693 | {
|
---|
694 | CString line;
|
---|
695 | while (s.readLine(line)) {
|
---|
696 | // check for end of section
|
---|
697 | if (line == "end") {
|
---|
698 | return;
|
---|
699 | }
|
---|
700 |
|
---|
701 | // parse argument: `nameAndArgs = [values][;[values]]'
|
---|
702 | // nameAndArgs := <name>[(arg[,...])]
|
---|
703 | // values := valueAndArgs[,valueAndArgs]...
|
---|
704 | // valueAndArgs := <value>[(arg[,...])]
|
---|
705 | CString::size_type i = 0;
|
---|
706 | CString name, value;
|
---|
707 | CConfigReadContext::ArgList nameArgs, valueArgs;
|
---|
708 | s.parseNameWithArgs("name", line, "=", i, name, nameArgs);
|
---|
709 | ++i;
|
---|
710 | s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs);
|
---|
711 |
|
---|
712 | bool handled = true;
|
---|
713 | if (name == "address") {
|
---|
714 | try {
|
---|
715 | m_synergyAddress = CNetworkAddress(value, kDefaultPort);
|
---|
716 | m_synergyAddress.resolve();
|
---|
717 | }
|
---|
718 | catch (XSocketAddress& e) {
|
---|
719 | throw XConfigRead(s,
|
---|
720 | CString("invalid address argument ") + e.what());
|
---|
721 | }
|
---|
722 | }
|
---|
723 | else if (name == "heartbeat") {
|
---|
724 | addOption("", kOptionHeartbeat, s.parseInt(value));
|
---|
725 | }
|
---|
726 | else if (name == "switchCorners") {
|
---|
727 | addOption("", kOptionScreenSwitchCorners, s.parseCorners(value));
|
---|
728 | }
|
---|
729 | else if (name == "switchCornerSize") {
|
---|
730 | addOption("", kOptionScreenSwitchCornerSize, s.parseInt(value));
|
---|
731 | }
|
---|
732 | else if (name == "switchDelay") {
|
---|
733 | addOption("", kOptionScreenSwitchDelay, s.parseInt(value));
|
---|
734 | }
|
---|
735 | else if (name == "switchDoubleTap") {
|
---|
736 | addOption("", kOptionScreenSwitchTwoTap, s.parseInt(value));
|
---|
737 | }
|
---|
738 | else if (name == "screenSaverSync") {
|
---|
739 | addOption("", kOptionScreenSaverSync, s.parseBoolean(value));
|
---|
740 | }
|
---|
741 | else if (name == "relativeMouseMoves") {
|
---|
742 | addOption("", kOptionRelativeMouseMoves, s.parseBoolean(value));
|
---|
743 | }
|
---|
744 | else if (name == "win32KeepForeground") {
|
---|
745 | addOption("", kOptionWin32KeepForeground, s.parseBoolean(value));
|
---|
746 | }
|
---|
747 | else {
|
---|
748 | handled = false;
|
---|
749 | }
|
---|
750 |
|
---|
751 | if (handled) {
|
---|
752 | // make sure handled options aren't followed by more values
|
---|
753 | if (i < line.size() && (line[i] == ',' || line[i] == ';')) {
|
---|
754 | throw XConfigRead(s, "to many arguments to %s", name.c_str());
|
---|
755 | }
|
---|
756 | }
|
---|
757 | else {
|
---|
758 | // make filter rule
|
---|
759 | CInputFilter::CRule rule(parseCondition(s, name, nameArgs));
|
---|
760 |
|
---|
761 | // save first action (if any)
|
---|
762 | if (!value.empty() || line[i] != ';') {
|
---|
763 | parseAction(s, value, valueArgs, rule, true);
|
---|
764 | }
|
---|
765 |
|
---|
766 | // get remaining activate actions
|
---|
767 | while (i < line.length() && line[i] != ';') {
|
---|
768 | ++i;
|
---|
769 | s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs);
|
---|
770 | parseAction(s, value, valueArgs, rule, true);
|
---|
771 | }
|
---|
772 |
|
---|
773 | // get deactivate actions
|
---|
774 | if (i < line.length() && line[i] == ';') {
|
---|
775 | // allow trailing ';'
|
---|
776 | i = line.find_first_not_of(" \t", i + 1);
|
---|
777 | if (i == CString::npos) {
|
---|
778 | i = line.length();
|
---|
779 | }
|
---|
780 | else {
|
---|
781 | --i;
|
---|
782 | }
|
---|
783 |
|
---|
784 | // get actions
|
---|
785 | while (i < line.length()) {
|
---|
786 | ++i;
|
---|
787 | s.parseNameWithArgs("value", line, ",\n",
|
---|
788 | i, value, valueArgs);
|
---|
789 | parseAction(s, value, valueArgs, rule, false);
|
---|
790 | }
|
---|
791 | }
|
---|
792 |
|
---|
793 | // add rule
|
---|
794 | m_inputFilter.addFilterRule(rule);
|
---|
795 | }
|
---|
796 | }
|
---|
797 | throw XConfigRead(s, "unexpected end of options section");
|
---|
798 | }
|
---|
799 |
|
---|
800 | void
|
---|
801 | CConfig::readSectionScreens(CConfigReadContext& s)
|
---|
802 | {
|
---|
803 | CString line;
|
---|
804 | CString screen;
|
---|
805 | while (s.readLine(line)) {
|
---|
806 | // check for end of section
|
---|
807 | if (line == "end") {
|
---|
808 | return;
|
---|
809 | }
|
---|
810 |
|
---|
811 | // see if it's the next screen
|
---|
812 | if (line[line.size() - 1] == ':') {
|
---|
813 | // strip :
|
---|
814 | screen = line.substr(0, line.size() - 1);
|
---|
815 |
|
---|
816 | // verify validity of screen name
|
---|
817 | if (!isValidScreenName(screen)) {
|
---|
818 | throw XConfigRead(s, "invalid screen name \"%{1}\"", screen);
|
---|
819 | }
|
---|
820 |
|
---|
821 | // add the screen to the configuration
|
---|
822 | if (!addScreen(screen)) {
|
---|
823 | throw XConfigRead(s, "duplicate screen name \"%{1}\"", screen);
|
---|
824 | }
|
---|
825 | }
|
---|
826 | else if (screen.empty()) {
|
---|
827 | throw XConfigRead(s, "argument before first screen");
|
---|
828 | }
|
---|
829 | else {
|
---|
830 | // parse argument: `<name>=<value>'
|
---|
831 | CString::size_type i = line.find_first_of(" \t=");
|
---|
832 | if (i == 0) {
|
---|
833 | throw XConfigRead(s, "missing argument name");
|
---|
834 | }
|
---|
835 | if (i == CString::npos) {
|
---|
836 | throw XConfigRead(s, "missing =");
|
---|
837 | }
|
---|
838 | CString name = line.substr(0, i);
|
---|
839 | i = line.find_first_not_of(" \t", i);
|
---|
840 | if (i == CString::npos || line[i] != '=') {
|
---|
841 | throw XConfigRead(s, "missing =");
|
---|
842 | }
|
---|
843 | i = line.find_first_not_of(" \t", i + 1);
|
---|
844 | CString value;
|
---|
845 | if (i != CString::npos) {
|
---|
846 | value = line.substr(i);
|
---|
847 | }
|
---|
848 |
|
---|
849 | // handle argument
|
---|
850 | if (name == "halfDuplexCapsLock") {
|
---|
851 | addOption(screen, kOptionHalfDuplexCapsLock,
|
---|
852 | s.parseBoolean(value));
|
---|
853 | }
|
---|
854 | else if (name == "halfDuplexNumLock") {
|
---|
855 | addOption(screen, kOptionHalfDuplexNumLock,
|
---|
856 | s.parseBoolean(value));
|
---|
857 | }
|
---|
858 | else if (name == "halfDuplexScrollLock") {
|
---|
859 | addOption(screen, kOptionHalfDuplexScrollLock,
|
---|
860 | s.parseBoolean(value));
|
---|
861 | }
|
---|
862 | else if (name == "shift") {
|
---|
863 | addOption(screen, kOptionModifierMapForShift,
|
---|
864 | s.parseModifierKey(value));
|
---|
865 | }
|
---|
866 | else if (name == "ctrl") {
|
---|
867 | addOption(screen, kOptionModifierMapForControl,
|
---|
868 | s.parseModifierKey(value));
|
---|
869 | }
|
---|
870 | else if (name == "alt") {
|
---|
871 | addOption(screen, kOptionModifierMapForAlt,
|
---|
872 | s.parseModifierKey(value));
|
---|
873 | }
|
---|
874 | else if (name == "meta") {
|
---|
875 | addOption(screen, kOptionModifierMapForMeta,
|
---|
876 | s.parseModifierKey(value));
|
---|
877 | }
|
---|
878 | else if (name == "super") {
|
---|
879 | addOption(screen, kOptionModifierMapForSuper,
|
---|
880 | s.parseModifierKey(value));
|
---|
881 | }
|
---|
882 | else if (name == "xtestIsXineramaUnaware") {
|
---|
883 | addOption(screen, kOptionXTestXineramaUnaware,
|
---|
884 | s.parseBoolean(value));
|
---|
885 | }
|
---|
886 | else if (name == "switchCorners") {
|
---|
887 | addOption(screen, kOptionScreenSwitchCorners,
|
---|
888 | s.parseCorners(value));
|
---|
889 | }
|
---|
890 | else if (name == "switchCornerSize") {
|
---|
891 | addOption(screen, kOptionScreenSwitchCornerSize,
|
---|
892 | s.parseInt(value));
|
---|
893 | }
|
---|
894 | else {
|
---|
895 | // unknown argument
|
---|
896 | throw XConfigRead(s, "unknown argument \"%{1}\"", name);
|
---|
897 | }
|
---|
898 | }
|
---|
899 | }
|
---|
900 | throw XConfigRead(s, "unexpected end of screens section");
|
---|
901 | }
|
---|
902 |
|
---|
903 | void
|
---|
904 | CConfig::readSectionLinks(CConfigReadContext& s)
|
---|
905 | {
|
---|
906 | CString line;
|
---|
907 | CString screen;
|
---|
908 | while (s.readLine(line)) {
|
---|
909 | // check for end of section
|
---|
910 | if (line == "end") {
|
---|
911 | return;
|
---|
912 | }
|
---|
913 |
|
---|
914 | // see if it's the next screen
|
---|
915 | if (line[line.size() - 1] == ':') {
|
---|
916 | // strip :
|
---|
917 | screen = line.substr(0, line.size() - 1);
|
---|
918 |
|
---|
919 | // verify we know about the screen
|
---|
920 | if (!isScreen(screen)) {
|
---|
921 | throw XConfigRead(s, "unknown screen name \"%{1}\"", screen);
|
---|
922 | }
|
---|
923 | if (!isCanonicalName(screen)) {
|
---|
924 | throw XConfigRead(s, "cannot use screen name alias here");
|
---|
925 | }
|
---|
926 | }
|
---|
927 | else if (screen.empty()) {
|
---|
928 | throw XConfigRead(s, "argument before first screen");
|
---|
929 | }
|
---|
930 | else {
|
---|
931 | // parse argument: `<name>[(<s0>,<e0>)]=<value>[(<s1>,<e1>)]'
|
---|
932 | // the stuff in brackets is optional. interval values must be
|
---|
933 | // in the range [0,100] and start < end. if not given the
|
---|
934 | // interval is taken to be (0,100).
|
---|
935 | CString::size_type i = 0;
|
---|
936 | CString side, dstScreen, srcArgString, dstArgString;
|
---|
937 | CConfigReadContext::ArgList srcArgs, dstArgs;
|
---|
938 | s.parseNameWithArgs("link", line, "=", i, side, srcArgs);
|
---|
939 | ++i;
|
---|
940 | s.parseNameWithArgs("screen", line, "", i, dstScreen, dstArgs);
|
---|
941 | CInterval srcInterval(s.parseInterval(srcArgs));
|
---|
942 | CInterval dstInterval(s.parseInterval(dstArgs));
|
---|
943 |
|
---|
944 | // handle argument
|
---|
945 | EDirection dir;
|
---|
946 | if (side == "left") {
|
---|
947 | dir = kLeft;
|
---|
948 | }
|
---|
949 | else if (side == "right") {
|
---|
950 | dir = kRight;
|
---|
951 | }
|
---|
952 | else if (side == "up") {
|
---|
953 | dir = kTop;
|
---|
954 | }
|
---|
955 | else if (side == "down") {
|
---|
956 | dir = kBottom;
|
---|
957 | }
|
---|
958 | else {
|
---|
959 | // unknown argument
|
---|
960 | throw XConfigRead(s, "unknown side \"%{1}\" in link", side);
|
---|
961 | }
|
---|
962 | if (!isScreen(dstScreen)) {
|
---|
963 | throw XConfigRead(s, "unknown screen name \"%{1}\"", dstScreen);
|
---|
964 | }
|
---|
965 | if (!connect(screen, dir,
|
---|
966 | srcInterval.first, srcInterval.second,
|
---|
967 | dstScreen,
|
---|
968 | dstInterval.first, dstInterval.second)) {
|
---|
969 | throw XConfigRead(s, "overlapping range");
|
---|
970 | }
|
---|
971 | }
|
---|
972 | }
|
---|
973 | throw XConfigRead(s, "unexpected end of links section");
|
---|
974 | }
|
---|
975 |
|
---|
976 | void
|
---|
977 | CConfig::readSectionAliases(CConfigReadContext& s)
|
---|
978 | {
|
---|
979 | CString line;
|
---|
980 | CString screen;
|
---|
981 | while (s.readLine(line)) {
|
---|
982 | // check for end of section
|
---|
983 | if (line == "end") {
|
---|
984 | return;
|
---|
985 | }
|
---|
986 |
|
---|
987 | // see if it's the next screen
|
---|
988 | if (line[line.size() - 1] == ':') {
|
---|
989 | // strip :
|
---|
990 | screen = line.substr(0, line.size() - 1);
|
---|
991 |
|
---|
992 | // verify we know about the screen
|
---|
993 | if (!isScreen(screen)) {
|
---|
994 | throw XConfigRead(s, "unknown screen name \"%{1}\"", screen);
|
---|
995 | }
|
---|
996 | if (!isCanonicalName(screen)) {
|
---|
997 | throw XConfigRead(s, "cannot use screen name alias here");
|
---|
998 | }
|
---|
999 | }
|
---|
1000 | else if (screen.empty()) {
|
---|
1001 | throw XConfigRead(s, "argument before first screen");
|
---|
1002 | }
|
---|
1003 | else {
|
---|
1004 | // verify validity of screen name
|
---|
1005 | if (!isValidScreenName(line)) {
|
---|
1006 | throw XConfigRead(s, "invalid screen alias \"%{1}\"", line);
|
---|
1007 | }
|
---|
1008 |
|
---|
1009 | // add alias
|
---|
1010 | if (!addAlias(screen, line)) {
|
---|
1011 | throw XConfigRead(s, "alias \"%{1}\" is already used", line);
|
---|
1012 | }
|
---|
1013 | }
|
---|
1014 | }
|
---|
1015 | throw XConfigRead(s, "unexpected end of aliases section");
|
---|
1016 | }
|
---|
1017 |
|
---|
1018 |
|
---|
1019 | CInputFilter::CCondition*
|
---|
1020 | CConfig::parseCondition(CConfigReadContext& s,
|
---|
1021 | const CString& name, const std::vector<CString>& args)
|
---|
1022 | {
|
---|
1023 | if (name == "keystroke") {
|
---|
1024 | if (args.size() != 1) {
|
---|
1025 | throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key)");
|
---|
1026 | }
|
---|
1027 |
|
---|
1028 | IPlatformScreen::CKeyInfo* keyInfo = s.parseKeystroke(args[0]);
|
---|
1029 |
|
---|
1030 | return new CInputFilter::CKeystrokeCondition(keyInfo);
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 | if (name == "mousebutton") {
|
---|
1034 | if (args.size() != 1) {
|
---|
1035 | throw XConfigRead(s, "syntax for condition: mousebutton(modifiers+button)");
|
---|
1036 | }
|
---|
1037 |
|
---|
1038 | IPlatformScreen::CButtonInfo* mouseInfo = s.parseMouse(args[0]);
|
---|
1039 |
|
---|
1040 | return new CInputFilter::CMouseButtonCondition(mouseInfo);
|
---|
1041 | }
|
---|
1042 |
|
---|
1043 | if (name == "connect") {
|
---|
1044 | if (args.size() != 1) {
|
---|
1045 | throw XConfigRead(s, "syntax for condition: connect([screen])");
|
---|
1046 | }
|
---|
1047 |
|
---|
1048 | CString screen = args[0];
|
---|
1049 | if (isScreen(screen)) {
|
---|
1050 | screen = getCanonicalName(screen);
|
---|
1051 | }
|
---|
1052 | else if (!screen.empty()) {
|
---|
1053 | throw XConfigRead(s, "unknown screen name \"%{1}\" in connect", screen);
|
---|
1054 | }
|
---|
1055 |
|
---|
1056 | return new CInputFilter::CScreenConnectedCondition(screen);
|
---|
1057 | }
|
---|
1058 |
|
---|
1059 | throw XConfigRead(s, "unknown argument \"%{1}\"", name);
|
---|
1060 | }
|
---|
1061 |
|
---|
1062 | void
|
---|
1063 | CConfig::parseAction(CConfigReadContext& s,
|
---|
1064 | const CString& name, const std::vector<CString>& args,
|
---|
1065 | CInputFilter::CRule& rule, bool activate)
|
---|
1066 | {
|
---|
1067 | CInputFilter::CAction* action;
|
---|
1068 |
|
---|
1069 | if (name == "keystroke" || name == "keyDown" || name == "keyUp") {
|
---|
1070 | if (args.size() < 1 || args.size() > 2) {
|
---|
1071 | throw XConfigRead(s, "syntax for action: keystroke(modifiers+key[,screens])");
|
---|
1072 | }
|
---|
1073 |
|
---|
1074 | IPlatformScreen::CKeyInfo* keyInfo;
|
---|
1075 | if (args.size() == 1) {
|
---|
1076 | keyInfo = s.parseKeystroke(args[0]);
|
---|
1077 | }
|
---|
1078 | else {
|
---|
1079 | std::set<CString> screens;
|
---|
1080 | parseScreens(s, args[1], screens);
|
---|
1081 | keyInfo = s.parseKeystroke(args[0], screens);
|
---|
1082 | }
|
---|
1083 |
|
---|
1084 | if (name == "keystroke") {
|
---|
1085 | IPlatformScreen::CKeyInfo* keyInfo2 =
|
---|
1086 | IKeyState::CKeyInfo::alloc(*keyInfo);
|
---|
1087 | action = new CInputFilter::CKeystrokeAction(keyInfo2, true);
|
---|
1088 | rule.adoptAction(action, true);
|
---|
1089 | action = new CInputFilter::CKeystrokeAction(keyInfo, false);
|
---|
1090 | activate = false;
|
---|
1091 | }
|
---|
1092 | else if (name == "keyDown") {
|
---|
1093 | action = new CInputFilter::CKeystrokeAction(keyInfo, true);
|
---|
1094 | }
|
---|
1095 | else {
|
---|
1096 | action = new CInputFilter::CKeystrokeAction(keyInfo, false);
|
---|
1097 | }
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 | else if (name == "mousebutton" ||
|
---|
1101 | name == "mouseDown" || name == "mouseUp") {
|
---|
1102 | if (args.size() != 1) {
|
---|
1103 | throw XConfigRead(s, "syntax for action: mousebutton(modifiers+button)");
|
---|
1104 | }
|
---|
1105 |
|
---|
1106 | IPlatformScreen::CButtonInfo* mouseInfo = s.parseMouse(args[0]);
|
---|
1107 |
|
---|
1108 | if (name == "mousebutton") {
|
---|
1109 | IPlatformScreen::CButtonInfo* mouseInfo2 =
|
---|
1110 | IPlatformScreen::CButtonInfo::alloc(*mouseInfo);
|
---|
1111 | action = new CInputFilter::CMouseButtonAction(mouseInfo2, true);
|
---|
1112 | rule.adoptAction(action, true);
|
---|
1113 | action = new CInputFilter::CMouseButtonAction(mouseInfo, false);
|
---|
1114 | activate = false;
|
---|
1115 | }
|
---|
1116 | else if (name == "mouseDown") {
|
---|
1117 | action = new CInputFilter::CMouseButtonAction(mouseInfo, true);
|
---|
1118 | }
|
---|
1119 | else {
|
---|
1120 | action = new CInputFilter::CMouseButtonAction(mouseInfo, false);
|
---|
1121 | }
|
---|
1122 | }
|
---|
1123 |
|
---|
1124 | /* XXX -- not supported
|
---|
1125 | else if (name == "modifier") {
|
---|
1126 | if (args.size() != 1) {
|
---|
1127 | throw XConfigRead(s, "syntax for action: modifier(modifiers)");
|
---|
1128 | }
|
---|
1129 |
|
---|
1130 | KeyModifierMask mask = s.parseModifier(args[0]);
|
---|
1131 |
|
---|
1132 | action = new CInputFilter::CModifierAction(mask, ~mask);
|
---|
1133 | }
|
---|
1134 | */
|
---|
1135 |
|
---|
1136 | else if (name == "switchToScreen") {
|
---|
1137 | if (args.size() != 1) {
|
---|
1138 | throw XConfigRead(s, "syntax for action: switchToScreen(name)");
|
---|
1139 | }
|
---|
1140 |
|
---|
1141 | CString screen = args[0];
|
---|
1142 | if (isScreen(screen)) {
|
---|
1143 | screen = getCanonicalName(screen);
|
---|
1144 | }
|
---|
1145 | else if (!screen.empty()) {
|
---|
1146 | throw XConfigRead(s, "unknown screen name in switchToScreen");
|
---|
1147 | }
|
---|
1148 |
|
---|
1149 | action = new CInputFilter::CSwitchToScreenAction(screen);
|
---|
1150 | }
|
---|
1151 |
|
---|
1152 | else if (name == "switchInDirection") {
|
---|
1153 | if (args.size() != 1) {
|
---|
1154 | throw XConfigRead(s, "syntax for action: switchInDirection(<left|right|up|down>)");
|
---|
1155 | }
|
---|
1156 |
|
---|
1157 | EDirection direction;
|
---|
1158 | if (args[0] == "left") {
|
---|
1159 | direction = kLeft;
|
---|
1160 | }
|
---|
1161 | else if (args[0] == "right") {
|
---|
1162 | direction = kRight;
|
---|
1163 | }
|
---|
1164 | else if (args[0] == "up") {
|
---|
1165 | direction = kTop;
|
---|
1166 | }
|
---|
1167 | else if (args[0] == "down") {
|
---|
1168 | direction = kBottom;
|
---|
1169 | }
|
---|
1170 | else {
|
---|
1171 | throw XConfigRead(s, "unknown direction \"%{1}\" in switchToScreen", args[0]);
|
---|
1172 | }
|
---|
1173 |
|
---|
1174 | action = new CInputFilter::CSwitchInDirectionAction(direction);
|
---|
1175 | }
|
---|
1176 |
|
---|
1177 | else if (name == "lockCursorToScreen") {
|
---|
1178 | if (args.size() > 1) {
|
---|
1179 | throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])");
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | CInputFilter::CLockCursorToScreenAction::Mode mode =
|
---|
1183 | CInputFilter::CLockCursorToScreenAction::kToggle;
|
---|
1184 | if (args.size() == 1) {
|
---|
1185 | if (args[0] == "off") {
|
---|
1186 | mode = CInputFilter::CLockCursorToScreenAction::kOff;
|
---|
1187 | }
|
---|
1188 | else if (args[0] == "on") {
|
---|
1189 | mode = CInputFilter::CLockCursorToScreenAction::kOn;
|
---|
1190 | }
|
---|
1191 | else if (args[0] == "toggle") {
|
---|
1192 | mode = CInputFilter::CLockCursorToScreenAction::kToggle;
|
---|
1193 | }
|
---|
1194 | else {
|
---|
1195 | throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])");
|
---|
1196 | }
|
---|
1197 | }
|
---|
1198 |
|
---|
1199 | if (mode != CInputFilter::CLockCursorToScreenAction::kOff) {
|
---|
1200 | m_hasLockToScreenAction = true;
|
---|
1201 | }
|
---|
1202 |
|
---|
1203 | action = new CInputFilter::CLockCursorToScreenAction(mode);
|
---|
1204 | }
|
---|
1205 |
|
---|
1206 | else {
|
---|
1207 | throw XConfigRead(s, "unknown action argument \"%{1}\"", name);
|
---|
1208 | }
|
---|
1209 |
|
---|
1210 | rule.adoptAction(action, activate);
|
---|
1211 | }
|
---|
1212 |
|
---|
1213 | void
|
---|
1214 | CConfig::parseScreens(CConfigReadContext& c,
|
---|
1215 | const CString& s, std::set<CString>& screens) const
|
---|
1216 | {
|
---|
1217 | screens.clear();
|
---|
1218 |
|
---|
1219 | CString::size_type i = 0;
|
---|
1220 | while (i < s.size()) {
|
---|
1221 | // find end of next screen name
|
---|
1222 | CString::size_type j = s.find(':', i);
|
---|
1223 | if (j == CString::npos) {
|
---|
1224 | j = s.size();
|
---|
1225 | }
|
---|
1226 |
|
---|
1227 | // extract name
|
---|
1228 | CString rawName;
|
---|
1229 | i = s.find_first_not_of(" \t", i);
|
---|
1230 | if (i < j) {
|
---|
1231 | rawName = s.substr(i, s.find_last_not_of(" \t", j - 1) - i + 1);
|
---|
1232 | }
|
---|
1233 |
|
---|
1234 | // add name
|
---|
1235 | if (rawName == "*") {
|
---|
1236 | screens.insert("*");
|
---|
1237 | }
|
---|
1238 | else if (!rawName.empty()) {
|
---|
1239 | CString name = getCanonicalName(rawName);
|
---|
1240 | if (name.empty()) {
|
---|
1241 | throw XConfigRead(c, "unknown screen name \"%{1}\"", rawName);
|
---|
1242 | }
|
---|
1243 | screens.insert(name);
|
---|
1244 | }
|
---|
1245 |
|
---|
1246 | // next
|
---|
1247 | i = j + 1;
|
---|
1248 | }
|
---|
1249 | }
|
---|
1250 |
|
---|
1251 | const char*
|
---|
1252 | CConfig::getOptionName(OptionID id)
|
---|
1253 | {
|
---|
1254 | if (id == kOptionHalfDuplexCapsLock) {
|
---|
1255 | return "halfDuplexCapsLock";
|
---|
1256 | }
|
---|
1257 | if (id == kOptionHalfDuplexNumLock) {
|
---|
1258 | return "halfDuplexNumLock";
|
---|
1259 | }
|
---|
1260 | if (id == kOptionHalfDuplexScrollLock) {
|
---|
1261 | return "halfDuplexScrollLock";
|
---|
1262 | }
|
---|
1263 | if (id == kOptionModifierMapForShift) {
|
---|
1264 | return "shift";
|
---|
1265 | }
|
---|
1266 | if (id == kOptionModifierMapForControl) {
|
---|
1267 | return "ctrl";
|
---|
1268 | }
|
---|
1269 | if (id == kOptionModifierMapForAlt) {
|
---|
1270 | return "alt";
|
---|
1271 | }
|
---|
1272 | if (id == kOptionModifierMapForMeta) {
|
---|
1273 | return "meta";
|
---|
1274 | }
|
---|
1275 | if (id == kOptionModifierMapForSuper) {
|
---|
1276 | return "super";
|
---|
1277 | }
|
---|
1278 | if (id == kOptionHeartbeat) {
|
---|
1279 | return "heartbeat";
|
---|
1280 | }
|
---|
1281 | if (id == kOptionScreenSwitchCorners) {
|
---|
1282 | return "switchCorners";
|
---|
1283 | }
|
---|
1284 | if (id == kOptionScreenSwitchCornerSize) {
|
---|
1285 | return "switchCornerSize";
|
---|
1286 | }
|
---|
1287 | if (id == kOptionScreenSwitchDelay) {
|
---|
1288 | return "switchDelay";
|
---|
1289 | }
|
---|
1290 | if (id == kOptionScreenSwitchTwoTap) {
|
---|
1291 | return "switchDoubleTap";
|
---|
1292 | }
|
---|
1293 | if (id == kOptionScreenSaverSync) {
|
---|
1294 | return "screenSaverSync";
|
---|
1295 | }
|
---|
1296 | if (id == kOptionXTestXineramaUnaware) {
|
---|
1297 | return "xtestIsXineramaUnaware";
|
---|
1298 | }
|
---|
1299 | if (id == kOptionRelativeMouseMoves) {
|
---|
1300 | return "relativeMouseMoves";
|
---|
1301 | }
|
---|
1302 | if (id == kOptionWin32KeepForeground) {
|
---|
1303 | return "win32KeepForeground";
|
---|
1304 | }
|
---|
1305 | return NULL;
|
---|
1306 | }
|
---|
1307 |
|
---|
1308 | CString
|
---|
1309 | CConfig::getOptionValue(OptionID id, OptionValue value)
|
---|
1310 | {
|
---|
1311 | if (id == kOptionHalfDuplexCapsLock ||
|
---|
1312 | id == kOptionHalfDuplexNumLock ||
|
---|
1313 | id == kOptionHalfDuplexScrollLock ||
|
---|
1314 | id == kOptionScreenSaverSync ||
|
---|
1315 | id == kOptionXTestXineramaUnaware ||
|
---|
1316 | id == kOptionRelativeMouseMoves ||
|
---|
1317 | id == kOptionWin32KeepForeground) {
|
---|
1318 | return (value != 0) ? "true" : "false";
|
---|
1319 | }
|
---|
1320 | if (id == kOptionModifierMapForShift ||
|
---|
1321 | id == kOptionModifierMapForControl ||
|
---|
1322 | id == kOptionModifierMapForAlt ||
|
---|
1323 | id == kOptionModifierMapForMeta ||
|
---|
1324 | id == kOptionModifierMapForSuper) {
|
---|
1325 | switch (value) {
|
---|
1326 | case kKeyModifierIDShift:
|
---|
1327 | return "shift";
|
---|
1328 |
|
---|
1329 | case kKeyModifierIDControl:
|
---|
1330 | return "ctrl";
|
---|
1331 |
|
---|
1332 | case kKeyModifierIDAlt:
|
---|
1333 | return "alt";
|
---|
1334 |
|
---|
1335 | case kKeyModifierIDMeta:
|
---|
1336 | return "meta";
|
---|
1337 |
|
---|
1338 | case kKeyModifierIDSuper:
|
---|
1339 | return "super";
|
---|
1340 |
|
---|
1341 | default:
|
---|
1342 | return "none";
|
---|
1343 | }
|
---|
1344 | }
|
---|
1345 | if (id == kOptionHeartbeat ||
|
---|
1346 | id == kOptionScreenSwitchCornerSize ||
|
---|
1347 | id == kOptionScreenSwitchDelay ||
|
---|
1348 | id == kOptionScreenSwitchTwoTap) {
|
---|
1349 | return CStringUtil::print("%d", value);
|
---|
1350 | }
|
---|
1351 | if (id == kOptionScreenSwitchCorners) {
|
---|
1352 | std::string result("none");
|
---|
1353 | if ((value & kTopLeftMask) != 0) {
|
---|
1354 | result += " +top-left";
|
---|
1355 | }
|
---|
1356 | if ((value & kTopRightMask) != 0) {
|
---|
1357 | result += " +top-right";
|
---|
1358 | }
|
---|
1359 | if ((value & kBottomLeftMask) != 0) {
|
---|
1360 | result += " +bottom-left";
|
---|
1361 | }
|
---|
1362 | if ((value & kBottomRightMask) != 0) {
|
---|
1363 | result += " +bottom-right";
|
---|
1364 | }
|
---|
1365 | return result;
|
---|
1366 | }
|
---|
1367 |
|
---|
1368 | return "";
|
---|
1369 | }
|
---|
1370 |
|
---|
1371 |
|
---|
1372 | //
|
---|
1373 | // CConfig::CName
|
---|
1374 | //
|
---|
1375 |
|
---|
1376 | CConfig::CName::CName(CConfig* config, const CString& name) :
|
---|
1377 | m_config(config),
|
---|
1378 | m_name(config->getCanonicalName(name))
|
---|
1379 | {
|
---|
1380 | // do nothing
|
---|
1381 | }
|
---|
1382 |
|
---|
1383 | bool
|
---|
1384 | CConfig::CName::operator==(const CString& name) const
|
---|
1385 | {
|
---|
1386 | CString canonical = m_config->getCanonicalName(name);
|
---|
1387 | return CStringUtil::CaselessCmp::equal(canonical, m_name);
|
---|
1388 | }
|
---|
1389 |
|
---|
1390 |
|
---|
1391 | //
|
---|
1392 | // CConfig::CCellEdge
|
---|
1393 | //
|
---|
1394 |
|
---|
1395 | CConfig::CCellEdge::CCellEdge(EDirection side, float position)
|
---|
1396 | {
|
---|
1397 | init("", side, CInterval(position, position));
|
---|
1398 | }
|
---|
1399 |
|
---|
1400 | CConfig::CCellEdge::CCellEdge(EDirection side, const CInterval& interval)
|
---|
1401 | {
|
---|
1402 | assert(interval.first >= 0.0f);
|
---|
1403 | assert(interval.second <= 1.0f);
|
---|
1404 | assert(interval.first < interval.second);
|
---|
1405 |
|
---|
1406 | init("", side, interval);
|
---|
1407 | }
|
---|
1408 |
|
---|
1409 | CConfig::CCellEdge::CCellEdge(const CString& name,
|
---|
1410 | EDirection side, const CInterval& interval)
|
---|
1411 | {
|
---|
1412 | assert(interval.first >= 0.0f);
|
---|
1413 | assert(interval.second <= 1.0f);
|
---|
1414 | assert(interval.first < interval.second);
|
---|
1415 |
|
---|
1416 | init(name, side, interval);
|
---|
1417 | }
|
---|
1418 |
|
---|
1419 | CConfig::CCellEdge::~CCellEdge()
|
---|
1420 | {
|
---|
1421 | // do nothing
|
---|
1422 | }
|
---|
1423 |
|
---|
1424 | void
|
---|
1425 | CConfig::CCellEdge::init(const CString& name, EDirection side,
|
---|
1426 | const CInterval& interval)
|
---|
1427 | {
|
---|
1428 | assert(side != kNoDirection);
|
---|
1429 |
|
---|
1430 | m_name = name;
|
---|
1431 | m_side = side;
|
---|
1432 | m_interval = interval;
|
---|
1433 | }
|
---|
1434 |
|
---|
1435 | CConfig::CInterval
|
---|
1436 | CConfig::CCellEdge::getInterval() const
|
---|
1437 | {
|
---|
1438 | return m_interval;
|
---|
1439 | }
|
---|
1440 |
|
---|
1441 | void
|
---|
1442 | CConfig::CCellEdge::setName(const CString& newName)
|
---|
1443 | {
|
---|
1444 | m_name = newName;
|
---|
1445 | }
|
---|
1446 |
|
---|
1447 | CString
|
---|
1448 | CConfig::CCellEdge::getName() const
|
---|
1449 | {
|
---|
1450 | return m_name;
|
---|
1451 | }
|
---|
1452 |
|
---|
1453 | EDirection
|
---|
1454 | CConfig::CCellEdge::getSide() const
|
---|
1455 | {
|
---|
1456 | return m_side;
|
---|
1457 | }
|
---|
1458 |
|
---|
1459 | bool
|
---|
1460 | CConfig::CCellEdge::overlaps(const CCellEdge& edge) const
|
---|
1461 | {
|
---|
1462 | const CInterval& x = m_interval;
|
---|
1463 | const CInterval& y = edge.m_interval;
|
---|
1464 | if (m_side != edge.m_side) {
|
---|
1465 | return false;
|
---|
1466 | }
|
---|
1467 | return (x.first >= y.first && x.first < y.second) ||
|
---|
1468 | (x.second > y.first && x.second <= y.second) ||
|
---|
1469 | (y.first >= x.first && y.first < x.second) ||
|
---|
1470 | (y.second > x.first && y.second <= x.second);
|
---|
1471 | }
|
---|
1472 |
|
---|
1473 | bool
|
---|
1474 | CConfig::CCellEdge::isInside(float x) const
|
---|
1475 | {
|
---|
1476 | return (x >= m_interval.first && x < m_interval.second);
|
---|
1477 | }
|
---|
1478 |
|
---|
1479 | float
|
---|
1480 | CConfig::CCellEdge::transform(float x) const
|
---|
1481 | {
|
---|
1482 | return (x - m_interval.first) / (m_interval.second - m_interval.first);
|
---|
1483 | }
|
---|
1484 |
|
---|
1485 |
|
---|
1486 | float
|
---|
1487 | CConfig::CCellEdge::inverseTransform(float x) const
|
---|
1488 | {
|
---|
1489 | return x * (m_interval.second - m_interval.first) + m_interval.first;
|
---|
1490 | }
|
---|
1491 |
|
---|
1492 | bool
|
---|
1493 | CConfig::CCellEdge::operator<(const CCellEdge& o) const
|
---|
1494 | {
|
---|
1495 | if (static_cast<int>(m_side) < static_cast<int>(o.m_side)) {
|
---|
1496 | return true;
|
---|
1497 | }
|
---|
1498 | else if (static_cast<int>(m_side) > static_cast<int>(o.m_side)) {
|
---|
1499 | return false;
|
---|
1500 | }
|
---|
1501 |
|
---|
1502 | return (m_interval.first < o.m_interval.first);
|
---|
1503 | }
|
---|
1504 |
|
---|
1505 | bool
|
---|
1506 | CConfig::CCellEdge::operator==(const CCellEdge& x) const
|
---|
1507 | {
|
---|
1508 | return (m_side == x.m_side && m_interval == x.m_interval);
|
---|
1509 | }
|
---|
1510 |
|
---|
1511 | bool
|
---|
1512 | CConfig::CCellEdge::operator!=(const CCellEdge& x) const
|
---|
1513 | {
|
---|
1514 | return !operator==(x);
|
---|
1515 | }
|
---|
1516 |
|
---|
1517 |
|
---|
1518 | //
|
---|
1519 | // CConfig::CCell
|
---|
1520 | //
|
---|
1521 |
|
---|
1522 | bool
|
---|
1523 | CConfig::CCell::add(const CCellEdge& src, const CCellEdge& dst)
|
---|
1524 | {
|
---|
1525 | // cannot add an edge that overlaps other existing edges but we
|
---|
1526 | // can exactly replace an edge.
|
---|
1527 | if (!hasEdge(src) && overlaps(src)) {
|
---|
1528 | return false;
|
---|
1529 | }
|
---|
1530 |
|
---|
1531 | m_neighbors.erase(src);
|
---|
1532 | m_neighbors.insert(std::make_pair(src, dst));
|
---|
1533 | return true;
|
---|
1534 | }
|
---|
1535 |
|
---|
1536 | void
|
---|
1537 | CConfig::CCell::remove(EDirection side)
|
---|
1538 | {
|
---|
1539 | for (CEdgeLinks::iterator j = m_neighbors.begin();
|
---|
1540 | j != m_neighbors.end(); ) {
|
---|
1541 | if (j->first.getSide() == side) {
|
---|
1542 | m_neighbors.erase(j++);
|
---|
1543 | }
|
---|
1544 | else {
|
---|
1545 | ++j;
|
---|
1546 | }
|
---|
1547 | }
|
---|
1548 | }
|
---|
1549 |
|
---|
1550 | void
|
---|
1551 | CConfig::CCell::remove(EDirection side, float position)
|
---|
1552 | {
|
---|
1553 | for (CEdgeLinks::iterator j = m_neighbors.begin();
|
---|
1554 | j != m_neighbors.end(); ++j) {
|
---|
1555 | if (j->first.getSide() == side && j->first.isInside(position)) {
|
---|
1556 | m_neighbors.erase(j);
|
---|
1557 | break;
|
---|
1558 | }
|
---|
1559 | }
|
---|
1560 | }
|
---|
1561 | void
|
---|
1562 | CConfig::CCell::remove(const CName& name)
|
---|
1563 | {
|
---|
1564 | for (CEdgeLinks::iterator j = m_neighbors.begin();
|
---|
1565 | j != m_neighbors.end(); ) {
|
---|
1566 | if (name == j->second.getName()) {
|
---|
1567 | m_neighbors.erase(j++);
|
---|
1568 | }
|
---|
1569 | else {
|
---|
1570 | ++j;
|
---|
1571 | }
|
---|
1572 | }
|
---|
1573 | }
|
---|
1574 |
|
---|
1575 | void
|
---|
1576 | CConfig::CCell::rename(const CName& oldName, const CString& newName)
|
---|
1577 | {
|
---|
1578 | for (CEdgeLinks::iterator j = m_neighbors.begin();
|
---|
1579 | j != m_neighbors.end(); ++j) {
|
---|
1580 | if (oldName == j->second.getName()) {
|
---|
1581 | j->second.setName(newName);
|
---|
1582 | }
|
---|
1583 | }
|
---|
1584 | }
|
---|
1585 |
|
---|
1586 | bool
|
---|
1587 | CConfig::CCell::hasEdge(const CCellEdge& edge) const
|
---|
1588 | {
|
---|
1589 | CEdgeLinks::const_iterator i = m_neighbors.find(edge);
|
---|
1590 | return (i != m_neighbors.end() && i->first == edge);
|
---|
1591 | }
|
---|
1592 |
|
---|
1593 | bool
|
---|
1594 | CConfig::CCell::overlaps(const CCellEdge& edge) const
|
---|
1595 | {
|
---|
1596 | CEdgeLinks::const_iterator i = m_neighbors.upper_bound(edge);
|
---|
1597 | if (i != m_neighbors.end() && i->first.overlaps(edge)) {
|
---|
1598 | return true;
|
---|
1599 | }
|
---|
1600 | if (i != m_neighbors.begin() && (--i)->first.overlaps(edge)) {
|
---|
1601 | return true;
|
---|
1602 | }
|
---|
1603 | return false;
|
---|
1604 | }
|
---|
1605 |
|
---|
1606 | bool
|
---|
1607 | CConfig::CCell::getLink(EDirection side, float position,
|
---|
1608 | const CCellEdge*& src, const CCellEdge*& dst) const
|
---|
1609 | {
|
---|
1610 | CCellEdge edge(side, position);
|
---|
1611 | CEdgeLinks::const_iterator i = m_neighbors.upper_bound(edge);
|
---|
1612 | if (i == m_neighbors.begin()) {
|
---|
1613 | return false;
|
---|
1614 | }
|
---|
1615 | --i;
|
---|
1616 | if (i->first.getSide() == side && i->first.isInside(position)) {
|
---|
1617 | src = &i->first;
|
---|
1618 | dst = &i->second;
|
---|
1619 | return true;
|
---|
1620 | }
|
---|
1621 | return false;
|
---|
1622 | }
|
---|
1623 |
|
---|
1624 | bool
|
---|
1625 | CConfig::CCell::operator==(const CCell& x) const
|
---|
1626 | {
|
---|
1627 | // compare options
|
---|
1628 | if (m_options != x.m_options) {
|
---|
1629 | return false;
|
---|
1630 | }
|
---|
1631 |
|
---|
1632 | // compare links
|
---|
1633 | if (m_neighbors.size() != x.m_neighbors.size()) {
|
---|
1634 | return false;
|
---|
1635 | }
|
---|
1636 | for (CEdgeLinks::const_iterator index1 = m_neighbors.begin(),
|
---|
1637 | index2 = x.m_neighbors.begin();
|
---|
1638 | index1 != m_neighbors.end();
|
---|
1639 | ++index1, ++index2) {
|
---|
1640 | if (index1->first != index2->first) {
|
---|
1641 | return false;
|
---|
1642 | }
|
---|
1643 | if (index1->second != index2->second) {
|
---|
1644 | return false;
|
---|
1645 | }
|
---|
1646 |
|
---|
1647 | // operator== doesn't compare names. only compare destination
|
---|
1648 | // names.
|
---|
1649 | if (!CStringUtil::CaselessCmp::equal(index1->second.getName(),
|
---|
1650 | index2->second.getName())) {
|
---|
1651 | return false;
|
---|
1652 | }
|
---|
1653 | }
|
---|
1654 | return true;
|
---|
1655 | }
|
---|
1656 |
|
---|
1657 | bool
|
---|
1658 | CConfig::CCell::operator!=(const CCell& x) const
|
---|
1659 | {
|
---|
1660 | return !operator==(x);
|
---|
1661 | }
|
---|
1662 |
|
---|
1663 | CConfig::CCell::const_iterator
|
---|
1664 | CConfig::CCell::begin() const
|
---|
1665 | {
|
---|
1666 | return m_neighbors.begin();
|
---|
1667 | }
|
---|
1668 |
|
---|
1669 | CConfig::CCell::const_iterator
|
---|
1670 | CConfig::CCell::end() const
|
---|
1671 | {
|
---|
1672 | return m_neighbors.end();
|
---|
1673 | }
|
---|
1674 |
|
---|
1675 |
|
---|
1676 | //
|
---|
1677 | // CConfig I/O
|
---|
1678 | //
|
---|
1679 |
|
---|
1680 | std::istream&
|
---|
1681 | operator>>(std::istream& s, CConfig& config)
|
---|
1682 | {
|
---|
1683 | CConfigReadContext context(s);
|
---|
1684 | config.read(context);
|
---|
1685 | return s;
|
---|
1686 | }
|
---|
1687 |
|
---|
1688 | std::ostream&
|
---|
1689 | operator<<(std::ostream& s, const CConfig& config)
|
---|
1690 | {
|
---|
1691 | // screens section
|
---|
1692 | s << "section: screens" << std::endl;
|
---|
1693 | for (CConfig::const_iterator screen = config.begin();
|
---|
1694 | screen != config.end(); ++screen) {
|
---|
1695 | s << "\t" << screen->c_str() << ":" << std::endl;
|
---|
1696 | const CConfig::CScreenOptions* options = config.getOptions(*screen);
|
---|
1697 | if (options != NULL && options->size() > 0) {
|
---|
1698 | for (CConfig::CScreenOptions::const_iterator
|
---|
1699 | option = options->begin();
|
---|
1700 | option != options->end(); ++option) {
|
---|
1701 | const char* name = CConfig::getOptionName(option->first);
|
---|
1702 | CString value = CConfig::getOptionValue(option->first,
|
---|
1703 | option->second);
|
---|
1704 | if (name != NULL && !value.empty()) {
|
---|
1705 | s << "\t\t" << name << " = " << value << std::endl;
|
---|
1706 | }
|
---|
1707 | }
|
---|
1708 | }
|
---|
1709 | }
|
---|
1710 | s << "end" << std::endl;
|
---|
1711 |
|
---|
1712 | // links section
|
---|
1713 | CString neighbor;
|
---|
1714 | s << "section: links" << std::endl;
|
---|
1715 | for (CConfig::const_iterator screen = config.begin();
|
---|
1716 | screen != config.end(); ++screen) {
|
---|
1717 | s << "\t" << screen->c_str() << ":" << std::endl;
|
---|
1718 |
|
---|
1719 | for (CConfig::link_const_iterator
|
---|
1720 | link = config.beginNeighbor(*screen),
|
---|
1721 | nend = config.endNeighbor(*screen); link != nend; ++link) {
|
---|
1722 | s << "\t\t" << CConfig::dirName(link->first.getSide()) <<
|
---|
1723 | CConfig::formatInterval(link->first.getInterval()) <<
|
---|
1724 | " = " << link->second.getName().c_str() <<
|
---|
1725 | CConfig::formatInterval(link->second.getInterval()) <<
|
---|
1726 | std::endl;
|
---|
1727 | }
|
---|
1728 | }
|
---|
1729 | s << "end" << std::endl;
|
---|
1730 |
|
---|
1731 | // aliases section (if there are any)
|
---|
1732 | if (config.m_map.size() != config.m_nameToCanonicalName.size()) {
|
---|
1733 | // map canonical to alias
|
---|
1734 | typedef std::multimap<CString, CString,
|
---|
1735 | CStringUtil::CaselessCmp> CMNameMap;
|
---|
1736 | CMNameMap aliases;
|
---|
1737 | for (CConfig::CNameMap::const_iterator
|
---|
1738 | index = config.m_nameToCanonicalName.begin();
|
---|
1739 | index != config.m_nameToCanonicalName.end();
|
---|
1740 | ++index) {
|
---|
1741 | if (index->first != index->second) {
|
---|
1742 | aliases.insert(std::make_pair(index->second, index->first));
|
---|
1743 | }
|
---|
1744 | }
|
---|
1745 |
|
---|
1746 | // dump it
|
---|
1747 | CString screen;
|
---|
1748 | s << "section: aliases" << std::endl;
|
---|
1749 | for (CMNameMap::const_iterator index = aliases.begin();
|
---|
1750 | index != aliases.end(); ++index) {
|
---|
1751 | if (index->first != screen) {
|
---|
1752 | screen = index->first;
|
---|
1753 | s << "\t" << screen.c_str() << ":" << std::endl;
|
---|
1754 | }
|
---|
1755 | s << "\t\t" << index->second.c_str() << std::endl;
|
---|
1756 | }
|
---|
1757 | s << "end" << std::endl;
|
---|
1758 | }
|
---|
1759 |
|
---|
1760 | // options section
|
---|
1761 | s << "section: options" << std::endl;
|
---|
1762 | const CConfig::CScreenOptions* options = config.getOptions("");
|
---|
1763 | if (options != NULL && options->size() > 0) {
|
---|
1764 | for (CConfig::CScreenOptions::const_iterator
|
---|
1765 | option = options->begin();
|
---|
1766 | option != options->end(); ++option) {
|
---|
1767 | const char* name = CConfig::getOptionName(option->first);
|
---|
1768 | CString value = CConfig::getOptionValue(option->first,
|
---|
1769 | option->second);
|
---|
1770 | if (name != NULL && !value.empty()) {
|
---|
1771 | s << "\t" << name << " = " << value << std::endl;
|
---|
1772 | }
|
---|
1773 | }
|
---|
1774 | }
|
---|
1775 | if (config.m_synergyAddress.isValid()) {
|
---|
1776 | s << "\taddress = " <<
|
---|
1777 | config.m_synergyAddress.getHostname().c_str() << std::endl;
|
---|
1778 | }
|
---|
1779 | s << config.m_inputFilter.format("\t");
|
---|
1780 | s << "end" << std::endl;
|
---|
1781 |
|
---|
1782 | return s;
|
---|
1783 | }
|
---|
1784 |
|
---|
1785 |
|
---|
1786 | //
|
---|
1787 | // CConfigReadContext
|
---|
1788 | //
|
---|
1789 |
|
---|
1790 | CConfigReadContext::CConfigReadContext(std::istream& s, SInt32 firstLine) :
|
---|
1791 | m_stream(s),
|
---|
1792 | m_line(firstLine - 1)
|
---|
1793 | {
|
---|
1794 | // do nothing
|
---|
1795 | }
|
---|
1796 |
|
---|
1797 | CConfigReadContext::~CConfigReadContext()
|
---|
1798 | {
|
---|
1799 | // do nothing
|
---|
1800 | }
|
---|
1801 |
|
---|
1802 | bool
|
---|
1803 | CConfigReadContext::readLine(CString& line)
|
---|
1804 | {
|
---|
1805 | ++m_line;
|
---|
1806 | while (std::getline(m_stream, line)) {
|
---|
1807 | // strip leading whitespace
|
---|
1808 | CString::size_type i = line.find_first_not_of(" \t");
|
---|
1809 | if (i != CString::npos) {
|
---|
1810 | line.erase(0, i);
|
---|
1811 | }
|
---|
1812 |
|
---|
1813 | // strip comments and then trailing whitespace
|
---|
1814 | i = line.find('#');
|
---|
1815 | if (i != CString::npos) {
|
---|
1816 | line.erase(i);
|
---|
1817 | }
|
---|
1818 | i = line.find_last_not_of(" \r\t");
|
---|
1819 | if (i != CString::npos) {
|
---|
1820 | line.erase(i + 1);
|
---|
1821 | }
|
---|
1822 |
|
---|
1823 | // return non empty line
|
---|
1824 | if (!line.empty()) {
|
---|
1825 | // make sure there are no invalid characters
|
---|
1826 | for (i = 0; i < line.length(); ++i) {
|
---|
1827 | if (!isgraph(line[i]) && line[i] != ' ' && line[i] != '\t') {
|
---|
1828 | throw XConfigRead(*this,
|
---|
1829 | "invalid character %{1}",
|
---|
1830 | CStringUtil::print("%#2x", line[i]));
|
---|
1831 | }
|
---|
1832 | }
|
---|
1833 |
|
---|
1834 | return true;
|
---|
1835 | }
|
---|
1836 |
|
---|
1837 | // next line
|
---|
1838 | ++m_line;
|
---|
1839 | }
|
---|
1840 | return false;
|
---|
1841 | }
|
---|
1842 |
|
---|
1843 | UInt32
|
---|
1844 | CConfigReadContext::getLineNumber() const
|
---|
1845 | {
|
---|
1846 | return m_line;
|
---|
1847 | }
|
---|
1848 |
|
---|
1849 | CConfigReadContext::operator void*() const
|
---|
1850 | {
|
---|
1851 | return m_stream;
|
---|
1852 | }
|
---|
1853 |
|
---|
1854 | bool
|
---|
1855 | CConfigReadContext::operator!() const
|
---|
1856 | {
|
---|
1857 | return !m_stream;
|
---|
1858 | }
|
---|
1859 |
|
---|
1860 | OptionValue
|
---|
1861 | CConfigReadContext::parseBoolean(const CString& arg) const
|
---|
1862 | {
|
---|
1863 | if (CStringUtil::CaselessCmp::equal(arg, "true")) {
|
---|
1864 | return static_cast<OptionValue>(true);
|
---|
1865 | }
|
---|
1866 | if (CStringUtil::CaselessCmp::equal(arg, "false")) {
|
---|
1867 | return static_cast<OptionValue>(false);
|
---|
1868 | }
|
---|
1869 | throw XConfigRead(*this, "invalid boolean argument \"%{1}\"", arg);
|
---|
1870 | }
|
---|
1871 |
|
---|
1872 | OptionValue
|
---|
1873 | CConfigReadContext::parseInt(const CString& arg) const
|
---|
1874 | {
|
---|
1875 | const char* s = arg.c_str();
|
---|
1876 | char* end;
|
---|
1877 | long tmp = strtol(s, &end, 10);
|
---|
1878 | if (*end != '\0') {
|
---|
1879 | // invalid characters
|
---|
1880 | throw XConfigRead(*this, "invalid integer argument \"%{1}\"", arg);
|
---|
1881 | }
|
---|
1882 | OptionValue value = static_cast<OptionValue>(tmp);
|
---|
1883 | if (value != tmp) {
|
---|
1884 | // out of range
|
---|
1885 | throw XConfigRead(*this, "integer argument \"%{1}\" out of range", arg);
|
---|
1886 | }
|
---|
1887 | return value;
|
---|
1888 | }
|
---|
1889 |
|
---|
1890 | OptionValue
|
---|
1891 | CConfigReadContext::parseModifierKey(const CString& arg) const
|
---|
1892 | {
|
---|
1893 | if (CStringUtil::CaselessCmp::equal(arg, "shift")) {
|
---|
1894 | return static_cast<OptionValue>(kKeyModifierIDShift);
|
---|
1895 | }
|
---|
1896 | if (CStringUtil::CaselessCmp::equal(arg, "ctrl")) {
|
---|
1897 | return static_cast<OptionValue>(kKeyModifierIDControl);
|
---|
1898 | }
|
---|
1899 | if (CStringUtil::CaselessCmp::equal(arg, "alt")) {
|
---|
1900 | return static_cast<OptionValue>(kKeyModifierIDAlt);
|
---|
1901 | }
|
---|
1902 | if (CStringUtil::CaselessCmp::equal(arg, "meta")) {
|
---|
1903 | return static_cast<OptionValue>(kKeyModifierIDMeta);
|
---|
1904 | }
|
---|
1905 | if (CStringUtil::CaselessCmp::equal(arg, "super")) {
|
---|
1906 | return static_cast<OptionValue>(kKeyModifierIDSuper);
|
---|
1907 | }
|
---|
1908 | if (CStringUtil::CaselessCmp::equal(arg, "none")) {
|
---|
1909 | return static_cast<OptionValue>(kKeyModifierIDNull);
|
---|
1910 | }
|
---|
1911 | throw XConfigRead(*this, "invalid argument \"%{1}\"", arg);
|
---|
1912 | }
|
---|
1913 |
|
---|
1914 | OptionValue
|
---|
1915 | CConfigReadContext::parseCorner(const CString& arg) const
|
---|
1916 | {
|
---|
1917 | if (CStringUtil::CaselessCmp::equal(arg, "left")) {
|
---|
1918 | return kTopLeftMask | kBottomLeftMask;
|
---|
1919 | }
|
---|
1920 | else if (CStringUtil::CaselessCmp::equal(arg, "right")) {
|
---|
1921 | return kTopRightMask | kBottomRightMask;
|
---|
1922 | }
|
---|
1923 | else if (CStringUtil::CaselessCmp::equal(arg, "top")) {
|
---|
1924 | return kTopLeftMask | kTopRightMask;
|
---|
1925 | }
|
---|
1926 | else if (CStringUtil::CaselessCmp::equal(arg, "bottom")) {
|
---|
1927 | return kBottomLeftMask | kBottomRightMask;
|
---|
1928 | }
|
---|
1929 | else if (CStringUtil::CaselessCmp::equal(arg, "top-left")) {
|
---|
1930 | return kTopLeftMask;
|
---|
1931 | }
|
---|
1932 | else if (CStringUtil::CaselessCmp::equal(arg, "top-right")) {
|
---|
1933 | return kTopRightMask;
|
---|
1934 | }
|
---|
1935 | else if (CStringUtil::CaselessCmp::equal(arg, "bottom-left")) {
|
---|
1936 | return kBottomLeftMask;
|
---|
1937 | }
|
---|
1938 | else if (CStringUtil::CaselessCmp::equal(arg, "bottom-right")) {
|
---|
1939 | return kBottomRightMask;
|
---|
1940 | }
|
---|
1941 | else if (CStringUtil::CaselessCmp::equal(arg, "none")) {
|
---|
1942 | return kNoCornerMask;
|
---|
1943 | }
|
---|
1944 | else if (CStringUtil::CaselessCmp::equal(arg, "all")) {
|
---|
1945 | return kAllCornersMask;
|
---|
1946 | }
|
---|
1947 | throw XConfigRead(*this, "invalid argument \"%{1}\"", arg);
|
---|
1948 | }
|
---|
1949 |
|
---|
1950 | OptionValue
|
---|
1951 | CConfigReadContext::parseCorners(const CString& args) const
|
---|
1952 | {
|
---|
1953 | // find first token
|
---|
1954 | CString::size_type i = args.find_first_not_of(" \t", 0);
|
---|
1955 | if (i == CString::npos) {
|
---|
1956 | throw XConfigRead(*this, "missing corner argument");
|
---|
1957 | }
|
---|
1958 | CString::size_type j = args.find_first_of(" \t", i);
|
---|
1959 |
|
---|
1960 | // parse first corner token
|
---|
1961 | OptionValue corners = parseCorner(args.substr(i, j - i));
|
---|
1962 |
|
---|
1963 | // get +/-
|
---|
1964 | i = args.find_first_not_of(" \t", j);
|
---|
1965 | while (i != CString::npos) {
|
---|
1966 | // parse +/-
|
---|
1967 | bool add;
|
---|
1968 | if (args[i] == '-') {
|
---|
1969 | add = false;
|
---|
1970 | }
|
---|
1971 | else if (args[i] == '+') {
|
---|
1972 | add = true;
|
---|
1973 | }
|
---|
1974 | else {
|
---|
1975 | throw XConfigRead(*this,
|
---|
1976 | "invalid corner operator \"%{1}\"",
|
---|
1977 | CString(args.c_str() + i, 1));
|
---|
1978 | }
|
---|
1979 |
|
---|
1980 | // get next corner token
|
---|
1981 | i = args.find_first_not_of(" \t", i + 1);
|
---|
1982 | j = args.find_first_of(" \t", i);
|
---|
1983 | if (i == CString::npos) {
|
---|
1984 | throw XConfigRead(*this, "missing corner argument");
|
---|
1985 | }
|
---|
1986 |
|
---|
1987 | // parse next corner token
|
---|
1988 | if (add) {
|
---|
1989 | corners |= parseCorner(args.substr(i, j - i));
|
---|
1990 | }
|
---|
1991 | else {
|
---|
1992 | corners &= ~parseCorner(args.substr(i, j - i));
|
---|
1993 | }
|
---|
1994 | i = args.find_first_not_of(" \t", j);
|
---|
1995 | }
|
---|
1996 |
|
---|
1997 | return corners;
|
---|
1998 | }
|
---|
1999 |
|
---|
2000 | CConfig::CInterval
|
---|
2001 | CConfigReadContext::parseInterval(const ArgList& args) const
|
---|
2002 | {
|
---|
2003 | if (args.size() == 0) {
|
---|
2004 | return CConfig::CInterval(0.0f, 1.0f);
|
---|
2005 | }
|
---|
2006 | if (args.size() != 2 || args[0].empty() || args[1].empty()) {
|
---|
2007 | throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
|
---|
2008 | }
|
---|
2009 |
|
---|
2010 | char* end;
|
---|
2011 | long startValue = strtol(args[0].c_str(), &end, 10);
|
---|
2012 | if (end[0] != '\0') {
|
---|
2013 | throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
|
---|
2014 | }
|
---|
2015 | long endValue = strtol(args[1].c_str(), &end, 10);
|
---|
2016 | if (end[0] != '\0') {
|
---|
2017 | throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
|
---|
2018 | }
|
---|
2019 |
|
---|
2020 | if (startValue < 0 || startValue > 100 ||
|
---|
2021 | endValue < 0 || endValue > 100 ||
|
---|
2022 | startValue >= endValue) {
|
---|
2023 | throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args));
|
---|
2024 | }
|
---|
2025 |
|
---|
2026 | return CConfig::CInterval(startValue / 100.0f, endValue / 100.0f);
|
---|
2027 | }
|
---|
2028 |
|
---|
2029 | void
|
---|
2030 | CConfigReadContext::parseNameWithArgs(
|
---|
2031 | const CString& type, const CString& line,
|
---|
2032 | const CString& delim, CString::size_type& index,
|
---|
2033 | CString& name, ArgList& args) const
|
---|
2034 | {
|
---|
2035 | // skip leading whitespace
|
---|
2036 | CString::size_type i = line.find_first_not_of(" \t", index);
|
---|
2037 | if (i == CString::npos) {
|
---|
2038 | throw XConfigRead(*this, CString("missing ") + type);
|
---|
2039 | }
|
---|
2040 |
|
---|
2041 | // find end of name
|
---|
2042 | CString::size_type j = line.find_first_of(" \t(" + delim, i);
|
---|
2043 | if (j == CString::npos) {
|
---|
2044 | j = line.length();
|
---|
2045 | }
|
---|
2046 |
|
---|
2047 | // save name
|
---|
2048 | name = line.substr(i, j - i);
|
---|
2049 | args.clear();
|
---|
2050 |
|
---|
2051 | // is it okay to not find a delimiter?
|
---|
2052 | bool needDelim = (!delim.empty() && delim.find('\n') == CString::npos);
|
---|
2053 |
|
---|
2054 | // skip whitespace
|
---|
2055 | i = line.find_first_not_of(" \t", j);
|
---|
2056 | if (i == CString::npos && needDelim) {
|
---|
2057 | // expected delimiter but didn't find it
|
---|
2058 | throw XConfigRead(*this, CString("missing ") + delim[0]);
|
---|
2059 | }
|
---|
2060 | if (i == CString::npos) {
|
---|
2061 | // no arguments
|
---|
2062 | index = line.length();
|
---|
2063 | return;
|
---|
2064 | }
|
---|
2065 | if (line[i] != '(') {
|
---|
2066 | // no arguments
|
---|
2067 | index = i;
|
---|
2068 | return;
|
---|
2069 | }
|
---|
2070 |
|
---|
2071 | // eat '('
|
---|
2072 | ++i;
|
---|
2073 |
|
---|
2074 | // parse arguments
|
---|
2075 | j = line.find_first_of(",)", i);
|
---|
2076 | while (j != CString::npos) {
|
---|
2077 | // extract arg
|
---|
2078 | CString arg(line.substr(i, j - i));
|
---|
2079 | i = j;
|
---|
2080 |
|
---|
2081 | // trim whitespace
|
---|
2082 | j = arg.find_first_not_of(" \t");
|
---|
2083 | if (j != CString::npos) {
|
---|
2084 | arg.erase(0, j);
|
---|
2085 | }
|
---|
2086 | j = arg.find_last_not_of(" \t");
|
---|
2087 | if (j != CString::npos) {
|
---|
2088 | arg.erase(j + 1);
|
---|
2089 | }
|
---|
2090 |
|
---|
2091 | // save arg
|
---|
2092 | args.push_back(arg);
|
---|
2093 |
|
---|
2094 | // exit loop at end of arguments
|
---|
2095 | if (line[i] == ')') {
|
---|
2096 | break;
|
---|
2097 | }
|
---|
2098 |
|
---|
2099 | // eat ','
|
---|
2100 | ++i;
|
---|
2101 |
|
---|
2102 | // next
|
---|
2103 | j = line.find_first_of(",)", i);
|
---|
2104 | }
|
---|
2105 |
|
---|
2106 | // verify ')'
|
---|
2107 | if (j == CString::npos) {
|
---|
2108 | // expected )
|
---|
2109 | throw XConfigRead(*this, "missing )");
|
---|
2110 | }
|
---|
2111 |
|
---|
2112 | // eat ')'
|
---|
2113 | ++i;
|
---|
2114 |
|
---|
2115 | // skip whitespace
|
---|
2116 | j = line.find_first_not_of(" \t", i);
|
---|
2117 | if (j == CString::npos && needDelim) {
|
---|
2118 | // expected delimiter but didn't find it
|
---|
2119 | throw XConfigRead(*this, CString("missing ") + delim[0]);
|
---|
2120 | }
|
---|
2121 |
|
---|
2122 | // verify delimiter
|
---|
2123 | if (needDelim && delim.find(line[j]) == CString::npos) {
|
---|
2124 | throw XConfigRead(*this, CString("expected ") + delim[0]);
|
---|
2125 | }
|
---|
2126 |
|
---|
2127 | if (j == CString::npos) {
|
---|
2128 | j = line.length();
|
---|
2129 | }
|
---|
2130 |
|
---|
2131 | index = j;
|
---|
2132 | return;
|
---|
2133 | }
|
---|
2134 |
|
---|
2135 | IPlatformScreen::CKeyInfo*
|
---|
2136 | CConfigReadContext::parseKeystroke(const CString& keystroke) const
|
---|
2137 | {
|
---|
2138 | return parseKeystroke(keystroke, std::set<CString>());
|
---|
2139 | }
|
---|
2140 |
|
---|
2141 | IPlatformScreen::CKeyInfo*
|
---|
2142 | CConfigReadContext::parseKeystroke(const CString& keystroke,
|
---|
2143 | const std::set<CString>& screens) const
|
---|
2144 | {
|
---|
2145 | CString s = keystroke;
|
---|
2146 |
|
---|
2147 | KeyModifierMask mask;
|
---|
2148 | if (!CKeyMap::parseModifiers(s, mask)) {
|
---|
2149 | throw XConfigRead(*this, "unable to parse key modifiers");
|
---|
2150 | }
|
---|
2151 |
|
---|
2152 | KeyID key;
|
---|
2153 | if (!CKeyMap::parseKey(s, key)) {
|
---|
2154 | throw XConfigRead(*this, "unable to parse key");
|
---|
2155 | }
|
---|
2156 |
|
---|
2157 | if (key == kKeyNone && mask == 0) {
|
---|
2158 | throw XConfigRead(*this, "missing key and/or modifiers in keystroke");
|
---|
2159 | }
|
---|
2160 |
|
---|
2161 | return IPlatformScreen::CKeyInfo::alloc(key, mask, 0, 0, screens);
|
---|
2162 | }
|
---|
2163 |
|
---|
2164 | IPlatformScreen::CButtonInfo*
|
---|
2165 | CConfigReadContext::parseMouse(const CString& mouse) const
|
---|
2166 | {
|
---|
2167 | CString s = mouse;
|
---|
2168 |
|
---|
2169 | KeyModifierMask mask;
|
---|
2170 | if (!CKeyMap::parseModifiers(s, mask)) {
|
---|
2171 | throw XConfigRead(*this, "unable to parse button modifiers");
|
---|
2172 | }
|
---|
2173 |
|
---|
2174 | char* end;
|
---|
2175 | ButtonID button = (ButtonID)strtol(s.c_str(), &end, 10);
|
---|
2176 | if (*end != '\0') {
|
---|
2177 | throw XConfigRead(*this, "unable to parse button");
|
---|
2178 | }
|
---|
2179 | if (s.empty() || button <= 0) {
|
---|
2180 | throw XConfigRead(*this, "invalid button");
|
---|
2181 | }
|
---|
2182 |
|
---|
2183 | return IPlatformScreen::CButtonInfo::alloc(button, mask);
|
---|
2184 | }
|
---|
2185 |
|
---|
2186 | KeyModifierMask
|
---|
2187 | CConfigReadContext::parseModifier(const CString& modifiers) const
|
---|
2188 | {
|
---|
2189 | CString s = modifiers;
|
---|
2190 |
|
---|
2191 | KeyModifierMask mask;
|
---|
2192 | if (!CKeyMap::parseModifiers(s, mask)) {
|
---|
2193 | throw XConfigRead(*this, "unable to parse modifiers");
|
---|
2194 | }
|
---|
2195 |
|
---|
2196 | if (mask == 0) {
|
---|
2197 | throw XConfigRead(*this, "no modifiers specified");
|
---|
2198 | }
|
---|
2199 |
|
---|
2200 | return mask;
|
---|
2201 | }
|
---|
2202 |
|
---|
2203 | CString
|
---|
2204 | CConfigReadContext::concatArgs(const ArgList& args)
|
---|
2205 | {
|
---|
2206 | CString s("(");
|
---|
2207 | for (size_t i = 0; i < args.size(); ++i) {
|
---|
2208 | if (i != 0) {
|
---|
2209 | s += ",";
|
---|
2210 | }
|
---|
2211 | s += args[i];
|
---|
2212 | }
|
---|
2213 | s += ")";
|
---|
2214 | return s;
|
---|
2215 | }
|
---|
2216 |
|
---|
2217 |
|
---|
2218 | //
|
---|
2219 | // CConfig I/O exceptions
|
---|
2220 | //
|
---|
2221 |
|
---|
2222 | XConfigRead::XConfigRead(const CConfigReadContext& context,
|
---|
2223 | const CString& error) :
|
---|
2224 | m_error(CStringUtil::print("line %d: %s",
|
---|
2225 | context.getLineNumber(), error.c_str()))
|
---|
2226 | {
|
---|
2227 | // do nothing
|
---|
2228 | }
|
---|
2229 |
|
---|
2230 | XConfigRead::XConfigRead(const CConfigReadContext& context,
|
---|
2231 | const char* errorFmt, const CString& arg) :
|
---|
2232 | m_error(CStringUtil::print("line %d: ", context.getLineNumber()) +
|
---|
2233 | CStringUtil::format(errorFmt, arg.c_str()))
|
---|
2234 | {
|
---|
2235 | // do nothing
|
---|
2236 | }
|
---|
2237 |
|
---|
2238 | XConfigRead::~XConfigRead()
|
---|
2239 | {
|
---|
2240 | // do nothing
|
---|
2241 | }
|
---|
2242 |
|
---|
2243 | CString
|
---|
2244 | XConfigRead::getWhat() const throw()
|
---|
2245 | {
|
---|
2246 | return format("XConfigRead", "read error: %{1}", m_error.c_str());
|
---|
2247 | }
|
---|