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