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..

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33847 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Fredrik Modeen
2009-10-30 21:35:17 +00:00
parent 1adcc57859
commit be2b059224
17 changed files with 3768 additions and 0 deletions
+1
View File
@@ -2,3 +2,4 @@ SubDir HAIKU_TOP src add-ons input_server filters ;
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 ;
@@ -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;
}
@@ -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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,369 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef CommandActuators_h
#define CommandActuators_h
#include <Message.h>
#include <String.h>
#include <Archivable.h>
#include <List.h>
#include <InputServerFilter.h>
#ifndef __INTEL__
#pragma export on
#endif
struct key_map; // declaration
class CommandActuator;
// Factory function: Given a text string, allocates and returns a
// CommandActuator. Returns NULL on failure (usually a parse error)
extern CommandActuator* CreateCommandActuator(const char* command);
// This file contains various CommandActuator classes. Each CommandActuator
// contains code to do something. They're functor objects, really. The input
// server add-on will execute the CommandActuator associated with a key combo
// when that key combo is detected.
// The abstract base class. Defines the interface.
_EXPORT class CommandActuator;
class CommandActuator : public BArchivable {
public:
CommandActuator(int32 argc, char** argv);
CommandActuator(BMessage* from);
// Called by the InputFilter whenever a key is pressed or depressed.
// It's important to ensure that this method returns quickly, as the
// input_server will block while it executes. (keyMsg) is the BMessage
// that triggered this call. (outlist) is a BList that additional input
// events may be added to. If (*asyncData) is set to non-NULL,
// KeyEventAsync() will be called asynchronously with (asyncData) as
// the argument. Returns the filter_result to be given back to the
// input_server. (Defaults to B_SKIP_MESSAGE)
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** asyncData,
BMessage* lastMouseMove)
{return B_SKIP_MESSAGE;}
// Called in a separate thread if (*setAsyncData) was set to non-NULL
// in KeyEvent(). Defaults to a no-op.
virtual void KeyEventAsync(const BMessage* keyUpMsg,
void* asyncData) {}
virtual status_t Archive(BMessage* into, bool deep = true)
const;
};
// This is the most common thing to do--launch a process.
_EXPORT class LaunchCommandActuator;
class LaunchCommandActuator : public CommandActuator {
public:
LaunchCommandActuator(int32 argc, char** argv);
LaunchCommandActuator(BMessage* from);
~LaunchCommandActuator();
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage* from);
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual void KeyEventAsync(const BMessage* keyMsg,
void* asyncData);
private:
bool _GetNextWord(char** setBegin, char** setEnd)
const;
char** fArgv;
int32 fArgc;
};
// Stupid actuator--just calls beep().
_EXPORT class BeepCommandActuator;
class BeepCommandActuator : public CommandActuator {
public:
BeepCommandActuator(int32 argc, char** argv);
BeepCommandActuator(BMessage* from);
~BeepCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage* from);
};
// This class will insert a string of keystrokes into the input stream.
_EXPORT class KeyStrokeSequenceCommandActuator;
class KeyStrokeSequenceCommandActuator : public CommandActuator {
public:
KeyStrokeSequenceCommandActuator(int32 argc,
char** argv);
KeyStrokeSequenceCommandActuator(
BMessage* from);
~KeyStrokeSequenceCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage * from);
private:
void _GenerateKeyCodes();
int32 _LookupKeyCode(key_map* map, char* keys,
int32 offsets[128], char key,
uint8* setStates, int32& setMod,
int32 setTo) const;
void _SetStateBit(uint8* setStates, uint32 key,
bool on = true) const;
uint8* fStates;
int32* fKeyCodes;
int32* fModCodes;
BString fSequence;
BList fOverrides;
BList fOverrideOffsets;
BList fOverrideModifiers;
BList fOverrideKeyCodes;
};
// This class will insert a string of keystrokes into the input stream.
_EXPORT class MIMEHandlerCommandActuator;
class MIMEHandlerCommandActuator : public CommandActuator {
public:
MIMEHandlerCommandActuator(int32 argc,
char** argv);
MIMEHandlerCommandActuator(BMessage* from);
~MIMEHandlerCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual void KeyEventAsync(const BMessage* keyUpMsg,
void* asyncData);
virtual status_t Archive(BMessage * into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage* from);
private:
BString fMimeType;
};
// Abstract base class for actuators that affect mouse buttons
_EXPORT class MouseCommandActuator;
class MouseCommandActuator : public CommandActuator {
public:
MouseCommandActuator(int32 argc, char** argv);
MouseCommandActuator(BMessage* from);
~MouseCommandActuator();
virtual status_t Archive(BMessage* into, bool deep = true)
const;
protected:
int32 _GetWhichButtons() const;
void _GenerateMouseButtonEvent(bool mouseDown,
const BMessage* keyMsg, BList* outlist,
BMessage* lastMouseMove);
private:
int32 fWhichButtons;
};
// This class sends a single mouse down event when activated, causing the mouse
// pointer to enter a "sticky down" state. Good for some things(like dragging).
_EXPORT class MouseDownCommandActuator;
class MouseDownCommandActuator : public MouseCommandActuator {
public:
MouseDownCommandActuator(int32 argc,
char** argv);
MouseDownCommandActuator(BMessage* from);
~MouseDownCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable * Instantiate(BMessage * from);
};
// This class sends a single mouse down up when activated, releasing any
// previously set "sticky down" state. Good for some things (like dragging).
_EXPORT class MouseUpCommandActuator;
class MouseUpCommandActuator : public MouseCommandActuator {
public:
MouseUpCommandActuator(int32 argc,
char** argv);
MouseUpCommandActuator(BMessage * from);
~MouseUpCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage* from);
};
// This class will send B_MOUSE_UP and B_MOUSE_DOWN events whenever B_KEY_UP or
// B_KEY_DOWN events are detected for its key This way a key can act sort of
// like a mouse button.
_EXPORT class MouseButtonCommandActuator;
class MouseButtonCommandActuator : public MouseCommandActuator {
public:
MouseButtonCommandActuator(int32 argc,
char** argv);
MouseButtonCommandActuator(BMessage* from);
~MouseButtonCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage* from);
private:
bool fKeyDown ;
};
// Base class for some actuators that control the position of the mouse pointer
_EXPORT class MoveMouseCommandActuator;
class MoveMouseCommandActuator : public CommandActuator {
public:
MoveMouseCommandActuator(int32 argc,
char** argv);
MoveMouseCommandActuator(BMessage* from);
~MoveMouseCommandActuator();
virtual status_t Archive(BMessage* into, bool deep) const;
protected:
void CalculateCoords(float& setX, float& setY)
const;
BMessage* CreateMouseMovedMessage(const BMessage* origMsg
, BPoint p, BList* outlist) const;
private:
void _ParseArg(const char* arg, float& setPercent,
float& setPixels) const;
float fXPercent;
float fYPercent;
float fXPixels;
float fYPixels;
};
// Actuator that specifies multiple sub-actuators to be executed in series
_EXPORT class MultiCommandActuator;
class MultiCommandActuator : public CommandActuator {
public:
MultiCommandActuator(int32 argc, char** argv);
MultiCommandActuator(BMessage* from);
~MultiCommandActuator();
virtual status_t Archive(BMessage* into, bool deep) const;
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** asyncData,
BMessage* lastMouseMove);
virtual void KeyEventAsync(const BMessage* keyUpMsg,
void * asyncData);
static BArchivable* Instantiate(BMessage* from);
private:
BList fSubActuators;
};
// Actuator for moving a mouse relative to its current position
_EXPORT class MoveMouseToCommandActuator;
class MoveMouseToCommandActuator : public MoveMouseCommandActuator {
public:
MoveMouseToCommandActuator(int32 argc,
char** argv);
MoveMouseToCommandActuator(BMessage* from);
~MoveMouseToCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg, BList* outlist
, void** setAsyncData,
BMessage* lastMouseMove);
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage* from);
};
// Actuator for moving a mouse relative to its current position
_EXPORT class MoveMouseByCommandActuator;
class MoveMouseByCommandActuator : public MoveMouseCommandActuator {
public:
MoveMouseByCommandActuator(int32 argc,
char** argv);
MoveMouseByCommandActuator(BMessage* from);
~MoveMouseByCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual status_t Archive(BMessage * into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage * from);
};
// Actuator to send BMessage to an application - written by Daniel Wesslen
_EXPORT class SendMessageCommandActuator;
class SendMessageCommandActuator : public CommandActuator {
public:
SendMessageCommandActuator(int32 argc,
char** argv);
SendMessageCommandActuator(BMessage* from);
~SendMessageCommandActuator();
virtual filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist, void** setAsyncData,
BMessage* lastMouseMove);
virtual void KeyEventAsync(const BMessage* keyUpMsg,
void* asyncData);
virtual status_t Archive(BMessage* into, bool deep = true)
const;
static BArchivable* Instantiate(BMessage * from);
private:
void _ParseFloatArgs(float* outArgs, int maxArgs
, const char* str) const;
BString fSignature;
BMessage fSendMsg;
};
#ifndef __INTEL__
#pragma export reset
#endif
#endif
@@ -0,0 +1,90 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#include "CommandExecutor.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <image.h>
#include "ShortcutsFilterConstants.h"
#include "CommandActuators.h"
CommandExecutor::CommandExecutor()
{
// empty
}
CommandExecutor::~CommandExecutor()
{
// empty
}
// Returns true if it is returning valid results into (*setBegin) and
// (*setEnd). If returning true, (*setBegin) now points to the first char in a
// new word, and (*setEnd) now points to the char after the last char in the
// word, which has been set to a NUL byte.
bool
CommandExecutor::GetNextWord(char** setBegin, char** setEnd) const
{
char* next = *setEnd; // we'll start one after the end of the last one...
while (next++) {
if (*next == '\0')
return false; // no words left!
else if (*next <= ' ')
*next = '\0';
else
break; // found a non-whitespace char!
}
*setBegin = next; // we found the first char!
while (next++) {
if (*next <= ' ') {
*next = '\0'; // terminate the word
*setEnd = next;
return true;
}
}
return false; // should never get here, actually
}
void
CommandExecutor::MessageReceived(BMessage* msg)
{
switch(msg->what) {
case B_UNMAPPED_KEY_DOWN:
case B_KEY_DOWN:
{
BMessage actMessage;
void* asyncData;
if ((msg->FindMessage("act", &actMessage) == B_NO_ERROR)
&& (msg->FindPointer("adata", &asyncData) == B_NO_ERROR)) {
BArchivable* arcObj = instantiate_object(&actMessage);
if (arcObj) {
CommandActuator* act = dynamic_cast<CommandActuator*>(arcObj);
if (act)
act->KeyEventAsync(msg, asyncData);
delete arcObj;
}
}
break;
}
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef CommandExecutor_h
#define CommandExecutor_h
#include <Looper.h>
#include <Message.h>
#include <OS.h>
// This thread receives BMessages telling it what
// to launch, and launches them.
class CommandExecutor : public BLooper {
public:
CommandExecutor();
~CommandExecutor();
virtual void MessageReceived(BMessage* msg);
private:
bool GetNextWord(char** setBeginWord, char** setEndWord)
const;
};
#endif
@@ -0,0 +1,17 @@
SubDir HAIKU_TOP src add-ons input_server filters shortcut_catcher ;
SetSubDirSupportedPlatformsBeOSCompatible ;
# Common files used here and in the app
StaticLibrary libshortcuts_shared.a :
BitFieldTesters.cpp
CommandActuators.cpp
KeyInfos.cpp
ParseCommandLine.cpp
;
Addon shortcut_catcher :
CommandExecutor.cpp
KeyCommandMap.cpp
ShortcutsServerFilter.cpp
: be game input_server libshortcuts_shared.a $(TARGET_LIBSUPC++) ;
@@ -0,0 +1,312 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#include "KeyCommandMap.h"
#include <stdio.h>
#include <OS.h>
#include <File.h>
#include <NodeMonitor.h>
#include <Entry.h>
#include <WindowScreen.h>
#include <MessageFilter.h>
#include <Beep.h>
#include "ShortcutsFilterConstants.h"
#include "BitFieldTesters.h"
#include "CommandActuators.h"
#define FILE_UPDATED 'fiUp'
class hks {
public:
hks(int32 key, BitFieldTester* t, CommandActuator* act, const BMessage& a)
:
fKey(key),
fTester(t),
fActuator(act),
fActuatorMessage(a)
{
// empty
}
~hks()
{
delete fActuator;
delete fTester;
}
int32 GetKey() const {return fKey;}
bool DoModifiersMatch(uint32 bits) const
{
return fTester->IsMatching(bits);
}
const BMessage& GetActuatorMsg() const {return fActuatorMessage;}
CommandActuator* GetActuator() {return fActuator;}
private:
int32 fKey;
BitFieldTester* fTester;
CommandActuator* fActuator;
const BMessage fActuatorMessage;
};
KeyCommandMap::KeyCommandMap(const char* file)
:
fSpecs(NULL)
{
fFileName = new char[strlen(file) + 1];
strcpy(fFileName, file);
BEntry fileEntry(fFileName);
if (fileEntry.InitCheck() == B_NO_ERROR) {
node_ref nref;
if (fileEntry.GetNodeRef(&nref) == B_NO_ERROR)
watch_node(&nref, B_WATCH_STAT, this);
}
BMessage msg(FILE_UPDATED);
PostMessage(&msg);
fPort = create_port(1, SHORTCUTS_CATCHER_PORT_NAME);
_PutMessageToPort(); // advertise our BMessenger to the world
}
KeyCommandMap::~KeyCommandMap()
{
if (fPort >= 0)
close_port(fPort);
for (int i = fInjects.CountItems() - 1; i >= 0; i--)
delete (BMessage*)fInjects.ItemAt(i);
stop_watching(this); // don't know if this is necessary, but it can't hurt
_DeleteHKSList(fSpecs);
delete [] fFileName;
}
void
KeyCommandMap::MouseMoved(const BMessage* mm)
{
// Save the mouse state for later...
fLastMouseMessage = *mm;
}
filter_result
KeyCommandMap::KeyEvent(const BMessage* keyMsg, BList* outlist,
const BMessenger& sendTo)
{
uint32 modifiers;
filter_result ret = B_DISPATCH_MESSAGE; // default: pass it on
if (keyMsg->FindInt32("modifiers", (int32*) &modifiers) == B_NO_ERROR) {
int32 key;
if (keyMsg->FindInt32("key", &key) == B_NO_ERROR) {
if (fSyncSpecs.Lock()) {
if (fSpecs != NULL) {
int num = fSpecs->CountItems();
for (int i = 0; i < num; i++) {
hks* next = (hks*) fSpecs->ItemAt(i);
if ((key == next->GetKey())
&& (next->DoModifiersMatch(modifiers))) {
void* asyncData = NULL;
ret = next->GetActuator()->
KeyEvent(keyMsg, outlist, &asyncData, &fLastMouseMessage);
if (asyncData) {
BMessage newMsg(*keyMsg);
newMsg.AddMessage("act", &next->GetActuatorMsg());
newMsg.AddPointer("adata", asyncData);
sendTo.SendMessage(&newMsg);
}
}
}
}
fSyncSpecs.Unlock();
}
}
}
return ret;
}
void
KeyCommandMap::DrainInjectedEvents(const BMessage* keyMsg, BList* outlist,
const BMessenger& sendTo)
{
BList temp;
if (fSyncSpecs.Lock()) {
temp = fInjects;
fInjects.MakeEmpty();
fSyncSpecs.Unlock();
}
int is = temp.CountItems();
for (int i = 0; i < is; i++) {
BMessage* msg = (BMessage*)temp.ItemAt(i);
BArchivable* arc = instantiate_object(msg);
if (arc) {
CommandActuator* act = dynamic_cast<CommandActuator*>(arc);
if (act) {
BMessage newMsg(*keyMsg);
newMsg.what = B_KEY_DOWN;
void* asyncData = NULL;
(void) act->KeyEvent(&newMsg, outlist, &asyncData,
&fLastMouseMessage);
if (asyncData) {
newMsg.AddMessage("act", msg);
newMsg.AddPointer("adata", asyncData);
sendTo.SendMessage(&newMsg);
}
}
delete arc;
}
delete msg;
}
}
void
KeyCommandMap::MessageReceived(BMessage* msg)
{
switch(msg->what) {
case EXECUTE_COMMAND:
{
BMessage subMsg;
if (msg->FindMessage("act", &subMsg) == B_NO_ERROR) {
if (fSyncSpecs.Lock()) {
fInjects.AddItem(new BMessage(subMsg));
fSyncSpecs.Unlock();
// This evil hack forces input_server to call Filter() on
// us so we can process the injected event.
BPoint lmp;
status_t err = fLastMouseMessage.FindPoint("where", &lmp);
if (err == B_NO_ERROR)
set_mouse_position((int32)lmp.x, (int32)lmp.y);
}
}
break;
}
case REPLENISH_MESSENGER:
_PutMessageToPort();
break;
case B_NODE_MONITOR:
case FILE_UPDATED:
{
BMessage fileMsg;
BFile file(fFileName, B_READ_ONLY);
if ((file.InitCheck() == B_NO_ERROR)
&& (fileMsg.Unflatten(&file) == B_NO_ERROR)) {
BList* newList = new BList;
// whatever this is set to will be deleted below.
// defaults to no deletion
BList* oldList = NULL;
int i = 0;
BMessage msg;
while (fileMsg.FindMessage("spec", i++, &msg) == B_NO_ERROR) {
uint32 key;
BMessage testerMsg;
BMessage actMsg;
if ((msg.FindInt32("key", (int32*) &key) == B_NO_ERROR)
&& ((msg.FindMessage("act", &actMsg)) == B_NO_ERROR)
&& ((msg.FindMessage("modtester", &testerMsg))
== B_NO_ERROR)) {
BArchivable* arcObj = instantiate_object(&testerMsg);
if (arcObj) {
BitFieldTester* tester =
dynamic_cast<BitFieldTester*>(arcObj);
if (tester) {
BArchivable* barcObj =
instantiate_object(&actMsg);
if (barcObj) {
CommandActuator* act =
dynamic_cast<CommandActuator*>(barcObj);
if (act)
newList->AddItem(
new hks(key, tester, act, actMsg));
else {
delete barcObj;
delete tester;
}
} else
delete tester;
} else
delete arcObj;
}
}
}
if (fSyncSpecs.Lock()) {
// swap in the new list
oldList = fSpecs;
fSpecs = newList;
fSyncSpecs.Unlock();
} else {
// wtf? This shouldn't happen...
oldList = newList; // but clean up if it does
}
_DeleteHKSList(oldList);
}
}
break;
}
}
// Deletes an HKS-filled BList and its contents.
void KeyCommandMap::_DeleteHKSList(BList* l)
{
if (l != NULL) {
int num = l->CountItems();
for (int i = 0; i < num; i++)
delete ((hks*) l->ItemAt(i));
delete l;
}
}
void KeyCommandMap::_PutMessageToPort()
{
if (fPort >= 0) {
BMessenger toMe(this);
BMessage m;
m.AddMessenger("target", toMe);
char buf[2048];
ssize_t fs = m.FlattenedSize();
if ((fs <= sizeof(buf)) && (m.Flatten(buf, fs) == B_NO_ERROR))
write_port_etc(fPort, 0, buf, fs, B_TIMEOUT, 250000);
}
}
@@ -0,0 +1,58 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef KeyCommandMap_h
#define KeyCommandMap_h
#include <List.h>
#include <Locker.h>
#include <Looper.h>
#include <Messenger.h>
#include <Message.h>
#include <MessageFilter.h>
// Maps BMessages to ShortcutsSpecs!
// The thread here gets file update messages, and updates
// the fSpecs list to match them (asynchronously).
class KeyCommandMap : public BLooper {
public:
KeyCommandMap(const char* watchFile);
~KeyCommandMap();
// Called when a key is pressed or depressed, in the input_server thread.
// (keyMsg) is the KEY_DOWN message given by the Input Server. (outlist) is
// a BList that additional BMessages can be added to (to insert events into
// the input stream) (sendMessagesTo) is the address of a queue to send
// command messages to, for async effects.
filter_result KeyEvent(const BMessage* keyMsg,
BList* outlist,
const BMessenger& sendMessagesTo);
// Called whenever the a B_MOUSE_MOVED message is received.
void MouseMoved(const BMessage* mouseMoveMsg);
void MessageReceived(BMessage* msg);
void DrainInjectedEvents(const BMessage* keyMsg,
BList* outlist,
const BMessenger& sendMessagesTo);
private:
void _PutMessageToPort();
void _DeleteHKSList(BList* list);
port_id fPort;
char* fFileName;
BLocker fSyncSpecs; // locks the lists below
BList fInjects;
BList* fSpecs;
BMessage fLastMouseMessage;
};
#endif
@@ -0,0 +1,186 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#include "KeyInfos.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <InterfaceDefs.h>
#define NUM_KEYS 256
#define MAX_UTF8_LENGTH 5 // up to 4 chars, plus a nul terminator
struct KeyLabelMap {
const char* fLabel;
uint8 fKeyCode;
};
// This is a table of keys-codes that have special, hard-coded labels.
static const struct KeyLabelMap keyLabels[] = {
{"<unset>", 0},
{"Esc", 1},
{"F1", 2},
{"F2", 3},
{"F3", 4},
{"F4", 5},
{"F5", 6},
{"F6", 7},
{"F7", 8},
{"F8", 9},
{"F9", 10},
{"F10", 11},
{"F11", 12},
{"F12", 13},
{"SysRq", 14},
{"ScrlLck", 15},
{"Pause", 16},
{"Bcksp", 30},
{"Insert", 31},
{"Home", 32},
{"PgUp", 33},
{"Num Lock", 34},
{"Kpd /", 35},
{"Kpd *", 36},
{"Kpd -", 37},
{"Tab", 38},
{"Delete", 52},
{"End", 53},
{"PgDn", 54},
{"Kpd 7", 55},
{"Kpd 8", 56},
{"Kpd 9", 57},
{"Kpd +", 58},
{"Caps Lock", 59},
{"Enter", 71},
{"Kpd 4", 72},
{"Kpd 5", 73},
{"Kpd 6", 74},
{"L.Shift", 75},
{"R.Shift", 86},
{"Up", 87},
{"Kpd 1", 88},
{"Kpd 2", 89},
{"Kpd 3", 90},
{"Kpd Entr", 91},
{"L.Control", 92},
{"L.Alt", 93},
{"Space", 94},
{"R.Alt", 95},
{"R.Control", 96},
{"Left", 97},
{"Down", 98},
{"Right", 99},
{"Kpd 0", 100},
{"Kpd .", 101},
{"L.Command", 102},
{"R.Command", 103},
{"Menu", 104},
{"PowerOn", 107},
};
// Key description strings (e.g. "A" or "Escape"). Null if no description is
// available.
static const char* keyDescriptions[NUM_KEYS];
// series of optional up-to-(4+1)-byte terminated UTF-8 character strings...
static char utfDescriptions[NUM_KEYS * MAX_UTF8_LENGTH];
static const char* FindSpecialKeyLabelFor(uint8 keyCode, int& last);
static const char*
FindSpecialKeyLabelFor(uint8 keyCode, int& last)
{
while ((keyLabels[last].fKeyCode < keyCode)
&& (last < (sizeof(keyLabels)/sizeof(struct KeyLabelMap))-1))
last++;
if (keyLabels[last].fKeyCode == keyCode)
return keyLabels[last].fLabel;
else
return NULL;
}
void
InitKeyIndices()
{
int nextSpecial = 0;
key_map* map;
char* keys;
get_key_map(&map, &keys);
for (int j = 0; j < NUM_KEYS; j++) {
keyDescriptions[j] = NULL; // default
const char* slabel = FindSpecialKeyLabelFor(j, nextSpecial);
int keyCode = map->normal_map[j];
if (keyCode >= 0) {
const char* mapDesc = &keys[keyCode];
uint8 len = *mapDesc;
for (int m = 0; m < MAX_UTF8_LENGTH; m++)
if (m < len)
utfDescriptions[j * MAX_UTF8_LENGTH + m] = mapDesc[m + 1];
else
utfDescriptions[j * MAX_UTF8_LENGTH + m] = '\0';
if (slabel)
keyDescriptions[j] = slabel;
else {
// If it's an ASCII letter, capitalize it.
char& c = utfDescriptions[j * MAX_UTF8_LENGTH];
if ((len == 1) && (isalpha(c)))
c = toupper(c);
if ((len > 1)||((len == 1) && (c > ' ')))
keyDescriptions[j] = &c;
}
} else
utfDescriptions[j * MAX_UTF8_LENGTH] = 0x00;
}
}
const char*
GetKeyUTF8(uint8 keyIndex)
{
return &utfDescriptions[keyIndex * MAX_UTF8_LENGTH];
}
const char*
GetKeyName(uint8 keyIndex)
{
return keyDescriptions[keyIndex];
}
int
GetNumKeyIndices()
{
return NUM_KEYS;
}
uint8
FindKeyCode(const char* keyName)
{
for (int i = 0; i < NUM_KEYS; i++)
if ((keyDescriptions[i])
&& (strcasecmp(keyName, keyDescriptions[i]) == 0))
return i;
return 0; // default to sentinel value
}
@@ -0,0 +1,33 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef KeyInfos_h
#define KeyInfos_h
#include <SupportDefs.h>
// Returns an ASCII string for the given key index, or NULL if a bad code is
// given.
const char* GetKeyName(uint8 keyIndex);
// Inverse of GetKeyName(). Finds the index of the given string. Returns 0 if
// the string was not found in the set of key names.
uint8 FindKeyCode(const char* keyName);
// Returns the UTF8 value for the given key, or "\0" if none.
const char* GetKeyUTF8(uint8 keyIndex);
// Returns the number of key indices that are known. (Currently 256). Indices
// (0...GetNumKeyIndices()-1) are valid.
int GetNumKeyIndices();
// Should be called at startup.
void InitKeyIndices();
#endif
@@ -0,0 +1,321 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
* Fredrik Modéen
*/
#include "ParseCommandLine.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <Roster.h>
#include <List.h>
#include <Entry.h>
#include <Directory.h>
#include <SupportKit.h>
// This char is used to hold words together into single words...
#define GUNK_CHAR 0x01
#define PATHTOTRACKER "/boot/system/Tracker"
// Turn all spaces that are not-to-be-counted-as-spaces into GUNK_CHAR chars.
static void
GunkSpaces(char* string)
{
bool insideQuote = false;
bool afterBackslash = false;
while (*string) {
switch(*string) {
case '\"':
if (!afterBackslash)
insideQuote = !insideQuote; // toggle escapement mode
break;
case ' ':
case '\t':
if ((insideQuote)||(afterBackslash))
*string = GUNK_CHAR;
break;
}
afterBackslash = (*string == '\\') ? !afterBackslash : false;
string++;
}
}
// Removes all un-escaped quotes and backslashes from the string, in place
static void
RemoveQuotes(char* string)
{
bool afterBackslash = false;
char* endString = strchr(string, '\0');
char* to = string;
while (*string) {
bool temp = (*string == '\\') ? !afterBackslash : false;
switch(*string) {
case '\"':
case '\\':
if (afterBackslash)
*(to++) = *string;
break;
case 'n':
*(to++) = afterBackslash ? '\n' : *string;
break;
case 't':
*(to++) = afterBackslash ? '\t' : *string;
break;
default:
*(to++) = *string;
break;
}
afterBackslash = temp;
string++;
}
*to = '\0';
if (to < endString)
*(to+1) = '\0'; // needs to be double-terminated!
}
static bool IsValidChar(char c);
static bool
IsValidChar(char c)
{
return ((c > ' ')||(c == '\n')||(c == '\t'));
}
// Returns true if it is returning valid results into (*setBegin) & (*setEnd).
// If returning true, (*setBegin) now points to the first char in a new word,
// and (*setEnd) now points to the char after the last char in the word, which
// has been set to a NUL byte.
static bool
GetNextWord(char** setBegin, char** setEnd)
{
char* next = *setEnd; // we'll start one after the end of the last one...
while (next++) {
if (*next == '\0')
return false; // no words left!
else if ((IsValidChar(*next) == false) && (*next != GUNK_CHAR))
*next = '\0';
else
break; // found a non-whitespace char!
}
*setBegin = next; // we found the first char!
while (next++) {
if ((IsValidChar(*next) == false) && (*next != GUNK_CHAR)) {
*next = '\0'; // terminate the word
*setEnd = next;
return true;
}
}
return false; // should never get here, actually
}
// Turns the gunk back into spaces
static void
UnGunk(char* str)
{
char* temp = str;
while (*temp) {
if (*temp == GUNK_CHAR)
*temp = ' ';
temp++;
}
}
char**
ParseArgvFromString(const char* command, int32& argc)
{
// make our own copy of the string...
int slen = strlen(command);
// need an extra nul byte to get GetNextWord() to stop
char* cmd = new char[slen + 2];
strcpy(cmd, command);
cmd[slen+1] = '\0'; // zero out the second nul byte
GunkSpaces(cmd);
RemoveQuotes(cmd);
BList wordlist;
char* beginWord = NULL, *endWord = cmd - 1;
while (GetNextWord(&beginWord, &endWord))
wordlist.AddItem(beginWord);
argc = wordlist.CountItems();
char** argv = new char* [argc + 1];
for (int i = 0; i < argc; i++) {
char* temp = (char*) wordlist.ItemAt(i);
argv[i] = new char[strlen(temp) + 1];
strcpy(argv[i], temp);
// turn space-markers back into real spaces...
UnGunk(argv[i]);
}
argv[argc] = NULL; // terminate the array
delete [] cmd; // don't need our local copy any more
return argv;
}
void
FreeArgv(char** argv)
{
if (argv) {
int i = 0;
while (argv[i]) {
delete [] argv[i];
i++;
}
}
delete [] argv;
}
// Make new, independent clone of an argv array and its strings.
char**
CloneArgv(char** argv)
{
int argc = 0;
while (argv[argc] != NULL)
argc++;
char** newArgv = new char* [argc + 1];
for (int i = 0; i < argc; i++) {
newArgv[i] = new char[strlen(argv[i]) + 1];
strcpy(newArgv[i], argv[i]);
}
newArgv[argc] = NULL;
return newArgv;
}
BString
ParseArgvZeroFromString(const char* command)
{
char* ret = NULL;
// make our own copy of the string...
int slen = strlen(command);
// need an extra nul byte to get GetNextWord() to stop
char* cmd = new char[slen + 2];
strcpy(cmd, command);
cmd[slen + 1] = '\0'; // zero out the second nul byte
GunkSpaces(cmd);
RemoveQuotes(cmd);
char* beginWord = NULL, *endWord = cmd - 1;
if (GetNextWord(&beginWord, &endWord)) {
ret = new char[strlen(beginWord) + 1];
strcpy(ret, beginWord);
UnGunk(ret);
}
delete [] cmd;
BString retStr(ret?ret:"");
delete [] ret;
return retStr;
}
bool
DoStandardEscapes(BString& string)
{
bool ret = false;
// Escape any characters that might mess us up
// note: check this first, or we'll detect the slashes WE put in!
ret |= EscapeChars(string, '\\');
ret |= EscapeChars(string, '\"');
ret |= EscapeChars(string, ' ');
ret |= EscapeChars(string, '\t');
return ret;
}
// Modifies (string) so that each instance of (badChar) in it is preceded by a
// backslash. Returns true iff modifications were made.
bool
EscapeChars(BString& string, char badChar)
{
if (string.FindFirst(badChar) == -1)
return false;
BString temp;
int stringLen = string.Length();
for (int i = 0; i < stringLen; i++) {
char next = string[i];
if (next == badChar)
temp += '\\';
temp += next;
}
string = temp;
return true;
}
// Launch the given app/project file. Put here so that Shortcuts and
// BartLauncher can share this code!
status_t
LaunchCommand(char** argv, int32 argc)
{
BEntry entry(argv[0], true);
if (entry.Exists()) {
// See if it's a directory. If it is, ask Tracker to open it, rather
// than launch.
BDirectory testDir(&entry);
if (testDir.InitCheck() == B_NO_ERROR) {
// Hack way to do this--really I should be able to do this by
// sending a BMessage. But how? When I finally get my copy of the
// BeOS Bible, maybe then I'll find out.
const char* trackerFile = PATHTOTRACKER;
char* temp = new char[strlen(trackerFile) + strlen(argv[0]) + 10];
sprintf(temp, "%s '%s'", trackerFile, argv[0]);
system(temp);
delete [] temp;
return B_NO_ERROR;
} else {
// It's not a directory. Must be a file.
entry_ref ref;
if (entry.GetRef(&ref) == B_NO_ERROR) {
if (argc > 1)
be_roster->Launch(&ref, argc-1, &argv[1]);
else
be_roster->Launch(&ref);
return B_NO_ERROR;
}
}
}
return B_ERROR;
}
@@ -0,0 +1,47 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef ParseCommandString_h
#define ParseCommandString_h
#include <String.h>
// Utility methods to extract arguments from a typed-in string.
// Returns an NULL-terminated argv array. Sets (setArgc) to the number of
// valid arguments in the array. It becomes the responsibility of the calling
// code to delete[] the array and each string in it. If (padFront > 0), then
// (padFront) extra "slots" will be allocated at the beginning of the returned
// argv array. These slots will be NULL, and will be counted in the (setArgc)
// result. It is the caller's responsibility to fill them...
char** ParseArgvFromString(const char* string, int32& setArgc);
// Call this to free the argv array returned by ParseArgvFromString().
char** CloneArgv(char** argv);
// Call this to free the argv array returned by ParseArgvFromString().
void FreeArgv(char** argv);
// Returns the first argument in the string.
BString ParseArgvZeroFromString(const char* string);
// Calls EscapeChars() on (string) for the following characters: backslash,
// single quote, double quote, space, and tab. The returns string should be
// parsable as a single word by the functions above.
bool DoStandardEscapes(BString& string);
// Modifies (string) by inserting slashes in front of each instance of badChar.
// Returns false iff no modifications were done.
bool EscapeChars(BString& string, char badChar);
// Launch an app, Tracker style. Put here so that it can be shared amongst
// my various apps...
status_t LaunchCommand(char** argv, int32 argc);
#endif
@@ -0,0 +1,24 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef ShortcutsConstants_h
#define ShortcutsConstants_h
#define SHORTCUTS_SETTING_FILE_NAME "shortcuts_settings"
#define SHORTCUTS_CATCHER_PORT_NAME "ShortcutsCatcherPort"
enum {
EXECUTE_COMMAND = 'exec', // Code: Execute "command" as given
REPLENISH_MESSENGER, // sent to tell us to write our port again
NUM_ACTION_CODES
};
#endif
@@ -0,0 +1,87 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#include "ShortcutsServerFilter.h"
#include <Path.h>
#include <FindDirectory.h>
#include "KeyCommandMap.h"
#include "KeyInfos.h"
#include "CommandExecutor.h"
#include "ShortcutsFilterConstants.h"
class BInputServerFilter;
// Called by input_server on startup. Must be exported as a "C" function!
BInputServerFilter* instantiate_input_filter()
{
return new ShortcutsServerFilter;
}
ShortcutsServerFilter::ShortcutsServerFilter()
:
fExecutor(new CommandExecutor)
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK)
path.Append(SHORTCUTS_SETTING_FILE_NAME);
fMap = new KeyCommandMap(path.Path());
InitKeyIndices();
fMessenger = BMessenger(fExecutor);
fMap->Run();
fExecutor->Run();
}
ShortcutsServerFilter::~ShortcutsServerFilter()
{
if (fMap->Lock())
fMap->Quit();
if (fExecutor->Lock())
fExecutor->Quit();
}
status_t
ShortcutsServerFilter::InitCheck()
{
return B_NO_ERROR;
}
filter_result
ShortcutsServerFilter::Filter(BMessage* msg, BList* outlist)
{
filter_result ret = B_DISPATCH_MESSAGE;
switch(msg->what)
{
case B_KEY_DOWN:
case B_KEY_UP:
case B_UNMAPPED_KEY_DOWN:
case B_UNMAPPED_KEY_UP:
ret = fMap->KeyEvent(msg, outlist, fMessenger);
break;
case B_MOUSE_MOVED:
case B_MOUSE_UP:
case B_MOUSE_DOWN:
fMap->MouseMoved(msg);
break;
}
fMap->DrainInjectedEvents(msg, outlist, fMessenger);
return ret;
}
@@ -0,0 +1,53 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef ShortcutsServerFilter_h
#define ShortcutsServerFilter_h
#include <stdio.h>
#include <Messenger.h>
#include <Message.h>
#include <List.h>
#include <InputServerFilter.h>
#ifdef __POWERPC__
#pragma export on
#endif
// export this for the input_server
extern "C" _EXPORT BInputServerFilter* instantiate_input_filter();
class KeyCommandMap;
class CommandExecutor;
class ShortcutsServerFilter : public BInputServerFilter {
public:
ShortcutsServerFilter();
virtual ~ShortcutsServerFilter();
virtual status_t InitCheck();
virtual filter_result Filter(BMessage* message, BList* outlist);
private:
// Tells us what command goes with a given key
KeyCommandMap* fMap;
// Executes the given commands
CommandExecutor* fExecutor;
// Points to fExecutor:declaration order is important!
BMessenger fMessenger;
};
#ifdef __POWERPC__
#pragma export reset
#endif
#endif