1/* 2 * Copyright 1999-2009 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jeremy Friesner 7 * Fredrik Mod��en 8 */ 9 10 11#include "CommandActuators.h" 12 13 14#include <stdio.h> 15#include <stdlib.h> 16#include <strings.h> 17 18#include <String.h> 19#include <Roster.h> 20#include <Alert.h> 21#include <Screen.h> 22#include <Rect.h> 23#include <View.h> 24#include <Directory.h> 25#include <Entry.h> 26#include <List.h> 27#include <Beep.h> 28 29 30#include "ParseCommandLine.h" 31#include "KeyInfos.h" 32 33#define IS_KEY_DOWN(msg) ((msg->what == B_KEY_DOWN) \ 34 || (msg->what == B_UNMAPPED_KEY_DOWN)) 35 36 37// factory function 38CommandActuator* 39CreateCommandActuator(const char* command) 40{ 41 CommandActuator* act = NULL; 42 int32 argc; 43 char** argv = ParseArgvFromString(command, argc); 44 if (command[0] == '*') { 45 if (argc > 0) { 46 char* c = argv[0] + 1; 47 if (strcmp(c, "InsertString") == 0) 48 act = new KeyStrokeSequenceCommandActuator(argc, argv); 49 else if (strcmp(c, "MoveMouse") == 0) 50 act = new MoveMouseByCommandActuator(argc, argv); 51 else if (strcmp(c, "MoveMouseTo") == 0) 52 act = new MoveMouseToCommandActuator(argc, argv); 53 else if (strcmp(c, "MouseButton") == 0) 54 act = new MouseButtonCommandActuator(argc, argv); 55 else if (strcmp(c, "LaunchHandler") == 0) 56 act = new MIMEHandlerCommandActuator(argc, argv); 57 else if (strcmp(c, "Multi") == 0) 58 act = new MultiCommandActuator(argc, argv); 59 else if (strcmp(c, "MouseDown") == 0) 60 act = new MouseDownCommandActuator(argc, argv); 61 else if (strcmp(c, "MouseUp") == 0) 62 act = new MouseUpCommandActuator(argc, argv); 63 else if (strcmp(c, "SendMessage") == 0) 64 act = new SendMessageCommandActuator(argc, argv); 65 else 66 act = new BeepCommandActuator(argc, argv); 67 } 68 } else 69 act = new LaunchCommandActuator(argc, argv); 70 71 FreeArgv(argv); 72 return act; 73} 74 75 76// #pragma mark - CommandActuator 77 78 79CommandActuator::CommandActuator(int32 argc, char** argv) 80{ 81} 82 83 84CommandActuator::CommandActuator(BMessage* from) 85 : 86 BArchivable(from) 87{ 88} 89 90 91status_t 92CommandActuator::Archive(BMessage* into, bool deep) const 93{ 94 status_t ret = BArchivable::Archive(into, deep); 95 return ret; 96} 97 98 99// #pragma mark - LaunchCommandActuator 100 101 102LaunchCommandActuator::LaunchCommandActuator(int32 argc, char** argv) 103 : 104 CommandActuator(argc, argv), 105 fArgv(CloneArgv(argv)), 106 fArgc(argc) 107{ 108} 109 110 111LaunchCommandActuator::LaunchCommandActuator(BMessage* from) 112 : 113 CommandActuator(from) 114{ 115 BList argList; 116 const char* temp; 117 int idx = 0; 118 while (from->FindString("largv", idx++, &temp) == B_OK) { 119 if (temp) { 120 char* copy = new char[strlen(temp) + 1]; 121 strcpy(copy, temp); 122 argList.AddItem(copy); 123 } 124 } 125 126 fArgc = argList.CountItems(); 127 fArgv = new char*[fArgc+ 1]; 128 129 for (int i = 0; i < fArgc; i++) 130 fArgv[i] = (char*) argList.ItemAt(i); 131 132 fArgv[fArgc] = NULL;// terminate the array 133} 134 135 136LaunchCommandActuator::~LaunchCommandActuator() 137{ 138 FreeArgv(fArgv); 139} 140 141 142filter_result 143LaunchCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 144 void** setAsyncData, BMessage* mouseMessage) 145{ 146 if (IS_KEY_DOWN(keyMessage)) { 147 // cause KeyEventAsync() to be called asynchronously 148 *setAsyncData = (void*) true; 149 } 150 return B_SKIP_MESSAGE; 151} 152 153 154status_t 155LaunchCommandActuator::Archive(BMessage* into, bool deep) const 156{ 157 status_t ret = CommandActuator::Archive(into, deep); 158 159 for (int i = 0; i < fArgc; i++) 160 into->AddString("largv", fArgv[i]); 161 162 return ret; 163} 164 165 166BArchivable* 167LaunchCommandActuator::Instantiate(BMessage* from) 168{ 169 if (validate_instantiation(from, "LaunchCommandActuator")) 170 return new LaunchCommandActuator(from); 171 else 172 return NULL; 173} 174 175 176void 177LaunchCommandActuator::KeyEventAsync(const BMessage* keyMessage, 178 void* asyncData) 179{ 180 if (be_roster == NULL) 181 return; 182 183 status_t result = B_OK; 184 BString string; 185 if (fArgc < 1) 186 string << "You didn't specify a command for this hotkey."; 187 else if ((result = LaunchCommand(fArgv, fArgc)) != B_OK) { 188 string << "Can't launch " << fArgv[0]; 189 string << ", no such file exists."; 190 string << " Please check your Shortcuts settings."; 191 } 192 193 if (fArgc < 1 || result != B_OK) { 194 BAlert* alert = new BAlert("Shortcuts launcher error", 195 string.String(), "OK"); 196 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 197 alert->Go(NULL); 198 } 199} 200 201 202// #pragma mark - MouseCommandActuator 203 204 205MouseCommandActuator::MouseCommandActuator(int32 argc, char** argv) 206 : 207 CommandActuator(argc, argv), 208 fWhichButtons(B_PRIMARY_MOUSE_BUTTON) 209{ 210 if (argc > 1) { 211 fWhichButtons = 0; 212 213 for (int i = 1; i < argc; i++) { 214 int buttonNumber = atoi(argv[i]); 215 216 switch(buttonNumber) { 217 case 1: 218 fWhichButtons |= B_PRIMARY_MOUSE_BUTTON; 219 break; 220 case 2: 221 fWhichButtons |= B_SECONDARY_MOUSE_BUTTON; 222 break; 223 case 3: 224 fWhichButtons |= B_TERTIARY_MOUSE_BUTTON; 225 break; 226 } 227 } 228 } 229} 230 231 232MouseCommandActuator::MouseCommandActuator(BMessage* from) 233 : 234 CommandActuator(from), 235 fWhichButtons(B_PRIMARY_MOUSE_BUTTON) 236{ 237 from->FindInt32("buttons", &fWhichButtons); 238} 239 240 241MouseCommandActuator::~MouseCommandActuator() 242{ 243} 244 245 246status_t 247MouseCommandActuator::Archive(BMessage* into, bool deep) const 248{ 249 status_t ret = CommandActuator::Archive(into, deep); 250 into->AddInt32("buttons", fWhichButtons); 251 return ret; 252} 253 254 255int32 256MouseCommandActuator::_GetWhichButtons() const 257{ 258 return fWhichButtons; 259} 260 261 262void 263MouseCommandActuator::_GenerateMouseButtonEvent(bool mouseDown, 264 const BMessage* keyMessage, BList* outList, BMessage* mouseMessage) 265{ 266 BMessage* fakeMouse = new BMessage(*mouseMessage); 267 fakeMouse->what = mouseDown ? B_MOUSE_DOWN : B_MOUSE_UP; 268 269 // Update the buttons to reflect which mouse buttons we are faking 270 fakeMouse->RemoveName("buttons"); 271 272 if (mouseDown) 273 fakeMouse->AddInt32("buttons", fWhichButtons); 274 275 // Trey sez you gotta keep then "when"'s increasing if you want 276 // click & drag to work! 277 int64 when; 278 279 const BMessage* lastMessage; 280 if (outList->CountItems() > 0) { 281 int32 last = outList->CountItems() - 1; 282 lastMessage = (const BMessage*)outList->ItemAt(last); 283 } else 284 lastMessage = keyMessage; 285 286 if (lastMessage->FindInt64("when", &when) == B_OK) { 287 when++; 288 fakeMouse->RemoveName("when"); 289 fakeMouse->AddInt64("when", when); 290 } 291 292 outList->AddItem(fakeMouse); 293} 294 295 296// #pragma mark - MouseDownCommandActuator 297 298 299MouseDownCommandActuator::MouseDownCommandActuator(int32 argc, char** argv) 300 : 301 MouseCommandActuator(argc, argv) 302{ 303} 304 305 306MouseDownCommandActuator::MouseDownCommandActuator(BMessage* from) 307 : 308 MouseCommandActuator(from) 309{ 310} 311 312 313MouseDownCommandActuator::~MouseDownCommandActuator() 314{ 315} 316 317 318filter_result 319MouseDownCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 320 void** setAsyncData, BMessage* mouseMessage) 321{ 322 if (IS_KEY_DOWN(keyMessage)) 323 _GenerateMouseButtonEvent(true, keyMessage, outList, mouseMessage); 324 325 return B_DISPATCH_MESSAGE; 326} 327 328 329status_t 330MouseDownCommandActuator::Archive(BMessage* into, bool deep) const 331{ 332 return MouseCommandActuator::Archive(into, deep); 333} 334 335 336BArchivable* 337MouseDownCommandActuator::Instantiate(BMessage* from) 338{ 339 if (validate_instantiation(from, "MouseDownCommandActuator")) 340 return new MouseDownCommandActuator(from); 341 else 342 return NULL; 343} 344 345 346// #pragma mark - MouseUpCommandActuator 347 348 349MouseUpCommandActuator::MouseUpCommandActuator(int32 argc, char** argv) 350 : 351 MouseCommandActuator(argc, argv) 352{ 353} 354 355 356MouseUpCommandActuator::MouseUpCommandActuator(BMessage* from) 357 : 358 MouseCommandActuator(from) 359{ 360} 361 362 363MouseUpCommandActuator::~MouseUpCommandActuator() 364{ 365} 366 367 368filter_result 369MouseUpCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 370 void** setAsyncData, BMessage* mouseMessage) 371{ 372 if (IS_KEY_DOWN(keyMessage)) 373 _GenerateMouseButtonEvent(false, keyMessage, outList, mouseMessage); 374 375 return B_DISPATCH_MESSAGE; 376} 377 378 379status_t 380MouseUpCommandActuator::Archive(BMessage* into, bool deep) const 381{ 382 return MouseCommandActuator::Archive(into, deep); 383} 384 385 386BArchivable* 387MouseUpCommandActuator::Instantiate(BMessage* from) 388{ 389 if (validate_instantiation(from, "MouseUpCommandActuator")) 390 return new MouseUpCommandActuator(from); 391 else 392 return NULL; 393} 394 395 396// #pragma mark - MouseButtonCommandActuator 397 398 399MouseButtonCommandActuator::MouseButtonCommandActuator(int32 argc, char** argv) 400 : 401 MouseCommandActuator(argc, argv), 402 fKeyDown(false) 403{ 404} 405 406 407MouseButtonCommandActuator::MouseButtonCommandActuator(BMessage* from) 408 : 409 MouseCommandActuator(from), 410 fKeyDown(false) 411{ 412} 413 414 415MouseButtonCommandActuator::~MouseButtonCommandActuator() 416{ 417} 418 419 420filter_result 421MouseButtonCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 422 void** setAsyncData, BMessage* mouseMessage) 423{ 424 if (IS_KEY_DOWN(keyMessage) != fKeyDown) { 425 _GenerateMouseButtonEvent(IS_KEY_DOWN(keyMessage), keyMessage, outList, 426 mouseMessage); 427 fKeyDown = IS_KEY_DOWN(keyMessage); 428 429 return B_DISPATCH_MESSAGE; 430 } else { 431 // This will handle key-repeats, which we don't want turned into lots 432 // of B_MOUSE_DOWN messages. 433 return B_SKIP_MESSAGE; 434 } 435} 436 437 438status_t 439MouseButtonCommandActuator::Archive(BMessage* into, bool deep) const 440{ 441 return MouseCommandActuator::Archive(into, deep); 442} 443 444 445BArchivable* 446MouseButtonCommandActuator::Instantiate(BMessage* from) 447{ 448 if (validate_instantiation(from, "MouseButtonCommandActuator")) 449 return new MouseButtonCommandActuator(from); 450 else 451 return NULL; 452} 453 454 455// #pragma mark - KeyStrokeSequenceCommandActuator 456 457 458KeyStrokeSequenceCommandActuator::KeyStrokeSequenceCommandActuator(int32 argc, 459 char** argv) 460 : 461 CommandActuator(argc, argv) 462{ 463 for (int s = 1; s < argc; s++) { 464 fSequence.Append(argv[s]); 465 if (s < argc - 1) 466 fSequence.Append(" "); 467 } 468 469 // Find any insert-unicode-here sequences and replace them with spaces... 470 int32 nextStart; 471 while ((nextStart = fSequence.FindFirst("$$")) >= 0) { 472 int32 nextEnd = fSequence.FindFirst("$$", nextStart + 2); 473 if (nextEnd >= 0) { 474 uint32 customKey= 0; 475 int32 unicodeVal= 0; 476 uint32 customMods = 0; 477 BString sub; 478 fSequence.CopyInto(sub, nextStart + 2, nextEnd-(nextStart + 2)); 479 sub.ToLower(); 480 481 if ((sub.FindFirst('-') >= 0) || ((sub.Length() > 0) 482 && ((sub.String()[0] < '0') || (sub.String()[0] > '9')))) { 483 484 const char* s = sub.String(); 485 while (*s == '-') s++;// go past any initial dashes 486 487 bool lastWasDash = true; 488 while (*s) { 489 if (lastWasDash) { 490 if (strncmp(s, "shift",5) == 0) 491 customMods |=B_LEFT_SHIFT_KEY| B_SHIFT_KEY; 492 else if (strncmp(s, "leftsh", 6) == 0) 493 customMods |=B_LEFT_SHIFT_KEY| B_SHIFT_KEY; 494 else if (strncmp(s, "rightsh",7) == 0) 495 customMods |=B_RIGHT_SHIFT_KEY | B_SHIFT_KEY; 496 else if (strncmp(s, "alt",3) == 0) 497 customMods |=B_LEFT_COMMAND_KEY| B_COMMAND_KEY; 498 else if (strncmp(s, "leftalt",7) == 0) 499 customMods |=B_LEFT_COMMAND_KEY| B_COMMAND_KEY; 500 else if (strncmp(s, "rightalt", 8) == 0) 501 customMods |=B_RIGHT_COMMAND_KEY | B_COMMAND_KEY; 502 else if (strncmp(s, "com",3) == 0) 503 customMods |=B_LEFT_COMMAND_KEY| B_COMMAND_KEY; 504 else if (strncmp(s, "leftcom",7) == 0) 505 customMods |=B_LEFT_COMMAND_KEY| B_COMMAND_KEY; 506 else if (strncmp(s, "rightcom", 8) == 0) 507 customMods |=B_RIGHT_COMMAND_KEY | B_COMMAND_KEY; 508 else if (strncmp(s, "con",3) == 0) 509 customMods |=B_LEFT_CONTROL_KEY| B_CONTROL_KEY; 510 else if (strncmp(s, "leftcon",7) == 0) 511 customMods |=B_LEFT_CONTROL_KEY| B_CONTROL_KEY; 512 else if (strncmp(s, "rightcon", 8) == 0) 513 customMods |=B_RIGHT_CONTROL_KEY | B_CONTROL_KEY; 514 else if (strncmp(s, "win",3) == 0) 515 customMods |=B_LEFT_OPTION_KEY | B_OPTION_KEY; 516 else if (strncmp(s, "leftwin",7) == 0) 517 customMods |=B_LEFT_OPTION_KEY | B_OPTION_KEY; 518 else if (strncmp(s, "rightwin", 8) == 0) 519 customMods |=B_RIGHT_OPTION_KEY| B_OPTION_KEY; 520 else if (strncmp(s, "opt",3) == 0) 521 customMods |=B_LEFT_OPTION_KEY | B_OPTION_KEY; 522 else if (strncmp(s, "leftopt",7) == 0) 523 customMods |=B_LEFT_OPTION_KEY | B_OPTION_KEY; 524 else if (strncmp(s, "rightopt", 8) == 0) 525 customMods |=B_RIGHT_OPTION_KEY| B_OPTION_KEY; 526 else if (strncmp(s, "menu", 4) == 0) 527 customMods |=B_MENU_KEY; 528 else if (strncmp(s, "caps", 4) == 0) 529 customMods |=B_CAPS_LOCK; 530 else if (strncmp(s, "scroll", 6) == 0) 531 customMods |=B_SCROLL_LOCK; 532 else if (strncmp(s, "num",3) == 0) 533 customMods |=B_NUM_LOCK; 534 else if (customKey == 0) { 535 BString arg = s; 536 int32 dashIdx = arg.FindFirst('-'); 537 538 if (dashIdx >= 0) 539 arg.Truncate(dashIdx); 540 541 uint32 key = (uint32)FindKeyCode(arg.String()); 542 543 if (key > 0) { 544 customKey = key; 545 const char* u = GetKeyUTF8(key); 546 547 //Parse the UTF8 back into an int32 548 switch(strlen(u)) { 549 case 1: 550 unicodeVal = ((uint32)(u[0]&0x7F)); 551 break; 552 case 2: 553 unicodeVal = ((uint32)(u[1]&0x3F)) | 554 (((uint32)(u[0]&0x1F)) << 6); 555 break; 556 case 3: 557 unicodeVal = ((uint32)(u[2]&0x3F)) | 558 (((uint32)(u[1]&0x3F)) << 6) | 559 (((uint32)(u[0]&0x0F)) << 12); 560 break; 561 default: unicodeVal = 0; 562 break; 563 } 564 } 565 } 566 lastWasDash = false; 567 } else 568 lastWasDash = (*s == '-'); 569 570 s++; 571 } 572 573 // If we have a letter, try to make it the correct case 574 if ((unicodeVal >= 'A') && (unicodeVal <= 'Z')) { 575 if ((customMods & B_SHIFT_KEY) == 0) 576 unicodeVal += 'a'-'A'; 577 } else if ((unicodeVal >= 'a') && (unicodeVal <= 'z')) { 578 if ((customMods & B_SHIFT_KEY) != 0) 579 unicodeVal -= 'a'-'A'; 580 } 581 } else { 582 unicodeVal = strtol(&(fSequence.String())[nextStart + 2], 583 NULL, 0); 584 customMods = (uint32) -1; 585 } 586 587 if (unicodeVal == 0) 588 unicodeVal = ' '; 589 590 BString newString = fSequence; 591 newString.Truncate(nextStart); 592 fOverrides.AddItem((void*)(addr_t)unicodeVal); 593 fOverrideOffsets.AddItem((void*)(addr_t)newString.Length()); 594 fOverrideModifiers.AddItem((void*)(addr_t)customMods); 595 fOverrideKeyCodes.AddItem((void*)(addr_t)customKey); 596 newString.Append((unicodeVal > 0 597 && unicodeVal < 127) ? (char)unicodeVal : ' ', 1); 598 newString.Append(&fSequence.String()[nextEnd + 2]); 599 fSequence = newString; 600 } else 601 break; 602 } 603 604 _GenerateKeyCodes(); 605} 606 607 608KeyStrokeSequenceCommandActuator::KeyStrokeSequenceCommandActuator( 609 BMessage* from) 610 : 611 CommandActuator(from) 612{ 613 const char* sequence; 614 if (from->FindString("sequence", 0, &sequence) == B_OK) 615 fSequence = sequence; 616 617 int32 temp; 618 for (int32 i = 0; from->FindInt32("ooffsets", i, &temp) == B_OK; i++) { 619 fOverrideOffsets.AddItem((void*)(addr_t)temp); 620 621 if (from->FindInt32("overrides", i, &temp) != B_OK) 622 temp = ' '; 623 624 fOverrides.AddItem((void*)(addr_t)temp); 625 626 if (from->FindInt32("omods", i, &temp) != B_OK) 627 temp = -1; 628 629 fOverrideModifiers.AddItem((void*)(addr_t)temp); 630 631 if (from->FindInt32("okeys", i, &temp) != B_OK) 632 temp = 0; 633 634 fOverrideKeyCodes.AddItem((void*)(addr_t)temp); 635 } 636 637 _GenerateKeyCodes(); 638} 639 640 641KeyStrokeSequenceCommandActuator::~KeyStrokeSequenceCommandActuator() 642{ 643 delete[] fKeyCodes; 644 delete[] fModCodes; 645 delete[] fStates; 646} 647 648 649void 650KeyStrokeSequenceCommandActuator::_GenerateKeyCodes() 651{ 652 int slen = fSequence.Length(); 653 fKeyCodes = new int32[slen]; 654 fModCodes = new int32[slen]; 655 fStates = new uint8[slen * 16]; 656 657 memset(fStates, 0, slen * 16); 658 659 key_map* map; 660 char* keys; 661 get_key_map(&map, &keys); 662 for (int i = 0; i < slen; i++) { 663 uint32 overrideKey = 0; 664 uint32 overrideMods = (uint32)-1; 665 for (int32 j = fOverrideOffsets.CountItems()-1; j >= 0; j--) { 666 if ((int32)(addr_t)fOverrideOffsets.ItemAt(j) == i) { 667 overrideKey= (uint32)(addr_t) fOverrideKeyCodes.ItemAt(j); 668 overrideMods = (uint32)(addr_t) fOverrideModifiers.ItemAt(j); 669 break; 670 } 671 } 672 673 uint8* states = &fStates[i * 16]; 674 int32& modCode = fModCodes[i]; 675 if (overrideKey == 0) { 676 // Gotta do reverse-lookups to find out the raw keycodes for a 677 // given character. Expensive--there oughtta be a better way to do 678 // this. 679 char next = fSequence.ByteAt(i); 680 int32 key = _LookupKeyCode(map, keys, map->normal_map, next, 681 states, modCode, 0); 682 if (key < 0) { 683 key = _LookupKeyCode(map, keys, map->shift_map, next, states, 684 modCode, B_LEFT_SHIFT_KEY | B_SHIFT_KEY); 685 } 686 687 if (key < 0) { 688 key = _LookupKeyCode(map, keys, map->caps_map, next, states, 689 modCode, B_CAPS_LOCK); 690 } 691 692 if (key < 0) { 693 key = _LookupKeyCode(map, keys, map->caps_shift_map, next, 694 states, modCode, 695 B_LEFT_SHIFT_KEY | B_SHIFT_KEY | B_CAPS_LOCK); 696 } 697 698 if (key < 0) { 699 key = _LookupKeyCode(map, keys, map->option_map, next, states, 700 modCode, B_LEFT_OPTION_KEY | B_OPTION_KEY); 701 } 702 703 if (key < 0) { 704 key = _LookupKeyCode(map, keys, map->option_shift_map, next, 705 states, modCode, B_LEFT_OPTION_KEY | B_OPTION_KEY 706 | B_LEFT_SHIFT_KEY | B_SHIFT_KEY); 707 } 708 709 if (key < 0) { 710 key = _LookupKeyCode(map, keys, map->option_caps_map, next, 711 states, modCode, 712 B_LEFT_OPTION_KEY | B_OPTION_KEY | B_CAPS_LOCK); 713 } 714 715 if (key < 0) { 716 key = _LookupKeyCode(map, keys, map->option_caps_shift_map, 717 next, states, modCode, B_LEFT_OPTION_KEY | B_OPTION_KEY 718 | B_CAPS_LOCK | B_LEFT_SHIFT_KEY | B_SHIFT_KEY); 719 } 720 721 if (key < 0) { 722 key = _LookupKeyCode(map, keys, map->control_map, next, states, 723 modCode, B_CONTROL_KEY); 724 } 725 726 fKeyCodes[i] = key >= 0 ? key : 0; 727 } 728 729 if (overrideMods != (uint32)-1) { 730 modCode = (int32)overrideMods; 731 732 // Clear any bits that might have been set by the lookups... 733 _SetStateBit(states, map->caps_key, false); 734 _SetStateBit(states, map->scroll_key, false); 735 _SetStateBit(states, map->num_key, false); 736 _SetStateBit(states, map->menu_key, false); 737 _SetStateBit(states, map->left_shift_key, false); 738 _SetStateBit(states, map->right_shift_key, false); 739 _SetStateBit(states, map->left_command_key, false); 740 _SetStateBit(states, map->right_command_key, false); 741 _SetStateBit(states, map->left_control_key, false); 742 _SetStateBit(states, map->right_control_key, false); 743 _SetStateBit(states, map->left_option_key, false); 744 _SetStateBit(states, map->right_option_key, false); 745 746 // And then set any bits that were specified in our override. 747 if (modCode & B_CAPS_LOCK) 748 _SetStateBit(states, map->caps_key); 749 750 if (modCode & B_SCROLL_LOCK) 751 _SetStateBit(states, map->scroll_key); 752 753 if (modCode & B_NUM_LOCK) 754 _SetStateBit(states, map->num_key); 755 756 if (modCode & B_MENU_KEY) 757 _SetStateBit(states, map->menu_key); 758 759 if (modCode & B_LEFT_SHIFT_KEY) 760 _SetStateBit(states, map->left_shift_key); 761 762 if (modCode & B_RIGHT_SHIFT_KEY) 763 _SetStateBit(states, map->right_shift_key); 764 765 if (modCode & B_LEFT_COMMAND_KEY) 766 _SetStateBit(states, map->left_command_key); 767 768 if (modCode & B_RIGHT_COMMAND_KEY) 769 _SetStateBit(states, map->right_command_key); 770 771 if (modCode & B_LEFT_CONTROL_KEY) 772 _SetStateBit(states, map->left_control_key); 773 774 if (modCode & B_RIGHT_CONTROL_KEY) 775 _SetStateBit(states, map->right_control_key); 776 777 if (modCode & B_LEFT_OPTION_KEY) 778 _SetStateBit(states, map->left_option_key); 779 780 if (modCode & B_RIGHT_OPTION_KEY) 781 _SetStateBit(states, map->right_option_key); 782 } 783 784 if (overrideKey > 0) { 785 if (overrideKey > 127) { 786 // invalid value? 787 overrideKey = 0; 788 } 789 790 fKeyCodes[i] = overrideKey; 791 _SetStateBit(states, overrideKey); 792 } 793 } 794 795 free(keys); 796 free(map); 797} 798 799 800int32 801KeyStrokeSequenceCommandActuator::_LookupKeyCode(key_map* map, char* keys, 802 int32 offsets[128], char c, uint8* setStates, int32& setModifier, 803 int32 setTo) const 804{ 805 for (int i = 0; i < 128; i++) { 806 if (keys[offsets[i]+ 1] == c) { 807 _SetStateBit(setStates, i); 808 809 if (setTo & B_SHIFT_KEY) 810 _SetStateBit(setStates, map->left_shift_key); 811 812 if (setTo & B_OPTION_KEY) 813 _SetStateBit(setStates, map->left_option_key); 814 815 if (setTo & B_CONTROL_KEY) 816 _SetStateBit(setStates, map->left_control_key); 817 818 if (setTo & B_CAPS_LOCK) 819 _SetStateBit(setStates, map->caps_key); 820 821 setModifier = setTo; 822 823 return i; 824 } 825 } 826 827 return -1; 828} 829 830 831void 832KeyStrokeSequenceCommandActuator::_SetStateBit(uint8* setStates, uint32 key, 833 bool on) const 834{ 835 if (on) 836 setStates[key / 8] |= (0x80 >> (key % 8)); 837 else 838 setStates[key / 8] &= ~(0x80 >> (key % 8)); 839} 840 841 842status_t 843KeyStrokeSequenceCommandActuator::Archive(BMessage* into, bool deep) const 844{ 845 status_t result = CommandActuator::Archive(into, deep); 846 if (result != B_OK) 847 return result; 848 849 into->AddString("sequence", fSequence.String()); 850 int32 numOverrides = fOverrideOffsets.CountItems(); 851 852 status_t overridesResult = B_OK; 853 for (int32 i = 0; i < numOverrides; i++) { 854 result = into->AddInt32("ooffsets", 855 (int32)(addr_t)fOverrideOffsets.ItemAt(i)); 856 if (result != B_OK) 857 overridesResult = B_ERROR; 858 859 result = into->AddInt32("overrides", 860 (int32)(addr_t)fOverrides.ItemAt(i)); 861 if (result != B_OK) 862 overridesResult = B_ERROR; 863 864 result = into->AddInt32("omods", 865 (int32)(addr_t)fOverrideModifiers.ItemAt(i)); 866 if (result != B_OK) 867 overridesResult = B_ERROR; 868 869 result = into->AddInt32("okeys", 870 (int32)(addr_t)fOverrideKeyCodes.ItemAt(i)); 871 } 872 873 return overridesResult == B_ERROR ? B_ERROR : result; 874} 875 876 877filter_result 878KeyStrokeSequenceCommandActuator::KeyEvent(const BMessage* keyMessage, 879 BList* outList, void** setAsyncData, BMessage* mouseMessage) 880{ 881 if (IS_KEY_DOWN(keyMessage)) { 882 BMessage temp(*keyMessage); 883 int numChars = fSequence.Length(); 884 for (int i = 0; i < numChars; i++) { 885 char nextChar = fSequence.ByteAt(i); 886 887 temp.RemoveName("modifiers"); 888 temp.AddInt32("modifiers", fModCodes[i]); 889 temp.RemoveName("key"); 890 temp.AddInt32("key", fKeyCodes[i]); 891 temp.RemoveName("raw_char"); 892 temp.AddInt32("raw_char", (int32) nextChar); 893 temp.RemoveName("byte"); 894 895 int32 override = -1; 896 for (int32 j = fOverrideOffsets.CountItems()-1; j >= 0; j--) { 897 int32 offset = (int32)(addr_t) fOverrideOffsets.ItemAt(j); 898 if (offset == i) { 899 override = (int32)(addr_t) fOverrides.ItemAt(j); 900 break; 901 } 902 } 903 904 char t[4]; 905 if (override >= 0) { 906 if (override < 0x80) { 907 // one-byte encoding 908 t[0] = (char) override; 909 t[1] = 0x00; 910 } else if (override < 0x800) { 911 // two-byte encoding 912 t[0] = 0xC0 | ((char)((override & 0x7C0)>>6)); 913 t[1] = 0x80 | ((char)((override & 0x03F)>>0)); 914 t[2] = 0x00; 915 } else { 916 // three-byte encoding 917 t[0] = 0xE0 | ((char)((override & 0xF000)>>12)); 918 t[1] = 0x80 | ((char)((override & 0x0FC0)>>6)); 919 t[2] = 0x80 | ((char)((override & 0x003F)>>0)); 920 t[3] = 0x00; 921 } 922 } else { 923 t[0] = nextChar; 924 t[1] = 0x00; 925 } 926 927 temp.RemoveName("byte"); 928 929 for (int m = 0; t[m] != 0x00; m++) 930 temp.AddInt8("byte", t[m]); 931 932 temp.RemoveName("states"); 933 temp.AddData("states", B_UINT8_TYPE, &fStates[i * 16], 16, true, 16); 934 temp.RemoveName("bytes"); 935 temp.AddString("bytes", t); 936 temp.what = B_KEY_DOWN; 937 outList->AddItem(new BMessage(temp)); 938 temp.what = B_KEY_UP; 939 outList->AddItem(new BMessage(temp)); 940 } 941 942 return B_DISPATCH_MESSAGE; 943 } else 944 return B_SKIP_MESSAGE; 945} 946 947 948BArchivable* 949KeyStrokeSequenceCommandActuator::Instantiate(BMessage* from) 950{ 951 if (validate_instantiation(from, "KeyStrokeSequenceCommandActuator")) 952 return new KeyStrokeSequenceCommandActuator(from); 953 else 954 return NULL; 955} 956 957 958// #pragma mark - MIMEHandlerCommandActuator 959 960 961MIMEHandlerCommandActuator::MIMEHandlerCommandActuator(int32 argc, char** argv) 962 : 963 CommandActuator(argc, argv), 964 fMimeType((argc > 1) ? argv[1] : "") 965{ 966} 967 968 969MIMEHandlerCommandActuator::MIMEHandlerCommandActuator(BMessage* from) 970 : 971 CommandActuator(from) 972{ 973 const char* temp; 974 if (from->FindString("mimeType", 0, &temp) == B_OK) 975 fMimeType = temp; 976} 977 978 979MIMEHandlerCommandActuator::~MIMEHandlerCommandActuator() 980{ 981} 982 983 984status_t 985MIMEHandlerCommandActuator::Archive(BMessage* into, bool deep) const 986{ 987 status_t ret = CommandActuator::Archive(into, deep); 988 into->AddString("mimeType", fMimeType.String()); 989 return ret; 990} 991 992 993filter_result 994MIMEHandlerCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 995 void** setAsyncData, BMessage* mouseMessage) 996{ 997 if (IS_KEY_DOWN(keyMessage)) 998 // cause KeyEventAsync() to be called asynchronously 999 *setAsyncData = (void*) true; 1000 return B_SKIP_MESSAGE; 1001} 1002 1003 1004void 1005MIMEHandlerCommandActuator::KeyEventAsync(const BMessage* keyMessage, 1006 void* asyncData) 1007{ 1008 if (be_roster == NULL) 1009 return; 1010 1011 BString string; 1012 status_t ret = be_roster->Launch(fMimeType.String()); 1013 if ((ret != B_OK) && (ret != B_ALREADY_RUNNING)) { 1014 string << "Can't launch handler for "; 1015 string << ", no such MIME type exists. Please check your Shortcuts"; 1016 string << " settings."; 1017 BAlert* alert = new BAlert("Shortcuts MIME launcher error", 1018 string.String(), "OK"); 1019 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 1020 alert->Go(NULL); 1021 } 1022} 1023 1024 1025BArchivable* MIMEHandlerCommandActuator::Instantiate(BMessage* from) 1026{ 1027 if (validate_instantiation(from, "MIMEHandlerCommandActuator")) 1028 return new MIMEHandlerCommandActuator(from); 1029 else 1030 return NULL; 1031} 1032 1033 1034// #pragma mark - BeepCommandActuator 1035 1036 1037BeepCommandActuator::BeepCommandActuator(int32 argc, char** argv) 1038 : 1039 CommandActuator(argc, argv) 1040{ 1041} 1042 1043 1044BeepCommandActuator::BeepCommandActuator(BMessage* from) 1045 : 1046 CommandActuator(from) 1047{ 1048} 1049 1050 1051BeepCommandActuator::~BeepCommandActuator() 1052{ 1053} 1054 1055 1056status_t 1057BeepCommandActuator::Archive(BMessage* into, bool deep) const 1058{ 1059 return CommandActuator::Archive(into, deep); 1060} 1061 1062 1063BArchivable* 1064BeepCommandActuator::Instantiate(BMessage* from) 1065{ 1066 if (validate_instantiation(from, "BeepCommandActuator")) 1067 return new BeepCommandActuator(from); 1068 else 1069 return NULL; 1070} 1071 1072 1073filter_result 1074BeepCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 1075 void** setAsyncData, BMessage* mouseMessage) 1076{ 1077 if (IS_KEY_DOWN(keyMessage)) 1078 beep(); 1079 1080 return B_SKIP_MESSAGE; 1081} 1082 1083 1084// #pragma mark - MultiCommandActuator 1085 1086 1087MultiCommandActuator::MultiCommandActuator(BMessage* from) 1088 : 1089 CommandActuator(from) 1090{ 1091 BMessage msg; 1092 for (int i = 0; from->FindMessage("subs", i, &msg) == B_OK; i++) { 1093 BArchivable* subObj = instantiate_object(&msg); 1094 if (subObj) { 1095 CommandActuator* ca = dynamic_cast < CommandActuator*>(subObj); 1096 1097 if (ca) 1098 fSubActuators.AddItem(ca); 1099 else 1100 delete subObj; 1101 } 1102 } 1103} 1104 1105 1106MultiCommandActuator::MultiCommandActuator(int32 argc, char** argv) 1107 : 1108 CommandActuator(argc, argv) 1109{ 1110 for (int i = 1; i < argc; i++) { 1111 CommandActuator* sub = CreateCommandActuator(argv[i]); 1112 1113 if (sub) 1114 fSubActuators.AddItem(sub); 1115 else 1116 printf("Error creating subActuator from [%s]\n", argv[i]); 1117 } 1118} 1119 1120 1121MultiCommandActuator::~MultiCommandActuator() 1122{ 1123 int numSubs = fSubActuators.CountItems(); 1124 for (int i = 0; i < numSubs; i++) 1125 delete ((CommandActuator*) fSubActuators.ItemAt(i)); 1126} 1127 1128 1129status_t 1130MultiCommandActuator::Archive(BMessage* into, bool deep) const 1131{ 1132 status_t ret = CommandActuator::Archive(into, deep); 1133 if (ret != B_OK) 1134 return ret; 1135 1136 int numSubs = fSubActuators.CountItems(); 1137 for (int i = 0; i < numSubs; i++) { 1138 BMessage msg; 1139 ret = ((CommandActuator*)fSubActuators.ItemAt(i))->Archive(&msg, deep); 1140 1141 if (ret != B_OK) 1142 return ret; 1143 1144 into->AddMessage("subs", &msg); 1145 } 1146 return B_OK; 1147} 1148 1149 1150BArchivable* 1151MultiCommandActuator::Instantiate(BMessage* from) 1152{ 1153 if (validate_instantiation(from, "MultiCommandActuator")) 1154 return new MultiCommandActuator(from); 1155 else 1156 return NULL; 1157} 1158 1159 1160filter_result 1161MultiCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 1162 void** asyncData, BMessage* mouseMessage) 1163{ 1164 BList* aDataList = NULL; // demand-allocated 1165 filter_result res = B_SKIP_MESSAGE; 1166 int numSubs = fSubActuators.CountItems(); 1167 for (int i = 0; i < numSubs; i++) { 1168 void* aData = NULL; 1169 status_t next = ((CommandActuator*)fSubActuators.ItemAt(i))-> 1170 KeyEvent(keyMessage, outList, &aData, mouseMessage); 1171 1172 if (next == B_DISPATCH_MESSAGE) 1173 // dispatch message if at least one sub wants it dispatched 1174 res = B_DISPATCH_MESSAGE; 1175 1176 if (aData) { 1177 if (aDataList == NULL) 1178 *asyncData = aDataList = new BList; 1179 1180 while (aDataList->CountItems() < i - 1) 1181 aDataList->AddItem(NULL); 1182 aDataList->AddItem(aData); 1183 } 1184 } 1185 return res; 1186} 1187 1188 1189void 1190MultiCommandActuator::KeyEventAsync(const BMessage* keyUpMsg, void* asyncData) 1191{ 1192 BList* list = (BList*) asyncData; 1193 int numSubs = list->CountItems(); 1194 for (int i = 0; i < numSubs; i++) { 1195 void* aData = list->ItemAt(i); 1196 if (aData) 1197 ((CommandActuator*) fSubActuators.ItemAt(i))-> 1198 KeyEventAsync(keyUpMsg, aData); 1199 } 1200 delete list; 1201} 1202 1203 1204// #pragma mark - MoveMouseCommandActuator 1205 1206 1207MoveMouseCommandActuator::MoveMouseCommandActuator(BMessage* from) 1208 : 1209 CommandActuator(from) 1210{ 1211 if (from->FindFloat("xPercent", &fXPercent) != B_OK) 1212 fXPercent = 0.0f; 1213 1214 if (from->FindFloat("yPercent", &fYPercent) != B_OK) 1215 fYPercent = 0.0f; 1216 1217 if (from->FindFloat("xPixels", &fXPixels) != B_OK) 1218 fXPixels = 0; 1219 1220 if (from->FindFloat("yPixels", &fYPixels) != B_OK) 1221 fYPixels = 0; 1222} 1223 1224 1225MoveMouseCommandActuator::MoveMouseCommandActuator(int32 argc, char** argv) 1226 : 1227 CommandActuator(argc, argv), 1228 fXPercent(0.0f), 1229 fYPercent(0.0f), 1230 fXPixels(0), 1231 fYPixels(0) 1232{ 1233 if (argc > 1) 1234 _ParseArg(argv[1], fXPercent, fXPixels); 1235 1236 if (argc > 2) 1237 _ParseArg(argv[2], fYPercent, fYPixels); 1238} 1239 1240 1241MoveMouseCommandActuator::~MoveMouseCommandActuator() 1242{ 1243} 1244 1245 1246status_t 1247MoveMouseCommandActuator::Archive(BMessage* into, bool deep) const 1248{ 1249 status_t ret = CommandActuator::Archive(into, deep); 1250 into->AddFloat("xPercent", fXPercent); 1251 into->AddFloat("yPercent", fYPercent); 1252 into->AddFloat("xPixels", fXPixels); 1253 into->AddFloat("yPixels", fYPixels); 1254 return ret; 1255} 1256 1257 1258void 1259MoveMouseCommandActuator::CalculateCoords(float& setX, float& setY) const 1260{ 1261 BScreen s; 1262 BRect frame = s.Frame(); 1263 setX = (frame.Width() * fXPercent) + fXPixels; 1264 setY = (frame.Height() * fYPercent) + fYPixels; 1265} 1266 1267 1268BMessage* 1269MoveMouseCommandActuator::CreateMouseMessage(const BMessage* original, 1270 BPoint where, BList* outList) const 1271{ 1272 // Force where into the screen space 1273 { 1274 BScreen screen; 1275 where.ConstrainTo(screen.Frame()); 1276 } 1277 1278 BMessage* newMessage = new BMessage(B_MOUSE_MOVED); 1279 1280 newMessage->AddPoint("where", where); 1281 1282 int32 buttons = 0; 1283 (void)original->FindInt32("buttons", &buttons); 1284 1285 if (buttons == 0) 1286 buttons = 1; 1287 1288 newMessage->AddInt32("buttons", buttons); 1289 1290 // Trey sez you gotta keep then "when"'s increasing if you want click&drag 1291 // to work! 1292 const BMessage* lastMessage; 1293 int32 last = outList->CountItems() - 1; 1294 1295 if (outList->CountItems() > 0) 1296 lastMessage = (const BMessage*)outList->ItemAt(last); 1297 else 1298 lastMessage = original; 1299 1300 int64 when; 1301 1302 if (lastMessage->FindInt64("when", &when) == B_OK) { 1303 when++; 1304 newMessage->RemoveName("when"); 1305 newMessage->AddInt64("when", when); 1306 } 1307 return newMessage; 1308} 1309 1310 1311static bool IsNumeric(char c); 1312static bool IsNumeric(char c) 1313{ 1314 return (((c >= '0') && (c <= '9')) || (c == '.') || (c == '-')); 1315} 1316 1317 1318// Parse a string of the form "10", "10%", "10+ 10%", or "10%+ 10" 1319void 1320MoveMouseCommandActuator::_ParseArg(const char* arg, float& setPercent, 1321 float& setPixels) const 1322{ 1323 char* temp = new char[strlen(arg) + 1]; 1324 strcpy(temp, arg); 1325 1326 // Find the percent part, if any 1327 char* percent = strchr(temp, '%'); 1328 if (percent) { 1329 // Rewind to one before the beginning of the number 1330 char* beginNum = percent - 1; 1331 while (beginNum >= temp) { 1332 char c = *beginNum; 1333 if (IsNumeric(c)) 1334 beginNum--; 1335 else 1336 break; 1337 } 1338 1339 // parse the number 1340 setPercent = atof(++beginNum)/100.0f; 1341 1342 // Now white it out to ease finding the other # 1343 while (beginNum <= percent) 1344 *(beginNum++) = ' '; 1345 } 1346 1347 // Find the pixel part, if any 1348 char* pixel = temp; 1349 while (!IsNumeric(*pixel)) { 1350 if (*pixel == '\0') 1351 break; 1352 pixel++; 1353 } 1354 setPixels = atof(pixel); 1355 delete [] temp; 1356} 1357 1358 1359// #pragma mark - MoveMouseToCommandActuator 1360 1361 1362MoveMouseToCommandActuator::MoveMouseToCommandActuator(BMessage* from) 1363 : 1364 MoveMouseCommandActuator(from) 1365{ 1366} 1367 1368 1369MoveMouseToCommandActuator::MoveMouseToCommandActuator(int32 argc, char** argv) 1370 : 1371 MoveMouseCommandActuator(argc, argv) 1372{ 1373} 1374 1375 1376MoveMouseToCommandActuator::~MoveMouseToCommandActuator() 1377{ 1378} 1379 1380 1381status_t 1382MoveMouseToCommandActuator::Archive(BMessage* into, bool deep) const 1383{ 1384 return MoveMouseCommandActuator::Archive(into, deep); 1385} 1386 1387 1388BArchivable* 1389MoveMouseToCommandActuator::Instantiate(BMessage* from) 1390{ 1391 if (validate_instantiation(from, "MoveMouseToCommandActuator")) 1392 return new MoveMouseToCommandActuator(from); 1393 else 1394 return NULL; 1395} 1396 1397 1398filter_result 1399MoveMouseToCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 1400 void** setAsyncData, BMessage* mouseMessage) 1401{ 1402 if (IS_KEY_DOWN(keyMessage)) { 1403 float x, y; 1404 CalculateCoords(x, y); 1405 BPoint where(x, y); 1406 BMessage* newMessage = CreateMouseMessage(keyMessage, where, outList); 1407 *mouseMessage = *newMessage; 1408 outList->AddItem(newMessage); 1409 1410 return B_DISPATCH_MESSAGE; 1411 } 1412 1413 return B_SKIP_MESSAGE; 1414} 1415 1416 1417// #pragma mark - MoveMouseByCommandActuator 1418 1419 1420MoveMouseByCommandActuator::MoveMouseByCommandActuator(BMessage* from) 1421 : 1422 MoveMouseCommandActuator(from) 1423{ 1424} 1425 1426 1427MoveMouseByCommandActuator::MoveMouseByCommandActuator(int32 argc, char** argv) 1428 : 1429 MoveMouseCommandActuator(argc, argv) 1430{ 1431} 1432 1433 1434MoveMouseByCommandActuator::~MoveMouseByCommandActuator() 1435{ 1436} 1437 1438 1439status_t MoveMouseByCommandActuator::Archive(BMessage* into, bool deep) const 1440{ 1441 status_t ret = MoveMouseCommandActuator::Archive(into, deep); 1442 return ret; 1443} 1444 1445 1446BArchivable* 1447MoveMouseByCommandActuator::Instantiate(BMessage* from) 1448{ 1449 if (validate_instantiation(from, "MoveMouseByCommandActuator")) 1450 return new MoveMouseByCommandActuator(from); 1451 else 1452 return NULL; 1453} 1454 1455 1456filter_result 1457MoveMouseByCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 1458 void** setAsyncData, BMessage* mouseMessage) 1459{ 1460 if (IS_KEY_DOWN(keyMessage)) { 1461 // Get the current mouse position 1462 BPoint where; 1463 if (mouseMessage->FindPoint("where", &where) == B_OK) { 1464 // Get the desired offset 1465 BPoint diff; 1466 CalculateCoords(diff.x, diff.y); 1467 where += diff; 1468 BMessage* newMessage = CreateMouseMessage(keyMessage, where, outList); 1469 *mouseMessage = *newMessage; 1470 outList->AddItem(newMessage); 1471 return B_DISPATCH_MESSAGE; 1472 } 1473 } 1474 return B_SKIP_MESSAGE; 1475} 1476 1477 1478// #pragma mark - SendMessageCommandActuator 1479 1480 1481SendMessageCommandActuator::SendMessageCommandActuator(int32 argc, char** argv) 1482 : 1483 CommandActuator(argc, argv), 1484 fSignature((argc > 1) ? argv[1] : "") 1485{ 1486 // Parse the what code. It may be in any of the following formats: 1487 // 12356 (int) 1488 // 'HELO' (chars enclosed in single quotes) 1489 // 0x12ab3c (hex) 1490 1491 if (argc > 2) { 1492 const char* whatStr = argv[2]; 1493 if ((whatStr[0] == '\'') 1494 && (strlen(whatStr) == 6) 1495 && (whatStr[5] == '\'')) { 1496 // Translate the characters into the uint32 they stand for. 1497 // Note that we must do this in a byte-endian-independant fashion 1498 // (no casting!) 1499 fSendMessage.what = 0; 1500 uint32 mult = 1; 1501 for (int i = 0; i < 4; i++) { 1502 fSendMessage.what += ((uint32)(whatStr[4 - i]))* mult; 1503 mult <<= 8; 1504 } 1505 } else if (strncmp(whatStr, "0x", 2) == 0) 1506 // translate hex string to decimal 1507 fSendMessage.what = strtoul(&whatStr[2], NULL, 16); 1508 else 1509 fSendMessage.what = atoi(whatStr); 1510 } else 1511 fSendMessage.what = 0; 1512 1513 for (int i = 3; i < argc; i++) { 1514 type_code tc = B_BOOL_TYPE;// default type when no value is present 1515 const char* arg = argv[i]; 1516 BString argString(arg); 1517 const char* equals = strchr(arg, '='); 1518 const char* value = "true";// default if no value is present 1519 1520 if (equals) { 1521 tc = B_STRING_TYPE;// default type when value is present 1522 value = equals + 1; 1523 const char* colon = strchr(arg, ':'); 1524 if (colon > equals) 1525 colon = NULL;// colons after the equals sign don't count 1526 1527 if (colon) { 1528 const char* typeStr = colon + 1; 1529 if (strncasecmp(typeStr, "string", 6) == 0) 1530 tc = B_STRING_TYPE; 1531 else if (strncasecmp(typeStr, "int8", 4) == 0) 1532 tc = B_INT8_TYPE; 1533 else if (strncasecmp(typeStr, "int16", 5) == 0) 1534 tc = B_INT16_TYPE; 1535 else if (strncasecmp(typeStr, "int32", 5) == 0) 1536 tc = B_INT32_TYPE; 1537 else if (strncasecmp(typeStr, "int64", 5) == 0) 1538 tc = B_INT64_TYPE; 1539 else if (strncasecmp(typeStr, "bool", 4) == 0) 1540 tc = B_BOOL_TYPE; 1541 else if (strncasecmp(typeStr, "float", 5) == 0) 1542 tc = B_FLOAT_TYPE; 1543 else if (strncasecmp(typeStr, "double", 6) == 0) 1544 tc = B_DOUBLE_TYPE; 1545 else if (strncasecmp(typeStr, "point", 5) == 0) 1546 tc = B_POINT_TYPE; 1547 else if (strncasecmp(typeStr, "rect", 4) == 0) 1548 tc = B_RECT_TYPE; 1549 1550 // remove the colon and stuff 1551 argString = argString.Truncate(colon - arg); 1552 } else 1553 // remove the equals and arg 1554 argString = argString.Truncate(equals - arg); 1555 } 1556 1557 switch(tc) { 1558 case B_STRING_TYPE: 1559 fSendMessage.AddString(argString.String(), value); 1560 break; 1561 1562 case B_INT8_TYPE: 1563 fSendMessage.AddInt8(argString.String(), (int8)atoi(value)); 1564 break; 1565 1566 case B_INT16_TYPE: 1567 fSendMessage.AddInt16(argString.String(), (int16)atoi(value)); 1568 break; 1569 1570 case B_INT32_TYPE: 1571 fSendMessage.AddInt32(argString.String(), (int32)atoi(value)); 1572 break; 1573 1574 case B_INT64_TYPE: 1575 fSendMessage.AddInt64(argString.String(), (int64)atoi(value)); 1576 break; 1577 1578 case B_BOOL_TYPE: 1579 fSendMessage.AddBool(argString.String(), ((value[0] == 't') 1580 || (value[0] == 'T'))); 1581 break; 1582 1583 case B_FLOAT_TYPE: 1584 fSendMessage.AddFloat(argString.String(), atof(value)); 1585 break; 1586 1587 case B_DOUBLE_TYPE: 1588 fSendMessage.AddDouble(argString.String(), (double)atof(value)); 1589 break; 1590 1591 case B_POINT_TYPE: 1592 { 1593 float pts[2] = {0.0f, 0.0f}; 1594 _ParseFloatArgs(pts, 2, value); 1595 fSendMessage.AddPoint(argString.String(), BPoint(pts[0], pts[1])); 1596 break; 1597 } 1598 1599 case B_RECT_TYPE: 1600 { 1601 float pts[4] = {0.0f, 0.0f, 0.0f, 0.0f}; 1602 _ParseFloatArgs(pts, 4, value); 1603 fSendMessage.AddRect(argString.String(), 1604 BRect(pts[0], pts[1], pts[2], pts[3])); 1605 break; 1606 } 1607 } 1608 } 1609} 1610 1611 1612void 1613SendMessageCommandActuator::_ParseFloatArgs(float* args, int maxArgs, 1614 const char* str) const 1615{ 1616 const char* next = str; 1617 for (int i = 0; i < maxArgs; i++) { 1618 args[i] = atof(next); 1619 next = strchr(next, ','); 1620 if (next) next++; 1621 else break; 1622 } 1623} 1624 1625 1626SendMessageCommandActuator::SendMessageCommandActuator(BMessage* from) 1627 : 1628 CommandActuator(from) 1629{ 1630 const char* temp; 1631 1632 if (from->FindString("signature", 0, &temp) == B_OK) 1633 fSignature = temp; 1634 1635 (void) from->FindMessage("sendmsg", &fSendMessage); 1636} 1637 1638 1639SendMessageCommandActuator::~SendMessageCommandActuator() 1640{ 1641} 1642 1643 1644status_t 1645SendMessageCommandActuator::Archive(BMessage* into, bool deep) const 1646{ 1647 status_t ret = CommandActuator::Archive(into, deep); 1648 into->AddString("signature", fSignature.String()); 1649 into->AddMessage("sendmsg", &fSendMessage); 1650 return ret; 1651} 1652 1653 1654filter_result 1655SendMessageCommandActuator::KeyEvent(const BMessage* keyMessage, BList* outList, 1656 void** setAsyncData, BMessage* mouseMessage) 1657{ 1658 if (IS_KEY_DOWN(keyMessage)) 1659 // cause KeyEventAsync() to be called asynchronously 1660 *setAsyncData = (void*) true; 1661 1662 return B_SKIP_MESSAGE; 1663} 1664 1665 1666void 1667SendMessageCommandActuator::KeyEventAsync(const BMessage* keyMessage, 1668 void* asyncData) 1669{ 1670 if (be_roster == NULL) 1671 return; 1672 1673 BString string; 1674 if (fSignature.Length() == 0) { 1675 string << "SendMessage: Target application signature not specified"; 1676 BAlert* alert = new BAlert("Shortcuts SendMessage error", 1677 string.String(), "OK"); 1678 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 1679 alert->Go(NULL); 1680 } else { 1681 status_t result = B_OK; 1682 BMessenger messenger(fSignature.String(), -1, &result); 1683 if (result == B_OK) 1684 messenger.SendMessage(&fSendMessage); 1685 } 1686} 1687 1688 1689BArchivable* 1690SendMessageCommandActuator::Instantiate(BMessage* from) 1691{ 1692 if (validate_instantiation(from, "SendMessageCommandActuator")) 1693 return new SendMessageCommandActuator(from); 1694 else 1695 return NULL; 1696} 1697