The code for an handwriting input method front-end, currently doesn't do much more than draw the strokes over the screen. The idea is to have a base backend class that will be used to call several backends like Lipi Toolkit or others. WIP.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25997 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol
2008-06-17 16:36:54 +00:00
parent 087bd9e838
commit a94e61350c
17 changed files with 1419 additions and 0 deletions
@@ -0,0 +1,256 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <BeBuild.h>
#include <Font.h>
#include <Message.h>
#include <String.h>
#include "DumpMessage.h"
//#define WHAT_ALWAYS_HEX 1
const char *msg_header_comment = "// new BMessage\n"; // avoids mime to think it's a .bmp ("BM")
// '_' also widely used in what codes
inline int myisprint(int c)
{
if (isalnum(c))
return 1;
return (c == '_')?1:0;
}
status_t HexDumpToStream(const void *data, size_t len, BDataIO &stream, const char *prefix = NULL)
{
const unsigned char *p = (unsigned char *)data;
char buffer[100];
size_t i, j;
for (i=0; i<len; i+=16) {
if (prefix) stream.Write(prefix, strlen(prefix));
sprintf(buffer, "0x%06lx: ", i);
stream.Write(buffer, strlen(buffer));
for (j=0; j<16; j++) {
if (i+j < len)
sprintf(buffer, "%02x", p[i+j]);
else
sprintf(buffer, " ");
if (j % 4 == 3)
sprintf(buffer+strlen(buffer), " ");
stream.Write(buffer, strlen(buffer));
}
sprintf(buffer, " '");
stream.Write(buffer, strlen(buffer));
for (j=0; j<16; j++) {
if (i+j >= len)
sprintf(buffer, " ");
//else if (p[i+j] < 255 && p[i+j] >= 0x20)
else if (isalpha(p[i+j]))
sprintf(buffer, "%c", p[i+j]);
else
sprintf(buffer, ".");
stream.Write(buffer, 1);
}
sprintf(buffer, "'\n");
stream.Write(buffer, strlen(buffer));
}
return B_OK;
}
/* look up human readable names from an other BMessage */
bool LookUpFieldName(const char **name, const char *field_name, BMessage *names)
{
if (names == NULL)
return false;
if (names->FindString(field_name, name) == B_OK)
return true;
return false;
}
status_t DumpMessageToStream(BMessage *message, BDataIO &stream, int tabCount, BMessage *names)
{
int32 index;
void *cookie = NULL;
const char *field_name;
type_code field_code;
int32 field_count;
char buffer[80];
char tabs[20];
const char *easy_name;
if (message == NULL)
return EINVAL;
if (tabCount < 1)
stream.Write(msg_header_comment, strlen(msg_header_comment));
memset(tabs, '\t', (++tabCount) + 1);
tabs[tabCount+1] = '\0';
//tabCount;
#ifndef WHAT_ALWAYS_HEX
if ( myisprint(message->what & 0x0ff) &&
myisprint((message->what >> 8) & 0x0ff) &&
myisprint((message->what >> 16) & 0x0ff) &&
myisprint((message->what >> 24) & 0x0ff))
sprintf(buffer, "BMessage('%c%c%c%c') {\n",
(char)(message->what >> 24) & 0x0ff,
(char)(message->what >> 16) & 0x0ff,
(char)(message->what >> 8) & 0x0ff,
(char)message->what & 0x0ff);
else
#endif
sprintf(buffer, "BMessage(0x%08lx) {\n", message->what);
// stream.Write(tabs+2, tabCount-2);
stream.Write(buffer, strlen(buffer));
#ifdef B_BEOS_VERSION_DANO
while (message->GetNextName(&cookie,
&field_name,
&field_code,
&field_count) == B_OK) {
#else
#warning mem leak likely! (name=char *)
for (int which=0; message->GetInfo(B_ANY_TYPE, which,
(char **)&field_name, &field_code, &field_count) == B_OK; which++) {
#endif
if (LookUpFieldName(&easy_name, field_name, names)) {
stream.Write(tabs+1, tabCount);
stream.Write("// ", 3);
stream.Write(easy_name, strlen(easy_name));
stream.Write("\n", 1);
}
for (index=0; index < field_count; index++) {
stream.Write(tabs+1, tabCount);
stream.Write(field_name, strlen(field_name));
if (field_count > 1) {
sprintf(buffer, "[%ld]", index);
stream.Write(buffer, strlen(buffer));
}
stream.Write(" = ", 3);
switch (field_code) {
case 'MSGG':
{
BMessage m;
if (message->FindMessage(field_name, index, &m) >= B_OK)
DumpMessageToStream(&m, stream, tabCount, names);
}
break;
#ifdef B_BEOS_VERSION_DANO
case 'FONt':
{
BFont f;
if (message->FindFlat(field_name, index, &f) >= B_OK)
stream << f;
stream.Write("\n", 1);
}
break;
case B_RGB_COLOR_TYPE:
{
rgb_color c;
if (message->FindRGBColor(field_name, index, &c) >= B_OK) {
sprintf(buffer, "rgb_color(%d,%d,%d,%d)",
c.red, c.green, c.blue, c.alpha);
stream.Write(buffer, strlen(buffer));
}
stream.Write("\n", 1);
}
break;
#else
#warning IMPLEMENT ME
#endif
case B_BOOL_TYPE:
{
bool value;
if (message->FindBool(field_name, index, &value) >= B_OK) {
sprintf(buffer, "bool(%s)", value?"true":"false");
stream.Write(buffer, strlen(buffer));
}
stream.Write("\n", 1);
}
break;
case B_INT32_TYPE:
{
int32 value;
if (message->FindInt32(field_name, index, &value) >= B_OK) {
#if 1
if (value == 0)
sprintf(buffer, "int32(0 or (nil))");
else
#endif
// sprintf(buffer, "int32(%d)", value);
sprintf(buffer, "int32(%ld or 0x%lx)", value, value);
stream.Write(buffer, strlen(buffer));
}
stream.Write("\n", 1);
}
break;
case B_FLOAT_TYPE:
{
float value;
if (message->FindFloat(field_name, index, &value) >= B_OK) {
sprintf(buffer, "float(%f)", value);
stream.Write(buffer, strlen(buffer));
}
stream.Write("\n", 1);
}
break;
case B_STRING_TYPE:
{
const char *value;
if (message->FindString(field_name, index, &value) >= B_OK) {
BString str(value);
str.CharacterEscape("\\\"\n", '\\');
//sprintf(buffer, "string(\"%s\", %ld bytes)", str.String(), strlen(value));
// DO NOT use buffer!
str.Prepend("string(\"");
str << "\", " << strlen(value) << " bytes)";
stream.Write(str.String(), strlen(str.String()));
}
stream.Write("\n", 1);
}
break;
case B_POINT_TYPE:
{
BPoint value;
if (message->FindPoint(field_name, index, &value) >= B_OK) {
sprintf(buffer, "BPoint(%1.1f, %1.1f)", value.x, value.y);
stream.Write(buffer, strlen(buffer));
}
stream.Write("\n", 1);
}
break;
default:
{
const void *data;
ssize_t numBytes = 0;
if (message->FindData(field_name, field_code, index, &data, &numBytes) != B_OK) {
//stream.Write("\n", 1);
break;
}
if ( isalnum(field_code & 0x0ff) &&
isalnum((field_code >> 8) & 0x0ff) &&
isalnum((field_code >> 16) & 0x0ff) &&
isalnum((field_code >> 24) & 0x0ff))
sprintf(buffer, "'%c%c%c%c' %ld bytes:\n",
(char)(field_code >> 24) & 0x0ff,
(char)(field_code >> 16) & 0x0ff,
(char)(field_code >> 8) & 0x0ff,
(char)field_code & 0x0ff,
numBytes);
else
sprintf(buffer, "0x%08lx %ld bytes:\n", field_code, numBytes);
stream.Write(buffer, strlen(buffer));
stream.Write("\n", 1);
HexDumpToStream(data, numBytes, stream, tabs);
}
break;
}
}
}
stream.Write(tabs+2, tabCount-1);
stream.Write("}\n", 2);
return B_OK;
}
@@ -0,0 +1,10 @@
#ifndef _DUMP_MESSAGE_H
#define _DUMP_MESSAGE_H
class BMessage;
class BDataIO;
status_t DumpMessageToStream(BMessage *message, BDataIO &stream, int tabCount = 0, BMessage *names = NULL);
#endif /* _DUMP_MESSAGE_H */
@@ -0,0 +1,21 @@
// will need better, stippi ?
// should have icons showing modes (word/char/num + caps)
const uchar PenIconData[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x4b, 0x4b, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x4b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x4b, 0xff, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x4b, 0x4b, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x4b, 0xff, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x4b, 0x4b, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x4b, 0x4b, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x4b, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x4b, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x4b, 0xff, 0xff, 0x00, 0x4b, 0x4b, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x4b, 0x4b, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x4b, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
@@ -0,0 +1,15 @@
#include <OS.h>
#include "PenInputBackend.h"
PenInputBackend::PenInputBackend(const char *name)
: BHandler(name)
{
}
PenInputBackend::~PenInputBackend()
{
}
@@ -0,0 +1,19 @@
#ifndef _PEN_INPUT_BACKEND_H
#define _PEN_INPUT_BACKEND_H
#include <Handler.h>
class PenInputBackend : public BHandler {
protected:
PenInputBackend(const char *name);
virtual ~PenInputBackend();
public:
status_t InitCheck() const { return fInitStatus; };
private:
status_t fInitStatus;
};
#endif /* _PEN_INPUT_BACKEND_H */
@@ -0,0 +1,126 @@
/*
Copyright 2007, Francois Revol. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#include <OS.h>
#include <Debug.h>
#include <View.h>
#if DEBUG
//#include <File.h>
#include <Alert.h>
#include <Button.h>
#include <TextView.h>
#include <StringIO.h>
#include "DumpMessage.h"
#endif
#include "PenInputInkWindow.h"
#include "PenInputLooper.h"
#include "PenInputStrings.h"
const rgb_color kInkColor = { 100, 100, 255, 0 };
class PenInputInkView : public BView {
public:
PenInputInkView(BRect frame, PenInputInkWindow *window);
virtual ~PenInputInkView();
virtual void Draw(BRect udpateRect);
private:
PenInputInkWindow *fWindow;
};
PenInputInkView::PenInputInkView(BRect frame, PenInputInkWindow *window)
: BView(frame, "PenInkView", B_FOLLOW_ALL, B_WILL_DRAW),
fWindow(window)
{
}
PenInputInkView::~PenInputInkView()
{
}
void PenInputInkView::Draw(BRect udpateRect)
{
/* ugh ? */
if (!fWindow)
return;
StrokeShape(&fWindow->fStrokes);
//DEBUG:StrokeRect(fWindow->fStrokes.Bounds());
}
PenInputInkWindow::PenInputInkWindow(BRect frame)
: BWindow(frame, "PenInputInkWindow",
B_NO_BORDER_WINDOW_LOOK,
B_FLOATING_ALL_WINDOW_FEEL,
B_NOT_MOVABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE |
B_NOT_MINIMIZABLE | B_NOT_RESIZABLE | B_AVOID_FOCUS,
B_ALL_WORKSPACES),
fStrokeCount(0)
{
PRINT(("%s\n", __FUNCTION__));
fInkView = new PenInputInkView(Bounds(), this);
fInkView->SetViewColor(B_TRANSPARENT_32_BIT);
fInkView->SetLowColor(B_TRANSPARENT_32_BIT);
//fInkView->SetHighColor(0,255,0);
fInkView->SetHighColor(kInkColor);
fInkView->SetPenSize(2.0);
AddChild(fInkView);
}
PenInputInkWindow::~PenInputInkWindow()
{
PRINT(("%s\n", __FUNCTION__));
}
void PenInputInkWindow::MessageReceived(BMessage *message)
{
BPoint where;
switch (message->what) {
case MSG_BEGIN_INK:
fStrokeCount = 0;
fStrokes.Clear();
// fall through
case MSG_SHOW_WIN:
if (IsHidden())
Show();
break;
case MSG_END_INK:
case MSG_HIDE_WIN:
if (!IsHidden())
Hide();
break;
case B_MOUSE_MOVED:
if (message->FindPoint("where", &where) == B_OK) {
fStrokes.LineTo(where);
fStrokeCount++;
//fInkView->Invalidate(fStrokes.Bounds()); // XXX
fInkView->Invalidate(Bounds()); // XXX
}
break;
case B_MOUSE_UP:
if (message->FindPoint("where", &where) == B_OK) {
fStrokes.LineTo(where);
fStrokeCount++;
//fInkView->Invalidate(fStrokes.Bounds()); // XXX
fInkView->Invalidate(Bounds()); // XXX
}
break;
case B_MOUSE_DOWN:
if (message->FindPoint("where", &where) == B_OK) {
fStrokes.MoveTo(where);
//fStrokeCount++;
//fInkView->Invalidate(fStrokes.Bounds()); // XXX
fInkView->Invalidate(Bounds()); // XXX
}
break;
default:
BWindow::MessageReceived(message);
return;
}
}
@@ -0,0 +1,26 @@
/*
Copyright 2005, Francois Revol. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#include <Window.h>
#include <Shape.h>
class PenInputInkView;
class PenInputInkWindow : public BWindow
{
public:
PenInputInkWindow(BRect frame);
virtual ~PenInputInkWindow();
void MessageReceived(BMessage *message);
private:
friend class PenInputInkView;
friend class PenInputLooper;//DEBUG
void ClearStrokes();
PenInputInkView *fInkView;
BShape fStrokes;
int32 fStrokeCount;
};
@@ -0,0 +1,255 @@
/*
Copyright 2007, Francois Revol. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#define DEBUG 1
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <Debug.h>
#include <List.h>
#include <Message.h>
#include <OS.h>
#include <Application.h>
#include <Menu.h>
#include <MenuItem.h>
#include <MessageRunner.h>
#include <Region.h>
#include <Screen.h>
#if DEBUG
//#include <File.h>
#include <Alert.h>
#include <Button.h>
#include <TextView.h>
#include <StringIO.h>
#include "DumpMessage.h"
#endif
#include "PenInputLooper.h"
#include "PenInputBackend.h"
#include "PenInputInkWindow.h"
#include "PenInputServerMethod.h"
#include "PenInputStrings.h"
PenInputLooper::PenInputLooper(PenInputServerMethod *method)
: BLooper("PenInputLooper", B_NORMAL_PRIORITY),
fOwner(method),
fInkWindow(NULL),
fBackend(NULL),
fDeskbarMenu(NULL),
fMouseDown(false),
fStroking(false),
fThresholdRunner(NULL),
fCachedMouseDown(NULL),
fShowInk(true),
fMouseDownThreshold(100000)
{
PRINT(("%s\n", __FUNCTION__));
//
fDeskbarMenu = new BMenu(_T("Options"));
BMenu *subMenu;
subMenu = new BMenu(_T("Backend"));
BMessage *msg;
msg = new BMessage(MSG_SET_BACKEND);
BMenuItem *item;
// for (i = 0; i < fBackends.CountItems(); i++) ...
item = new BMenuItem(_T("Default"), msg);
item->SetMarked(true);
subMenu->AddItem(item);
item = new BMenuItem(subMenu);
fDeskbarMenu->AddItem(item);
msg = new BMessage(MSG_SHOW_INK);
item = new BMenuItem(_T("Show Ink"), msg);
item->SetMarked(true);
fDeskbarMenu->AddItem(item);
fDeskbarMenu->SetFont(be_plain_font);
fOwner->SetMenu(fDeskbarMenu, BMessenger(NULL, this));
#if 0
BRegion region;
fOwner->GetScreenRegion(&region);
fInkWindow = new PenInputInkWindow(region.Frame());
#endif
BScreen screen;
fInkWindow = new PenInputInkWindow(screen.Frame());
fInkWindow->Show();
fInkWindow->Lock();
fInkWindow->Hide();
fInkWindow->Unlock();
fInkWindowMsgr = BMessenger(NULL, fInkWindow);
BMessage m(MSG_CHECK_PEN_DOWN);
fThresholdRunner = new BMessageRunner(BMessenger(NULL, this), &m, fMouseDownThreshold, 0);
Run();
}
void PenInputLooper::Quit()
{
PRINT(("%s\n", __FUNCTION__));
delete fThresholdRunner;
fInkWindow->Lock();
fInkWindow->Quit();
fOwner->SetMenu(NULL, BMessenger());
delete fDeskbarMenu;
BLooper::Quit();
}
void PenInputLooper::DispatchMessage(BMessage *message, BHandler *handler)
{
switch (message->what) {
#if 0
case B_MOUSE_MOVED:
case B_MOUSE_DOWN:
case B_MOUSE_UP:
case B_INPUT_METHOD_EVENT:
//case B_REPLY:
if (fBackend) {
fBackend->MessageReceived(message);
return;
}
#endif
default:
return BLooper::DispatchMessage(message, handler);
}
}
void PenInputLooper::MessageReceived(BMessage *message)
{
int32 v;
int32 buttons;
bool b;
#if 1
{
//message->Flatten(&fDebugFile);
BStringIO sio;
DumpMessageToStream(message, sio);
fInkWindow->Lock();
sio << BString("StrokesCount: ");
BString tmp;
tmp << fInkWindow->fStrokeCount;
sio << tmp;
sio << BString("\nStrokes.Bounds: ");
sio << (fInkWindow->fStrokes.Bounds());
sio << BString("\n");
fInkWindow->Unlock();
fOwner->fDebugAlert->Lock();
fOwner->fDebugAlert->TextView()->Insert("Looper:\n");
fOwner->fDebugAlert->TextView()->Insert(sio.String());
fOwner->fDebugAlert->Unlock();
}
#endif
switch (message->what) {
case MSG_CHECK_PEN_DOWN:
if (fCachedMouseDown) {
/* nothing happened, we want to move the mouse */
EnqueueMessage(fCachedMouseDown);
fCachedMouseDown = NULL;
}
break;
case B_MOUSE_MOVED:
if (!fMouseDown) { /* definitely not writing */
/* pass it along */
EnqueueMessage(DetachCurrentMessage());
break;
}
if (fShowInk) {
BMessage *msg = new BMessage(*message);
fInkWindowMsgr.SendMessage(msg);
}
if (fBackend)
fBackend->MessageReceived(message);
else
EnqueueMessage(DetachCurrentMessage());
break;
case B_MOUSE_DOWN:
if (message->FindInt32("buttons", &buttons) == B_OK) {
if (!(buttons & B_PRIMARY_MOUSE_BUTTON)) {
/* pass it along */
EnqueueMessage(DetachCurrentMessage());
break;
}
}
fMouseDown = true;
if (fShowInk) {
{
BMessage *msg = new BMessage(MSG_BEGIN_INK);
fInkWindowMsgr.SendMessage(msg);
}
BMessage *msg = new BMessage(*message);
fInkWindowMsgr.SendMessage(msg);
}
if (fBackend)
fBackend->MessageReceived(message);
break;
case B_MOUSE_UP:
if (message->FindInt32("buttons", &buttons) == B_OK) {
if (!fMouseDown || (buttons & B_PRIMARY_MOUSE_BUTTON)) {
/* pass it along */
EnqueueMessage(DetachCurrentMessage());
break;
}
}
fMouseDown = false;
if (fShowInk) {
BMessage *msg = new BMessage(*message);
fInkWindowMsgr.SendMessage(msg);
{
BMessage *msg = new BMessage(MSG_END_INK);
fInkWindowMsgr.SendMessage(msg);
}
}
if (fBackend)
fBackend->MessageReceived(message);
break;
case B_INPUT_METHOD_EVENT:
if (fBackend)
fBackend->MessageReceived(message);
break;
case MSG_METHOD_ACTIVATED:
if (message->FindBool(MSGF_ACTIVE, &b) < B_OK)
b = false;
HandleMethodActivated(b);
break;
case B_REPLY:
default:
BLooper::MessageReceived(message);
break;
}
}
void PenInputLooper::EnqueueMessage(BMessage *message)
{
fOwner->EnqueueMessage(message);
}
status_t PenInputLooper::InitCheck()
{
return B_OK;
}
void PenInputLooper::HandleMethodActivated(bool active)
{
/*
if (fShowInk && active)
fInkWindowMsgr.SendMessage(MSG_SHOW_WIN);
if (fShowInk && !active)
fInkWindowMsgr.SendMessage(MSG_END_INK);
*/
}
@@ -0,0 +1,69 @@
/*
Copyright 2007, Francois Revol. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _PEN_INPUT_LOOPER_H
#define _PEN_INPUT_LOOPER_H
#include <MessageRunner.h>
#include <Messenger.h>
#include <Looper.h>
/* internal messages */
#define MSG_METHOD_ACTIVATED 'IMAc'
#define MSGF_ACTIVE "active" /* bool */
#define MSG_BEGIN_INK 'InkB'
#define MSG_END_INK 'InkE'
#define MSG_SHOW_WIN 'ShoW'
#define MSG_HIDE_WIN 'HidW'
#define MSG_CHECK_PEN_DOWN 'ChkP'
/* menu messages */
#define MSG_SET_BACKEND 'SetB'
#define MSGF_BACKEND "backend" /* string */
#define MSG_SHOW_INK 'InkS' /* toggle */
class BMenu;
class BWindow;
class PenInputServerMethod;
class PenInputInkWindow;
class PenInputBackend;
class PenInputLooper : public BLooper
{
public:
PenInputLooper(PenInputServerMethod *method);
virtual void Quit();
void DispatchMessage(BMessage *message, BHandler *handler);
void MessageReceived(BMessage *message);
void EnqueueMessage(BMessage *message);
status_t InitCheck();
// virtual ~PenInputLooper();
void MethodActivated(bool active);
private:
friend class PenInputInkWindow;
void HandleMethodActivated(bool active);
PenInputServerMethod *fOwner;
PenInputInkWindow *fInkWindow;
PenInputBackend *fBackend;
BMenu *fDeskbarMenu;
BMessenger fInkWindowMsgr;
bool fMouseDown;
bool fStroking;
BMessageRunner *fThresholdRunner;
BMessage *fCachedMouseDown;
/* config */
bool fShowInk;
bigtime_t fMouseDownThreshold;
};
#endif /* _PEN_INPUT_LOOPER_H */
@@ -0,0 +1,217 @@
/*
Copyright 2007, Francois Revol. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
//#define DEBUG 1
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <Debug.h>
#include <List.h>
#include <Message.h>
#include <OS.h>
#include <Application.h>
#include <Menu.h>
#include <MenuItem.h>
#include <Region.h>
#if DEBUG
//#include <File.h>
#include <Alert.h>
#include <Button.h>
#include <TextView.h>
#include <StringIO.h>
#include "DumpMessage.h"
#endif
#include <add-ons/input_server/InputServerDevice.h>
#include <add-ons/input_server/InputServerMethod.h>
#include "PenIcon.h"
#include "PenInputServerMethod.h"
#include "PenInputLooper.h"
#include "PenInputStrings.h"
BInputServerMethod* instantiate_input_method()
{
PRINT(("%s\n", __FUNCTION__));
return (new PenInputServerMethod());
}
PenInputServerMethod::PenInputServerMethod()
: BInputServerMethod("Pen", PenIconData),
fEnabled(false)
{
PRINT(("%s\n", __FUNCTION__));
#if DEBUG
//fDebugFile.SetTo("/tmp/PenInputMethodMessages.txt", B_READ_WRITE|B_CREATE_FILE);
fDebugAlert = new BAlert("PenInput Debug", "Plip \n\n\n\n\n\n\n\n\n\n\n\n\n", "Ok");
fDebugAlert->SetLook(B_TITLED_WINDOW_LOOK);
fDebugAlert->TextView()->MakeSelectable();
fDebugAlert->TextView()->SelectAll();
fDebugAlert->TextView()->Delete();
fDebugAlert->ButtonAt(0)->SetEnabled(false);
BRegion r;
GetScreenRegion(&r);
BString s;
s << r.CountRects() << " rects\n";
fDebugAlert->TextView()->Insert(s.String());
fDebugAlert->Go(NULL);
#endif
}
PenInputServerMethod::~PenInputServerMethod()
{
PRINT(("%s\n", __FUNCTION__));
SetMenu(NULL, BMessenger());
#if DEBUG
fDebugAlert->Lock();
fDebugAlert->Quit();
#endif
BLooper *looper = NULL;
fLooper.Target(&looper);
if (looper != NULL)
{
if (looper->Lock())
looper->Quit();
}
}
status_t PenInputServerMethod::InitCheck()
{
PenInputLooper *looper;
status_t err;
PRINT(("%s\n", __FUNCTION__));
looper = new PenInputLooper(this);
looper->Lock();
err = looper->InitCheck();
looper->Unlock();
fLooper = BMessenger(NULL, looper);
return err;
}
filter_result PenInputServerMethod::Filter(BMessage *message, BList *outList)
{
status_t err;
filter_result res = B_DISPATCH_MESSAGE;
if (!IsEnabled())
return B_DISPATCH_MESSAGE;
#if 0//DEBUG
//message->Flatten(&fDebugFile);
BStringIO sio;
DumpMessageToStream(message, sio);
fDebugAlert->Lock();
fDebugAlert->TextView()->Insert(sio.String());
fDebugAlert->Unlock();
#endif
switch (message->what) {
case B_KEY_UP:
case B_KEY_DOWN:
case B_UNMAPPED_KEY_UP:
case B_UNMAPPED_KEY_DOWN:
case B_MODIFIERS_CHANGED:
case B_MOUSE_WHEEL_CHANGED:
return B_DISPATCH_MESSAGE;
default:
//case B_MOUSE_MOVED:
fLooper.SendMessage(message);
return B_SKIP_MESSAGE;
}
#if 0
if (message->what == B_MOUSE_MOVED) {
BMessage *mDown = new BMessage(B_KEY_DOWN);
BMessage *mUp;
char states[16];
mDown->AddInt32("modifiers", 0x0);
mDown->AddInt32("key", 94);
mDown->AddInt32("raw_char", 32);
mDown->AddData("states", 'UBYT', states, sizeof(states));
mDown->AddString("bytes", " ");
mDown->AddData("byte", 'BYTE', " ", 1);
mUp = new BMessage(*mDown);
mUp->what = B_KEY_UP;
outList->AddItem(mDown);
outList->AddItem(mUp);
}
#endif
if (message->what == B_MOUSE_DOWN) {
int32 buttons;
int32 modifiers;
BPoint where;
if (message->FindInt32("buttons", &buttons) == B_OK) {
/* replace first with a button that likely won't exist,
* and so shouldn't cause any side effect (hmm err...) */
/* XXX: use get_mouse_map() ? */
if (buttons == B_PRIMARY_MOUSE_BUTTON)
//message->ReplaceInt32("buttons", 0x0000);
message->what = B_MOUSE_UP;
}
#if 0
outList->AddItem(new BMessage(*message));
BMessage *m = new BMessage(B_MOUSE_MOVED);
if (message->FindInt32("buttons", &buttons) == B_OK)
m->AddInt32("buttons", buttons);
if (message->FindInt32("modifiers", &modifiers) == B_OK)
m->AddInt32("modifiers", modifiers);
if (message->FindPoint("where", &where) == B_OK)
m->AddPoint("where", where);
outList->AddItem(m);
#endif
#if DEBUG
fDebugAlert->Lock();
fDebugAlert->TextView()->Insert(">>>\n");
fDebugAlert->Unlock();
#endif
#if 0
m = new BMessage(B_INPUT_METHOD_EVENT);
m->AddInt32("be:opcode", B_INPUT_METHOD_STARTED);
m->AddMessenger("be:reply_to", this);
EnqueueMessage(m);
m = new BMessage(B_INPUT_METHOD_EVENT);
m->AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
m->AddString("be:string", " ");
EnqueueMessage(m);
m = new BMessage(B_INPUT_METHOD_EVENT);
m->AddInt32("be:opcode", B_INPUT_METHOD_STOPPED);
EnqueueMessage(m);
sleep(3);
#endif
#if DEBUG
fDebugAlert->Lock();
fDebugAlert->TextView()->Insert("<<<\n");
fDebugAlert->Unlock();
#endif
}
return (res);
}
status_t PenInputServerMethod::MethodActivated(bool active)
{
fEnabled = active;
BMessage msg(MSG_METHOD_ACTIVATED);
if (active)
msg.AddBool(MSGF_ACTIVE, true);
fLooper.SendMessage( &msg );
return B_OK;
}
@@ -0,0 +1,45 @@
/*
Copyright 2005, Francois Revol. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _PEN_INPUT_SERVER_METHOD_H
#define _PEN_INPUT_SERVER_METHOD_H
#include <OS.h>
#include <Messenger.h>
#include <add-ons/input_server/InputServerMethod.h>
#if DEBUG
//#include <File.h>
class BAlert;
#endif
class BList;
class BMessage;
class PenInputLooper;
extern "C" _EXPORT BInputServerMethod* instantiate_input_method();
class PenInputServerMethod : public BInputServerMethod
{
public:
PenInputServerMethod();
virtual ~PenInputServerMethod();
virtual status_t InitCheck();
virtual filter_result Filter(BMessage *message, BList *outList);
virtual status_t MethodActivated(bool active);
bool IsEnabled() const { return fEnabled; };
private:
friend PenInputLooper;//DEBUG
bool fEnabled;
//BLocker fLocker;
BMessenger fLooper;
#if DEBUG
//BFile fDebugFile;
BAlert *fDebugAlert;
#endif
};
#endif /* _PEN_INPUT_SERVER_METHOD_H */
@@ -0,0 +1,12 @@
#ifndef _PEN_INPUT_STRINGS_H
#define _PEN_INPUT_STRINGS_H
#ifndef _T
#define _T(s) s
#endif
/* more to come */
#endif /* _PEN_INPUT_STRINGS_H */
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
quit application/x-vnd.Be-input_server
tagfile=/tmp/dokillinputserver
tmout=$((30))
touch $tagfile
(alert "All is fine" "Ok"; rm $tagfile) &
sleep $tmout
if [ -e $tagfile ]; then
rm ~/config/add-ons/input_server/methods/Pen
quit application/x-vnd.Be-input_server
kill -9 input_server
rm $tagfile
fi
+1
View File
@@ -0,0 +1 @@
/system/servers/input_server
@@ -0,0 +1,88 @@
/*
* minimalistic Dano-like BStringIO
* (c) 2007, François Revol.
*/
#include <BeBuild.h>
#ifndef B_BEOS_VERSION_DANO
#include <StringIO.h>
#include <Rect.h>
#include <unistd.h>
//#include <stdint.h>
// stripped down BStringIO
BStringIO::BStringIO()
{
fString = new BString;
}
BStringIO::~BStringIO()
{
delete fString;
}
ssize_t
BStringIO::ReadAt(off_t pos, void *buffer, size_t size)
{
return EIO;
}
ssize_t
BStringIO::WriteAt(off_t pos, const void *buffer, size_t size)
{
if (pos > (2147483647L)/*INT32_MAX*/)
return EINVAL;
if (fString->Length() < pos)
fString->Insert(' ', (int32)(pos - fString->Length()), fString->Length());
fString->Remove((int32)pos, size);
fString->Insert((const char *)buffer, size, (int32)pos);
return size;
}
off_t
BStringIO::Seek(off_t pos, uint32 seek_mode)
{
switch (seek_mode) {
case SEEK_CUR:
fPosition += pos;
return fPosition;
case SEEK_SET:
fPosition = pos;
return fPosition;
case SEEK_END:
fPosition = fString->Length() - pos;
if (fPosition < 0)
fPosition = 0;
return fPosition;
default:
return EINVAL;
}
}
off_t
BStringIO::Position() const
{
return fPosition;
}
status_t
BStringIO::SetSize(off_t size)
{
return EINVAL;
}
const char *
BStringIO::String() const
{
return fString->String();
}
// ops
BStringIO & BStringIO::operator<<(const BString & s) {this->BPositionIO::Write(s.String(), s.Length()); return *this;};
BStringIO & BStringIO::operator<<(const BRect & r) {BString s; s << "Rect{" << r.left << r.top << r.right << r.bottom << "}"; this->BPositionIO::Write(s.String(), s.Length()); return *this;};
#endif /* B_BEOS_VERSION_DANO */
@@ -0,0 +1,49 @@
/*
* minimalistic Dano-ilke BStringIO
* (c) 2007, François Revol.
*/
#include <BeBuild.h>
#ifdef B_BEOS_VERSION_DANO
#include_next <StringIO.h>
#else
#ifndef _STRING_IO_H
#define _STRING_IO_H
#include <String.h>
#include <DataIO.h>
//#include <stdint.h>
// stripped down BStringIO
class BStringIO : public BPositionIO {
public:
BStringIO();
virtual ~BStringIO();
virtual ssize_t ReadAt(off_t pos, void *buffer, size_t size);
virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t size);
virtual off_t Seek(off_t pos, uint32 seek_mode);
virtual off_t Position() const;
virtual status_t SetSize(off_t size);
// void SetBlockSize(size_t blocksize);
const char* String() const;
// size_t StringLength() const;
BStringIO & operator<<(const BString & s);
BStringIO & operator<<(const BRect & r);
private:
off_t fPosition;
BString *fString;
};
#endif /* _STRING_IO_H */
#endif
@@ -0,0 +1,192 @@
## ********************************* ##
## Zeta Generic Makefile v3.0 ##
## Fill in this file to specify the project being created, and the referenced
## makefile-engine will do all of the hard work for you.
## Application Specific Settings ---------------------------------------------
# specify the name of the binary
NAME := Pen
# specify the type of binary
# APP: Application
# SHARED: Shared library or add-on
# STATIC: Static library archive
# DRIVER: Kernel Driver
# MODULE: Kernel Module
# DECOR: A window decorator project
TYPE := SHARED
# add support for new Pe and Eddie features
# to fill in generic makefile
#%{
# @src->@
# specify the source files to use
# full paths or paths relative to the makefile can be included
# all files, regardless of directory, will have their object
# files created in the common object directory.
# Note that this means this makefile will not work correctly
# if two source files with the same name (source.c or source.cpp)
# are included from different directories. Also note that spaces
# in folder names do not work well with this makefile.
SRCS := PenInputServerMethod.cpp \
PenInputLooper.cpp \
PenInputInkWindow.cpp \
PenInputBackend.cpp \
DumpMessage.cpp \
compat/StringIO.cpp
# specify the resource files to use
# full path or a relative path to the resource file can be used.
RSRCS :=
# Specify your RDEF files, if any.
RDEFS :=
# @<-src@
#%}
# end support for Pe and Eddie
# specify additional libraries to link against
# there are two acceptable forms of library specifications
# - if your library follows the naming pattern of:
# libXXX.so or libXXX.a you can simply specify XXX
# library: libbe.so entry: be
#
# - if your library does not follow the standard library
# naming scheme you need to specify the path to the library
# and it's name
# library: my_lib.a entry: my_lib.a or path/my_lib.a
LIBS := _APP_ be
# specify additional paths to directories following the standard
# libXXX.so or libXXX.a naming scheme. You can specify full paths
# or paths relative to the makefile. The paths included may not
# be recursive, so include all of the paths where libraries can
# be found. Directories where source files are found are
# automatically included.
LIBPATHS :=
# additional paths to look for system headers
# thes use the form: #include <header>
# source file directories are NOT auto-included here
SYSTEM_INCLUDE_PATHS := compat
# additional paths to look for local headers
# thes use the form: #include "header"
# source file directories are automatically included
LOCAL_INCLUDE_PATHS :=
# specify the level of optimization that you desire
# NONE, SOME, FULL
OPTIMIZE :=
# specify any preprocessor symbols to be defined. The symbols will not
# have their values set automatically; you must supply the value (if any)
# to use. For example, setting DEFINES to "DEBUG=1" will cause the
# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG"
# would pass "-DDEBUG" on the compiler's command line.
DEFINES := DEBUG=1
# specify special warning levels
# if unspecified default warnings will be used
# NONE = supress all warnings
# ALL = enable all warnings
WARNINGS :=
# specify whether image symbols will be created
# so that stack crawls in the debugger are meaningful
# if TRUE symbols will be created
SYMBOLS :=
# specify debug settings
# if TRUE will allow application to be run from a source-level
# debugger. Note that this will disable all optimzation.
DEBUGGER :=
# specify additional compiler flags for all files
COMPILER_FLAGS :=
# specify additional linker flags
LINKER_FLAGS :=
# specify the version of this particular item
# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL")
#E This may also be specified in a resource.
APP_VERSION :=
# (for TYPE == DRIVER only) Specify desired location of driver in the /dev
# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will
# instruct the driverinstall rule to place a symlink to your driver's binary in
# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at
# /dev/video/usb when loaded. Default is "misc".
DRIVER_PATH :=
# Specify if you want the object files to be somewhere besides the default location.
OBJ_DIR :=
# Specify a non default placement for the target
TARGET_DIR :=
# Specify a directory for the 'install' target.
INSTALL_DIR :=
# Specify the name of this makefile.
# If you leave this blank, the makefile will not be considered as part of the
# dependenies for the project, and the project will not be rebuilt when the makefile
# is changed
MAKEFILE :=
# Specify TRUE if you want the install target to create links in the BeMenu
MENU_LINKS :=
# Related to MENU_LINKS, specify the name of the direcotry in the BeMenu
# you wish the link to go in. If the directory does not exist, it will be
# created.
APP_MENU :=
# If, for some reason, you don't want to use the dependencies (flex and yacc seem to choke
# on them), set this to false
DODEPS :=
# Set this variable if you have an svg text file you wish to use as your targets
# icon.
SVG_ICON :=
# If you have some fancy custom build steps to do, specify them here
EXTRA_BUILD_STEPS =
# If you have some other files that should trigger a re-link, such as libs in the same
# project that may get rebuilt, specify the full path to them here.
EXTRA_DEPS :=
###########################################################################################
# The following variables are commented out here because the can be very useful to just
# set at the command line or in the env at time of compiling, allowing you to leave your
# makefile the same, but change the build types easily.
# If you wish to have the program output a profiling session file which can be read by bprof,
# set this to 'true'
#BUILD_PROFILE :=
# If you wish to have a debug build,
# set this to 'true'
#BUILD_DEBUG :=
# If you wish to have a build which can do memory checking when MALLOC_DEBUG=15 is set,
# set this to 'true'
#CHECK_MEM :=
# If you want to see the complete build line for every file, then set this to 'true',
# otherwise it will tell you at the end what the build flags were.
#CHATTY :=
## include the makefile-engine
include $(BUILDHOME)/etc/makefile-engine