#include "JoyWin.h"
#include "MessageWin.h"
#include "CalibWin.h"
#include "Global.h"
#include "PortItem.h"
#include <stdio.h>
#include <stdlib.h>
#include <Box.h>
#include <Button.h>
#include <CheckBox.h>
#include <ListView.h>
#include <ListItem.h>
#include <ScrollView.h>
#include <String.h>
#include <StringView.h>
#include <Application.h>
#include <View.h>
#include <Path.h>
#include <Entry.h>
#include <Directory.h>
#include <Alert.h>
#include <File.h>
#include <SymLink.h>
#include <Messenger.h>
#include <Directory.h>
#include <Joystick.h>
#include <FindDirectory.h>
#include <Joystick.h>
#define JOYSTICKPATH "/dev/joystick/"
#define JOYSTICKFILEPATH "/boot/system/data/joysticks/"
#define JOYSTICKFILESETTINGS "/boot/home/config/settings/joysticks/"
#define SELECTGAMEPORTFIRST "Select a game port first"
static int
ShowMessage(char* string)
{
BAlert *alert = new BAlert("Message", string, "OK");
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
return alert->Go();
}
JoyWin::JoyWin(BRect frame, const char *title)
: BWindow(frame, title, B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_NOT_ZOOMABLE), fSystemUsedSelect(false),
fJoystick(new BJoystick)
{
fProbeButton = new BButton(BRect(15.00, 260.00, 115.00, 285.00),
"ProbeButton", "Probe", new BMessage(PROBE));
fCalibrateButton = new BButton(BRect(270.00, 260.00, 370.00, 285.00),
"CalibrateButton", "Calibrate", new BMessage(CALIBRATE));
fGamePortL = new BListView(BRect(15.00, 30.00, 145.00, 250.00),
"gamePort");
fGamePortL->SetSelectionMessage(new BMessage(PORT_SELECTED));
fGamePortL->SetInvocationMessage(new BMessage(PORT_INVOKE));
fConControllerL = new BListView(BRect(175.00,30.00,370.00,250.00),
"conController");
fConControllerL->SetSelectionMessage(new BMessage(JOY_SELECTED));
fConControllerL->SetInvocationMessage(new BMessage(JOY_INVOKE));
fGamePortS = new BStringView(BRect(15, 5, 160, 25), "gpString",
"Game port");
fGamePortS->SetFont(be_bold_font);
fConControllerS = new BStringView(BRect(170, 5, 330, 25), "ccString",
"Connected controller");
fConControllerS->SetFont(be_bold_font);
fCheckbox = new BCheckBox(BRect(131.00, 260.00, 227.00, 280.00),
"Disabled", "Disabled", new BMessage(DISABLEPORT));
BBox *box = new BBox( Bounds(),"box", B_FOLLOW_ALL,
B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE,
B_PLAIN_BORDER);
box->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
box->AddChild(new BScrollView("PortScroll", fGamePortL,
B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW, false, true));
box->AddChild(new BScrollView("ConScroll", fConControllerL, B_FOLLOW_ALL,
B_WILL_DRAW, false, true));
box->AddChild(fCheckbox);
box->AddChild(fGamePortS);
box->AddChild(fConControllerS);
box->AddChild(fProbeButton);
box->AddChild(fCalibrateButton);
AddChild(box);
SetSizeLimits(400, 600, Bounds().Height(), Bounds().Height());
int32 nr = fJoystick->CountDevices();
for (int32 i = 0; i < nr;i++) {
char buf[B_OS_NAME_LENGTH];
fJoystick->GetDeviceName(i, buf, B_OS_NAME_LENGTH);
fGamePortL->AddItem(new PortItem(buf));
}
fGamePortL->Select(0);
_AddToList(fConControllerL, JOY_SELECTED, JOYSTICKFILEPATH);
_GetSettings();
}
JoyWin::~JoyWin()
{
be_app_messenger.SendMessage(B_QUIT_REQUESTED);
}
void
JoyWin::MessageReceived(BMessage *message)
{
switch(message->what)
{
case DISABLEPORT:
break;
{
PortItem *item = _GetSelectedItem(fGamePortL);
if (item != NULL) {
if(fCheckbox->Value()) {
item->SetEnabled(false);
_SelectDeselectJoystick(fConControllerL, false);
} else {
item->SetEnabled(true);
_SelectDeselectJoystick(fConControllerL, true);
_PerformProbe(item->Text());
}
}
break;
}
case PORT_SELECTED:
{
PortItem *item = _GetSelectedItem(fGamePortL);
if (item != NULL) {
fSystemUsedSelect = true;
if (item->IsEnabled()) {
fCheckbox->SetValue(false);
_SelectDeselectJoystick(fConControllerL, true);
} else {
fCheckbox->SetValue(true);
_SelectDeselectJoystick(fConControllerL, false);
}
if (_CheckJoystickExist(item->Text()) == B_ERROR) {
if (_ShowCantFindFileMessage(item->Text()) == B_OK) {
_PerformProbe(item->Text());
}
} else {
BString str(_FindFilePathForSymLink(JOYSTICKFILESETTINGS,
item));
if (str != NULL) {
BString str(_FixPathToName(str.String()));
int32 id = _FindStringItemInList(fConControllerL,
new PortItem(str.String()));
if (id > -1) {
fConControllerL->Select(id);
item->SetJoystickName(BString(str.String()));
}
}
}
} else {
fConControllerL->DeselectAll();
ShowMessage((char*)SELECTGAMEPORTFIRST);
}
break;
}
case PROBE:
case PORT_INVOKE:
{
PortItem *item = _GetSelectedItem(fGamePortL);
if (item != NULL) {
_PerformProbe(item->Text());
} else
ShowMessage((char*)SELECTGAMEPORTFIRST);
break;
}
case JOY_SELECTED:
{
if (!fSystemUsedSelect) {
PortItem *controllerName = _GetSelectedItem(fConControllerL);
PortItem *portname = _GetSelectedItem(fGamePortL);
if (portname != NULL && controllerName != NULL) {
portname->SetJoystickName(BString(controllerName->Text()));
BString str = portname->GetOldJoystickName();
if (str != NULL) {
BString strOldFile(JOYSTICKFILESETTINGS);
strOldFile.Append(portname->Text());
BEntry entry(strOldFile.String());
entry.Remove();
}
BString strLinkPlace(JOYSTICKFILESETTINGS);
strLinkPlace.Append(portname->Text());
BString strLinkTo(JOYSTICKFILEPATH);
strLinkTo.Append(controllerName->Text());
BDirectory *dir = new BDirectory();
dir->CreateSymLink(strLinkPlace.String(),
strLinkTo.String(), NULL);
} else
ShowMessage((char*)SELECTGAMEPORTFIRST);
}
fSystemUsedSelect = false;
break;
}
case CALIBRATE:
case JOY_INVOKE:
{
PortItem *controllerName = _GetSelectedItem(fConControllerL);
PortItem *portname = _GetSelectedItem(fGamePortL);
if (portname != NULL) {
if (controllerName == NULL)
_ShowNoDeviceConnectedMessage("known", portname->Text());
else {
_ShowNoDeviceConnectedMessage(controllerName->Text(), portname->Text());
}
} else
ShowMessage((char*)SELECTGAMEPORTFIRST);
break;
}
default:
BWindow::MessageReceived(message);
break;
}
}
bool
JoyWin::QuitRequested()
{
_ApplyChanges();
return BWindow::QuitRequested();
}
status_t
JoyWin::_AddToList(BListView *list, uint32 command, const char* rootPath,
BEntry *rootEntry)
{
BDirectory root;
if ( rootEntry != NULL )
root.SetTo( rootEntry );
else if ( rootPath != NULL )
root.SetTo( rootPath );
else
return B_ERROR;
BEntry entry;
while ((root.GetNextEntry(&entry)) > B_ERROR ) {
if (entry.IsDirectory()) {
_AddToList(list, command, rootPath, &entry);
} else {
BPath path;
entry.GetPath(&path);
BString str(path.Path());
str.RemoveFirst(rootPath);
list->AddItem(new PortItem(str.String()));
}
}
return B_OK;
}
status_t
JoyWin::_Calibrate()
{
CalibWin* calibw;
BRect rect(100, 100, 500, 400);
calibw = new CalibWin(rect, "Calibrate", B_DOCUMENT_WINDOW_LOOK,
B_NORMAL_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_ZOOMABLE);
calibw->Show();
return B_OK;
}
status_t
JoyWin::_PerformProbe(const char* path)
{
status_t err = B_ERROR;
err = _ShowProbeMesage(path);
if (err != B_OK) {
return err;
}
MessageWin* mesgw = new MessageWin(Frame(),"Probing", B_MODAL_WINDOW_LOOK,
B_MODAL_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_ZOOMABLE);
mesgw->Show();
int32 number = fConControllerL->CountItems();
PortItem *item;
for (int i = 0; i < number; i++) {
fConControllerL->Select(i);
int32 selected = fConControllerL->CurrentSelection();
item = dynamic_cast<PortItem*>(fConControllerL->ItemAt(selected));
BString str("Looking for: ");
str << item->Text() << " in port " << path;
mesgw->SetText(str.String());
_FindSettingString(item->Text(), JOYSTICKFILEPATH);
}
mesgw->Hide();
_ShowNoCompatibleJoystickMessage();
return B_OK;
}
status_t
JoyWin::_ApplyChanges()
{
BString str = _BuildDisabledJoysticksFile();
return B_OK;
}
status_t
JoyWin::_GetSettings()
{
return B_OK;
}
status_t
JoyWin::_CheckJoystickExist(const char* path)
{
BString str(JOYSTICKFILESETTINGS);
str << path;
BFile file;
status_t status = file.SetTo(str.String(), B_READ_ONLY | B_FAIL_IF_EXISTS);
if (status == B_FILE_EXISTS || status == B_OK)
return B_OK;
else
return B_ERROR;
}
status_t
JoyWin::_ShowProbeMesage(const char* device)
{
BString str("An attempt will be made to probe the port '");
str << device << "' to try to figure out what kind of joystick (if any) ";
str << "are attached. There is a small chance this process might cause ";
str << "your machine to lock up and require a reboot. Make sure you have ";
str << "saved changes in all open applications before you start probing.";
BAlert *alert = new BAlert("test1", str.String(), "Probe", "Cancel");
alert->SetShortcut(1, B_ESCAPE);
int32 bindex = alert->Go();
if (bindex == 0)
return B_OK;
else
return B_ERROR;
}
status_t
JoyWin::_ShowCantFindFileMessage(const char* port)
{
BString str("The file '");
str << _FixPathToName(port).String() << "' used by '" << port;
str << "' cannot be found.\n Do you want to ";
str << "try auto-detecting a joystick for this port?";
BAlert *alert = new BAlert("test1", str.String(), "Stop", "Probe");
alert->SetShortcut(1, B_ENTER);
int32 bindex = alert->Go();
if (bindex == 1)
return B_OK;
else
return B_ERROR;
}
void
JoyWin::_ShowNoCompatibleJoystickMessage()
{
BString str("There were no compatible joysticks detected on this game");
str << " port. Try another port, or ask the manufacturer of your joystick";
str << " for a driver designed for Haiku or BeOS.";
BAlert *alert = new BAlert("test1", str.String(), "OK");
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
}
void
JoyWin::_ShowNoDeviceConnectedMessage(const char* joy, const char* port)
{
BString str("There does not appear to be a ");
str << joy << " device connected to the port '" << port << "'.";
BAlert *alert = new BAlert("test1", str.String(), "Stop");
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
}
BString
JoyWin::_BuildDisabledJoysticksFile()
{
BString temp("# This is a list of disabled joystick devices.");
temp << "# Do not include the /dev/joystick/ part of the device name.";
int32 number = fGamePortL->CountItems();
PortItem *item;
for (int i = 0; i < number; i++) {
item = dynamic_cast<PortItem*>(fGamePortL->ItemAt(i));
if (!item->IsEnabled())
temp << "disable = \"" << item->Text() << "\"";
}
return temp;
}
PortItem*
JoyWin::_GetSelectedItem(BListView* list)
{
int32 id = list->CurrentSelection();
if (id > -1) {
return dynamic_cast<PortItem*>(list->ItemAt(id));
} else {
return NULL;
}
}
BString
JoyWin::_FixPathToName(const char* port)
{
BString temp(port);
temp = temp.Remove(0, temp.FindLast('/') + 1) ;
return temp;
}
void
JoyWin::_SelectDeselectJoystick(BListView* list, bool enable)
{
list->DeselectAll();
int32 number = fGamePortL->CountItems();
PortItem *item;
for (int i = 0; i < number; i++) {
item = dynamic_cast<PortItem*>(list->ItemAt(i));
if (!item) {
printf("%s: PortItem at %d is null!\n", __func__, i);
continue;
}
item->SetEnabled(enable);
}
}
int32
JoyWin::_FindStringItemInList(BListView *view, PortItem *item)
{
PortItem *strItem = NULL;
int32 number = view->CountItems();
for (int32 i = 0; i < number; i++) {
strItem = dynamic_cast<PortItem*>(view->ItemAt(i));
if (!strcmp(strItem->Text(), item->Text())) {
return i;
}
}
delete strItem;
return -1;
}
BString
JoyWin::_FindFilePathForSymLink(const char* symLinkPath, PortItem *item)
{
BPath path(symLinkPath);
path.Append(item->Text());
BEntry entry(path.Path());
if (entry.IsSymLink()) {
BSymLink symLink(&entry);
BDirectory parent;
entry.GetParent(&parent);
symLink.MakeLinkedPath(&parent, &path);
BString str(path.Path());
return str;
}
return NULL;
}
status_t
JoyWin::_FindStick(const char* name)
{
BJoystick *stick = new BJoystick();
return stick->Open(name);
}
const char*
JoyWin::_FindSettingString(const char* name, const char* strPath)
{
BString str;
BPath path(strPath);
path.Append(name);
fFileTempProbeJoystick = new BFile(path.Path(), B_READ_ONLY);
status_t err = fFileTempProbeJoystick->InitCheck();
if (err == B_OK) {
return "";
} else
printf("BFile.SetTo error: %s, Path = %s\n", strerror(err), str.String());
return "";
}