[haiku-commits] r33847 - in haiku/trunk/src/add-ons/input_server/filters: . shortcut_catcher

  • From: fredrik@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 30 Oct 2009 22:35:17 +0100 (CET)

Author: modeenf
Date: 2009-10-30 22:35:17 +0100 (Fri, 30 Oct 2009)
New Revision: 33847
Changeset: http://dev.haiku-os.org/changeset/33847/haiku

Added:
   haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.cpp
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.h
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/CommandActuators.cpp
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/CommandActuators.h
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/CommandExecutor.cpp
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/CommandExecutor.h
   haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/Jamfile
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.cpp
   haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/KeyCommandMap.h
   haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/KeyInfos.cpp
   haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/KeyInfos.h
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.h
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/ShortcutsFilterConstants.h
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/ShortcutsServerFilter.cpp
   
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/ShortcutsServerFilter.h
Modified:
   haiku/trunk/src/add-ons/input_server/filters/Jamfile
Log:
So here it goes..
I hope I have fixed all parts that don't follow our guidelines. (that python 
script was good start)
This is the filter..

Modified: haiku/trunk/src/add-ons/input_server/filters/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/input_server/filters/Jamfile        2009-10-30 
15:52:07 UTC (rev 33846)
+++ haiku/trunk/src/add-ons/input_server/filters/Jamfile        2009-10-30 
21:35:17 UTC (rev 33847)
@@ -2,3 +2,4 @@
 
 SubInclude HAIKU_TOP src add-ons input_server filters screen_saver ;
 SubInclude HAIKU_TOP src add-ons input_server filters vmware_mouse ;
+SubInclude HAIKU_TOP src add-ons input_server filters shortcut_catcher ;

Added: 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.cpp
===================================================================
--- 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.cpp
                           (rev 0)
+++ 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.cpp
   2009-10-30 21:35:17 UTC (rev 33847)
@@ -0,0 +1,305 @@
+/*
+ * Copyright 1999-2009 Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Jeremy Friesner
+ */
+ 
+
+#include "BitFieldTesters.h"
+
+ 
+#include <stdio.h>
+
+BitFieldTester::BitFieldTester()
+{
+       // empty
+}
+
+
+BitFieldTester::BitFieldTester(BMessage* from)
+       :
+       BArchivable(from)
+{
+       // empty
+}
+
+
+status_t
+BitFieldTester::Archive(BMessage* into, bool deep) const
+{
+       return BArchivable::Archive(into, deep);
+} 
+
+
+// ---------------- ConstantFieldTester starts -------------------------------
+ConstantFieldTester::ConstantFieldTester(bool result)
+       :
+       fResult(result)
+{
+       // empty
+}
+
+
+ConstantFieldTester::ConstantFieldTester(BMessage* from)
+       :
+       BitFieldTester(from)
+{
+       if (from->FindBool("ctRes", &fResult) != B_NO_ERROR)
+               printf("ConstantFieldTester: Error, no ctRes!\n");
+}
+
+ 
+status_t
+ConstantFieldTester::Archive(BMessage* into, bool deep) const
+{
+       status_t ret = BitFieldTester::Archive(into, deep);
+       into->AddBool("ctRes", fResult);
+       return ret;
+}
+
+
+BArchivable*
+ConstantFieldTester::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "ConstantFieldTester"))
+               return new ConstantFieldTester(from);
+       else
+               return NULL;
+}
+
+
+bool
+ConstantFieldTester::IsMatching(uint32 field)
+{
+       return fResult;
+}
+
+
+// ---------------- HasBitsFieldTester starts -------------------------------
+HasBitsFieldTester::HasBitsFieldTester(uint32 requiredBits, 
+       uint32 forbiddenBits)
+       : 
+       fRequiredBits(requiredBits), 
+       fForbiddenBits(forbiddenBits)
+{
+       // empty
+}
+
+
+HasBitsFieldTester::HasBitsFieldTester(BMessage* from)
+       :
+       BitFieldTester(from)
+{
+       if (from->FindInt32("rqBits", (int32*) &fRequiredBits) != B_NO_ERROR)
+               printf("HasBitsFieldTester: Error, no rqBits!\n");
+       
+       if (from->FindInt32("fbBits", (int32*) &fForbiddenBits) != B_NO_ERROR)
+               printf("HasBitsFieldTester: Error, no fbBits!\n");
+}
+
+
+status_t
+HasBitsFieldTester::Archive(BMessage* into, bool deep) const
+{
+       status_t ret = BitFieldTester::Archive(into, deep);
+       into->AddInt32("rqBits", fRequiredBits);
+       into->AddInt32("fbBits", fForbiddenBits);
+       return ret;
+}
+
+
+BArchivable*
+HasBitsFieldTester::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "HasBitsFieldTester"))
+               return new HasBitsFieldTester(from);
+       else
+               return NULL;
+}
+
+
+bool
+HasBitsFieldTester::IsMatching(uint32 field)
+{
+       return ((((fRequiredBits & (~field)) == 0)) 
+                               && ((fForbiddenBits & (~field)) == 
fForbiddenBits));
+}
+
+
+// ---------------- NotFieldTester starts -------------------------------
+NotFieldTester::NotFieldTester(BitFieldTester* slave)
+       :
+       fSlave(slave)
+{
+       // empty
+}
+
+
+NotFieldTester::~NotFieldTester()
+{
+       delete fSlave;
+}
+
+
+NotFieldTester::NotFieldTester(BMessage* from)
+       : 
+       BitFieldTester(from), 
+       fSlave(NULL)
+{
+       BMessage slaveMsg;
+       if (from->FindMessage("nSlave", &slaveMsg) == B_NO_ERROR) {
+               BArchivable* slaveObj = instantiate_object(&slaveMsg);
+               if (slaveObj) {
+                       fSlave = dynamic_cast<BitFieldTester*>(slaveObj);
+                       if (fSlave == NULL) {
+                               printf("NotFieldTester: 
+                                       Error casting slaveObj to 
BitFieldTester!\n");
+                               delete slaveObj;
+                       }
+               } else
+                       printf("NotFieldTester: instantiate_object returned 
NULL!\n");
+       } else
+               printf("NotFieldTester: Couldn't unarchive NotFieldTester 
slave!\n");
+}
+
+
+status_t
+NotFieldTester::Archive(BMessage* into, bool deep) const
+{
+       if (fSlave == NULL)
+               return B_ERROR;
+
+       status_t ret = BitFieldTester::Archive(into, deep);
+
+       if (ret == B_NO_ERROR) {
+               BMessage msg;
+               ret = fSlave->Archive(&msg, deep);
+               into->AddMessage("nSlave", &msg);
+       }
+
+       return ret;
+}
+
+
+BArchivable*
+NotFieldTester::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "NotFieldTester"))
+               return new NotFieldTester(from);
+       else
+               return NULL;
+}
+
+
+bool
+NotFieldTester::IsMatching(uint32 field)
+{
+       return fSlave ? (!fSlave->IsMatching(field)) : false;
+}
+
+
+// ---------------- MinMatchFieldTester starts -------------------------------
+MinMatchFieldTester::MinMatchFieldTester(int minNum, bool deleteSlaves)
+       :
+       fMinNum(minNum),
+       fDeleteSlaves(deleteSlaves) // fDeleteSlaves state not archived!
+{
+       // empty
+}
+
+
+MinMatchFieldTester::~MinMatchFieldTester()
+{
+       if (fDeleteSlaves) {
+               int nr = fSlaves.CountItems();
+               for (int i = 0; i < nr; i++)
+                       delete ((BitFieldTester*) fSlaves.ItemAt(i));
+       }
+}
+
+
+MinMatchFieldTester::MinMatchFieldTester(BMessage* from)
+       : 
+       BitFieldTester(from),
+       fDeleteSlaves(true)
+{
+       int i = 0;
+       BMessage slaveMsg;
+       while (from->FindMessage("mSlave", i++, &slaveMsg) == B_NO_ERROR) {
+               BArchivable* slaveObj = instantiate_object(&slaveMsg);
+               if (slaveObj) {
+                       BitFieldTester* nextSlave = 
dynamic_cast<BitFieldTester*>(slaveObj);
+                       if (nextSlave)
+                               fSlaves.AddItem(nextSlave);
+                       else {
+                               printf("MinMatchFieldTester:
+                                       Error casting slaveObj to 
BitFieldTester!\n");
+                               delete slaveObj;
+                       }
+               } else
+                       printf("MinMatchFieldTester: instantiate_object 
returned NULL!\n");
+       }
+
+       if (from->FindInt32("mMin", (int32*) &fMinNum) != B_NO_ERROR)
+               printf("MinMatchFieldTester: Error getting mMin!\n");
+}
+
+
+// (slave) should be allocated with new, becomes property of this object.
+void
+MinMatchFieldTester::AddSlave(const BitFieldTester* slave)
+{
+       fSlaves.AddItem((void*) slave);
+}
+
+
+status_t
+MinMatchFieldTester::Archive(BMessage* into, bool deep) const
+{
+       status_t ret = BitFieldTester::Archive(into, deep);
+
+       if (ret == B_NO_ERROR) {
+               int nr = fSlaves.CountItems();
+               for (int i = 0; i < nr; i++) {
+                       BMessage msg;
+                       ret = 
((BitFieldTester*)fSlaves.ItemAt(i))->Archive(&msg, deep);
+                       if (ret != B_NO_ERROR)
+                               return ret;
+
+                       into->AddMessage("mSlave", &msg);
+               }
+       }
+
+       into->AddInt32("mMin", fMinNum);
+       return ret;
+}
+
+
+BArchivable*
+MinMatchFieldTester::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "MinMatchFieldTester"))
+               return new MinMatchFieldTester(from);
+       else
+               return NULL;
+}
+
+
+// Returns true if at least (fMinNum) slaves return true.
+bool
+MinMatchFieldTester::IsMatching(uint32 field)
+{
+       int nr = fSlaves.CountItems();
+       if ((fMinNum == 0) && (nr == 0))
+               return true; // 0 >= 0, so this should return true!
+
+       int count = 0;
+       
+       for (int i = 0; i < nr; i++)
+               if ((((BitFieldTester*)fSlaves.ItemAt(i))->IsMatching(field)) 
+                               && (++count >= fMinNum))
+                       return true;
+       return false;
+}

Added: 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.h
===================================================================
--- 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.h 
                            (rev 0)
+++ 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/BitFieldTesters.h 
    2009-10-30 21:35:17 UTC (rev 33847)
@@ -0,0 +1,121 @@
+/*
+ * Copyright 1999-2009 Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Jeremy Friesner
+ */
+
+
+#ifndef BitFieldTesters_h
+#define BitFieldTesters_h
+
+
+#include <Archivable.h>
+#include <List.h>
+#include <Message.h>
+
+
+// This file contains various BitTester classes, each of which defines a 
+// sequence of bit testing logics to do on a uint32.
+
+#ifndef __INTEL__
+#pragma export on 
+#endif
+
+// The abstract base class. Defines the interface.
+_EXPORT class BitFieldTester;
+class BitFieldTester : public BArchivable {
+public:
+                                                       BitFieldTester();
+                                                       
BitFieldTester(BMessage* from);
+
+       virtual bool                    IsMatching(uint32 field) = 0;
+       virtual status_t                Archive(BMessage* into, bool deep = 
true) const;
+};
+
+
+// This version always returns the value specified in the constructor.
+_EXPORT class ConstantFieldTester;
+class ConstantFieldTester : public BitFieldTester {
+public:
+                                                       
ConstantFieldTester(bool result);
+                                                       
ConstantFieldTester(BMessage* from);
+
+       virtual status_t                Archive(BMessage* into, bool deep = 
true) const;
+       static  BArchivable*    Instantiate(BMessage* from);
+       virtual bool                    IsMatching(uint32 field);
+
+private:
+                       bool                    fResult;
+};
+
+
+// This version matches if all requiredBits are found in the field,
+// and no forbiddenBits are found.
+_EXPORT class HasBitsFieldTester;
+class HasBitsFieldTester : public BitFieldTester {
+public:
+                                                       
HasBitsFieldTester(uint32 requiredBits, 
+                                                               uint32 
forbiddenBits = 0);
+                                                       
HasBitsFieldTester(BMessage* from);
+
+       virtual status_t                Archive(BMessage* into, bool deep = 
true) const;
+       static  BArchivable*    Instantiate(BMessage* from);
+       virtual bool                    IsMatching(uint32 field);
+
+private:
+                       uint32                  fRequiredBits;
+                       uint32                  fForbiddenBits;
+};
+
+
+// This one negates the tester it holds.
+_EXPORT class NotFieldTester;
+class NotFieldTester : public BitFieldTester {
+public:
+       // (slave) should be allocated with new, becomes property of this 
object.
+                                                       
NotFieldTester(BitFieldTester* slave);
+                                                       
NotFieldTester(BMessage* from);
+                                                       ~NotFieldTester();
+
+       virtual status_t                Archive(BMessage* into, bool deep = 
true) const;
+       static  BArchivable*    Instantiate(BMessage* from);
+       virtual bool                    IsMatching(uint32 field);
+
+private:
+                       BitFieldTester* fSlave;
+};
+
+
+// The most interesting class: This one returns true if at least (minNum) of
+// its slaves return true. It can be used for OR (i.e. minNum==1), AND 
+// (i.e. minNum==numberofchildren), or anything in between!
+_EXPORT class MinMatchFieldTester;
+class MinMatchFieldTester : public BitFieldTester {
+public:
+                                                       MinMatchFieldTester(int 
minNum, 
+                                                               bool 
deleteSlaves = true);
+                                                       
MinMatchFieldTester(BMessage* from);
+                                                       ~MinMatchFieldTester();
+
+       // (slave) should be allocated with new, becomes property of this 
object.
+                       void                    AddSlave(const BitFieldTester* 
slave);
+
+       virtual status_t                Archive(BMessage* into, bool deep = 
true) const;
+       static  BArchivable*    Instantiate(BMessage* from);
+       virtual bool                    IsMatching(uint32 field);
+
+private:
+                       BList                   fSlaves;
+                       int32                   fMinNum;
+
+       // true if we should delete all our slaves when we are deleted.
+                       bool                    fDeleteSlaves;
+};
+
+#ifndef __INTEL__
+#pragma export reset 
+#endif
+
+#endif

Added: 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/CommandActuators.cpp
===================================================================
--- 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/CommandActuators.cpp
                          (rev 0)
+++ 
haiku/trunk/src/add-ons/input_server/filters/shortcut_catcher/CommandActuators.cpp
  2009-10-30 21:35:17 UTC (rev 33847)
@@ -0,0 +1,1713 @@
+/*
+ * Copyright 1999-2009 Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Jeremy Friesner
+ *             Fredrik Modéen
+ */
+
+
+#include "CommandActuators.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include <String.h>
+#include <Roster.h>
+#include <Alert.h>
+#include <Screen.h>
+#include <Rect.h>
+#include <View.h>
+#include <Directory.h>
+#include <Entry.h>
+#include <List.h>
+#include <Beep.h>
+
+
+#include "ParseCommandLine.h"
+#include "KeyInfos.h"
+
+#define IS_KEY_DOWN(msg) ((msg->what == B_KEY_DOWN) \
+       || (msg->what == B_UNMAPPED_KEY_DOWN))
+
+// Factory function
+CommandActuator* 
+CreateCommandActuator(const char* command)
+{
+       CommandActuator* act = NULL; 
+       int32 argc;
+       char** argv = ParseArgvFromString(command, argc);
+       if (command[0] == '*') {
+               if (argc > 0) {
+                       char* c = argv[0] + 1;
+                       if (strcmp(c, "InsertString") == 0) 
+                               act = new 
KeyStrokeSequenceCommandActuator(argc, argv);
+                       else if (strcmp(c, "MoveMouse") == 0)
+                               act = new MoveMouseByCommandActuator(argc, 
argv);
+                       else if (strcmp(c, "MoveMouseTo") == 0)
+                               act = new MoveMouseToCommandActuator(argc, 
argv);
+                       else if (strcmp(c, "MouseButton") == 0) 
+                               act = new MouseButtonCommandActuator(argc, 
argv);
+                       else if (strcmp(c, "LaunchHandler") == 0)
+                               act = new MIMEHandlerCommandActuator(argc, 
argv);
+                       else if (strcmp(c, "Multi") == 0) 
+                               act = new MultiCommandActuator(argc, argv);
+                       else if (strcmp(c, "MouseDown") == 0) 
+                               act = new MouseDownCommandActuator(argc, argv);
+                       else if (strcmp(c, "MouseUp") == 0) 
+                               act = new MouseUpCommandActuator(argc, argv);
+                       else if (strcmp(c, "SendMessage") == 0) 
+                               act = new SendMessageCommandActuator(argc, 
argv);
+                       else
+                               act = new BeepCommandActuator(argc, argv);
+               }
+       } else
+               act = new LaunchCommandActuator(argc, argv);
+
+       FreeArgv(argv);
+       return act;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CommandActuator
+//
+///////////////////////////////////////////////////////////////////////////////
+CommandActuator::CommandActuator(int32 argc, char** argv)
+{
+       // empty
+}
+
+
+CommandActuator::CommandActuator(BMessage* from)
+       :
+       BArchivable(from)
+{
+       // empty
+}
+
+
+status_t
+CommandActuator::Archive(BMessage* into, bool deep) const
+{
+       status_t ret = BArchivable::Archive(into, deep);
+       return ret;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// LaunchCommandActuator
+//
+///////////////////////////////////////////////////////////////////////////////
+LaunchCommandActuator::LaunchCommandActuator(int32 argc, char** argv)
+       :
+       CommandActuator(argc, argv), 
+       fArgv(CloneArgv(argv)), 
+       fArgc(argc)
+{
+       // empty
+}
+
+
+LaunchCommandActuator::LaunchCommandActuator(BMessage* from)
+       :
+       CommandActuator(from)
+{
+       BList argList;
+       const char* temp;
+       int idx = 0;
+       while (from->FindString("largv", idx++, &temp) == B_NO_ERROR) {
+               if (temp) {
+                       char* copy = new char[strlen(temp) + 1];
+                       strcpy(copy, temp);
+                       argList.AddItem(copy);
+               }
+       }
+
+       fArgc = argList.CountItems();
+       fArgv = new char*[fArgc+ 1];
+       
+       for (int i = 0; i < fArgc; i++) 
+               fArgv[i] = (char*) argList.ItemAt(i);
+       
+       fArgv[fArgc] = NULL;// terminate the array
+}
+
+
+LaunchCommandActuator::~LaunchCommandActuator()
+{
+       FreeArgv(fArgv);
+}
+
+
+filter_result
+LaunchCommandActuator::KeyEvent(const BMessage* keyMsg, BList* outlist, 
+       void** setAsyncData, BMessage* lastMouseMove)
+{
+       if (IS_KEY_DOWN(keyMsg)) {
+               // cause KeyEventAsync() to be called asynchronously
+               *setAsyncData = (void*) true;
+       }
+       return B_SKIP_MESSAGE;
+}
+
+
+status_t
+LaunchCommandActuator::Archive(BMessage* into, bool deep) const
+{
+       status_t ret = CommandActuator::Archive(into, deep);
+       
+       for (int i = 0; i < fArgc; i++)
+               into->AddString("largv", fArgv[i]);
+
+       return ret;
+}
+
+
+BArchivable*
+LaunchCommandActuator ::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "LaunchCommandActuator"))
+               return new LaunchCommandActuator(from);
+       else
+               return NULL;
+}
+
+
+void
+LaunchCommandActuator::KeyEventAsync(const BMessage* keyMsg, 
+       void* asyncData)
+{
+       if (be_roster) {
+               status_t err = B_OK;
+               BString str;            
+               BString str1("Shortcuts Launcher Error");
+               if (fArgc < 1)
+                       str << "You didn't specify a command for this hotkey.";
+               else if ((err = LaunchCommand(fArgv, fArgc)) != B_NO_ERROR) {
+                       str << "Can't launch " << fArgv[0];
+                       str << ", no such file exists.";
+                       str << " Please check your Shortcuts settings.";
+               }
+
+               if (fArgc < 1 || err != B_NO_ERROR)
+                       (new BAlert(str1.String(), str.String(), 
"Ok"))->Go(NULL);      
+       }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// MouseCommandActuator
+//
+///////////////////////////////////////////////////////////////////////////////
+MouseCommandActuator::MouseCommandActuator(int32 argc, char** argv)
+       :
+       CommandActuator(argc, argv), 
+       fWhichButtons(B_PRIMARY_MOUSE_BUTTON)
+{
+       if (argc > 1) {
+               fWhichButtons = 0;
+
+               for (int i = 1; i < argc; i++) {
+                       int buttonNumber = atoi(argv[i]);
+                       
+                       switch(buttonNumber) {
+                               case 1: 
+                                       fWhichButtons |= B_PRIMARY_MOUSE_BUTTON;
+                               break;
+                               case 2:
+                                       fWhichButtons |= 
B_SECONDARY_MOUSE_BUTTON;
+                               break;
+                               case 3:
+                                       fWhichButtons |= 
B_TERTIARY_MOUSE_BUTTON;
+                               break;
+                       }
+               }
+       }
+}
+
+
+MouseCommandActuator::MouseCommandActuator(BMessage* from)
+       :
+       CommandActuator(from),
+       fWhichButtons(B_PRIMARY_MOUSE_BUTTON)
+{
+       from->FindInt32("buttons", &fWhichButtons);
+}
+
+
+MouseCommandActuator::~MouseCommandActuator()
+{
+       // empty
+}
+
+
+status_t
+MouseCommandActuator::Archive(BMessage* into, bool deep) const
+{
+       status_t ret = CommandActuator::Archive(into, deep);
+       into->AddInt32("buttons", fWhichButtons); 
+       return ret;
+}
+
+
+int32
+MouseCommandActuator::_GetWhichButtons() const
+{
+       return fWhichButtons;
+}
+
+
+void
+MouseCommandActuator::_GenerateMouseButtonEvent(bool mouseDown, 
+       const BMessage* keyMsg, BList* outlist, BMessage* lastMouseMove)
+{ 
+       BMessage* fakeMouse = new BMessage(*lastMouseMove);
+       fakeMouse->what = mouseDown ? B_MOUSE_DOWN : B_MOUSE_UP;
+ 
+       // Update the buttons to reflect which mouse buttons we are faking
+       fakeMouse->RemoveName("buttons");
+       
+       if (mouseDown) 
+               fakeMouse->AddInt32("buttons", fWhichButtons); 
+
+       // Trey sez you gotta keep then "when"'s increasing if you want 
+       // click & drag to work!
+       int64 when;
+       
+       const BMessage* lastMessage;
+       
+       if (outlist->CountItems() > 0) {
+               int nr = outlist->CountItems() - 1;
+               lastMessage = (const BMessage*)outlist->ItemAt(nr);
+       } else
+               lastMessage =keyMsg;
+       
+       if (lastMessage->FindInt64("when", &when) == B_NO_ERROR) {
+               when++;
+               fakeMouse->RemoveName("when");
+               fakeMouse->AddInt64("when", when);
+       }
+       outlist->AddItem(fakeMouse);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// MouseDownCommandActuator
+//
+///////////////////////////////////////////////////////////////////////////////
+MouseDownCommandActuator::MouseDownCommandActuator(int32 argc, char** argv)
+       :
+       MouseCommandActuator(argc, argv)
+{
+       // empty
+}
+
+
+MouseDownCommandActuator::MouseDownCommandActuator(BMessage* from)
+       :
+       MouseCommandActuator(from)
+{
+       // empty
+}
+
+
+MouseDownCommandActuator::~MouseDownCommandActuator()
+{
+       // empty
+}
+
+
+filter_result
+MouseDownCommandActuator::KeyEvent(const BMessage* keyMsg, BList* outlist, 
+       void** setAsyncData, BMessage* lastMouseMove)
+{
+       if (IS_KEY_DOWN(keyMsg)) 
+               _GenerateMouseButtonEvent(true, keyMsg, outlist, lastMouseMove);
+       
+       return B_DISPATCH_MESSAGE;
+}
+
+
+status_t
+MouseDownCommandActuator::Archive(BMessage* into, bool deep) const
+{
+       return MouseCommandActuator::Archive(into, deep);
+}
+
+
+BArchivable*
+MouseDownCommandActuator ::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "MouseDownCommandActuator")) 
+               return new MouseDownCommandActuator(from);
+       else
+               return NULL;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// MouseUpCommandActuator
+//
+///////////////////////////////////////////////////////////////////////////////
+MouseUpCommandActuator::MouseUpCommandActuator(int32 argc, char** argv)
+       :
+       MouseCommandActuator(argc, argv)
+{
+       // empty
+}
+
+
+MouseUpCommandActuator::MouseUpCommandActuator(BMessage* from)
+       :
+       MouseCommandActuator(from)
+{
+       // empty
+}
+
+
+MouseUpCommandActuator::~MouseUpCommandActuator()
+{
+       // empty
+}
+
+
+filter_result
+MouseUpCommandActuator::KeyEvent(const BMessage* keyMsg, BList* outlist, 
+       void** setAsyncData, BMessage* lastMouseMove)
+{
+       if (IS_KEY_DOWN(keyMsg)) 
+               _GenerateMouseButtonEvent(false, keyMsg, outlist, 
lastMouseMove);
+       return B_DISPATCH_MESSAGE;
+}
+
+
+status_t
+MouseUpCommandActuator::Archive(BMessage* into, bool deep) const
+{
+       return MouseCommandActuator::Archive(into, deep);
+}
+
+
+BArchivable*
+MouseUpCommandActuator ::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "MouseUpCommandActuator")) 
+               return new MouseUpCommandActuator(from);
+       else
+               return NULL;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// MouseButtonCommandActuator
+//
+///////////////////////////////////////////////////////////////////////////////
+MouseButtonCommandActuator::MouseButtonCommandActuator(int32 argc, char** argv)
+       :
+       MouseCommandActuator(argc, argv),
+       fKeyDown(false)
+{
+       // empty
+}
+
+
+MouseButtonCommandActuator::MouseButtonCommandActuator(BMessage* from)
+       :
+       MouseCommandActuator(from),
+       fKeyDown(false)
+{
+       // empty
+}
+
+
+MouseButtonCommandActuator::~MouseButtonCommandActuator()
+{
+       // empty
+}
+
+
+filter_result
+MouseButtonCommandActuator::KeyEvent(const BMessage* keyMsg, BList* outlist, 
+       void** setAsyncData, BMessage* lastMouseMove)
+{
+       if (IS_KEY_DOWN(keyMsg) != fKeyDown) {
+               _GenerateMouseButtonEvent(IS_KEY_DOWN(keyMsg), keyMsg, outlist, 
+                       lastMouseMove);
+               fKeyDown = IS_KEY_DOWN(keyMsg);
+               return B_DISPATCH_MESSAGE;
+       } else
+               // This will handle key-repeats, which we don't want turned 
into lots 
+               // of B_MOUSE_DOWN messages.
+               return B_SKIP_MESSAGE;
+}
+
+
+status_t
+MouseButtonCommandActuator::Archive(BMessage* into, bool deep) const
+{
+       return MouseCommandActuator::Archive(into, deep);
+}
+
+
+BArchivable*
+MouseButtonCommandActuator ::Instantiate(BMessage* from)
+{
+       if (validate_instantiation(from, "MouseButtonCommandActuator")) 
+               return new MouseButtonCommandActuator(from);
+       else
+               return NULL;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// KeyStrokeSequenceCommandActuator
+//
+///////////////////////////////////////////////////////////////////////////////
+KeyStrokeSequenceCommandActuator::KeyStrokeSequenceCommandActuator(int32 argc, 
+       char** argv)
+       :
+       CommandActuator(argc, argv)
+{
+       for (int s = 1; s < argc; s++) {
+               fSequence.Append(argv[s]);
+               if (s < argc - 1)
+                       fSequence.Append(" ");
+       }
+
+       // Find any insert-unicode-here sequences and replace them with 
spaces...
+       int32 nextStart;
+       while ((nextStart = fSequence.FindFirst("$$")) >= 0) {
+               int32 nextEnd = fSequence.FindFirst("$$", nextStart + 2);
+               if (nextEnd >= 0) {
+                       uint32 customKey= 0;
+                       int32 unicodeVal= 0;
+                       uint32 customMods = 0;
+                       BString sub; 
+                       fSequence.CopyInto(sub, nextStart + 2, 
nextEnd-(nextStart + 2));
+                       sub.ToLower();
+                       
+                       if ((sub.FindFirst('-') >= 0) || ((sub.Length() > 0)
+                               && ((sub.String()[0] < '0') || (sub.String()[0] 
> '9')))) {
+                       
+                               const char* s = sub.String();
+                               while (*s == '-') s++;// go past any initial 
dashes
+
+                               bool lastWasDash = true;
+                               while (*s) {                    
+                                       if (lastWasDash) {
+                                               if (strncmp(s, "shift",5) == 0)
+                                                       customMods 
|=B_LEFT_SHIFT_KEY| B_SHIFT_KEY;
+                                               else if (strncmp(s, "leftsh", 
6) == 0) 
+                                                       customMods 
|=B_LEFT_SHIFT_KEY| B_SHIFT_KEY;
+                                               else if (strncmp(s, 
"rightsh",7) == 0) 
+                                                       customMods 
|=B_RIGHT_SHIFT_KEY | B_SHIFT_KEY;
+                                               else if (strncmp(s, "alt",3) == 
0) 
+                                                       customMods 
|=B_LEFT_COMMAND_KEY| B_COMMAND_KEY;
+                                               else if (strncmp(s, 
"leftalt",7) == 0) 
+                                                       customMods 
|=B_LEFT_COMMAND_KEY| B_COMMAND_KEY;
+                                               else if (strncmp(s, "rightalt", 
8) == 0) 
+                                                       customMods 
|=B_RIGHT_COMMAND_KEY | B_COMMAND_KEY;
+                                               else if (strncmp(s, "com",3) == 
0) 
+                                                       customMods 
|=B_LEFT_COMMAND_KEY| B_COMMAND_KEY;
+                                               else if (strncmp(s, 
"leftcom",7) == 0) 
+                                                       customMods 
|=B_LEFT_COMMAND_KEY| B_COMMAND_KEY;
+                                               else if (strncmp(s, "rightcom", 
8) == 0) 
+                                                       customMods 
|=B_RIGHT_COMMAND_KEY | B_COMMAND_KEY;
+                                               else if (strncmp(s, "con",3) == 
0) 
+                                                       customMods 
|=B_LEFT_CONTROL_KEY| B_CONTROL_KEY;
+                                               else if (strncmp(s, 
"leftcon",7) == 0) 
+                                                       customMods 
|=B_LEFT_CONTROL_KEY| B_CONTROL_KEY;
+                                               else if (strncmp(s, "rightcon", 
8) == 0) 
+                                                       customMods 
|=B_RIGHT_CONTROL_KEY | B_CONTROL_KEY;
+                                               else if (strncmp(s, "win",3) == 
0) 
+                                                       customMods 
|=B_LEFT_OPTION_KEY | B_OPTION_KEY;
+                                               else if (strncmp(s, 
"leftwin",7) == 0) 
+                                                       customMods 
|=B_LEFT_OPTION_KEY | B_OPTION_KEY;
+                                               else if (strncmp(s, "rightwin", 
8) == 0) 
+                                                       customMods 
|=B_RIGHT_OPTION_KEY| B_OPTION_KEY;
+                                               else if (strncmp(s, "opt",3) == 
0) 
+                                                       customMods 
|=B_LEFT_OPTION_KEY | B_OPTION_KEY;
+                                               else if (strncmp(s, 
"leftopt",7) == 0) 
+                                                       customMods 
|=B_LEFT_OPTION_KEY | B_OPTION_KEY;
+                                               else if (strncmp(s, "rightopt", 
8) == 0) 
+                                                       customMods 
|=B_RIGHT_OPTION_KEY| B_OPTION_KEY;
+                                               else if (strncmp(s, "menu", 4) 
== 0) 
+                                                       customMods |=B_MENU_KEY;
+                                               else if (strncmp(s, "caps", 4) 
== 0) 

[... truncated: 2873 lines follow ...]

Other related posts: