* Copyright 2005-2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
* Distributed under the terms of the MIT license.
*/
#include "MasterServerDevice.h"
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Directory.h>
#include <Entry.h>
#include <InterfaceDefs.h>
#include <Message.h>
#include <NodeMonitor.h>
#include <OS.h>
#include <Path.h>
#include <Screen.h>
#include <View.h>
#include <File.h>
#include "PointingDevice.h"
#include "PointingDeviceFactory.h"
#define DEFAULT_CLICK_SPEED 250000
static const char* kWatchFolder = "input/wacom/usb";
static const char* kDeviceFolder = "/dev/input/wacom/usb";
static const char* kDeviceName = "Wacom Tablet";
BInputServerDevice*
instantiate_input_device()
{
return (new MasterServerDevice());
}
MasterServerDevice::MasterServerDevice()
: BInputServerDevice(),
fDevices(1),
fActive(false),
fDblClickSpeed(DEFAULT_CLICK_SPEED),
fPS2DisablerThread(B_ERROR),
fDeviceLock("device list lock")
{
get_mouse_speed(kDeviceName, &fSpeed);
get_mouse_acceleration(kDeviceName, &fAcceleration);
get_click_speed(kDeviceName, &fDblClickSpeed);
_CalculateAccelerationTable();
if (_LockDevices()) {
_SearchDevices();
fActive = true;
for (int32 i = 0; PointingDevice* device = (PointingDevice*)fDevices.ItemAt(i); i++) {
device->Start();
}
_UnlockDevices();
}
StartMonitoringDevice(kWatchFolder);
}
MasterServerDevice::~MasterServerDevice()
{
_StopAll();
if (_LockDevices()) {
while (PointingDevice* device = (PointingDevice*)fDevices.RemoveItem((int32)0))
delete device;
_UnlockDevices();
}
}
status_t
MasterServerDevice::InitCheck()
{
return BInputServerDevice::InitCheck();
}
status_t
MasterServerDevice::SystemShuttingDown()
{
_StopAll();
PRINT(("---------------------------------\n\n"));
return (BInputServerDevice::SystemShuttingDown());
}
status_t
MasterServerDevice::Start(const char* device, void* cookie)
{
return B_OK;
}
status_t
MasterServerDevice::Stop(const char* device, void* cookie)
{
fActive = false;
_StopAll();
return StopMonitoringDevice(kWatchFolder);
}
status_t
MasterServerDevice::Control(const char* device, void* cookie, uint32 code, BMessage* message)
{
switch (code) {
case B_MOUSE_SPEED_CHANGED:
get_mouse_speed(device, &fSpeed);
_CalculateAccelerationTable();
break;
case B_CLICK_SPEED_CHANGED:
get_click_speed(device, &fDblClickSpeed);
break;
case B_MOUSE_ACCELERATION_CHANGED:
get_mouse_acceleration(device, &fAcceleration);
_CalculateAccelerationTable();
break;
case B_NODE_MONITOR:
_HandleNodeMonitor(message);
break;
default:
BInputServerDevice::Control(device, cookie, code, message);
break;
}
return B_OK;
}
void
MasterServerDevice::_SearchDevices()
{
if (_LockDevices()) {
BDirectory dir(kDeviceFolder);
if (dir.InitCheck() >= B_OK) {
entry_ref ref;
while (dir.GetNextRef(&ref) >= B_OK) {
PRINT(("examining devfs entry '%s'\n", ref.name));
if (strcmp(ref.name, "control") != 0) {
BPath path(&ref);
if (path.InitCheck() >= B_OK) {
_AddDevice(path.Path());
}
}
}
} else
PRINT(("folder '%s' not found\n", kDeviceFolder));
PRINT(("done examing devfs\n"));
_UnlockDevices();
}
}
void
MasterServerDevice::_StopAll()
{
if (_LockDevices()) {
for (int32 i = 0; PointingDevice* device
= (PointingDevice*)fDevices.ItemAt(i); i++)
device->Stop();
_UnlockDevices();
}
}
void
MasterServerDevice::_AddDevice(const char* path)
{
if (_LockDevices()) {
PointingDevice* device = PointingDeviceFactory::DeviceFor(this, path);
if (device && device->InitCheck() >= B_OK
&& fDevices.AddItem((void*)device)) {
PRINT(("pointing device added (%s)\n", path));
if (fActive)
device->Start();
input_device_ref device = { (char*)kDeviceName, B_POINTING_DEVICE, (void*)this };
input_device_ref* deviceList[2] = { &device, NULL };
RegisterDevices(deviceList);
} else {
PRINT(("pointing device not added (%s)\n", path));
if (device) {
PRINT((" vendor: %0*x, product: %0*x\n", 4, device->VendorID(),
4, device->ProductID()));
}
delete device;
}
_UnlockDevices();
}
}
void
MasterServerDevice::_HandleNodeMonitor(BMessage* message)
{
int32 opcode;
if (message->FindInt32("opcode", &opcode) < B_OK)
return;
switch (opcode) {
case B_ENTRY_CREATED:
const char* name;
ino_t directory;
dev_t device;
if (message->FindString("name", &name) >= B_OK
&& strcmp(name, "control") != 0
&& message->FindInt64("directory", (int64*)&directory) >= B_OK
&& message->FindInt32("device", (int32*)&device) >= B_OK) {
entry_ref ref(device, directory, name);
BPath path(&ref);
if (path.InitCheck() >= B_OK) {
_AddDevice(path.Path());
}
}
break;
case B_ENTRY_REMOVED: {
BDirectory dir(kDeviceFolder);
if (dir.InitCheck() >= B_OK) {
for (int32 i = 0; PointingDevice* pointingDevice
= (PointingDevice*)fDevices.ItemAt(i); i++) {
entry_ref ref;
dir.Rewind();
bool found = false;
while (dir.GetNextRef(&ref) >= B_OK) {
BPath path(&ref);
if (strcmp(pointingDevice->DevicePath(),
path.Path()) == 0) {
found = true;
break;
}
}
if (!found) {
PRINT(("removing device '%s'\n", pointingDevice->DevicePath()));
if (_LockDevices()) {
if (fDevices.RemoveItem((void*)pointingDevice)) {
delete pointingDevice;
i--;
}
_UnlockDevices();
}
}
}
}
break;
}
}
}
void
MasterServerDevice::_CalculateAccelerationTable()
{
for (int x = 1; x <= 128; x++){
fAccelerationTable[x] = (x / (128 * (1 - (((float)fSpeed + 8192) / 262144))))
* (x / (128 * (1 - (((float)fSpeed + 8192) / 262144))))
+ ((((float)fAcceleration + 4000) / 262144)
* (x / (128 * (1 - (((float)fSpeed + 8192) / 262144)))));
}
for (int x = 255; x > 128; x--){
fAccelerationTable[x] = -(fAccelerationTable[(255 - x)]);
}
fAccelerationTable[0] = fAccelerationTable[1] / 2;
fAccelerationTable[255] = -fAccelerationTable[0];
}
bool
MasterServerDevice::_LockDevices()
{
return fDeviceLock.Lock();
}
void
MasterServerDevice::_UnlockDevices()
{
fDeviceLock.Unlock();
}