/* * Copyright 2007-2009 Haiku. * Distributed under the terms of the MIT License. * * Authors: * Oliver Ruiz Dorantes oliver.ruiz.dorantes_at_gmail.com * Ryan Leavengood leavengood@gmail.com * Fredrik Modéen fredrik@modeen.se */ #include "JoyWin.h" #include "MessageWin.h" #include "CalibWin.h" #include "Global.h" #include "PortItem.h" //#include "FileReadWrite.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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); // Add listViews with their scrolls 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)); // Adding object box->AddChild(fCheckbox); box->AddChild(fGamePortS); box->AddChild(fConControllerS); box->AddChild(fProbeButton); box->AddChild(fCalibrateButton); AddChild(box); SetSizeLimits(400, 600, Bounds().Height(), Bounds().Height()); /* Add all the devices */ int32 nr = fJoystick->CountDevices(); for (int32 i = 0; i < nr;i++) { //BString str(path.Path()); char buf[B_OS_NAME_LENGTH]; fJoystick->GetDeviceName(i, buf, B_OS_NAME_LENGTH); fGamePortL->AddItem(new PortItem(buf)); } fGamePortL->Select(0); /* Add the joysticks specifications */ _AddToList(fConControllerL, JOY_SELECTED, JOYSTICKFILEPATH); _GetSettings(); } JoyWin::~JoyWin() { //delete fFileTempProbeJoystick; be_app_messenger.SendMessage(B_QUIT_REQUESTED); } void JoyWin::MessageReceived(BMessage *message) { // message->PrintToStream(); switch(message->what) { case DISABLEPORT: break; { PortItem *item = _GetSelectedItem(fGamePortL); if (item != NULL) { //ToDo: item->SetEnabled(true); //don't work as you can't select a item that are disabled if(fCheckbox->Value()) { item->SetEnabled(false); _SelectDeselectJoystick(fConControllerL, false); } else { item->SetEnabled(true); _SelectDeselectJoystick(fConControllerL, true); _PerformProbe(item->Text()); } } //else //printf("We have a null value\n"); break; } case PORT_SELECTED: { PortItem *item = _GetSelectedItem(fGamePortL); if (item != NULL) { fSystemUsedSelect = true; if (item->IsEnabled()) { //printf("SetEnabled = false\n"); fCheckbox->SetValue(false); _SelectDeselectJoystick(fConControllerL, true); } else { //printf("SetEnabled = true\n"); 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) { //printf("invoke.. inte null\n"); _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()); /* ToDo: Check for a device, and show calibrate window if so */ } } else ShowMessage((char*)SELECTGAMEPORTFIRST); break; } default: BWindow::MessageReceived(message); break; } } bool JoyWin::QuitRequested() { _ApplyChanges(); return BWindow::QuitRequested(); } //---------------------- Private ---------------------------------// 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++) { // Do a search in JOYSTICKFILEPATH with item->Text() find the string // that starts with "gadget" (tex gadget = "GamePad Pro") remove // spacing and the "=" ty to open this one, if failed move to next and // try to open.. list those that suxesfully work fConControllerL->Select(i); int32 selected = fConControllerL->CurrentSelection(); item = dynamic_cast(fConControllerL->ItemAt(selected)); BString str("Looking for: "); str << item->Text() << " in port " << path; mesgw->SetText(str.String()); _FindSettingString(item->Text(), JOYSTICKFILEPATH); //Need a check to find joysticks (don't know how right now so show a // don't find message) } mesgw->Hide(); //Need a if !found then show this message. else list joysticks. _ShowNoCompatibleJoystickMessage(); return B_OK; } status_t JoyWin::_ApplyChanges() { BString str = _BuildDisabledJoysticksFile(); //ToDo; Save the string as the file "disabled_joysticks" under settings // (/boot/home/config/settings/disabled_joysticks) return B_OK; } status_t JoyWin::_GetSettings() { // ToDo; Read the file "disabled_joysticks" and make the port with the // same name disabled (/boot/home/config/settings/disabled_joysticks) 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; } //Used when a files/joysticks are no were to be found 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(); } // Use this function to get a string of disabled ports 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(fGamePortL->ItemAt(i)); if (!item->IsEnabled()) temp << "disable = \"" << item->Text() << "\""; } return temp; } PortItem* JoyWin::_GetSelectedItem(BListView* list) { int32 id = list->CurrentSelection(); if (id > -1) { //PortItem *item = dynamic_cast(list->ItemAt(id)); return dynamic_cast(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(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(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) { //Make a BJoystick try open it BString str; BPath path(strPath); path.Append(name); fFileTempProbeJoystick = new BFile(path.Path(), B_READ_ONLY); //status_t err = find_directory(B_SYSTEM_ETC_DIRECTORY, &path); // if (err == B_OK) { //BString str(path.Path()); //str << "/joysticks/" << name; //printf("path'%s'\n", str.String()); //err = file->SetTo(strPath, B_READ_ONLY); status_t err = fFileTempProbeJoystick->InitCheck(); if (err == B_OK) { //FileReadWrite frw(fFileTempProbeJoystick); //printf("Get going\n"); //printf("Opening file = %s\n", path.Path()); //while (frw.Next(str)) { //printf("In While loop\n"); // printf("getline %s \n", str.String()); //Test to open joystick with x number //} /*while (_GetLine(str)) { //printf("In While loop\n"); printf("getline %s \n", str.String()); //Test to open joystick with x number }*/ return ""; } else printf("BFile.SetTo error: %s, Path = %s\n", strerror(err), str.String()); // } else // printf("find_directory error: %s\n", strerror(err)); // delete file; return ""; } /* //Function to get a line from a file bool JoyWin::_GetLine(BString& string) { // Fill up the buffer with the first chunk of code if (fPositionInBuffer == 0) fAmtRead = fFileTempProbeJoystick->Read(&fBuffer, sizeof(fBuffer)); while (fAmtRead > 0) { while (fPositionInBuffer < fAmtRead) { // Return true if we hit a newline or the end of the file if (fBuffer[fPositionInBuffer] == '\n') { fPositionInBuffer++; //Convert begin int32 state = 0; int32 bufferLen = string.Length(); int32 destBufferLen = bufferLen; char destination[destBufferLen]; // if (fSourceEncoding) // convert_to_utf8(fSourceEncoding, string.String(), &bufferLen, destination, &destBufferLen, &state); string = destination; return true; } string += fBuffer[fPositionInBuffer]; fPositionInBuffer++; } // Once the buffer runs out, grab some more and start again fAmtRead = fFileTempProbeJoystick->Read(&fBuffer, sizeof(fBuffer)); fPositionInBuffer = 0; } return false; } */